summaryrefslogtreecommitdiff
path: root/compiler_and_linker/FrontEnd
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_and_linker/FrontEnd')
-rw-r--r--compiler_and_linker/FrontEnd/C/CABI.c2033
-rw-r--r--compiler_and_linker/FrontEnd/C/CBrowse.c737
-rw-r--r--compiler_and_linker/FrontEnd/C/CClass.c2312
-rw-r--r--compiler_and_linker/FrontEnd/C/CDecl.c4845
-rw-r--r--compiler_and_linker/FrontEnd/C/CError.c1098
-rw-r--r--compiler_and_linker/FrontEnd/C/CException.c2183
-rw-r--r--compiler_and_linker/FrontEnd/C/CExpr.c4971
-rw-r--r--compiler_and_linker/FrontEnd/C/CExpr2.c4206
-rw-r--r--compiler_and_linker/FrontEnd/C/CExprConvMatch.c2518
-rw-r--r--compiler_and_linker/FrontEnd/C/CFunc.c3224
-rw-r--r--compiler_and_linker/FrontEnd/C/CInit.c3082
-rw-r--r--compiler_and_linker/FrontEnd/C/CInline.c4206
-rw-r--r--compiler_and_linker/FrontEnd/C/CMangler.c713
-rw-r--r--compiler_and_linker/FrontEnd/C/CParser.c3477
-rw-r--r--compiler_and_linker/FrontEnd/C/CPrec.c3482
-rw-r--r--compiler_and_linker/FrontEnd/C/CPrep.c2
-rw-r--r--compiler_and_linker/FrontEnd/C/CPreprocess.c676
-rw-r--r--compiler_and_linker/FrontEnd/C/CRTTI.c940
-rw-r--r--compiler_and_linker/FrontEnd/C/CSOM.c2068
-rw-r--r--compiler_and_linker/FrontEnd/C/CTemplateClass.c1632
-rw-r--r--compiler_and_linker/FrontEnd/C/CTemplateFunc.c1383
-rw-r--r--compiler_and_linker/FrontEnd/C/CTemplateNew.c1880
-rw-r--r--compiler_and_linker/FrontEnd/C/CTemplateTools.c1962
-rw-r--r--compiler_and_linker/FrontEnd/Common/CIRTransform.c534
-rw-r--r--compiler_and_linker/FrontEnd/Common/COptimizer.c1831
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/BitVector.h36
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IROUseDef.c1432
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IROUseDef.h48
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.c400
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.h30
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroBitVect.c112
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroCSE.c1038
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroCSE.h45
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroDump.c660
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroDump.h27
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c560
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.h8
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroEval.c914
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroEval.h14
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.c1531
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.h8
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.c439
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.h97
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroJump.c267
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroJump.h12
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.c1797
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.h165
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroLoop.c2324
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroLoop.h111
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c564
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroMalloc.h15
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.c5734
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.h25
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysisADTs.c2736
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c593
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroPropagate.h35
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c774
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.h8
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroSubable.c160
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroSubable.h10
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroTransform.c2794
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroTransform.h13
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.c2305
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.h23
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroUtil.c1262
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroUtil.h127
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroVars.c1430
-rw-r--r--compiler_and_linker/FrontEnd/Optimizer/IroVars.h51
68 files changed, 86728 insertions, 1 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CABI.c b/compiler_and_linker/FrontEnd/C/CABI.c
new file mode 100644
index 0000000..2a88de1
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CABI.c
@@ -0,0 +1,2033 @@
+#include "compiler/CABI.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CException.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInit.h"
+#include "compiler/CInline.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CScope.h"
+#include "compiler/CSOM.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/types.h"
+
+typedef struct OffsetList {
+ struct OffsetList *next;
+ SInt32 offset;
+} OffsetList;
+
+static OffsetList *trans_vtboffsets;
+static BClassList cabi_pathroot;
+static BClassList *cabi_pathcur;
+static TypeClass *cabi_loop_class;
+static Boolean cabi_loop_construct;
+
+short CABI_GetStructResultArgumentIndex(TypeFunc *tfunc) {
+ return 0;
+}
+
+Type *CABI_GetSizeTType(void) {
+ return TYPE(&stunsignedlong);
+}
+
+Type *CABI_GetPtrDiffTType(void) {
+ return TYPE(&stsignedlong);
+}
+
+SInt16 CABI_StructSizeAlignValue(Type *type, SInt32 size) {
+ SInt16 align = CMach_GetTypeAlign(type);
+ if (align <= 1)
+ return 0;
+ else
+ return (align - 1) & (align - ((size & (align - 1))));
+}
+
+void CABI_ReverseBitField(TypeBitfield *tbitfield) {
+ UInt8 bits;
+ UInt8 a;
+ UInt8 b;
+
+ switch (tbitfield->bitfieldtype->size) {
+ case 1:
+ bits = 8;
+ break;
+ case 2:
+ bits = 16;
+ break;
+ case 4:
+ bits = 32;
+ break;
+ case 8:
+ bits = 64;
+ break;
+ default:
+ CError_FATAL(172);
+ }
+
+ b = tbitfield->bitlength;
+ a = tbitfield->offset;
+ tbitfield->offset = (bits - a) - b;
+}
+
+static void CABI_AllocateZeroVTablePointer(void *unk, TypeClass *tclass) {
+ ClassList *base;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (!base->is_virtual && base->base->vtable)
+ return;
+ }
+
+ tclass->size += void_ptr.size;
+}
+
+static SInt32 CABI_GetBaseSize(TypeClass *tclass) {
+ SInt32 size = tclass->size;
+
+ if (copts.vbase_abi_v2 && tclass->vbases)
+ return tclass->vbases->offset;
+
+ return size;
+}
+
+static void CABI_AllocateBases(ClassLayout *layout, TypeClass *tclass) {
+ Boolean flag;
+ TypeClass *baseclass;
+ ClassList *base;
+ VClassList *vbase;
+ SInt32 size;
+
+ flag = 0;
+ size = tclass->size;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (!base->is_virtual) {
+ baseclass = base->base;
+ if (!(baseclass->flags & CLASS_EMPTY)) {
+ base->offset = size + CMach_MemberAlignValue(TYPE(baseclass), size);
+ if (copts.vbase_abi_v2) {
+ size = base->offset + CABI_GetBaseSize(baseclass);
+ } else {
+ size = base->offset + baseclass->size;
+ for (vbase = baseclass->vbases; vbase; vbase = vbase->next)
+ size -= vbase->base->size;
+ }
+ flag = 0;
+ } else {
+ if (flag)
+ base->offset = ++size;
+ else
+ base->offset = size;
+ flag = 1;
+ }
+ }
+ }
+
+ tclass->size = size;
+}
+
+static void CABI_AllocateVirtualBasePointers(ClassLayout *layout, TypeClass *tclass) {
+ ClassList *base;
+ SInt32 size;
+
+ size = tclass->size;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (base->is_virtual) {
+ base->offset = size + CMach_MemberAlignValue(TYPE(&void_ptr), size);
+ size = base->offset + void_ptr.size;
+ }
+ }
+
+ tclass->size = size;
+}
+
+static SInt32 CABI_GetMemberOffset(TypeClass *tclass, HashNameNode *name) {
+ ObjMemberVar *ivar;
+
+ if (!name)
+ return 0;
+
+ ivar = tclass->ivars;
+ while (1) {
+ if (ivar->name == name)
+ return ivar->offset;
+
+ if (!(ivar = ivar->next))
+ CError_FATAL(362);
+ }
+}
+
+static void CABI_AllocateMembers(ClassLayout *layout, TypeClass *tclass) {
+ ObjMemberVar *ivar;
+ SInt32 initialSize;
+ SInt32 maxSize;
+ TypeClass *unionClass;
+ SInt32 unionStart;
+ Boolean inAnonUnion;
+ Boolean removeNoNameIvars;
+
+ removeNoNameIvars = 0;
+ initialSize = maxSize = tclass->size;
+ CMach_StructLayoutInitOffset(maxSize);
+
+ unionClass = NULL;
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ if (!ivar->anonunion) {
+ if (!(ivar->offset & 0x80000000)) {
+ if (tclass->mode == CLASS_MODE_UNION)
+ CMach_StructLayoutInitOffset(initialSize);
+
+ if (IS_TYPE_BITFIELD(ivar->type))
+ ivar->offset = CMach_StructLayoutBitfield(TYPE_BITFIELD(ivar->type), ivar->qual);
+ else
+ ivar->offset = CMach_StructLayoutGetOffset(ivar->type, ivar->qual);
+
+ if (tclass->mode == CLASS_MODE_UNION) {
+ SInt32 tmp = CMach_StructLayoutGetCurSize();
+ if (tmp > maxSize)
+ maxSize = tmp;
+ }
+
+ unionClass = NULL;
+ } else {
+ CError_ASSERT(412, unionClass);
+ ivar->offset = unionStart + CABI_GetMemberOffset(unionClass, ivar->name);
+ if (!inAnonUnion)
+ ivar->anonunion = 1;
+ inAnonUnion = 0;
+ }
+
+ if (ivar->name == no_name_node || ivar->name == NULL)
+ removeNoNameIvars = 1;
+ } else {
+ CError_ASSERT(422, IS_TYPE_CLASS(ivar->type));
+
+ if (tclass->mode == CLASS_MODE_UNION)
+ CMach_StructLayoutInitOffset(initialSize);
+
+ unionStart = CMach_StructLayoutGetOffset(ivar->type, ivar->qual);
+ unionClass = TYPE_CLASS(ivar->type);
+ inAnonUnion = 1;
+
+ if (tclass->mode == CLASS_MODE_UNION) {
+ SInt32 tmp = CMach_StructLayoutGetCurSize();
+ if (tmp > maxSize)
+ maxSize = tmp;
+ }
+
+ removeNoNameIvars = 1;
+ }
+
+ if (layout->vtable_ivar == ivar)
+ tclass->vtable->offset = ivar->offset;
+ }
+
+ if (removeNoNameIvars) {
+ ObjMemberVar **ptr = &tclass->ivars;
+ while (*ptr) {
+ if ((*ptr)->name == NULL || (*ptr)->name == no_name_node)
+ *ptr = (*ptr)->next;
+ else
+ ptr = &(*ptr)->next;
+ }
+ }
+
+ if (tclass->mode == CLASS_MODE_UNION)
+ tclass->size = maxSize;
+ else
+ tclass->size = CMach_StructLayoutGetCurSize();
+
+ if (copts.reverse_bitfields) {
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ if (IS_TYPE_BITFIELD(ivar->type))
+ CABI_ReverseBitField(TYPE_BITFIELD(ivar->type));
+ }
+ }
+}
+
+static void CABI_AllocateVirtualBases(ClassLayout *layout, TypeClass *tclass) {
+ VClassList *vbase;
+ SInt32 size;
+
+ size = tclass->size;
+
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ vbase->offset = size + CMach_MemberAlignValue(TYPE(vbase->base), size);
+ size = vbase->offset + CABI_GetBaseSize(vbase->base);
+
+ if (vbase->has_override)
+ size += CMach_MemberAlignValue(TYPE(&stunsignedlong), size) + 4;
+ }
+
+ tclass->size = size;
+}
+
+static Boolean CABI_FindZeroDeltaVPtr(TypeClass *tclass) {
+ ClassList *base;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (!base->is_virtual && base->base->vtable && !base->offset) {
+ tclass->vtable->offset = base->base->vtable->offset;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static Object *CABI_FindZeroVirtualBaseMember(TypeClass *tclass, Object *obj) {
+ NameSpaceObjectList *nsol;
+ ClassList *base;
+ Object *chk;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (!base->is_virtual && !base->offset && !base->voffset && base->base->vtable) {
+ for (nsol = CScope_FindName(base->base->nspace, obj->name); nsol; nsol = nsol->next) {
+ chk = OBJECT(nsol->object);
+ if (
+ chk->otype == OT_OBJECT &&
+ chk->datatype == DVFUNC &&
+ CClass_GetOverrideKind(TYPE_FUNC(chk->type), TYPE_FUNC(obj->type), 0) == 1
+ )
+ return chk;
+ }
+
+ if ((chk = CABI_FindZeroVirtualBaseMember(base->base, obj)))
+ return chk;
+ }
+ }
+
+ return NULL;
+}
+
+void CABI_AddVTable(TypeClass *tclass) {
+ tclass->vtable = galloc(sizeof(VTable));
+ memclrw(tclass->vtable, sizeof(VTable));
+}
+
+SInt32 CABI_GetVTableOffset(TypeClass *tclass) {
+ return 0;
+}
+
+static SInt32 CABI_GetBaseVTableSize(TypeClass *tclass) {
+ VClassList *vbase;
+ SInt32 size;
+
+ size = tclass->vtable->size;
+
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ if (vbase->base->vtable)
+ size -= CABI_GetBaseVTableSize(vbase->base);
+ }
+
+ return size;
+}
+
+static void CABI_ApplyClassFlags(Object *obj, UInt8 flags, Boolean unused) {
+ if (flags & CLASS_EFLAGS_INTERNAL)
+ obj->flags = obj->flags | OBJECT_INTERNAL;
+ if (flags & CLASS_EFLAGS_IMPORT)
+ obj->flags = obj->flags | OBJECT_IMPORT;
+ if (flags & CLASS_EFLAGS_EXPORT)
+ obj->flags = obj->flags | OBJECT_EXPORT;
+}
+
+static void CABI_AllocateVTable(ClassLayout *layout, TypeClass *tclass) {
+ SInt32 size;
+ ObjBase *objbase;
+ Object *obj;
+ ObjMemberVar *ivar;
+ ClassList *base;
+ VClassList *vbase;
+ int i;
+
+ size = 0;
+
+ if (!tclass->vtable) {
+ CABI_AddVTable(tclass);
+ layout->xA = layout->lex_order_count - 1;
+ }
+
+ if (!CABI_FindZeroDeltaVPtr(tclass)) {
+ ivar = galloc(sizeof(ObjMemberVar));
+ memclrw(ivar, sizeof(ObjMemberVar));
+
+ ivar->otype = OT_MEMBERVAR;
+ ivar->access = ACCESSPUBLIC;
+ ivar->name = vptr_name_node;
+ ivar->type = TYPE(&void_ptr);
+ layout->vtable_ivar = ivar;
+
+ for (i = layout->xA; ; i--) {
+ if (i < 0) {
+ ivar->next = tclass->ivars;
+ tclass->ivars = ivar;
+ break;
+ }
+
+ CError_ASSERT(666, layout->objlist[i]);
+
+ if (layout->objlist[i]->otype == OT_MEMBERVAR) {
+ ivar->next = OBJ_MEMBER_VAR(layout->objlist[i])->next;
+ OBJ_MEMBER_VAR(layout->objlist[i])->next = ivar;
+ break;
+ }
+ }
+
+ if (tclass->flags & (CLASS_SINGLE_OBJECT | CLASS_COM_OBJECT))
+ size = void_ptr.size;
+ else
+ size = 8;
+ } else {
+ layout->vtable_ivar = NULL;
+ }
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (base->base->vtable && !base->is_virtual) {
+ base->voffset = size;
+ if (copts.vbase_abi_v2) {
+ size += CABI_GetBaseVTableSize(base->base);
+ } else {
+ size += base->base->vtable->size;
+ for (vbase = base->base->vbases; vbase; vbase = vbase->next) {
+ if (vbase->base->vtable)
+ size -= vbase->base->vtable->size;
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < layout->lex_order_count; i++) {
+ CError_ASSERT(714, objbase = layout->objlist[i]);
+
+ if (objbase->otype == OT_OBJECT && OBJECT(objbase)->datatype == DVFUNC) {
+ TypeMemberFunc *tmethod = TYPE_METHOD(OBJECT(objbase)->type);
+ Object *baseobj = CABI_FindZeroVirtualBaseMember(tclass, OBJECT(objbase));
+
+ if (baseobj) {
+ tmethod->vtbl_index = TYPE_METHOD(baseobj->type)->vtbl_index;
+ } else {
+ tmethod->vtbl_index = size;
+ size += 4;
+ }
+ }
+ }
+
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ if (vbase->base->vtable) {
+ vbase->voffset = size;
+ if (copts.vbase_abi_v2)
+ size += CABI_GetBaseVTableSize(vbase->base);
+ else
+ size += vbase->base->vtable->size;
+ }
+ }
+
+ obj = CParser_NewCompilerDefDataObject();
+ CABI_ApplyClassFlags(obj, tclass->eflags, 0);
+
+ obj->name = CMangler_VTableName(tclass);
+ obj->type = CDecl_NewStructType(size, 4);
+ obj->qual = Q_CONST;
+ obj->nspace = tclass->nspace;
+ switch (tclass->action) {
+ case CLASS_ACTION_0:
+ obj->sclass = TK_STATIC;
+ obj->qual |= Q_20000;
+ break;
+ }
+
+ CParser_UpdateObject(obj, NULL);
+
+ tclass->vtable->object = obj;
+ tclass->vtable->owner = tclass;
+ tclass->vtable->size = size;
+}
+
+void CABI_LayoutClass(ClassLayout *layout, TypeClass *tclass) {
+ char saveAlignMode = copts.structalignment;
+
+ tclass->size = 0;
+ if (!tclass->sominfo) {
+ if (tclass->bases)
+ CABI_AllocateBases(layout, tclass);
+ if (tclass->flags & CLASS_HAS_VBASES)
+ CABI_AllocateVirtualBasePointers(layout, tclass);
+ if (layout->has_vtable)
+ CABI_AllocateVTable(layout, tclass);
+ CABI_AllocateMembers(layout, tclass);
+ if (tclass->flags & CLASS_HAS_VBASES)
+ CABI_AllocateVirtualBases(layout, tclass);
+ } else {
+ copts.structalignment = AlignMode2_PPC;
+ CABI_AllocateMembers(layout, tclass);
+ }
+
+ tclass->align = CMach_GetClassAlign(tclass);
+ if (tclass->size == 0) {
+ tclass->size = 1;
+ tclass->flags = tclass->flags | CLASS_EMPTY;
+ } else {
+ tclass->size += CABI_StructSizeAlignValue(TYPE(tclass), tclass->size);
+ }
+
+ tclass->flags = tclass->flags | CLASS_COMPLETED;
+
+ copts.structalignment = saveAlignMode;
+}
+
+void CABI_MakeDefaultArgConstructor(TypeClass *tclass, Object *func) {
+ DefArgCtorInfo *info;
+ Boolean saveDebugInfo;
+ ENodeList *copied;
+ ENodeList *argexprs;
+ FuncArg *args;
+ CScopeSave savedScope;
+ Statement firstStmt;
+ Statement returnStmt;
+
+ CError_FATAL(860);
+
+ if (anyerrors || func->access == ACCESSNONE)
+ return;
+
+ CError_ASSERT(866, info = func->u.func.defargdata);
+
+ CABI_ApplyClassFlags(func, tclass->eflags, 0);
+
+ CScope_SetFunctionScope(func, &savedScope);
+
+ CFunc_FuncGenSetup(&firstStmt, func);
+
+ saveDebugInfo = copts.filesyminfo;
+ copts.filesyminfo = 0;
+
+ CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
+
+ if (tclass->flags & CLASS_HAS_VBASES)
+ arguments->next->object->name = no_name_node;
+
+ firstStmt.next = &returnStmt;
+
+ memclrw(&returnStmt, sizeof(Statement));
+ returnStmt.type = ST_RETURN;
+ returnStmt.expr = lalloc(sizeof(ENode));
+ returnStmt.expr->type = EFUNCCALL;
+ returnStmt.expr->cost = 200;
+ returnStmt.expr->flags = 0;
+ returnStmt.expr->rtype = TYPE(&void_ptr);
+
+ returnStmt.expr->data.funccall.funcref = CExpr_MakeObjRefNode(info->default_func, 0);
+ returnStmt.expr->data.funccall.functype = TYPE_FUNC(info->default_func->type);
+ args = TYPE_FUNC(info->default_func->type)->args;
+ returnStmt.expr->data.funccall.args = lalloc(sizeof(ENodeList));
+ argexprs = returnStmt.expr->data.funccall.args;
+
+ argexprs->node = create_objectnode(arguments->object);
+
+ if (tclass->flags & CLASS_HAS_VBASES) {
+ args = args->next;
+ argexprs->next = lalloc(sizeof(ENodeList));
+ argexprs = argexprs->next;
+ argexprs->node = create_objectnode(arguments->next->object);
+ }
+
+ args = args->next;
+ argexprs->next = lalloc(sizeof(ENodeList));
+ argexprs = argexprs->next;
+ argexprs->node = CInline_CopyExpression(info->default_arg, CopyMode0);
+
+ while ((args = args->next) && args->dexpr) {
+ argexprs->next = lalloc(sizeof(ENodeList));
+ argexprs = argexprs->next;
+ argexprs->node = CInline_CopyExpression(args->dexpr, CopyMode0);
+ }
+
+ argexprs->next = NULL;
+
+ CFunc_CodeCleanup(&firstStmt);
+ CFunc_Gen(&firstStmt, func, 0);
+
+ CScope_RestoreScope(&savedScope);
+ copts.filesyminfo = saveDebugInfo;
+
+ func->u.func.defargdata = NULL;
+}
+
+static Object *CABI_ThisArg(void) {
+ CError_ASSERT(931, arguments && IS_TYPE_POINTER_ONLY(arguments->object->type));
+ return arguments->object;
+}
+
+ENode *CABI_MakeThisExpr(TypeClass *tclass, SInt32 offset) {
+ ENode *expr;
+
+ if (tclass) {
+ if (!tclass->sominfo) {
+ expr = create_objectnode(CABI_ThisArg());
+ if (tclass->flags & CLASS_HANDLEOBJECT)
+ expr = makemonadicnode(expr, EINDIRECT);
+ } else {
+ expr = CSOM_SOMSelfObjectExpr(tclass);
+ }
+ } else {
+ expr = create_objectnode(CABI_ThisArg());
+ expr->rtype = TYPE(&void_ptr);
+ }
+
+ if (offset)
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD);
+
+ return expr;
+}
+
+static Object *CABI_VArg(void) {
+ CError_ASSERT(976, arguments && arguments->next && IS_TYPE_INT(arguments->next->object->type));
+ return arguments->next->object;
+}
+
+static ENode *CABI_MakeVArgExpr(void) {
+ return create_objectnode(CABI_VArg());
+}
+
+static ENode *CABI_MakeCopyConArgExpr(TypeClass *tclass, Boolean flag) {
+ ObjectList *args;
+
+ CError_ASSERT(1000, args = arguments);
+ CError_ASSERT(1001, args = args->next);
+ if (flag && (tclass->flags & CLASS_HAS_VBASES))
+ CError_ASSERT(1002, args = args->next);
+ CError_ASSERT(1003, IS_TYPE_POINTER_ONLY(args->object->type));
+
+ return create_objectnode(args->object);
+}
+
+static ENode *CABI_InitVBasePtr1(ENode *expr, TypeClass *tclass1, TypeClass *tclass2, TypeClass *tclass3, SInt32 offset) {
+ ClassList *base;
+ SInt32 newOffset;
+ OffsetList *list;
+
+ for (base = tclass2->bases; base; base = base->next) {
+ if (base->base == tclass3 && base->is_virtual) {
+ newOffset = offset + base->offset;
+
+ for (list = trans_vtboffsets; list; list = list->next) {
+ if (newOffset == list->offset)
+ break;
+ }
+
+ if (!list) {
+ list = lalloc(sizeof(OffsetList));
+ list->offset = newOffset;
+ list->next = trans_vtboffsets;
+ trans_vtboffsets = list;
+
+ expr = makediadicnode(
+ makemonadicnode(CABI_MakeThisExpr(NULL, newOffset), EINDIRECT),
+ expr,
+ EASS);
+ }
+ }
+
+ if (base->is_virtual)
+ newOffset = CClass_VirtualBaseOffset(tclass1, base->base);
+ else
+ newOffset = offset + base->offset;
+
+ expr = CABI_InitVBasePtr1(expr, tclass1, base->base, tclass3, newOffset);
+ }
+
+ return expr;
+}
+
+static Statement *CABI_InitVBasePtrs(Statement *stmt, TypeClass *tclass) {
+ ENode *expr;
+ VClassList *vbase;
+
+ for (vbase = tclass->vbases, trans_vtboffsets = NULL; vbase; vbase = vbase->next) {
+ expr = CABI_InitVBasePtr1(CABI_MakeThisExpr(NULL, vbase->offset), tclass, tclass, vbase->base, 0);
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr;
+ }
+
+ return stmt;
+}
+
+static OffsetList *CABI_GetVBasePath(TypeClass *tclass, TypeClass *baseclass) {
+ ClassList *base;
+ OffsetList *best;
+ OffsetList *list;
+ OffsetList *scan;
+ short bestLength;
+ short length;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (base->base == baseclass && base->is_virtual) {
+ best = lalloc(sizeof(OffsetList));
+ best->next = NULL;
+ best->offset = base->offset;
+ return best;
+ }
+ }
+
+ best = NULL;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if ((list = CABI_GetVBasePath(base->base, baseclass))) {
+ for (scan = list->next, length = 1; scan; scan = scan->next)
+ length++;
+
+ if (base->is_virtual)
+ length++;
+
+ if (!best || length < bestLength) {
+ if (base->is_virtual) {
+ best = lalloc(sizeof(OffsetList));
+ best->next = list;
+ best->offset = base->offset;
+ } else {
+ best = list;
+ best->offset += base->offset;
+ }
+ bestLength = length;
+ }
+ }
+ }
+
+ return best;
+}
+
+static ENode *CABI_GetVBasePtr(TypeClass *tclass, TypeClass *baseclass) {
+ OffsetList *path;
+ ENode *expr;
+
+ CError_ASSERT(1127, path = CABI_GetVBasePath(tclass, baseclass));
+
+ expr = makemonadicnode(CABI_MakeThisExpr(NULL, path->offset), EINDIRECT);
+
+ while ((path = path->next)) {
+ if (path->offset)
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), path->offset), EADD);
+ expr = makemonadicnode(expr, EINDIRECT);
+ }
+
+ return expr;
+}
+
+static SInt32 CABI_FindNVBase(TypeClass *tclass, TypeClass *baseclass, SInt32 offset) {
+ ClassList *base;
+ SInt32 tmp;
+
+ if (tclass == baseclass)
+ return offset;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (!base->is_virtual && (tmp = CABI_FindNVBase(base->base, baseclass, offset + base->offset)) >= 0)
+ return tmp;
+ }
+
+ return -1;
+}
+
+SInt32 CABI_GetCtorOffsetOffset(TypeClass *tclass, TypeClass *baseclass) {
+ SInt32 baseSize;
+ SInt32 size;
+ char saveAlignMode;
+
+ size = CABI_GetBaseSize(tclass);
+ if (baseclass) {
+ baseSize = CABI_FindNVBase(tclass, baseclass, 0);
+ CError_ASSERT(1178, baseSize >= 0);
+ size -= baseSize;
+ }
+
+ saveAlignMode = copts.structalignment;
+ if (tclass->eflags & CLASS_EFLAGS_F0)
+ copts.structalignment = ((tclass->eflags & CLASS_EFLAGS_F0) >> 4) - 1;
+ size += CMach_MemberAlignValue(TYPE(&stunsignedlong), size);
+ copts.structalignment = saveAlignMode;
+
+ return size;
+}
+
+static Statement *CABI_InitVBaseCtorOffsets(Statement *stmt, TypeClass *tclass) {
+ VClassList *vbase;
+ Object *tempObj;
+ ENode *expr;
+ ENode *vbaseptr;
+ SInt32 vboffset;
+ SInt32 ctorOffsetOffset;
+
+ tempObj = NULL;
+
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ if (vbase->has_override) {
+ if (!tempObj)
+ tempObj = create_temp_object(TYPE(&void_ptr));
+
+ vboffset = CClass_VirtualBaseOffset(tclass, vbase->base);
+ ctorOffsetOffset = CABI_GetCtorOffsetOffset(vbase->base, NULL);
+ vbaseptr = CABI_GetVBasePtr(tclass, vbase->base);
+ CError_ASSERT(1215, vbaseptr);
+
+ expr = makediadicnode(create_objectnode(tempObj), vbaseptr, EASS);
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr;
+
+ expr = makediadicnode(
+ create_objectnode(tempObj),
+ intconstnode(TYPE(&stunsignedlong), ctorOffsetOffset),
+ EADD);
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TYPE(&stunsignedlong);
+ expr = makediadicnode(
+ expr,
+ makediadicnode(
+ CABI_MakeThisExpr(NULL, vboffset),
+ create_objectnode(tempObj),
+ ESUB),
+ EASS);
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr;
+ }
+ }
+
+ return stmt;
+}
+
+static Statement *CABI_InitVTablePtrs(Statement *stmt, Object *vtableObj, TypeClass *tclass, TypeClass *baseclass, SInt32 offset, SInt32 voffset) {
+ ClassList *base;
+ BClassList *orig_pathcur;
+ SInt32 newOffset;
+ SInt32 newVOffset;
+ OffsetList *offsetList;
+ SInt32 vtblOffset;
+ ENode *vtblExpr;
+ ENode *pathExpr;
+ BClassList path;
+
+ if (baseclass->vtable->owner == baseclass) {
+ vtblOffset = offset + baseclass->vtable->offset;
+ for (offsetList = trans_vtboffsets; offsetList; offsetList = offsetList->next) {
+ if (vtblOffset == offsetList->offset)
+ break;
+ }
+
+ if (!offsetList) {
+ offsetList = lalloc(sizeof(OffsetList));
+ offsetList->offset = vtblOffset;
+ offsetList->next = trans_vtboffsets;
+ trans_vtboffsets = offsetList;
+
+ vtblExpr = create_objectrefnode(vtableObj);
+ vtblExpr->rtype = TYPE(&void_ptr);
+ if ((vtblOffset = voffset + CABI_GetVTableOffset(baseclass)))
+ vtblExpr = makediadicnode(vtblExpr, intconstnode(TYPE(&stunsignedlong), vtblOffset), EADD);
+
+ pathExpr = CClass_AccessPathCast(&cabi_pathroot, CABI_MakeThisExpr(tclass, 0), 0);
+ if (baseclass->vtable->offset && !canadd(pathExpr, baseclass->vtable->offset)) {
+ pathExpr = makediadicnode(pathExpr, intconstnode(TYPE(&stunsignedlong), baseclass->vtable->offset), EADD);
+ optimizecomm(pathExpr);
+ }
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = makediadicnode(makemonadicnode(pathExpr, EINDIRECT), vtblExpr, EASS);
+ }
+ }
+
+ for (base = baseclass->bases; base; base = base->next) {
+ if (base->base->vtable) {
+ orig_pathcur = cabi_pathcur;
+
+ cabi_pathcur->next = &path;
+ path.next = NULL;
+ path.type = TYPE(base->base);
+ cabi_pathcur = &path;
+
+ if (base->is_virtual) {
+ newOffset = CClass_VirtualBaseOffset(tclass, base->base);
+ newVOffset = CClass_VirtualBaseVTableOffset(tclass, base->base);
+ } else {
+ newOffset = offset + base->offset;
+ newVOffset = voffset + base->voffset;
+ }
+
+ stmt = CABI_InitVTablePtrs(stmt, vtableObj, tclass, base->base, newOffset, newVOffset);
+
+ cabi_pathcur = orig_pathcur;
+ }
+ }
+
+ return stmt;
+}
+
+static Boolean CABI_IsOperatorNew(ObjBase *obj) {
+ return
+ obj->otype == OT_OBJECT &&
+ IS_TYPE_FUNC(OBJECT(obj)->type) &&
+ TYPE_FUNC(OBJECT(obj)->type)->args &&
+ TYPE_FUNC(OBJECT(obj)->type)->args->type == CABI_GetSizeTType() &&
+ !TYPE_FUNC(OBJECT(obj)->type)->args->next;
+}
+
+Object *CABI_ConstructorCallsNew(TypeClass *tclass) {
+ NameSpaceObjectList *nsol;
+ NameResult pr;
+
+ if (!tclass->sominfo && (tclass->flags & CLASS_HANDLEOBJECT)) {
+ if (CScope_FindClassMemberObject(tclass, &pr, CMangler_OperatorName(TK_NEW))) {
+ if (pr.obj_10) {
+ if (CABI_IsOperatorNew(pr.obj_10))
+ return OBJECT(pr.obj_10);
+ } else {
+ for (nsol = pr.nsol_14; nsol; nsol = nsol->next) {
+ if (CABI_IsOperatorNew(nsol->object))
+ return OBJECT(nsol->object);
+ }
+ }
+ }
+
+ return newh_func;
+ }
+
+ return NULL;
+}
+
+void CABI_TransConstructor(Object *obj, Statement *firstStmt, TypeClass *tclass, TransConstructorCallback callback, Boolean has_try) {
+ Statement *stmt;
+ Object *tmpfunc;
+ Object *tmpfunc2;
+ CLabel *label;
+ ENode *expr;
+ ClassList *base;
+ VClassList *vbase;
+ ObjMemberVar *ivar;
+ Type *type;
+ CtorChain *chain;
+ Boolean errorflag;
+
+ stmt = firstStmt;
+
+ if ((tmpfunc = CABI_ConstructorCallsNew(tclass))) {
+ label = newlabel();
+
+ stmt = CFunc_InsertStatement(ST_IFGOTO, firstStmt);
+ stmt->expr = CABI_MakeThisExpr(NULL, 0);
+ stmt->label = label;
+
+ expr = makediadicnode(
+ CABI_MakeThisExpr(NULL, 0),
+ funccallexpr(tmpfunc, intconstnode(CABI_GetSizeTType(), tclass->size), NULL, NULL, NULL),
+ EASS);
+ stmt = CFunc_InsertStatement(ST_IFGOTO, stmt);
+ stmt->expr = expr;
+ stmt->label = label;
+
+ stmt = CFunc_InsertStatement(ST_RETURN, stmt);
+ stmt->expr = NULL;
+
+ stmt = CFunc_InsertStatement(ST_LABEL, stmt);
+ stmt->label = label;
+ label->stmt = stmt;
+ }
+
+ if (has_try) {
+ for (stmt = firstStmt; ; stmt = stmt->next) {
+ CError_ASSERT(1408, stmt);
+ if (stmt->type == ST_BEGINCATCH)
+ break;
+ }
+ }
+
+ if (!tclass->sominfo) {
+ if (tclass->flags & CLASS_HAS_VBASES) {
+ label = newlabel();
+
+ stmt = CFunc_InsertStatement(ST_IFGOTO, stmt);
+ stmt->expr = CExpr_New_EEQU_Node(CABI_MakeVArgExpr(), intconstnode(TYPE(&stsignedshort), 0));
+ stmt->label = label;
+
+ stmt = CABI_InitVBasePtrs(stmt, tclass);
+
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ if (!callback) {
+ for (chain = ctor_chain; chain; chain = chain->next) {
+ if (chain->what == CtorChain_VBase && chain->u.vbase == vbase)
+ break;
+ }
+
+ if (chain) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = chain->objexpr;
+ } else {
+ expr = CClass_DefaultConstructorCall(
+ vbase->base,
+ tclass,
+ CABI_MakeThisExpr(NULL, vbase->offset),
+ 0, 1, 1, &errorflag);
+ if (expr) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr;
+ } else if (errorflag) {
+ CError_Error(CErrorStr213, tclass, 0, vbase->base, 0);
+ }
+ }
+ } else {
+ stmt = callback(stmt, tclass, vbase->base, vbase->offset, 1);
+ }
+
+ if ((tmpfunc = CClass_Destructor(vbase->base)))
+ CExcept_RegisterMember(stmt, CABI_ThisArg(), vbase->offset, tmpfunc, CABI_VArg(), 0);
+ }
+
+ stmt = CFunc_InsertStatement(ST_LABEL, stmt);
+ stmt->label = label;
+ label->stmt = stmt;
+ }
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (base->is_virtual)
+ continue;
+
+ if (!callback) {
+ for (chain = ctor_chain; chain; chain = chain->next) {
+ if (chain->what == CtorChain_Base && chain->u.base == base)
+ break;
+ }
+
+ if (chain) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = chain->objexpr;
+ } else {
+ expr = CClass_DefaultConstructorCall(
+ base->base,
+ tclass,
+ CABI_MakeThisExpr(NULL, base->offset),
+ 0, 1, 0, &errorflag);
+ if (expr) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr;
+ } else if (errorflag) {
+ CError_Error(CErrorStr213, tclass, 0, base->base, 0);
+ }
+ }
+ } else {
+ stmt = callback(stmt, tclass, base->base, base->offset, 1);
+ }
+
+ if ((tmpfunc = CClass_Destructor(base->base)))
+ CExcept_RegisterMember(stmt, CABI_ThisArg(), base->offset, tmpfunc, NULL, 0);
+ }
+
+ if (tclass->vtable && tclass->vtable->object && tclass->vtable->owner == tclass) {
+ cabi_pathroot.next = NULL;
+ cabi_pathroot.type = TYPE(tclass);
+ cabi_pathcur = &cabi_pathroot;
+ trans_vtboffsets = NULL;
+
+ stmt = CABI_InitVTablePtrs(stmt, tclass->vtable->object, tclass, tclass, 0, 0);
+ }
+ }
+
+ if (!tclass->sominfo && (tclass->flags & CLASS_FLAGS_8000))
+ stmt = CABI_InitVBaseCtorOffsets(stmt, tclass);
+
+ if (!callback) {
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ for (chain = ctor_chain; chain; chain = chain->next) {
+ if (chain->what == CtorChain_MemberVar && chain->u.membervar == ivar) {
+ if (IS_TYPE_ARRAY(ivar->type))
+ chain = NULL;
+ break;
+ }
+ }
+
+ if (chain) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = chain->objexpr;
+ type = ivar->type;
+ switch (type->type) {
+ case TYPEARRAY:
+ do {
+ type = TPTR_TARGET(type);
+ } while (IS_TYPE_ARRAY(type));
+ if (IS_TYPE_CLASS(type)) {
+ if ((tmpfunc = CClass_Destructor(TYPE_CLASS(type)))) {
+ CError_ASSERT(1560, type->size);
+ CExcept_RegisterMemberArray(
+ stmt,
+ CABI_ThisArg(),
+ ivar->offset,
+ tmpfunc,
+ ivar->type->size / type->size,
+ type->size);
+ }
+ }
+ break;
+ case TYPECLASS:
+ if ((tmpfunc = CClass_Destructor(TYPE_CLASS(type)))) {
+ CExcept_RegisterMember(
+ stmt,
+ CABI_ThisArg(),
+ ivar->offset,
+ tmpfunc,
+ NULL,
+ 1);
+ }
+ break;
+ }
+ } else {
+ type = ivar->type;
+ switch (type->type) {
+ case TYPEARRAY:
+ do {
+ type = TPTR_TARGET(type);
+ } while (IS_TYPE_ARRAY(type));
+ if (IS_TYPE_CLASS(type) && CClass_Constructor(TYPE_CLASS(type))) {
+ if (
+ (tmpfunc = CClass_DefaultConstructor(TYPE_CLASS(type))) ||
+ (tmpfunc = CClass_DummyDefaultConstructor(TYPE_CLASS(type)))
+ )
+ {
+ tmpfunc2 = CClass_Destructor(TYPE_CLASS(type));
+ if (tmpfunc2)
+ tmpfunc2 = CABI_GetDestructorObject(tmpfunc2, 1);
+
+ stmt = CInit_ConstructClassArray(
+ stmt,
+ TYPE_CLASS(type),
+ tmpfunc,
+ tmpfunc2,
+ CABI_MakeThisExpr(tclass, ivar->offset),
+ ivar->type->size / type->size);
+
+ if (tmpfunc2)
+ CExcept_RegisterMemberArray(
+ stmt,
+ CABI_ThisArg(),
+ ivar->offset,
+ tmpfunc2,
+ ivar->type->size / type->size,
+ type->size);
+ } else {
+ CError_Error(CErrorStr214, tclass, 0, ivar->name->name);
+ }
+ }
+ break;
+ case TYPECLASS:
+ expr = CClass_DefaultConstructorCall(
+ TYPE_CLASS(type),
+ NULL,
+ CABI_MakeThisExpr(tclass, ivar->offset),
+ 1, 1, 0, &errorflag);
+ if (expr) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr;
+ } else if (errorflag) {
+ CError_Error(CErrorStr214, tclass, 0, ivar->name->name);
+ }
+
+ if ((tmpfunc = CClass_Destructor(TYPE_CLASS(type)))) {
+ if (!expr) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = nullnode();
+ }
+ CExcept_RegisterMember(
+ stmt,
+ CABI_ThisArg(),
+ ivar->offset,
+ tmpfunc,
+ NULL,
+ 1);
+ }
+ break;
+ }
+ }
+ }
+ } else {
+ stmt = callback(stmt, tclass, NULL, 0, 1);
+ }
+
+ if (!tclass->sominfo) {
+ for (stmt = firstStmt->next; stmt; stmt = stmt->next) {
+ if (stmt->type == ST_RETURN) {
+ CError_ASSERT(1661, !stmt->expr);
+ stmt->expr = CABI_MakeThisExpr(NULL, 0);
+ }
+ }
+ }
+}
+
+void CABI_MakeDefaultConstructor(TypeClass *tclass, Object *func) {
+ Boolean saveDebugInfo;
+ CScopeSave savedScope;
+ Statement firstStmt;
+ Statement returnStmt;
+
+ if (anyerrors || func->access == ACCESSNONE)
+ return;
+
+ CABI_ApplyClassFlags(func, tclass->eflags, 0);
+
+ CScope_SetFunctionScope(func, &savedScope);
+
+ CFunc_FuncGenSetup(&firstStmt, func);
+
+ saveDebugInfo = copts.filesyminfo;
+ copts.filesyminfo = 0;
+
+ CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
+
+ ctor_chain = NULL;
+ if (tclass->flags & CLASS_HAS_VBASES)
+ arguments->next->object->name = CParser_GetUniqueName();
+
+ firstStmt.next = &returnStmt;
+
+ memclrw(&returnStmt, sizeof(Statement));
+ returnStmt.type = ST_RETURN;
+
+ CABI_TransConstructor(func, &firstStmt, tclass, NULL, 0);
+
+ CFunc_CodeCleanup(&firstStmt);
+ CFunc_Gen(&firstStmt, func, 0);
+
+ CScope_RestoreScope(&savedScope);
+ copts.filesyminfo = saveDebugInfo;
+}
+
+static ENode *CABI_AssignObject(TypeClass *tclass, ENode *expr1, ENode *expr2) {
+ Object *assignfunc;
+ FuncArg *arg;
+
+ assignfunc = CClass_AssignmentOperator(tclass);
+ if (!assignfunc) {
+ expr1 = makemonadicnode(expr1, EINDIRECT);
+ expr1->rtype = TYPE(tclass);
+ return makediadicnode(expr1, expr2, EASS);
+ }
+
+ CError_ASSERT(1731,
+ IS_TYPE_FUNC(assignfunc->type) &&
+ (arg = TYPE_FUNC(assignfunc->type)->args) &&
+ (arg = arg->next));
+
+ expr2 = argumentpromotion(expr2, arg->type, arg->qual, 1);
+ return funccallexpr(assignfunc, expr1, expr2, NULL, NULL);
+}
+
+static Type *CABI_FindIntegralSizeType(SInt32 size) {
+ if (stunsignedchar.size == size)
+ return TYPE(&stunsignedchar);
+ if (stunsignedshort.size == size)
+ return TYPE(&stunsignedshort);
+ if (stunsignedint.size == size)
+ return TYPE(&stunsignedint);
+ if (stunsignedlong.size == size)
+ return TYPE(&stunsignedlong);
+ if (stunsignedlonglong.size == size)
+ return TYPE(&stunsignedlonglong);
+
+ CError_FATAL(1756);
+ return NULL;
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct CopyRegion {
+ struct CopyRegion *next;
+ Type *type;
+ SInt32 start;
+ SInt32 end;
+ Boolean flag;
+} CopyRegion;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static CopyRegion *CABI_AppendCopyRegion(CopyRegion *regions, Type *type, SInt32 start, Boolean flag) {
+ CopyRegion *region;
+ SInt32 end;
+
+ if (IS_TYPE_BITFIELD(type))
+ type = TYPE_BITFIELD(type)->bitfieldtype;
+
+ end = start + type->size;
+
+ if (flag) {
+ for (region = regions; region; region = region->next) {
+ if (region->flag) {
+ if (region->start <= start && region->end >= end)
+ return regions;
+
+ if (region->start >= start && region->end <= end) {
+ region->type = type;
+ region->start = start;
+ region->end = end;
+ for (region = region->next; region; region = region->next) {
+ if (region->start >= start && region->end <= end)
+ region->end = region->start;
+ }
+ return regions;
+ }
+ }
+ }
+ }
+
+ if (regions) {
+ region = regions;
+ while (region->next)
+ region = region->next;
+
+ region->next = lalloc(sizeof(CopyRegion));
+ region = region->next;
+ } else {
+ regions = lalloc(sizeof(CopyRegion));
+ region = regions;
+ }
+
+ region->next = NULL;
+ region->type = type;
+ region->start = start;
+ region->end = end;
+ region->flag = flag;
+
+ return regions;
+}
+
+static ENode *CABI_ClassInitLoopCallBack(ENode *var1, ENode *var2) {
+ ENodeList *list;
+
+ var2 = makemonadicnode(var2, EINDIRECT);
+ var2->rtype = TYPE(cabi_loop_class);
+
+ if (cabi_loop_construct) {
+ list = lalloc(sizeof(ENodeList));
+ memclrw(list, sizeof(ENodeList));
+ list->node = var2;
+ return CExpr_ConstructObject(cabi_loop_class, var1, list, 1, 1, 0, 1, 1);
+ } else {
+ return CABI_AssignObject(cabi_loop_class, var1, var2);
+ }
+}
+
+static Statement *CABI_CopyConAssignCB(Statement *stmt, TypeClass *tclass, TypeClass *baseclass, SInt32 offset, Boolean flag) {
+ ENode *expr;
+ ENode *expr2;
+ ENode *startExpr;
+ ENode *endExpr;
+ ENodeList *list;
+ ObjMemberVar *ivar;
+ CopyRegion *regions;
+ Type *type;
+ SInt32 i;
+ SInt32 count;
+ Boolean isFlagNotSet;
+ Object *tmpfunc;
+
+ if (baseclass) {
+ if (baseclass->flags & CLASS_EMPTY) {
+ if (
+ (flag && !CClass_CopyConstructor(baseclass)) ||
+ (!flag && !CClass_AssignmentOperator(baseclass))
+ )
+ return stmt;
+ }
+
+ expr = CABI_MakeCopyConArgExpr(tclass, flag);
+ expr->rtype = TYPE(baseclass);
+ expr->data.monadic = CClass_DirectBasePointerCast(expr->data.monadic, tclass, baseclass);
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ if (flag) {
+ list = lalloc(sizeof(ENodeList));
+ list->next = NULL;
+ list->node = expr;
+
+ stmt->expr = CExpr_ConstructObject(
+ baseclass,
+ CABI_MakeThisExpr(NULL, offset),
+ list,
+ 1, 0, 0, 0, 1);
+ } else {
+ stmt->expr = CABI_AssignObject(
+ baseclass,
+ CClass_DirectBasePointerCast(CABI_MakeThisExpr(NULL, 0), tclass, baseclass),
+ expr);
+ }
+ } else {
+ isFlagNotSet = !flag;
+ for (ivar = tclass->ivars, regions = NULL; ivar; ivar = ivar->next) {
+ if (ivar->name == vptr_name_node)
+ continue;
+
+ type = ivar->type;
+ if (isFlagNotSet) {
+ if (CParser_IsConst(type, ivar->qual) || IS_TYPE_REFERENCE(type) != 0) {
+ CError_Error(CErrorStr387, tclass, 0);
+ isFlagNotSet = 0;
+ }
+ }
+
+ switch (type->type) {
+ case TYPEARRAY:
+ while (IS_TYPE_ARRAY(type))
+ type = TPTR_TARGET(type);
+ if (!IS_TYPE_CLASS(type)) {
+ regions = CABI_AppendCopyRegion(regions, ivar->type, ivar->offset, 1);
+ break;
+ }
+ case TYPECLASS:
+ if (flag) {
+ if (CClass_CopyConstructor(TYPE_CLASS(type)) || CClass_CopyConstructor(TYPE_CLASS(type))) {
+ regions = CABI_AppendCopyRegion(regions, ivar->type, ivar->offset, 0);
+ break;
+ }
+ } else {
+ if (CClass_AssignmentOperator(TYPE_CLASS(type))) {
+ regions = CABI_AppendCopyRegion(regions, ivar->type, ivar->offset, 0);
+ break;
+ }
+ }
+ default:
+ regions = CABI_AppendCopyRegion(regions, ivar->type, ivar->offset, 1);
+ }
+ }
+
+ for (; regions; regions = regions->next) {
+ if (regions->start >= regions->end)
+ continue;
+
+ type = regions->type;
+ expr = CABI_MakeCopyConArgExpr(tclass, flag);
+ expr->rtype = type;
+
+ if (!canadd(expr->data.monadic, regions->start)) {
+ expr->data.monadic = makediadicnode(
+ expr->data.monadic,
+ intconstnode(TYPE(&stunsignedlong), regions->start),
+ EADD);
+ optimizecomm(expr->data.monadic);
+ }
+
+ if (!regions->flag) {
+ if (IS_TYPE_ARRAY(type)) {
+ while (IS_TYPE_ARRAY(type))
+ type = TPTR_TARGET(type);
+
+ CError_ASSERT(1966, IS_TYPE_CLASS(type));
+
+ if (type->size) {
+ count = regions->type->size / type->size;
+ if (count > 4) {
+ startExpr = CABI_MakeThisExpr(tclass, regions->start);
+ endExpr = CABI_MakeThisExpr(tclass, regions->start + regions->type->size);
+ expr = CABI_MakeCopyConArgExpr(tclass, flag)->data.monadic;
+ if (!canadd(expr, regions->start)) {
+ expr = makediadicnode(
+ expr,
+ intconstnode(TYPE(&stunsignedlong), regions->start),
+ EADD);
+ optimizecomm(expr);
+ }
+
+ cabi_loop_class = TYPE_CLASS(type);
+ cabi_loop_construct = flag;
+ stmt = CFunc_GenerateLoop(
+ stmt,
+ CDecl_NewPointerType(type),
+ startExpr,
+ endExpr,
+ intconstnode(TYPE(&stunsignedlong), type->size),
+ expr,
+ CABI_ClassInitLoopCallBack);
+ } else {
+ for (i = 0, offset = regions->start; i < count; i++, offset += type->size) {
+ expr = CABI_MakeCopyConArgExpr(tclass, flag);
+ expr->rtype = type;
+
+ if (!canadd(expr->data.monadic, offset)) {
+ expr->data.monadic = makediadicnode(
+ expr->data.monadic,
+ intconstnode(TYPE(&stunsignedlong), offset),
+ EADD);
+ optimizecomm(expr->data.monadic);
+ }
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ if (flag) {
+ list = lalloc(sizeof(ENodeList));
+ memclrw(list, sizeof(ENodeList));
+ list->node = expr;
+ stmt->expr = CExpr_ConstructObject(
+ TYPE_CLASS(type),
+ CABI_MakeThisExpr(tclass, offset),
+ list,
+ 1, 1, 0, 1, 1);
+ } else {
+ stmt->expr = CABI_AssignObject(
+ TYPE_CLASS(type),
+ CABI_MakeThisExpr(tclass, offset),
+ expr);
+ }
+ }
+ }
+
+ if (flag && (tmpfunc = CClass_Destructor(TYPE_CLASS(type))))
+ CExcept_RegisterMemberArray(stmt, CABI_ThisArg(), regions->start, tmpfunc, count, type->size);
+ }
+ } else {
+ CError_ASSERT(2027, IS_TYPE_CLASS(type));
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+
+ if (flag) {
+ list = lalloc(sizeof(ENodeList));
+ memclrw(list, sizeof(ENodeList));
+ list->node = expr;
+ stmt->expr = CExpr_ConstructObject(
+ TYPE_CLASS(type),
+ CABI_MakeThisExpr(tclass, regions->start),
+ list,
+ 1, 1, 0, 1, 1);
+
+ if ((tmpfunc = CClass_Destructor(TYPE_CLASS(type))))
+ CExcept_RegisterMember(stmt, CABI_ThisArg(), regions->start, tmpfunc, NULL, 1);
+ } else {
+ stmt->expr = CABI_AssignObject(
+ TYPE_CLASS(type),
+ CABI_MakeThisExpr(tclass, regions->start),
+ expr);
+ }
+ }
+ } else {
+ if (IS_TYPE_ARRAY(type)) {
+ if (type->size > 1 && ((regions->start & 1) || (type->size & 1))) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = funccallexpr(
+ copy_func,
+ CABI_MakeThisExpr(tclass, regions->start),
+ getnodeaddress(expr, 0),
+ intconstnode(CABI_GetSizeTType(), type->size),
+ NULL);
+ continue;
+ }
+
+ type = CDecl_NewStructType(type->size, CMach_GetTypeAlign(type));
+ expr->rtype = type;
+ }
+
+ expr2 = makemonadicnode(CABI_MakeThisExpr(tclass, regions->start), EINDIRECT);
+ expr2->rtype = type;
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = makediadicnode(expr2, expr, EASS);
+ }
+ }
+ }
+
+ return stmt;
+}
+
+void CABI_MakeDefaultCopyConstructor(TypeClass *tclass, Object *func) {
+ Boolean saveDebugInfo;
+ CScopeSave savedScope;
+ Statement firstStmt;
+ Statement returnStmt;
+
+ if (anyerrors || func->access == ACCESSNONE)
+ return;
+
+ CABI_ApplyClassFlags(func, tclass->eflags, 0);
+
+ CScope_SetFunctionScope(func, &savedScope);
+
+ CFunc_FuncGenSetup(&firstStmt, func);
+
+ saveDebugInfo = copts.filesyminfo;
+ copts.filesyminfo = 0;
+
+ CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
+
+ ctor_chain = NULL;
+ if (tclass->flags & CLASS_HAS_VBASES)
+ arguments->next->object->name = CParser_GetUniqueName();
+
+ firstStmt.next = &returnStmt;
+
+ memclrw(&returnStmt, sizeof(Statement));
+ returnStmt.type = ST_RETURN;
+
+ CABI_TransConstructor(func, &firstStmt, tclass, CABI_CopyConAssignCB, 0);
+
+ CFunc_CodeCleanup(&firstStmt);
+ CFunc_Gen(&firstStmt, func, 0);
+
+ CScope_RestoreScope(&savedScope);
+ copts.filesyminfo = saveDebugInfo;
+}
+
+void CABI_MakeDefaultAssignmentOperator(TypeClass *tclass, Object *func) {
+ Boolean saveDebugInfo;
+ Statement *stmt;
+ ClassList *base;
+ VClassList *vbase;
+ ENode *expr1;
+ ENode *expr2;
+ CScopeSave savedScope;
+ Statement firstStmt;
+
+ if (anyerrors || func->access == ACCESSNONE)
+ return;
+
+ CABI_ApplyClassFlags(func, tclass->eflags, 0);
+
+ CScope_SetFunctionScope(func, &savedScope);
+
+ CFunc_FuncGenSetup(&firstStmt, func);
+
+ saveDebugInfo = copts.filesyminfo;
+ copts.filesyminfo = 0;
+
+ CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
+
+ stmt = curstmt;
+
+ if (tclass->mode == CLASS_MODE_UNION) {
+ expr1 = makemonadicnode(CABI_MakeThisExpr(tclass, 0), EINDIRECT);
+ expr1->rtype = TYPE(tclass);
+
+ expr2 = CABI_MakeCopyConArgExpr(tclass, 0);
+ expr2->rtype = TYPE(tclass);
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = makediadicnode(expr1, expr2, EASS);
+ } else {
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ stmt = CABI_CopyConAssignCB(stmt, tclass, vbase->base, vbase->offset, 0);
+ }
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (!base->is_virtual)
+ stmt = CABI_CopyConAssignCB(stmt, tclass, base->base, base->offset, 0);
+ }
+
+ stmt = CABI_CopyConAssignCB(stmt, tclass, NULL, 0, 0);
+ }
+
+ stmt = CFunc_InsertStatement(ST_RETURN, stmt);
+ stmt->expr = CABI_MakeThisExpr(NULL, 0);
+
+ CFunc_CodeCleanup(&firstStmt);
+ CFunc_Gen(&firstStmt, func, 0);
+
+ CScope_RestoreScope(&savedScope);
+ copts.filesyminfo = saveDebugInfo;
+}
+
+static Statement *CABI_DestroyMembers(Statement *stmt, ObjMemberVar *ivars, TypeClass *tclass) {
+ Type *type;
+ Object *dtor;
+ ENode *expr;
+
+ for (; ivars; ivars = ivars->next) {
+ type = ivars->type;
+
+ if (IS_TYPE_ARRAY(type)) {
+ while (IS_TYPE_ARRAY(type))
+ type = TPTR_TARGET(type);
+
+ if (IS_TYPE_CLASS(type) && (dtor = CClass_Destructor(TYPE_CLASS(type)))) {
+ dtor = CABI_GetDestructorObject(dtor, 1);
+ stmt = CABI_DestroyMembers(stmt, ivars->next, tclass);
+ expr = create_objectrefnode(dtor);
+ expr->flags = expr->flags | ENODE_FLAG_80;
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = funccallexpr(
+ darr_func,
+ CABI_MakeThisExpr(tclass, ivars->offset),
+ expr,
+ intconstnode(TYPE(&stsignedlong), type->size),
+ intconstnode(TYPE(&stsignedlong), ivars->type->size / type->size)
+ );
+ return stmt;
+ }
+ } else {
+ if (IS_TYPE_CLASS(type) && (dtor = CClass_Destructor(TYPE_CLASS(type)))) {
+ stmt = CABI_DestroyMembers(stmt, ivars->next, tclass);
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = CABI_DestroyObject(
+ dtor,
+ CABI_MakeThisExpr(tclass, ivars->offset),
+ CABIDestroy1,
+ 1,
+ 0
+ );
+ return stmt;
+ }
+ }
+ }
+
+ return stmt;
+}
+
+static Statement *CABI_DestroyBases(Statement *stmt, ClassList *bases) {
+ ClassList *base;
+ Object *dtor;
+ SInt32 count;
+ SInt32 i;
+
+ base = bases;
+ count = 0;
+ while (base) {
+ base = base->next;
+ count++;
+ }
+
+ while (count > 0) {
+ base = bases;
+ i = count;
+ while (i-- > 1)
+ base = base->next;
+
+ if (!base->is_virtual && (dtor = CClass_Destructor(base->base))) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = CABI_DestroyObject(
+ dtor,
+ CABI_MakeThisExpr(NULL, base->offset),
+ CABIDestroy0,
+ 1,
+ 0);
+ }
+
+ count--;
+ }
+
+ return stmt;
+}
+
+static Statement *CABI_DestroyVBases(Statement *stmt, VClassList *vbases) {
+ Object *dtor;
+
+ for (; vbases; vbases = vbases->next) {
+ if ((dtor = CClass_Destructor(vbases->base))) {
+ stmt = CABI_DestroyVBases(stmt, vbases->next);
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = CABI_DestroyObject(
+ dtor,
+ CABI_MakeThisExpr(NULL, vbases->offset),
+ CABIDestroy0,
+ 1,
+ 0);
+ break;
+ }
+ }
+
+ return stmt;
+}
+
+void CABI_TransDestructor(Object *obj1, Object *obj2, Statement *stmt, TypeClass *tclass, CABIDestroyMode mode) {
+ CLabel *label2;
+ Boolean flag29;
+ CLabel *label;
+ Statement *scan;
+ Boolean flag25;
+ Boolean flag24;
+ Boolean flag23;
+ CLabel *label3;
+ Object *dealloc;
+ Boolean deallocFlag;
+
+ if (tclass->sominfo) {
+ flag24 = 0;
+ flag25 = 0;
+ flag29 = 0;
+ flag23 = 1;
+ } else {
+ flag24 = 1;
+ flag23 = 1;
+ flag25 = 1;
+ flag29 = 1;
+ }
+
+ label = newlabel();
+
+ for (scan = stmt; scan; scan = scan->next) {
+ if (scan->type == ST_RETURN) {
+ CError_ASSERT(2329, !scan->expr);
+ scan->type = ST_GOTO;
+ scan->label = label;
+ }
+
+ if (scan->next && scan->next->type == ST_RETURN && !scan->next->next) {
+ CError_ASSERT(2334, !scan->next->expr);
+ scan->next = NULL;
+ break;
+ }
+ }
+
+ scan = stmt;
+
+ if (flag29) {
+ label2 = newlabel();
+ scan = CFunc_InsertStatement(ST_IFNGOTO, scan);
+ scan->expr = CABI_MakeThisExpr(NULL, 0);
+ scan->label = label2;
+ }
+
+ if (flag25 && tclass->vtable && tclass->vtable->object && tclass->vtable->owner == tclass) {
+ cabi_pathroot.next = NULL;
+ cabi_pathroot.type = TYPE(tclass);
+ cabi_pathcur = &cabi_pathroot;
+ trans_vtboffsets = NULL;
+ scan = CABI_InitVTablePtrs(scan, tclass->vtable->object, tclass, tclass, 0, 0);
+ }
+
+ if (!tclass->sominfo && (tclass->flags & CLASS_FLAGS_8000))
+ CABI_InitVBaseCtorOffsets(scan, tclass);
+
+ scan = stmt;
+ while (scan->next)
+ scan = scan->next;
+
+ scan = CFunc_InsertStatement(ST_LABEL, scan);
+ scan->label = label;
+ scan->dobjstack = NULL;
+ label->stmt = scan;
+
+ if (flag23 && !(tclass->flags & CLASS_HANDLEOBJECT))
+ scan = CABI_DestroyMembers(scan, tclass->ivars, tclass);
+
+ if (flag25 && tclass->bases)
+ scan = CABI_DestroyBases(scan, tclass->bases);
+
+ if (flag24 && (tclass->flags & CLASS_HAS_VBASES)) {
+ label3 = newlabel();
+ scan = CFunc_InsertStatement(ST_IFNGOTO, scan);
+ scan->expr = CABI_MakeVArgExpr();
+ scan->label = label3;
+
+ scan = CABI_DestroyVBases(scan, tclass->vbases);
+
+ scan = CFunc_InsertStatement(ST_LABEL, scan);
+ scan->label = label3;
+ label3->stmt = scan;
+ }
+
+ if (flag29) {
+ scan = CFunc_InsertStatement(ST_IFGOTO, scan);
+ scan->expr = CExpr_New_ELESSEQU_Node(CABI_MakeVArgExpr(), intconstnode(TYPE(&stsignedshort), 0));
+ scan->label = label2;
+
+ scan = CFunc_InsertStatement(ST_EXPRESSION, scan);
+ dealloc = CParser_FindDeallocationObject(TYPE(tclass), NULL, 0, 0, &deallocFlag);
+ if (deallocFlag) {
+ scan->expr = funccallexpr(
+ dealloc,
+ CABI_MakeThisExpr(NULL, 0),
+ intconstnode(CABI_GetSizeTType(), tclass->size),
+ NULL,
+ NULL);
+ } else {
+ scan->expr = funccallexpr(dealloc, CABI_MakeThisExpr(NULL, 0), NULL, NULL, NULL);
+ }
+
+ scan = CFunc_InsertStatement(ST_LABEL, scan);
+ scan->label = label2;
+ label2->stmt = scan;
+ }
+
+ scan = CFunc_InsertStatement(ST_RETURN, scan);
+ if (tclass->sominfo)
+ scan->expr = NULL;
+ else
+ scan->expr = CABI_MakeThisExpr(NULL, 0);
+}
+
+void CABI_MakeDefaultDestructor(TypeClass *tclass, Object *func) {
+ Boolean saveDebugInfo;
+ CScopeSave savedScope;
+ Statement firstStmt;
+ Statement returnStmt;
+
+ if (anyerrors || func->access == ACCESSNONE)
+ return;
+
+ CABI_ApplyClassFlags(func, tclass->eflags, 0);
+
+ CScope_SetFunctionScope(func, &savedScope);
+
+ CFunc_FuncGenSetup(&firstStmt, func);
+
+ saveDebugInfo = copts.filesyminfo;
+ copts.filesyminfo = 0;
+
+ CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
+
+ firstStmt.next = &returnStmt;
+
+ memclrw(&returnStmt, sizeof(Statement));
+ returnStmt.type = ST_RETURN;
+
+ CFunc_CodeCleanup(&firstStmt);
+
+ CABI_TransDestructor(func, func, &firstStmt, tclass, CABIDestroy0);
+
+ CFunc_Gen(&firstStmt, func, 0);
+
+ CScope_RestoreScope(&savedScope);
+ copts.filesyminfo = saveDebugInfo;
+}
+
+static void CABI_CreateLayeredDestructor(TypeClass *tclass, Object *obj1, Object *func, CABIDestroyMode mode) {
+ Boolean saveDebugInfo;
+ CScopeSave savedScope;
+ Statement firstStmt;
+ Statement returnStmt;
+
+ CError_FATAL(2524);
+
+ CScope_SetFunctionScope(func, &savedScope);
+
+ CFunc_FuncGenSetup(&firstStmt, func);
+
+ saveDebugInfo = copts.filesyminfo;
+ copts.filesyminfo = 0;
+
+ CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
+
+ firstStmt.next = &returnStmt;
+
+ memclrw(&returnStmt, sizeof(Statement));
+ returnStmt.type = ST_RETURN;
+
+ CFunc_CodeCleanup(&firstStmt);
+
+ CABI_TransDestructor(obj1, func, &firstStmt, tclass, mode);
+
+ CFunc_Gen(&firstStmt, func, 0);
+
+ CScope_RestoreScope(&savedScope);
+ copts.filesyminfo = saveDebugInfo;
+}
+
+void CABI_MakeLayeredDestructor(TypeClass *tclass, Object *func) {
+ Object *dtor;
+ CABIDestroyMode mode;
+
+ CError_FATAL(2557);
+
+ if (anyerrors || func->access == ACCESSNONE)
+ return;
+
+ if ((dtor = CClass_Destructor(tclass))) {
+ if (CABI_GetDestructorObject(dtor, CABIDestroy0) == func)
+ mode = CABIDestroy0;
+ else if (CABI_GetDestructorObject(dtor, CABIDestroy2) == func)
+ mode = CABIDestroy2;
+ else if (CABI_GetDestructorObject(dtor, CABIDestroy3) == func)
+ mode = CABIDestroy3;
+ else if (CABI_GetDestructorObject(dtor, CABIDestroy1) == func)
+ mode = CABIDestroy1;
+ else
+ CError_FATAL(2567);
+ }
+
+ CABI_CreateLayeredDestructor(tclass, dtor, func, mode);
+}
+
+Object *CABI_GetDestructorObject(Object *obj, CABIDestroyMode mode) {
+ return obj;
+}
+
+static void CABI_AddLayeredDestructor(TypeClass *tclass, Object *dtor, HashNameNode *name, Boolean is_virtual) {
+ Object *func;
+
+ CError_FATAL(2667);
+
+ func = CParser_NewFunctionObject(NULL);
+ func->nspace = dtor->nspace;
+ func->name = name;
+ func->type = TYPE(CDecl_MakeDefaultDtorType(tclass, is_virtual));
+ func->qual = Q_20000 | Q_MANGLE_NAME;
+ func->qual |= Q_INLINE;
+ CABI_ApplyClassFlags(func, tclass->eflags, 1);
+
+ CError_ASSERT(2678, IS_TYPE_FUNC(func->type));
+ TYPE_FUNC(func->type)->flags |= FUNC_AUTO_GENERATED;
+
+ if (dtor->datatype == DVFUNC) {
+ func->datatype = DVFUNC;
+ CMangler_GetLinkName(func);
+ func->datatype = DFUNC;
+ }
+
+ CScope_AddObject(func->nspace, func->name, OBJ_BASE(func));
+}
+
+void CABI_AddLayeredDestructors(TypeClass *tclass) {
+ Object *dtor;
+
+ CError_FATAL(2707);
+
+ if ((dtor = CClass_Destructor(tclass))) {
+ CABI_AddLayeredDestructor(tclass, dtor, CMangler_DeleteDtorName(), 1);
+ CABI_AddLayeredDestructor(tclass, dtor, CMangler_SDeleteDtorName(), 1);
+ if (tclass->vbases)
+ CABI_AddLayeredDestructor(tclass, dtor, CMangler_VBaseDtorName(), 0);
+ }
+}
+
+ENode *CABI_DestroyObject(Object *dtor, ENode *objexpr, CABIDestroyMode mode, Boolean flag1, Boolean flag2) {
+ ENode *expr;
+ short arg;
+ ENodeList *list;
+
+ switch (mode) {
+ case CABIDestroy2:
+ case CABIDestroy3:
+ if (flag2)
+ arg = 1;
+ else
+ arg = -1;
+ break;
+ case CABIDestroy1:
+ arg = -1;
+ break;
+ case CABIDestroy0:
+ arg = 0;
+ break;
+ default:
+ CError_FATAL(2786);
+ }
+
+ expr = lalloc(sizeof(ENode));
+ expr->type = EFUNCCALL;
+ expr->cost = 200;
+ expr->flags = 0;
+ expr->rtype = &stvoid;
+ expr->data.funccall.funcref = create_objectrefnode(dtor);
+ if (flag1)
+ expr->data.funccall.funcref->flags = expr->data.funccall.funcref->flags | ENODE_FLAG_80;
+ expr->data.funccall.functype = TYPE_FUNC(dtor->type);
+ dtor->flags = dtor->flags | OBJECT_USED;
+
+ list = lalloc(sizeof(ENodeList));
+ list->node = objexpr;
+ expr->data.funccall.args = list;
+
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->next = NULL;
+ list->node = intconstnode(TYPE(&stsignedshort), arg);
+
+ return expr;
+}
diff --git a/compiler_and_linker/FrontEnd/C/CBrowse.c b/compiler_and_linker/FrontEnd/C/CBrowse.c
new file mode 100644
index 0000000..12ea4c8
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CBrowse.c
@@ -0,0 +1,737 @@
+#include "compiler/CBrowse.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/Unmangle.h"
+#include "compiler/objects.h"
+#include "compiler/templates.h"
+#include "cos.h"
+#include "plugin.h"
+
+Boolean gUseTokenStreamSource;
+Boolean gForceSourceLoc;
+Boolean gUseNameTable;
+static GList gBrowseData;
+static GList gClassData;
+static GList gMemberFuncList;
+static int gNextMemberFuncID;
+
+enum ELanguage {
+ langUnknown,
+ langC,
+ langCPlus,
+ langPascal,
+ langObjectPascal,
+ langJava,
+ langAssembler,
+ langFortran,
+ langRez
+};
+
+enum EBrowserItem {
+ browseFunction,
+ browseGlobal,
+ browseClass,
+ browseMacro,
+ browseEnum,
+ browseTypedef,
+ browseConstant,
+ browseTemplate,
+ browsePackage,
+ browseCompSymbolStart = 0x70,
+ browseEnd = 0xFF
+};
+
+enum {
+ kAbstract = 1,
+ kStatic = 2,
+ kFinal = 4,
+ kMember = 8,
+
+ kInterface = 0x80,
+ kPublic = 0x100,
+
+ kInline = 0x80,
+ kPascal = 0x100,
+ kAsm = 0x200,
+ kVirtual = 0x400,
+ kCtor = 0x800,
+ kDtor = 0x1000,
+ kNative = 0x2000,
+ kSynch = 0x4000,
+ kIntrinsic = 0x8000,
+ kConst = 0x10000,
+
+ kTransient = 0x80,
+ kVolatile = 0x100
+};
+
+enum EAccess {
+ accessNone = 0,
+ accessPrivate = 1,
+ accessProtected = 2,
+ accessPublic = 4
+};
+
+enum EMember {
+ memberFunction,
+ memberData,
+ memberEnd = 0xFF
+};
+
+enum ETemplateType {
+ templateClass,
+ templateFunction
+};
+
+static enum EAccess gFromAccessType[] = {
+ accessPublic,
+ accessPrivate,
+ accessProtected,
+ accessNone
+};
+
+typedef struct BrowseHeader {
+ SInt32 browse_header;
+ SInt32 browse_version;
+ SInt16 browse_language;
+ SInt16 uses_name_table;
+ SInt32 earliest_compatible_version;
+ SInt32 reserved[15];
+} BrowseHeader;
+
+// forward decls
+static void RecordUndefinedMemberFunctions(void);
+
+void CBrowse_Setup(CompilerLinkerParamBlk *params) {
+ BrowseHeader hdr;
+
+ CError_ASSERT(123, params != NULL);
+
+ params->object.browsedata = NULL;
+
+ InitGList(&gBrowseData, 0x10000);
+ InitGList(&gMemberFuncList, 1024);
+
+ gNextMemberFuncID = 1;
+ gForceSourceLoc = 0;
+ gUseNameTable = 0;
+
+ memclrw(&hdr, sizeof(hdr));
+ hdr.browse_header = 0xBEABBAEB;
+ hdr.browse_version = 2;
+ hdr.earliest_compatible_version = 2;
+ hdr.browse_language = copts.cplusplus ? langCPlus : langC;
+ hdr.uses_name_table = gUseNameTable;
+
+ AppendGListData(&gBrowseData, &hdr, sizeof(hdr));
+}
+
+void CBrowse_Finish(CompilerLinkerParamBlk *params) {
+ CWMemHandle hnd;
+
+ CError_ASSERT(151, params != NULL);
+
+ if (gBrowseData.size >= sizeof(BrowseHeader)) {
+ RecordUndefinedMemberFunctions();
+ AppendGListByte(&gBrowseData, -1);
+
+ COS_ResizeHandle(gBrowseData.data, gBrowseData.size);
+
+ if (CWSecretAttachHandle(params->context, gBrowseData.data, &hnd) == cwNoErr) {
+ params->object.browsedata = hnd;
+ gBrowseData.data = NULL;
+ }
+ }
+}
+
+void CBrowse_Cleanup(CompilerLinkerParamBlk *params) {
+ FreeGList(&gBrowseData);
+ FreeGList(&gClassData);
+ FreeGList(&gMemberFuncList);
+}
+
+static void AppendGList(GList *dst, GList *src) {
+ SInt32 offset = dst->size;
+
+ AppendGListNoData(dst, src->size);
+ memcpy(*dst->data + offset, *src->data, src->size);
+}
+
+static void RecordName(GList *gl, const char *str, SInt32 id) {
+ HashNameNode *name;
+
+ CError_ASSERT(190, gl && str && *str);
+
+ if (id < 0 && gUseNameTable) {
+ for (name = name_hash_nodes[CHash(str)]; name; name = name->next) {
+ if (!strcmp(str, name->name)) {
+ id = name->id;
+ break;
+ }
+ }
+ }
+
+ if (id >= 0 && gUseNameTable) {
+ AppendGListWord(gl, -1);
+ AppendGListLong(gl, id);
+ } else {
+ int len = strlen(str);
+ AppendGListWord(gl, len);
+ if (len)
+ AppendGListData(gl, str, len + 1);
+ }
+}
+
+void CBrowse_BeginClass(DeclInfo *di, GList *gl) {
+ char *buf;
+ ClassList *base;
+ SInt32 i;
+ TypeClass *tclass;
+
+ CError_ASSERT(227, di && di->thetype && gl);
+
+ *gl = gClassData;
+
+ if (
+ !di->file ||
+ !di->file->fileID ||
+ !di->file->recordbrowseinfo ||
+ !di->file2 ||
+ !di->file2->fileID ||
+ di->sourceoffset <= 0
+ )
+ {
+ memclrw(&gClassData, sizeof(gClassData));
+ return;
+ }
+
+ if (IsTempName(TYPE_CLASS(di->thetype)->classname)) {
+ memclrw(&gClassData, sizeof(gClassData));
+ return;
+ }
+
+ InitGList(&gClassData, 0x4000);
+ AppendGListByte(&gClassData, browseClass);
+ AppendGListWord(&gClassData, di->file->fileID);
+ AppendGListWord(&gClassData, di->file2->fileID);
+ AppendGListLong(&gClassData, di->sourceoffset - 1);
+ CError_ASSERT(270, gClassData.size == 9);
+ AppendGListLong(&gClassData, di->sourceoffset - 1);
+ AppendGListLong(&gClassData, 0);
+ RecordName(&gClassData, TYPE_CLASS(di->thetype)->classname->name, TYPE_CLASS(di->thetype)->classname->id);
+
+ CMangler_MangleType(di->thetype, 0);
+ AppendGListByte(&name_mangle_list, 0);
+
+ buf = lalloc(name_mangle_list.size + 1);
+ strcpy(buf, *name_mangle_list.data);
+
+ while (*buf && *buf >= '0' && *buf <= '9')
+ buf++;
+
+ if (strcmp(TYPE_CLASS(di->thetype)->classname->name, buf))
+ RecordName(&gClassData, buf, -1);
+ else
+ AppendGListWord(&gClassData, 0);
+
+ AppendGListLong(&gClassData, 0);
+
+ i = 0;
+ base = TYPE_CLASS(di->thetype)->bases;
+ while (base) {
+ base = base->next;
+ i++;
+ }
+
+ AppendGListByte(&gClassData, i);
+
+ for (base = TYPE_CLASS(di->thetype)->bases; base; base = base->next) {
+ AppendGListByte(&gClassData, gFromAccessType[base->access]);
+ AppendGListByte(&gClassData, base->is_virtual);
+
+ tclass = base->base;
+ if ((tclass->flags & CLASS_IS_TEMPL_INST) && !TEMPL_CLASS_INST(tclass)->is_specialized)
+ tclass = TYPE_CLASS(TEMPL_CLASS_INST(tclass)->templ);
+
+ CMangler_MangleType(TYPE(tclass), 0);
+ AppendGListByte(&name_mangle_list, 0);
+
+ buf = lalloc(name_mangle_list.size + 1);
+ strcpy(buf, *name_mangle_list.data);
+
+ while (*buf && *buf >= '0' && *buf <= '9')
+ buf++;
+
+ i = base->base->classname->id;
+ while (*buf && *buf >= '0' && *buf <= '9') {
+ i = -1;
+ buf++;
+ }
+
+ RecordName(&gClassData, buf, i);
+ }
+}
+
+void CBrowse_AddClassMemberVar(ObjMemberVar *ivar, SInt32 startOffset, SInt32 endOffset) {
+ short len;
+
+ CError_ASSERT(360, ivar);
+
+ if (gClassData.data && startOffset > 0 && endOffset >= startOffset) {
+ if (tk == ';')
+ endOffset++;
+
+ AppendGListByte(&gClassData, memberData);
+ AppendGListByte(&gClassData, gFromAccessType[ivar->access]);
+ AppendGListLong(&gClassData, 0);
+ AppendGListLong(&gClassData, startOffset - 1);
+ AppendGListLong(&gClassData, endOffset - 1);
+
+ len = strlen(ivar->name->name);
+ AppendGListWord(&gClassData, len);
+ AppendGListData(&gClassData, ivar->name->name, len + 1);
+ }
+}
+
+void CBrowse_AddClassMemberFunction(Object *object, SInt32 startOffset, SInt32 endOffset) {
+ SInt32 flags;
+ SInt32 id;
+ TypeMemberFunc *tfunc;
+
+ CError_ASSERT(380, object);
+
+ if (
+ !IsTempName(object->name) &&
+ gClassData.data &&
+ startOffset > 0 &&
+ endOffset >= startOffset
+ )
+ {
+ flags = 0;
+ CError_ASSERT(391, object->type && IS_TYPE_FUNC(object->type));
+ tfunc = TYPE_METHOD(object->type);
+
+ if (tfunc->flags & FUNC_AUTO_GENERATED)
+ return;
+
+ if (object->datatype == DVFUNC)
+ flags |= kVirtual;
+ if (tfunc->flags & FUNC_PURE)
+ flags |= kAbstract;
+ if (tfunc->is_static)
+ flags |= kStatic;
+ if (tfunc->flags & FUNC_IS_CTOR)
+ flags |= kCtor;
+ if (tfunc->flags & FUNC_IS_DTOR)
+ flags |= kDtor;
+
+ AppendGListByte(&gClassData, memberFunction);
+ AppendGListByte(&gClassData, gFromAccessType[object->access]);
+ AppendGListLong(&gClassData, flags);
+
+ id = tfunc->funcid;
+ if (id <= 0) {
+ // TODO: this is not 64-bit safe
+ if (!(tfunc->flags & FUNC_DEFINED) || id == -1)
+ AppendGListLong(&gMemberFuncList, (SInt32) object);
+ tfunc->funcid = id = gNextMemberFuncID++;
+ }
+
+ AppendGListLong(&gClassData, id);
+ AppendGListLong(&gClassData, startOffset - 1);
+ AppendGListLong(&gClassData, endOffset);
+ }
+}
+
+void CBrowse_AddClassMemberData(Object *object, SInt32 startOffset, SInt32 endOffset) {
+ short len;
+
+ CError_ASSERT(435, object);
+
+ if (gClassData.data && startOffset > 0 && endOffset >= startOffset && object->datatype == DDATA) {
+ if (tk == ';')
+ endOffset++;
+
+ AppendGListByte(&gClassData, memberData);
+ AppendGListByte(&gClassData, gFromAccessType[object->access]);
+ AppendGListLong(&gClassData, kStatic);
+ AppendGListLong(&gClassData, startOffset - 1);
+ AppendGListLong(&gClassData, endOffset - 1);
+
+ len = strlen(object->name->name);
+ AppendGListWord(&gClassData, len);
+ AppendGListData(&gClassData, object->name->name, len + 1);
+ }
+}
+
+void CBrowse_EndClass(SInt32 offset, GList *gl) {
+ CError_ASSERT(453, gl);
+
+ if (gClassData.data) {
+ if (gClassData.size > 0) {
+ if (tk == ';')
+ offset++;
+ memcpy(*gClassData.data + 9, &offset, 4);
+ AppendGList(&gBrowseData, &gClassData);
+ AppendGListByte(&gBrowseData, memberEnd);
+ }
+ FreeGList(&gClassData);
+ }
+
+ gClassData = *gl;
+}
+
+void CBrowse_BeginStruct(DeclInfo *di, TypeStruct *tstruct, GList *gl) {
+ HashNameNode *name;
+
+ CError_ASSERT(480, di && gl);
+
+ *gl = gClassData;
+
+ if (
+ !di->file ||
+ !di->file->fileID ||
+ !di->file->recordbrowseinfo ||
+ !di->file2 ||
+ !di->file2->fileID ||
+ di->sourceoffset <= 0
+ )
+ {
+ memclrw(&gClassData, sizeof(gClassData));
+ return;
+ }
+
+ name = tstruct->name;
+ if (!name || IsTempName(name)) {
+ memclrw(&gClassData, sizeof(gClassData));
+ return;
+ }
+
+ InitGList(&gClassData, 0x4000);
+ AppendGListByte(&gClassData, browseClass);
+ AppendGListWord(&gClassData, di->file->fileID);
+ AppendGListWord(&gClassData, di->file2->fileID);
+ AppendGListLong(&gClassData, di->sourceoffset - 1);
+ CError_ASSERT(521, gClassData.size == 9);
+ AppendGListLong(&gClassData, di->sourceoffset - 1);
+ AppendGListLong(&gClassData, 0);
+ RecordName(&gClassData, name->name, name->id);
+ AppendGListWord(&gClassData, 0);
+ AppendGListLong(&gClassData, 0);
+ AppendGListByte(&gClassData, 0);
+}
+
+void CBrowse_AddStructMember(StructMember *member, SInt32 startOffset, SInt32 endOffset) {
+ short len;
+
+ if (tk == ';')
+ endOffset++;
+
+ if (gClassData.data && member && startOffset > 0 && endOffset >= startOffset) {
+ AppendGListByte(&gClassData, memberData);
+ AppendGListByte(&gClassData, accessPublic);
+ AppendGListLong(&gClassData, 0);
+ AppendGListLong(&gClassData, startOffset - 1);
+ AppendGListLong(&gClassData, endOffset - 1);
+
+ len = strlen(member->name->name);
+ AppendGListWord(&gClassData, len);
+ AppendGListData(&gClassData, member->name->name, len + 1);
+ }
+}
+
+void CBrowse_EndStruct(SInt32 offset, GList *gl) {
+ CError_ASSERT(558, gl);
+
+ if (gClassData.data) {
+ if (offset > 0 && gClassData.size > 0) {
+ memcpy(*gClassData.data + 9, &offset, 4);
+ AppendGList(&gBrowseData, &gClassData);
+ AppendGListByte(&gBrowseData, memberEnd);
+ }
+ FreeGList(&gClassData);
+ }
+
+ gClassData = *gl;
+}
+
+static void EmitStandardData(int item, int fileID1, int fileID2, SInt32 startOffset, SInt32 endOffset, const char *str, SInt32 id, const char *str2, SInt32 id2) {
+ CError_ASSERT(584, str);
+
+ AppendGListByte(&gBrowseData, item);
+ AppendGListWord(&gBrowseData, fileID1);
+ AppendGListWord(&gBrowseData, fileID2);
+ AppendGListLong(&gBrowseData, startOffset - 1);
+ AppendGListLong(&gBrowseData, endOffset - 1);
+ AppendGListLong(&gBrowseData, 0);
+
+ RecordName(&gBrowseData, str, id);
+ if (str2 && str2 != str)
+ RecordName(&gBrowseData, str2, id2);
+ else
+ AppendGListWord(&gBrowseData, 0);
+}
+
+void CBrowse_NewTypedef(NameSpace *nspace, HashNameNode *name, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) {
+ CError_ASSERT(618, file1 && file1->recordbrowseinfo);
+
+ if (file2 && file2->fileID && startOffset > 0 && endOffset >= startOffset) {
+ EmitStandardData(browseTypedef,
+ file1->fileID, file2->fileID,
+ startOffset, endOffset,
+ name->name, name->id,
+ CError_GetQualifiedName(nspace, name), -1);
+ }
+}
+
+void CBrowse_NewEnum(NameSpace *nspace, HashNameNode *name, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) {
+ CError_ASSERT(632, file1 && file1->recordbrowseinfo);
+
+ if (file2 && file2->fileID && startOffset > 0 && endOffset >= startOffset) {
+ EmitStandardData(browseEnum,
+ file1->fileID, file2->fileID,
+ startOffset, endOffset,
+ name->name, name->id,
+ CError_GetQualifiedName(nspace, name), -1);
+ }
+}
+
+void CBrowse_NewEnumConstant(NameSpace *nspace, HashNameNode *name, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) {
+ CError_ASSERT(646, file1 && file1->recordbrowseinfo);
+
+ if (tk == ',')
+ endOffset++;
+
+ if (file2 && file2->fileID && startOffset > 0 && endOffset >= startOffset) {
+ EmitStandardData(browseConstant,
+ file1->fileID, file2->fileID,
+ startOffset, endOffset,
+ name->name, name->id,
+ CError_GetQualifiedName(nspace, name), -1);
+ }
+}
+
+static HashNameNode *CBrowse_GetLinkName(Object *object) {
+ return CMangler_GetLinkName(object);
+}
+
+static void RecordFunction(Object *object, int fileID1, int fileID2, SInt32 startOffset, SInt32 endOffset) {
+ TypeFunc *tfunc;
+ char *tmp;
+ Boolean flag;
+ char *str29;
+ HashNameNode *linkname;
+ SInt32 flags;
+ char *namestr;
+ SInt32 nameid;
+ char *namestr2;
+ SInt32 nameid2;
+ int funcid;
+ char buf[2048];
+ char buf2[256];
+
+ CError_ASSERT(740, object->type && IS_TYPE_FUNC(object->type));
+
+ if (IsTempName(object->name))
+ return;
+
+ tfunc = TYPE_FUNC(object->type);
+ if ((tfunc->flags & (FUNC_AUTO_GENERATED | FUNC_INTRINSIC)) && (!fileID2 || startOffset < 0))
+ return;
+
+ linkname = object->name;
+ tmp = linkname->name;
+ if (!(linkname->name[0] == '_' && linkname->name[1] == '_')) {
+ namestr = tmp;
+ nameid = linkname->id;
+ switch (tmp[0]) {
+ case '.':
+ nameid = -1;
+ namestr += 1;
+ break;
+ case '_':
+ switch (tmp[1]) {
+ case '#':
+ case '%':
+ case '@':
+ nameid = -1;
+ namestr += 2;
+ break;
+ }
+ break;
+ }
+ } else {
+ flag = 1;
+ if (tfunc->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR)) {
+ tmp = TYPE_METHOD(tfunc)->theclass->classname->name;
+ while (*tmp >= '0' && *tmp <= '9')
+ tmp++;
+ MWUnmangleClassName(tmp, buf, sizeof(buf));
+
+ str29 = buf;
+ if ((tmp = strrchr(str29, ':')))
+ str29 = tmp + 1;
+
+ if (tfunc->flags & FUNC_IS_DTOR) {
+ buf2[0] = '~';
+ strncpy(&buf2[1], str29, sizeof(buf2) - 1);
+ namestr = buf2;
+ } else {
+ namestr = str29;
+ }
+
+ flag = 0;
+ }
+
+ if (flag) {
+ MWUnmangle(object->name->name, buf, sizeof(buf));
+ namestr = buf;
+ }
+
+ nameid = -1;
+ }
+
+ while (*namestr >= '0' && *namestr <= '9') {
+ nameid = -1;
+ namestr++;
+ }
+
+ namestr2 = NULL;
+ nameid2 = -1;
+
+ linkname = CBrowse_GetLinkName(object);
+ if (object->name != linkname) {
+ namestr2 = linkname->name;
+ if (linkname->name[0] == '.')
+ namestr2++;
+ else
+ nameid2 = linkname->id;
+ }
+
+ EmitStandardData(browseFunction, fileID1, fileID2, startOffset, endOffset, namestr, nameid, namestr2, nameid2);
+
+ flags = 0;
+ if (object->qual & Q_INLINE)
+ flags |= kInline;
+ if (object->qual & Q_PASCAL)
+ flags |= kPascal;
+ if (object->qual & Q_ASM)
+ flags |= kAsm;
+ if (object->sclass == TK_STATIC)
+ flags |= kStatic;
+ if (tfunc->flags & FUNC_METHOD)
+ flags |= kMember;
+ AppendGListLong(&gBrowseData, flags);
+
+ funcid = 0;
+ if (tfunc->flags & FUNC_METHOD) {
+ funcid = TYPE_METHOD(tfunc)->funcid;
+ if (funcid <= 0) {
+ TYPE_METHOD(tfunc)->funcid = funcid = gNextMemberFuncID++;
+ }
+ }
+ AppendGListLong(&gBrowseData, funcid);
+}
+
+void CBrowse_NewFunction(Object *object, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) {
+ CError_ASSERT(890, file1 && file1->recordbrowseinfo);
+
+ if (file2 && file2->fileID && startOffset > 0 && (endOffset + 1) >= startOffset)
+ RecordFunction(object, file1->fileID, file2->fileID, startOffset, endOffset + 1);
+}
+
+void CBrowse_NewData(Object *object, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) {
+ char *namestr = NULL;
+ SInt32 flags = 0;
+ Boolean is_const = is_const_object(object);
+
+ CError_ASSERT(912, file1 && file1->recordbrowseinfo);
+ CError_ASSERT(913, object);
+
+ if (tk == ';')
+ endOffset++;
+
+ if (file2 && file2->fileID && startOffset > 0 && endOffset >= startOffset) {
+ HashNameNode *name = CBrowse_GetLinkName(object);
+ if (object->name != name)
+ namestr = name->name;
+
+ EmitStandardData(
+ is_const ? browseConstant : browseGlobal,
+ file1->fileID, file2->fileID,
+ startOffset, endOffset,
+ object->name->name, object->name->id,
+ namestr, name->id
+ );
+
+ if (!is_const) {
+ if (object->sclass == TK_STATIC)
+ flags |= kStatic;
+ AppendGListLong(&gBrowseData, flags);
+ }
+ }
+}
+
+void CBrowse_NewMacro(Macro *macro, CPrepFileInfo *file, SInt32 startOffset, SInt32 endOffset) {
+ CError_ASSERT(951, !file || (file->recordbrowseinfo && !macro->is_special));
+
+ if (file && file->fileID && startOffset > 0 && endOffset >= startOffset)
+ EmitStandardData(
+ browseMacro,
+ file->fileID, file->fileID,
+ startOffset, endOffset,
+ macro->name->name, macro->name->id,
+ NULL, -1
+ );
+}
+
+void CBrowse_NewTemplateClass(TemplClass *tmclass, CPrepFileInfo *file, SInt32 startOffset, SInt32 endOffset) {
+ CError_ASSERT(965, !file || file->recordbrowseinfo);
+
+ if (file && file->fileID && startOffset > 0 && endOffset >= startOffset) {
+ EmitStandardData(
+ browseTemplate,
+ file->fileID, file->fileID,
+ startOffset, endOffset,
+ tmclass->theclass.classname->name, tmclass->theclass.classname->id,
+ NULL, -1
+ );
+ AppendGListByte(&gBrowseData, templateClass);
+ }
+}
+
+void CBrowse_NewTemplateFunc(TemplateFunction *tmfunc) {
+ CError_ASSERT(979, !tmfunc->srcfile || tmfunc->srcfile->recordbrowseinfo);
+
+ if (tmfunc->srcfile && tmfunc->srcfile->fileID && tmfunc->startoffset > 0 && tmfunc->endoffset >= tmfunc->startoffset) {
+ EmitStandardData(
+ browseTemplate,
+ tmfunc->srcfile->fileID, tmfunc->srcfile->fileID,
+ tmfunc->startoffset, tmfunc->endoffset,
+ tmfunc->name->name, tmfunc->name->id,
+ NULL, -1
+ );
+ AppendGListByte(&gBrowseData, templateFunction);
+ }
+}
+
+static void RecordUndefinedMemberFunctions(void) {
+ int i;
+ int count;
+ Object **array;
+
+ COS_LockHandleHi(gMemberFuncList.data);
+
+ count = gMemberFuncList.size / sizeof(Object *);
+ array = (Object **) *gMemberFuncList.data;
+ for (i = 0; i < count; i++, array++) {
+ if (IS_TYPE_FUNC((*array)->type) && !(TYPE_FUNC((*array)->type)->flags & FUNC_DEFINED))
+ RecordFunction(*array, 0, 0, -1, -1);
+ }
+
+ COS_UnlockHandle(gMemberFuncList.data);
+}
diff --git a/compiler_and_linker/FrontEnd/C/CClass.c b/compiler_and_linker/FrontEnd/C/CClass.c
new file mode 100644
index 0000000..fad276e
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CClass.c
@@ -0,0 +1,2312 @@
+#include "compiler/CClass.h"
+#include "compiler/CABI.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CInit.h"
+#include "compiler/CInline.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CObjC.h"
+#include "compiler/CParser.h"
+#include "compiler/CRTTI.h"
+#include "compiler/CSOM.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/CodeGen.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct OVClassBase {
+ struct OVClassBase *next;
+ struct OVClass *ovclass;
+ Boolean is_virtual;
+} OVClassBase;
+
+typedef struct OVFunc {
+ struct OVFunc *next;
+ Object *obj;
+ struct OVClass *ovc8;
+ struct OVFunc *ovfC;
+ struct OVFunc *ovf10;
+} OVFunc;
+
+typedef struct OVClass {
+ TypeClass *tclass;
+ OVFunc *vfuncs;
+ OVClassBase *bases;
+ SInt32 offset;
+ SInt32 voffset;
+ Boolean alloced_vtable;
+} OVClass;
+
+typedef struct ThunkList {
+ struct ThunkList *next;
+ Object *thunkobj;
+ Object *obj;
+ SInt32 a;
+ SInt32 b;
+ SInt32 c;
+} ThunkList;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static TypeClass *main_class;
+static ThunkList *cclass_thunklist;
+static TypeClass *cclass_isbase_mostderived;
+static SInt32 cclass_isbase_foundoffset;
+static Boolean cclass_isambigbase;
+static short cclass_founddepth;
+static char *vtable_object_data;
+static SInt32 vtable_data_size;
+static OLinkList *vtable_object_links;
+static TypeClass *cclass_vbase;
+static OVClass *cclass_ovbase;
+static OVClass *cclass_root;
+static Object *found_pure;
+static Boolean check_pures;
+static Object *cclass_dominator_vobject;
+static SInt32 cclass_dominator_voffset;
+static Object *cclass_dominator_oobject;
+static TypeClass *cclass_dominator_oclass;
+static SInt32 cclass_dominator_ooffset;
+static Object *cclass_dominator_eobject;
+
+void CClass_Init(void) {
+ cclass_thunklist = NULL;
+}
+
+void CClass_GenThunks(void) {
+ ThunkList *list;
+
+ for (list = cclass_thunklist; list; list = list->next) {
+ list->thunkobj->flags |= OBJECT_DEFINED;
+ CodeGen_GenVDispatchThunk(list->thunkobj, list->obj, list->a, list->b, list->c);
+ }
+}
+
+static Object *CClass_ThunkObject(Object *obj, SInt32 a, SInt32 b, SInt32 c) {
+ Object *thunkobj;
+ ThunkList *list;
+
+ CInline_ObjectAddrRef(obj);
+ for (list = cclass_thunklist; list; list = list->next) {
+ if (obj == list->obj && a == list->a && b == list->b && c == list->c)
+ return list->thunkobj;
+ }
+
+ thunkobj = CParser_NewCompilerDefFunctionObject();
+ thunkobj->name = CMangler_ThunkName(obj, a, b, c);
+ thunkobj->type = TYPE(&rt_func);
+ thunkobj->sclass = TK_EXTERN;
+ thunkobj->qual = Q_20000;
+ thunkobj->u.func.linkname = thunkobj->name;
+
+ list = galloc(sizeof(ThunkList));
+ list->thunkobj = thunkobj;
+ list->obj = obj;
+ list->a = a;
+ list->b = b;
+ list->c = c;
+ list->next = cclass_thunklist;
+ cclass_thunklist = list;
+
+ return thunkobj;
+}
+
+static Boolean CClass_IsZeroOffsetClass(TypeClass *a, TypeClass *b) {
+ while (1) {
+ if (a == b)
+ return 1;
+
+ if (!a->bases || a->bases->is_virtual)
+ return 0;
+
+ a = a->bases->base;
+ }
+}
+
+static UInt8 CClass_IsCovariantResult(Type *a, UInt32 qualA, Type *b, UInt32 qualB, Boolean errorflag) {
+ TypeClass *tclassA;
+ TypeClass *tclassB;
+
+ if (
+ IS_TYPE_POINTER_ONLY(a) &&
+ IS_TYPE_POINTER_ONLY(b) &&
+ TPTR_QUAL(a) == TPTR_QUAL(b) &&
+ !CParser_IsMoreCVQualified(qualB, qualA) &&
+ IS_TYPE_CLASS(TPTR_TARGET(a)) &&
+ IS_TYPE_CLASS(TPTR_TARGET(b))
+ )
+ {
+ tclassA = TYPE_CLASS(TPTR_TARGET(a));
+ tclassB = TYPE_CLASS(TPTR_TARGET(b));
+ if (tclassA == tclassB || CClass_IsBaseClass(tclassB, tclassA, NULL, errorflag, errorflag)) {
+ if (!CClass_IsZeroOffsetClass(tclassB, tclassA))
+ return 2;
+ else
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+UInt8 CClass_GetOverrideKind(TypeFunc *a, TypeFunc *b, Boolean errorflag) {
+ if (!a->args || !b->args)
+ return 0;
+
+ if (
+ (a->flags & FUNC_CALL_CONV_MASK) != (b->flags & FUNC_CALL_CONV_MASK) ||
+ !is_arglistsame(a->args->next, b->args->next) ||
+ a->args->qual != b->args->qual
+ )
+ return 0;
+
+ if (!is_typesame(a->functype, b->functype)) {
+ switch (CClass_IsCovariantResult(a->functype, a->qual, b->functype, b->qual, errorflag)) {
+ case 0:
+ if (errorflag)
+ CError_Error(CErrorStr227);
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ return 2;
+ default:
+ CError_FATAL(225);
+ }
+ }
+
+ return 1;
+}
+
+Boolean CClass_IsEmpty(TypeClass *tclass) {
+ ClassList *base;
+
+ if (tclass->ivars)
+ return 0;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (!CClass_IsEmpty(base->base))
+ return 0;
+ }
+
+ return 1;
+}
+
+Boolean CClass_IsNonStaticMemberFunc(TypeFunc *tfunc) {
+ return IS_TYPEFUNC_NONSTATIC_METHOD(tfunc) || (tfunc->flags & FUNC_FLAGS_80);
+}
+
+Object *CClass_DefaultConstructor(TypeClass *tclass) {
+ NameSpaceObjectList *nsol;
+ Object *object;
+
+ for (nsol = CScope_FindName(tclass->nspace, constructor_name_node); nsol; nsol = nsol->next) {
+ object = OBJECT(nsol->object);
+ if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) {
+ if ((tclass->flags & CLASS_HAS_VBASES) && !tclass->sominfo) {
+ if (TYPE_FUNC(object->type)->args->next && !TYPE_FUNC(object->type)->args->next->next)
+ return object;
+ } else {
+ if (!TYPE_FUNC(object->type)->args->next)
+ return object;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+Object *CClass_DummyDefaultConstructor(TypeClass *tclass) {
+ Object *ctor;
+ FuncArg *args;
+ NameSpaceObjectList *nsol;
+ HashNameNode *name;
+ TypeMemberFunc *tmethod;
+ Object *object;
+ ObjectList list;
+
+ ctor = NULL;
+
+ for (nsol = CScope_FindName(tclass->nspace, constructor_name_node); nsol; nsol = nsol->next) {
+ object = OBJECT(nsol->object);
+ if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) {
+ CError_ASSERT(305, args = TYPE_FUNC(object->type)->args);
+ args = args->next;
+ if ((tclass->flags & CLASS_HAS_VBASES) && !tclass->sominfo) {
+ CError_ASSERT(309, args);
+ args = args->next;
+ }
+ CError_ASSERT(312, args);
+
+ if (args->dexpr) {
+ if (ctor) {
+ list.next = NULL;
+ list.object = object;
+ CError_OverloadedFunctionError(ctor, &list);
+ break;
+ }
+ ctor = object;
+ }
+ }
+ }
+
+ if (!ctor) {
+ CError_Error(CErrorStr203);
+ return NULL;
+ }
+
+ name = GetHashNameNodeExport("__defctor");
+ if ((nsol = CScope_FindName(tclass->nspace, name))) {
+ CError_ASSERT(339, nsol->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(nsol->object)->type));
+ return OBJECT(nsol->object);
+ }
+
+ tmethod = galloc(sizeof(TypeMemberFunc));
+ memclrw(tmethod, sizeof(TypeMemberFunc));
+
+ tmethod->type = TYPEFUNC;
+ tmethod->functype = TYPE(&void_ptr);
+ tmethod->flags = FUNC_METHOD;
+ tmethod->theclass = tclass;
+ CDecl_SetFuncFlags(TYPE_FUNC(tmethod), 0);
+
+ if ((tclass->flags & CLASS_HAS_VBASES) && !tclass->sominfo)
+ CDecl_AddArgument(TYPE_FUNC(tmethod), TYPE(&stsignedshort));
+
+ CDecl_AddThisPointerArgument(TYPE_FUNC(tmethod), tclass);
+
+ object = CParser_NewCompilerDefFunctionObject();
+ object->type = TYPE(tmethod);
+ object->qual = Q_INLINE | Q_MANGLE_NAME;
+ object->nspace = tclass->nspace;
+ object->name = name;
+
+ CScope_AddObject(tclass->nspace, name, OBJ_BASE(object));
+ CParser_RegisterDummyCtorFunction(object, ctor);
+ return object;
+}
+
+ENode *CClass_DefaultConstructorCall(TypeClass *tclass, TypeClass *b, ENode *objexpr, SInt32 varg, Boolean flag1, Boolean flag2, Boolean *errorflag) {
+ NameSpaceObjectList *nsol;
+ Object *ctor;
+ Object *object;
+ FuncArg *args;
+ ENodeList *argexprs;
+ ENode *expr;
+ BClassList *path;
+ BClassList list1;
+ ObjectList objlist;
+ BClassList list2;
+ short founddepth;
+ Boolean isambigbase;
+
+ *errorflag = 0;
+
+ if (!(nsol = CScope_FindName(tclass->nspace, constructor_name_node)))
+ return NULL;
+
+ ctor = NULL;
+ do {
+ object = OBJECT(nsol->object);
+ if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) {
+ CError_ASSERT(397, args = TYPE_FUNC(object->type)->args);
+
+ args = args->next;
+
+ if ((tclass->flags & CLASS_HAS_VBASES) && !tclass->sominfo) {
+ CError_ASSERT(401, args);
+ args = args->next;
+ }
+
+ if (!args || args->dexpr) {
+ if (ctor) {
+ objlist.next = NULL;
+ objlist.object = object;
+ CError_OverloadedFunctionError(ctor, &objlist);
+ break;
+ }
+ ctor = object;
+ }
+ }
+ } while ((nsol = nsol->next));
+
+ if (!ctor) {
+ *errorflag = 1;
+ return NULL;
+ }
+
+ if (flag1) {
+ if (b) {
+ if (flag2) {
+ if ((path = CClass_GetBasePath(b, tclass, &founddepth, &isambigbase)))
+ list1 = *path;
+ else
+ goto skipCheck;
+ } else {
+ list1.next = &list2;
+ list1.type = TYPE(b);
+ list2.next = NULL;
+ list2.type = TYPE(tclass);
+ }
+ } else {
+ list1.next = NULL;
+ list1.type = TYPE(tclass);
+ }
+ CClass_CheckPathAccess(&list1, ctor, ctor->access);
+ }
+
+skipCheck:
+ if ((tclass->flags & CLASS_HAS_VBASES) && !tclass->sominfo) {
+ argexprs = lalloc(sizeof(ENodeList));
+ argexprs->next = NULL;
+ argexprs->node = intconstnode(TYPE(&stsignedshort), varg);
+ } else {
+ argexprs = NULL;
+ }
+
+ CError_ASSERT(471, IS_TYPE_POINTER_ONLY(objexpr->rtype));
+
+ objexpr = makemonadicnode(objexpr, EINDIRECT);
+ objexpr->rtype = TYPE(tclass);
+
+ list1.next = NULL;
+ list1.type = TYPE(tclass);
+
+ expr = CExpr_GenericFuncCall(
+ &list1,
+ objexpr,
+ 0,
+ ctor,
+ NULL,
+ NULL,
+ argexprs,
+ 0,
+ 0,
+ 0
+ );
+
+ if (ENODE_IS2(expr, EFUNCCALL, EFUNCCALLP))
+ expr->rtype = CDecl_NewPointerType(TYPE(tclass));
+
+ return expr;
+}
+
+Object *CClass_AssignmentOperator(TypeClass *tclass) {
+ NameSpaceObjectList *nsol;
+ Object *object;
+
+ for (nsol = CScope_FindName(tclass->nspace, asop_name_node); nsol; nsol = nsol->next) {
+ object = OBJECT(nsol->object);
+ if (
+ object->otype == OT_OBJECT &&
+ IS_TYPE_FUNC(object->type) &&
+ TYPE_FUNC(object->type)->args &&
+ TYPE_FUNC(object->type)->args->next &&
+ !TYPE_FUNC(object->type)->args->next->next
+ )
+ {
+ if (
+ IS_TYPE_CLASS(TYPE_FUNC(object->type)->args->next->type) &&
+ TYPE_CLASS(TYPE_FUNC(object->type)->args->next->type) == tclass
+ )
+ return object;
+
+ if (
+ IS_TYPE_REFERENCE(TYPE_FUNC(object->type)->args->next->type) &&
+ TPTR_TARGET(TYPE_FUNC(object->type)->args->next->type) == TYPE(tclass)
+ )
+ return object;
+ }
+ }
+
+ return NULL;
+}
+
+Object *CClass_CopyConstructor(TypeClass *tclass) {
+ NameSpaceObjectList *nsol;
+ Object *object;
+ FuncArg *args;
+
+ if (tclass->sominfo)
+ return NULL;
+
+ for (nsol = CScope_FindName(tclass->nspace, constructor_name_node); nsol; nsol = nsol->next) {
+ object = OBJECT(nsol->object);
+ if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) {
+ CError_ASSERT(532, args = TYPE_FUNC(object->type)->args);
+
+ args = args->next;
+
+ if (tclass->flags & CLASS_HAS_VBASES) {
+ CError_ASSERT(536, args);
+ args = args->next;
+ }
+
+ if (
+ args &&
+ args != &elipsis &&
+ (!args->next || args->next->dexpr) &&
+ IS_TYPE_REFERENCE(args->type) &&
+ TPTR_TARGET(args->type) == TYPE(tclass)
+ )
+ return object;
+ }
+ }
+
+ return NULL;
+}
+
+NameSpaceObjectList *CClass_MemberObject(TypeClass *tclass, HashNameNode *name) {
+ NameSpaceObjectList *nsol;
+
+ if ((nsol = CScope_FindName(tclass->nspace, name)) && nsol->object->otype == OT_OBJECT)
+ return nsol;
+
+ return NULL;
+}
+
+NameSpaceObjectList *CClass_Constructor(TypeClass *tclass) {
+ NameSpaceObjectList *nsol;
+
+ if (
+ (nsol = CScope_FindName(tclass->nspace, constructor_name_node)) &&
+ nsol->object->otype == OT_OBJECT &&
+ IS_TYPE_FUNC(OBJECT(nsol->object)->type)
+ )
+ return nsol;
+
+ return NULL;
+}
+
+Object *CClass_Destructor(TypeClass *tclass) {
+ NameSpaceObjectList *nsol;
+
+ for (nsol = CScope_FindName(tclass->nspace, destructor_name_node); nsol; nsol = nsol->next) {
+ if (
+ nsol->object->otype == OT_OBJECT &&
+ IS_TYPE_FUNC(OBJECT(nsol->object)->type)
+ )
+ return OBJECT(nsol->object);
+ }
+
+ return NULL;
+}
+
+Boolean CClass_IsConstructor(Object *obj) {
+ return obj && IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_IS_CTOR);
+}
+
+Boolean CClass_IsDestructor(Object *obj) {
+ return obj && IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_IS_DTOR);
+}
+
+Boolean CClass_IsPODClass(TypeClass *tclass) {
+ NameSpaceObjectList *nsol;
+ Object *object;
+ ObjMemberVar *ivar;
+ Type *type;
+
+ if (tclass->vtable || tclass->bases || CClass_Destructor(tclass))
+ return 0;
+
+ for (nsol = CClass_Constructor(tclass); nsol; nsol = nsol->next) {
+ if (
+ nsol->object->otype == OT_OBJECT &&
+ IS_TYPE_FUNC(OBJECT(nsol->object)->type) &&
+ !(TYPE_FUNC(OBJECT(nsol->object)->type)->flags & FUNC_AUTO_GENERATED)
+ )
+ return 0;
+ }
+
+ object = CClass_AssignmentOperator(tclass);
+ if (object && !(TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED))
+ return 0;
+
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ if (ivar->access != ACCESSPUBLIC)
+ return 0;
+
+ type = ivar->type;
+ while (IS_TYPE_ARRAY(type))
+ type = TPTR_TARGET(type);
+
+ switch (type->type) {
+ case TYPECLASS:
+ if (!CClass_IsPODClass(TYPE_CLASS(type)))
+ return 0;
+ break;
+ case TYPEMEMBERPOINTER:
+ return 0;
+ case TYPEPOINTER:
+ if (TPTR_QUAL(type) & Q_REFERENCE)
+ return 0;
+ break;
+ }
+ }
+
+ return 1;
+}
+
+Boolean CClass_IsTrivialCopyClass(TypeClass *tclass) {
+ Object *object;
+ ClassList *base;
+ ObjMemberVar *ivar;
+ Type *type;
+
+ if (tclass->vtable || tclass->vbases || CClass_Destructor(tclass))
+ return 0;
+
+ object = CClass_CopyConstructor(tclass);
+ if (object && IS_TYPE_FUNC(object->type) && !(TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED))
+ return 0;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (!CClass_IsTrivialCopyClass(base->base))
+ return 0;
+ }
+
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ type = ivar->type;
+ while (IS_TYPE_ARRAY(type))
+ type = TPTR_TARGET(type);
+
+ if (IS_TYPE_CLASS(type) && !CClass_IsTrivialCopyClass(TYPE_CLASS(type)))
+ return 0;
+ }
+
+ return 1;
+}
+
+Boolean CClass_IsTrivialCopyAssignClass(TypeClass *tclass) {
+ Object *object;
+ ObjMemberVar *ivar;
+ Type *type;
+
+ if (tclass->vtable || tclass->bases || CClass_Destructor(tclass))
+ return 0;
+
+ object = CClass_AssignmentOperator(tclass);
+ if (object && !(TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED))
+ return 0;
+
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ type = ivar->type;
+ while (IS_TYPE_ARRAY(type))
+ type = TPTR_TARGET(type);
+
+ if (IS_TYPE_REFERENCE(type))
+ return 0;
+ if (CParser_IsConst(type, ivar->qual))
+ return 0;
+ if (IS_TYPE_CLASS(type) && !CClass_IsTrivialCopyAssignClass(TYPE_CLASS(type)))
+ return 0;
+ }
+
+ return 1;
+}
+
+Boolean CClass_ReferenceArgument(TypeClass *tclass) {
+ if ((tclass->flags & (CLASS_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST)
+ CDecl_CompleteType(TYPE(tclass));
+
+ if (copts.simple_class_byval)
+ return !CClass_IsTrivialCopyClass(tclass);
+
+ return CClass_Destructor(tclass) || CClass_CopyConstructor(tclass);
+}
+
+BClassList *CClass_GetPathCopy(BClassList *path, Boolean is_global) {
+ BClassList *last;
+ BClassList *copy;
+
+ if (!path)
+ return NULL;
+
+ copy = last = is_global ? galloc(sizeof(BClassList)) : lalloc(sizeof(BClassList));
+ last->next = path->next;
+ last->type = path->type;
+
+ while ((path = path->next)) {
+ last->next = is_global ? galloc(sizeof(BClassList)) : lalloc(sizeof(BClassList));
+ last = last->next;
+ last->next = path->next;
+ last->type = path->type;
+ }
+
+ return copy;
+}
+
+BClassList *CClass_AppendPath(BClassList *dest, BClassList *src) {
+ BClassList *last;
+
+ if (!(last = dest))
+ return src;
+
+ while (last->next)
+ last = last->next;
+
+ while (src && src->type == last->type)
+ src = src->next;
+
+ last->next = src;
+ return dest;
+}
+
+static AccessType CClass_GetPathAccess(BClassList *path) {
+ AccessType result;
+ ClassList *base;
+ TypeClass *tclass;
+
+ CError_ASSERT(930, path);
+
+ result = ACCESSPUBLIC;
+
+ while (1) {
+ tclass = TYPE_CLASS(path->type);
+ if (!(path = path->next))
+ break;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (base->base == TYPE_CLASS(path->type))
+ break;
+ }
+
+ CError_ASSERT(939, base);
+
+ switch (base->access) {
+ case ACCESSPUBLIC:
+ break;
+ case ACCESSPROTECTED:
+ if (result == ACCESSPUBLIC)
+ result = ACCESSPROTECTED;
+ break;
+ case ACCESSPRIVATE:
+ if (result == ACCESSPUBLIC || result == ACCESSPROTECTED)
+ result = ACCESSPRIVATE;
+ else
+ return ACCESSNONE;
+ break;
+ case ACCESSNONE:
+ return ACCESSNONE;
+ default:
+ CError_FATAL(960);
+ }
+ }
+
+ return result;
+}
+
+Boolean CClass_IsMoreAccessiblePath(BClassList *path1, BClassList *path2) {
+ switch (CClass_GetPathAccess(path2)) {
+ case ACCESSPUBLIC:
+ return 0;
+ case ACCESSNONE:
+ return 1;
+ default:
+ CError_FATAL(978);
+ case ACCESSPROTECTED:
+ switch (CClass_GetPathAccess(path1)) {
+ case ACCESSPUBLIC:
+ return 1;
+ case ACCESSPRIVATE:
+ case ACCESSPROTECTED:
+ case ACCESSNONE:
+ return 0;
+ default:
+ CError_FATAL(987);
+ }
+ case ACCESSPRIVATE:
+ switch (CClass_GetPathAccess(path1)) {
+ case ACCESSPUBLIC:
+ case ACCESSPROTECTED:
+ return 1;
+ case ACCESSPRIVATE:
+ case ACCESSNONE:
+ return 0;
+ default:
+ CError_FATAL(997);
+ }
+ }
+
+ return 0;
+}
+
+static BClassList *CClass_GetBasePathRec(TypeClass *a, TypeClass *b, SInt32 offset, short depth) {
+ ClassList *base;
+ BClassList *checkpath;
+ BClassList *bestpath;
+ BClassList *newpath;
+ SInt32 newOffset;
+
+ for (base = a->bases, bestpath = NULL; base; base = base->next) {
+ if (base->is_virtual)
+ newOffset = CClass_VirtualBaseOffset(cclass_isbase_mostderived, base->base);
+ else
+ newOffset = offset + base->offset;
+
+ if (base->base == b) {
+ if (cclass_founddepth && newOffset != cclass_isbase_foundoffset) {
+ cclass_isambigbase = 1;
+ return NULL;
+ }
+
+ cclass_isbase_foundoffset = newOffset;
+ cclass_founddepth = depth;
+
+ bestpath = lalloc(sizeof(BClassList));
+ bestpath->next = NULL;
+ bestpath->type = TYPE(b);
+ } else if ((checkpath = CClass_GetBasePathRec(base->base, b, newOffset, depth + 1))) {
+ newpath = lalloc(sizeof(BClassList));
+ newpath->next = checkpath;
+ newpath->type = TYPE(base->base);
+ if (!bestpath || CClass_IsMoreAccessiblePath(newpath, bestpath))
+ bestpath = newpath;
+ }
+ }
+
+ return bestpath;
+}
+
+BClassList *CClass_GetBasePath(TypeClass *a, TypeClass *b, short *founddepth, Boolean *isambigbase) {
+ BClassList *path;
+ BClassList *result;
+
+ if ((a->flags & (CLASS_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST)
+ CDecl_CompleteType(TYPE(a));
+ if ((b->flags & (CLASS_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST)
+ CDecl_CompleteType(TYPE(b));
+
+ cclass_founddepth = 0;
+ cclass_isbase_mostderived = a;
+ cclass_isbase_foundoffset = -1;
+ cclass_isambigbase = 0;
+
+ if ((path = CClass_GetBasePathRec(a, b, 0, 1))) {
+ *founddepth = cclass_founddepth;
+ *isambigbase = cclass_isambigbase;
+
+ result = lalloc(sizeof(BClassList));
+ result->next = path;
+ result->type = TYPE(a);
+ return result;
+ } else {
+ *isambigbase = 0;
+ return NULL;
+ }
+}
+
+Boolean CClass_IsBaseClass(TypeClass *a, TypeClass *b, short *founddepth, Boolean pathcheckflag, Boolean ambigerrorflag) {
+ BClassList *path;
+ short depth;
+ Boolean isambigbase;
+
+ if ((path = CClass_GetBasePath(a, b, &depth, &isambigbase))) {
+ if (isambigbase && ambigerrorflag)
+ CError_Error(CErrorStr188);
+
+ if (pathcheckflag)
+ CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC);
+
+ if (founddepth)
+ *founddepth = depth;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+TypeClass *CClass_GetQualifiedClass(void) {
+ DeclInfo di;
+
+ memclrw(&di, sizeof(di));
+ CParser_GetDeclSpecs(&di, 0);
+
+ if (IS_TYPE_CLASS(di.thetype))
+ return TYPE_CLASS(di.thetype);
+
+ return NULL;
+}
+
+ENode *CClass_AccessPathCast(BClassList *path, ENode *expr, Boolean reverse) {
+ ClassList *base;
+ SInt32 offset;
+
+ while (path && path->next) {
+ base = TYPE_CLASS(path->type)->bases;
+ while (1) {
+ if (base->base == TYPE_CLASS(path->next->type))
+ break;
+ CError_ASSERT(1157, base = base->next);
+ }
+
+ if (base->is_virtual) {
+ if (reverse) {
+ CError_Error(CErrorStr164);
+ break;
+ }
+
+ if (!base->base->sominfo) {
+ offset = base->offset;
+ if (offset && !canadd(expr, offset)) {
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD);
+ optimizecomm(expr);
+ }
+
+ expr->rtype = CDecl_NewPointerType(CDecl_NewPointerType(TYPE(base->base)));
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = expr->data.monadic->rtype;
+ }
+ } else {
+ offset = base->offset;
+ if (offset) {
+ if (reverse)
+ offset = -offset;
+ if (!canadd(expr, offset)) {
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD);
+ optimizecomm(expr);
+ }
+ }
+ }
+
+ path = path->next;
+ }
+
+ return expr;
+}
+
+ENode *CClass_ClassPointerCast(ENode *expr, TypeClass *a, TypeClass *b, Boolean typconflag, Boolean ambigerrorflag, Boolean pathcheckflag) {
+ BClassList *path;
+ Boolean reverse;
+ short depth;
+ Boolean isambigbase;
+
+ reverse = 0;
+
+ if (a != b) {
+ if (!(path = CClass_GetBasePath(a, b, &depth, &isambigbase))) {
+ CError_ASSERT(1216, typconflag);
+ if ((path = CClass_GetBasePath(b, a, &depth, &isambigbase))) {
+ reverse = 1;
+ goto doCast;
+ }
+ } else {
+ doCast:
+ if (isambigbase && ambigerrorflag)
+ CError_Error(CErrorStr188);
+ if (pathcheckflag)
+ CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC);
+ if (!(a->flags & CLASS_SINGLE_OBJECT) && !b->sominfo)
+ expr = CClass_AccessPathCast(path, expr, reverse);
+ }
+ }
+
+ if (typconflag && ENODE_IS(expr, EINDIRECT) && IS_TYPE_POINTER_ONLY(expr->rtype))
+ expr = makemonadicnode(expr, ETYPCON);
+
+ return expr;
+}
+
+ENode *CClass_DirectBasePointerCast(ENode *expr, TypeClass *a, TypeClass *b) {
+ ClassList *base;
+ VClassList *vbase;
+ BClassList *path;
+ BClassList list1;
+ BClassList list2;
+ short depth;
+ Boolean isambigbase;
+
+ for (base = a->bases; base; base = base->next) {
+ if (base->base == b) {
+ list1.next = &list2;
+ list1.type = TYPE(a);
+ list2.next = NULL;
+ list2.type = TYPE(b);
+ return CClass_AccessPathCast(&list1, expr, 0);
+ }
+ }
+
+ for (vbase = a->vbases; vbase; vbase = vbase->next) {
+ if (vbase->base == b) {
+ CError_ASSERT(1273, path = CClass_GetBasePath(a, b, &depth, &isambigbase));
+ return CClass_AccessPathCast(path, expr, 0);
+ }
+ }
+
+ CError_FATAL(1277);
+ return expr;
+}
+
+SInt32 CClass_GetPathOffset(BClassList *path) {
+ SInt32 offset;
+ ClassList *base;
+
+ offset = 0;
+
+ while (path->next) {
+ if (path->type != path->next->type) {
+ for (base = TYPE_CLASS(path->type)->bases; base; base = base->next) {
+ if (base->base == TYPE_CLASS(path->next->type))
+ break;
+ }
+
+ if (!base) {
+ CError_Error(CErrorStr221);
+ return offset;
+ }
+ }
+
+ if (base->is_virtual)
+ return -1;
+ offset += base->offset;
+
+ path = path->next;
+ }
+
+ return offset;
+}
+
+Boolean CClass_ClassDominates(TypeClass *tclass, TypeClass *baseclass) {
+ ClassList *base;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (base->base == baseclass || CClass_ClassDominates(base->base, baseclass))
+ return 1;
+ }
+
+ return 0;
+}
+
+SInt32 CClass_VirtualBaseOffset(TypeClass *tclass, TypeClass *baseclass) {
+ VClassList *vbase;
+
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ if (vbase->base == baseclass)
+ return vbase->offset;
+ }
+
+ CError_FATAL(1342);
+ return 0;
+}
+
+SInt32 CClass_VirtualBaseVTableOffset(TypeClass *tclass, TypeClass *baseclass) {
+ VClassList *vbase;
+
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ if (vbase->base == baseclass)
+ return vbase->voffset;
+ }
+
+ CError_FATAL(1359);
+ return 0;
+}
+
+SInt32 CClass_GetMemberOffset(TypeClass *tclass, HashNameNode *name, ObjMemberVar **resultIvar) {
+ ObjMemberVar *ivar;
+ ClassList *base;
+ SInt32 offset;
+ SInt32 tmp;
+ Boolean foundflag;
+
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ if (ivar->name == name) {
+ if (resultIvar)
+ *resultIvar = ivar;
+ return ivar->offset;
+ }
+ }
+
+ for (base = tclass->bases, foundflag = 0; base; base = base->next) {
+ switch ((tmp = CClass_GetMemberOffset(base->base, name, resultIvar))) {
+ case -3:
+ case -2:
+ return tmp;
+ case -1:
+ break;
+ default:
+ if (base->is_virtual)
+ return -3;
+ if (foundflag)
+ return -2;
+ foundflag = 1;
+ offset = base->offset + tmp;
+ }
+ }
+
+ return foundflag ? offset : -1;
+}
+
+Boolean CClass_OverridesBaseMember(TypeClass *tclass, HashNameNode *name, Object *obj) {
+ NameSpaceObjectList *nsol;
+ ClassList *base;
+ Boolean result;
+
+ result = 0;
+ for (base = tclass->bases; base; base = base->next) {
+ if (base->base->vtable) {
+ for (nsol = CScope_FindName(base->base->nspace, name); nsol; nsol = nsol->next) {
+ if (
+ nsol->object->otype == OT_OBJECT &&
+ OBJECT(nsol->object)->datatype == DVFUNC &&
+ CClass_GetOverrideKind(TYPE_FUNC(OBJECT(nsol->object)->type), TYPE_FUNC(obj->type), 1)
+ )
+ result = 1;
+ }
+
+ if (CClass_OverridesBaseMember(base->base, name, obj))
+ result = 1;
+ }
+ }
+
+ return result;
+}
+
+static OVClass *CClass_FindOVClass(OVClass *ovclass, TypeClass *tclass, SInt32 offset) {
+ OVClassBase *ovbase;
+
+ if (ovclass->tclass == tclass && ovclass->offset == offset)
+ return ovclass;
+
+ for (ovbase = ovclass->bases; ovbase; ovbase = ovbase->next) {
+ if ((ovclass = CClass_FindOVClass(ovbase->ovclass, tclass, offset)))
+ return ovclass;
+ }
+
+ return NULL;
+}
+
+static OVClass *CClass_BuildOVClassTree(OVClass *root, TypeClass *tclass, SInt32 offset, SInt32 voffset) {
+ ClassList *base;
+ Object *object;
+ OVClass *tree;
+ OVFunc *ovfunc;
+ OVClassBase *ovbase;
+ SInt32 vboffset;
+ SInt32 vbvoffset;
+ CScopeObjectIterator iter;
+
+ tree = lalloc(sizeof(OVClass));
+ memclrw(tree, sizeof(OVClass));
+
+ tree->tclass = tclass;
+ tree->offset = offset;
+ tree->voffset = voffset;
+ if (!root)
+ root = tree;
+
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (object->datatype == DVFUNC) {
+ ovfunc = lalloc(sizeof(OVFunc));
+ memclrw(ovfunc, sizeof(OVFunc));
+
+ ovfunc->next = tree->vfuncs;
+ ovfunc->obj = object;
+ tree->vfuncs = ovfunc;
+ }
+ }
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (base->base->vtable || base->base->sominfo) {
+ ovbase = lalloc(sizeof(OVClassBase));
+ memclrw(ovbase, sizeof(OVClassBase));
+
+ if (base->is_virtual) {
+ vboffset = CClass_VirtualBaseOffset(main_class, base->base);
+ if (!(ovbase->ovclass = CClass_FindOVClass(root, base->base, vboffset))) {
+ vbvoffset = CClass_VirtualBaseVTableOffset(main_class, base->base);
+ ovbase->ovclass = CClass_BuildOVClassTree(root, base->base, vboffset, vbvoffset);
+ }
+ ovbase->is_virtual = 1;
+ } else {
+ ovbase->ovclass = CClass_BuildOVClassTree(
+ root,
+ base->base,
+ offset + base->offset,
+ voffset + base->voffset);
+ ovbase->is_virtual = 0;
+ }
+
+ ovbase->next = tree->bases;
+ tree->bases = ovbase;
+ }
+ }
+
+ return tree;
+}
+
+static Boolean CClass_IsBaseOf(OVClass *a, OVClass *b) {
+ OVClassBase *ovbase;
+
+ for (ovbase = b->bases; ovbase; ovbase = ovbase->next) {
+ if (
+ (ovbase->ovclass->tclass == a->tclass && ovbase->ovclass->offset == a->offset) ||
+ CClass_IsBaseOf(a, ovbase->ovclass)
+ )
+ {
+ if (!cclass_ovbase && ovbase->is_virtual)
+ cclass_ovbase = ovbase->ovclass;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void CClass_FindOVFunc(OVClass *a, OVClass *b, OVFunc *func) {
+ OVFunc *scan;
+ OVClassBase *ovbase;
+ UInt8 overrideKind;
+
+ if (CClass_IsBaseOf(b, a)) {
+ for (scan = a->vfuncs; scan; scan = scan->next) {
+ if (
+ (func->obj->name == scan->obj->name) &&
+ (overrideKind = CClass_GetOverrideKind(TYPE_FUNC(func->obj->type), TYPE_FUNC(scan->obj->type), 0))
+ )
+ {
+ if (func->ovc8) {
+ if (func->ovc8->tclass == a->tclass || CClass_ClassDominates(func->ovc8->tclass, a->tclass))
+ return;
+ if (!CClass_ClassDominates(a->tclass, func->ovc8->tclass)) {
+ func->ovf10 = scan;
+ return;
+ }
+ }
+
+ if (a == cclass_root) {
+ TYPE_FUNC(scan->obj->type)->flags |= FUNC_FLAGS_20;
+ if (overrideKind == 2)
+ TYPE_FUNC(scan->obj->type)->flags |= FUNC_FLAGS_400000;
+ }
+
+ func->ovc8 = a;
+ func->ovfC = scan;
+ func->ovf10 = NULL;
+ return;
+ }
+ }
+
+ for (ovbase = a->bases; ovbase; ovbase = ovbase->next)
+ CClass_FindOVFunc(ovbase->ovclass, b, func);
+ }
+}
+
+static TypeList *CClass_GetCoVariantClassList(TypeList *list, TypeClass *tclass, Object *func, Boolean flag) {
+ Object *object;
+ TypeList *scan;
+ Type *type;
+ ClassList *base;
+ CScopeObjectIterator iter;
+
+ if (!flag) {
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (
+ object->name == func->name &&
+ object->datatype == DVFUNC &&
+ CClass_GetOverrideKind(TYPE_FUNC(object->type), TYPE_FUNC(func->type), 0) == 2
+ )
+ {
+ CError_ASSERT(1686,
+ IS_TYPE_POINTER_ONLY(TYPE_FUNC(object->type)->functype) &&
+ IS_TYPE_CLASS(TPTR_TARGET(TYPE_FUNC(object->type)->functype)));
+
+ type = TPTR_TARGET(TYPE_FUNC(object->type)->functype);
+ for (scan = list; scan; scan = scan->next) {
+ if (scan->type == type)
+ break;
+ }
+
+ if (!scan) {
+ scan = lalloc(sizeof(TypeList));
+ scan->type = type;
+ scan->next = list;
+ list = scan;
+ }
+ }
+ }
+ }
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (base->base->vtable)
+ list = CClass_GetCoVariantClassList(list, base->base, func, 0);
+ }
+
+ return list;
+}
+
+static TypeMemberFunc *CClass_GetCovariantType(TypeMemberFunc *tmethod, Type *type) {
+ TypePointer *tptr;
+ TypeMemberFunc *result;
+
+ CError_ASSERT(1724,
+ IS_TYPE_METHOD(tmethod) &&
+ IS_TYPE_POINTER_ONLY(tmethod->functype));
+
+ tptr = galloc(sizeof(TypePointer));
+ *tptr = *TYPE_POINTER(tmethod->functype);
+ tptr->target = type;
+
+ result = galloc(sizeof(TypeMemberFunc));
+ *result = *tmethod;
+ result->flags &= ~(FUNC_FLAGS_20 | FUNC_FLAGS_400000);
+ result->functype = TYPE(tptr);
+ return result;
+}
+
+static Object *CClass_FindCovariantFunction(Object *func, Type *type) {
+ NameSpaceObjectList *nsol;
+
+ nsol = CScope_FindName(
+ TYPE_METHOD(func->type)->theclass->nspace,
+ CMangler_GetCovariantFunctionName(func, TYPE_CLASS(type)));
+
+ CError_ASSERT(1754, nsol && !nsol->next && nsol->object->otype == OT_OBJECT);
+
+ return OBJECT(nsol->object);
+}
+
+static ObjectList *CClass_DeclareCovariantFuncs(ObjectList *list, Object *func, TypeClass *tclass) {
+ Object *newfunc;
+ HashNameNode *name;
+ TypeList *types;
+ ObjectList *newlist;
+
+ for (types = CClass_GetCoVariantClassList(NULL, tclass, func, 1); types; types = types->next) {
+ name = CMangler_GetCovariantFunctionName(func, TYPE_CLASS(types->type));
+
+ newfunc = galloc(sizeof(Object));
+ memclrw(newfunc, sizeof(Object));
+
+ newfunc->otype = OT_OBJECT;
+ newfunc->datatype = DFUNC;
+ newfunc->section = func->section;
+ newfunc->nspace = func->nspace;
+ newfunc->name = name;
+ newfunc->type = TYPE(CClass_GetCovariantType(TYPE_METHOD(func->type), types->type));
+ newfunc->qual = func->qual & ~Q_INLINE;
+ newfunc->sclass = func->sclass;
+ newfunc->u.func.linkname = name;
+
+ newlist = lalloc(sizeof(ObjectList));
+ newlist->object = newfunc;
+ newlist->next = list;
+ list = newlist;
+ }
+
+ return list;
+}
+
+void CClass_DefineCovariantFuncs(Object *method, CI_FuncData *ifuncdata) {
+ NameSpace *nspace;
+ TypeList *types;
+ Object *covariantFunc;
+ Statement *stmt;
+ Type *tptr;
+ Statement firstStmt;
+
+ for (types = CClass_GetCoVariantClassList(NULL, TYPE_METHOD(method->type)->theclass, method, 1); types; types = types->next) {
+ covariantFunc = CClass_FindCovariantFunction(method, types->type);
+ tptr = CDecl_NewPointerType(types->type);
+
+ nspace = CFunc_FuncGenSetup(&firstStmt, covariantFunc);
+ CInline_UnpackIFunctionData(covariantFunc, ifuncdata, &firstStmt);
+
+ for (stmt = &firstStmt; stmt; stmt = stmt->next) {
+ if (stmt->type == ST_RETURN && stmt->expr)
+ stmt->expr = CExpr_AssignmentPromotion(stmt->expr, tptr, ENODE_QUALS(stmt->expr), 0);
+ }
+
+ CFunc_Gen(&firstStmt, covariantFunc, 0);
+ cscope_current = nspace->parent;
+ }
+}
+
+static void CClass_OverrideOVClassTree(OVClass *ovclass) {
+ OVClassBase *ovbase;
+ OVFunc *ovfunc;
+
+ if (cclass_root != ovclass) {
+ for (ovfunc = ovclass->vfuncs; ovfunc; ovfunc = ovfunc->next)
+ CClass_FindOVFunc(cclass_root, ovclass, ovfunc);
+ }
+
+ for (ovbase = ovclass->bases; ovbase; ovbase = ovbase->next)
+ CClass_OverrideOVClassTree(ovbase->ovclass);
+}
+
+static void CClass_AllocVTableRec(OVClass *ovclass) {
+ OVFunc *ovfunc;
+ Object *object;
+ SInt32 offset27;
+ SInt32 offset26;
+ SInt32 offset23;
+ OVClassBase *ovbase;
+ OLinkList *link;
+
+ if (ovclass->alloced_vtable)
+ return;
+
+ for (ovfunc = ovclass->vfuncs; ovfunc; ovfunc = ovfunc->next) {
+ offset27 = ovclass->voffset + TYPE_METHOD(ovfunc->obj->type)->vtbl_index + CABI_GetVTableOffset(ovclass->tclass);
+ CError_ASSERT(1867, offset27 < vtable_data_size);
+
+ if (!(vtable_object_data[offset27])) {
+ if (ovfunc->ovfC) {
+ object = ovfunc->ovfC->obj;
+ if (
+ (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_400000) &&
+ CClass_GetOverrideKind(TYPE_FUNC(ovfunc->obj->type), TYPE_FUNC(object->type), 0) == 2
+ )
+ {
+ CError_ASSERT(1887,
+ IS_TYPE_POINTER_ONLY(TYPE_FUNC(ovfunc->obj->type)->functype) &&
+ IS_TYPE_CLASS(TPTR_TARGET(TYPE_FUNC(ovfunc->obj->type)->functype)));
+ object = CClass_FindCovariantFunction(
+ object,
+ TPTR_TARGET(TYPE_FUNC(ovfunc->obj->type)->functype));
+ }
+
+ if ((offset26 = ovfunc->ovc8->offset - ovclass->offset)) {
+ if (!(TYPE_FUNC(object->type)->flags & FUNC_PURE)) {
+ cclass_ovbase = NULL;
+ CError_ASSERT(1899, CClass_IsBaseOf(ovclass, ovfunc->ovc8));
+
+ if (cclass_ovbase && (main_class->flags & CLASS_FLAGS_8000)) {
+ offset23 = ovclass->offset - cclass_ovbase->offset;
+ offset23 = CABI_GetCtorOffsetOffset(cclass_ovbase->tclass, NULL) - offset23;
+ CError_ASSERT(1906, offset23 > 0);
+ object = CClass_ThunkObject(object, offset26, 0, offset23);
+ } else {
+ object = CClass_ThunkObject(object, offset26, 0, -1);
+ }
+ }
+ }
+ } else {
+ object = ovfunc->obj;
+ }
+
+ if (!(TYPE_FUNC(object->type)->flags & FUNC_PURE)) {
+ link = lalloc(sizeof(OLinkList));
+ link->next = vtable_object_links;
+ link->obj = object;
+ link->offset = offset27;
+ link->somevalue = 0;
+ vtable_object_links = link;
+ vtable_object_data[offset27] = 1;
+ }
+ }
+ }
+
+ ovclass->alloced_vtable = 1;
+
+ for (ovbase = ovclass->bases; ovbase; ovbase = ovbase->next)
+ CClass_AllocVTableRec(ovbase->ovclass);
+}
+
+static Object *CClass_CheckClass(OVClass *ovclass, Boolean errorflag) {
+ Object *object;
+ Object *check;
+ OVFunc *ovfunc;
+ OVClassBase *ovbase;
+
+ object = NULL;
+
+ for (ovfunc = ovclass->vfuncs; ovfunc; ovfunc = ovfunc->next) {
+ if (ovfunc->ovf10 && errorflag)
+ CError_Error(CErrorStr251, main_class, 0, ovfunc->obj, ovfunc->ovfC->obj, ovfunc->ovf10->obj);
+
+ if (!object) {
+ check = ovfunc->ovfC ? ovfunc->ovfC->obj : ovfunc->obj;
+ if (TYPE_FUNC(check->type)->flags & FUNC_PURE)
+ object = check;
+ }
+ }
+
+ for (ovbase = ovclass->bases; ovbase; ovbase = ovbase->next) {
+ if (object)
+ CClass_CheckClass(ovbase->ovclass, errorflag);
+ else
+ object = CClass_CheckClass(ovbase->ovclass, errorflag);
+ }
+
+ return object;
+}
+
+static void CClass_AllocVTable(TypeClass *tclass) {
+ OVClass *ovclass;
+
+ main_class = tclass;
+ ovclass = CClass_BuildOVClassTree(NULL, tclass, 0, 0);
+ cclass_root = ovclass;
+ CClass_OverrideOVClassTree(ovclass);
+ CClass_CheckClass(ovclass, 1);
+ CClass_AllocVTableRec(ovclass);
+}
+
+static Object *CClass_CheckVirtuals(TypeClass *tclass) {
+ OVClass *ovclass;
+
+ main_class = tclass;
+ ovclass = CClass_BuildOVClassTree(NULL, tclass, 0, 0);
+ cclass_root = ovclass;
+ CClass_OverrideOVClassTree(ovclass);
+ return CClass_CheckClass(ovclass, 0);
+}
+
+static void CClass_CheckVirtualBaseOverrides(OVClass *a, OVClass *b, Boolean flag) {
+ VClassList *vbase;
+ OVFunc *ovfunc;
+ OVClassBase *ovbase;
+
+ if (flag) {
+ for (ovfunc = b->vfuncs; ovfunc; ovfunc = ovfunc->next) {
+ if (ovfunc->ovfC) {
+ cclass_ovbase = NULL;
+ CError_ASSERT(2040, CClass_IsBaseOf(b, ovfunc->ovc8));
+
+ if (cclass_ovbase) {
+ for (vbase = a->tclass->vbases; vbase; vbase = vbase->next) {
+ if (vbase->base == cclass_ovbase->tclass)
+ break;
+ }
+
+ CError_ASSERT(2047, vbase);
+ vbase->has_override = 1;
+ }
+ }
+ }
+ }
+
+ for (ovbase = b->bases; ovbase; ovbase = ovbase->next) {
+ CClass_CheckVirtualBaseOverrides(a, ovbase->ovclass, flag || ovbase->is_virtual);
+ }
+}
+
+static void CClass_CheckHideVirtual(OVClass *a, OVClass *b) {
+ OVClassBase *ovbase;
+ OVFunc *ovfunc;
+ Object *foundObject;
+ Boolean isAlias;
+ Object *object;
+ CScopeObjectIterator iter;
+
+ if (a != b) {
+ for (ovfunc = b->vfuncs; ovfunc; ovfunc = ovfunc->next) {
+ if (ovfunc->ovc8 != a) {
+ foundObject = NULL;
+ isAlias = 0;
+ CScope_InitObjectIterator(&iter, a->tclass->nspace);
+
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (object->name == ovfunc->obj->name && IS_TYPE_FUNC(object->type)) {
+ if (object->datatype != DALIAS) {
+ if (!(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_20))
+ foundObject = object;
+ } else {
+ if (object->u.alias.object == ovfunc->obj) {
+ // don't show a warning if this is just an alias to the base function
+ isAlias = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (foundObject && !isAlias)
+ CError_Warning(CErrorStr225, foundObject, ovfunc->obj);
+ }
+ }
+ }
+
+ for (ovbase = b->bases; ovbase; ovbase = ovbase->next)
+ CClass_CheckHideVirtual(a, ovbase->ovclass);
+}
+
+void CClass_CheckOverrides(TypeClass *tclass) {
+ OVClass *tree;
+ Object *object;
+ ObjectList *objlist;
+ ClassList *base;
+ VClassList *vbase;
+ int i;
+ CScopeObjectIterator iter;
+
+ i = 0;
+ for (base = tclass->bases; base; base = base->next) {
+ base->offset = i;
+ base->voffset = i;
+ i++;
+ }
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ vbase->offset = i;
+ vbase->voffset = i;
+ i++;
+ }
+
+ main_class = tclass;
+ tree = CClass_BuildOVClassTree(NULL, tclass, 0, 0);
+ cclass_root = tree;
+
+ CClass_OverrideOVClassTree(tree);
+ if (CClass_CheckClass(tree, 0))
+ tclass->flags |= CLASS_ABSTRACT;
+
+ if (copts.warn_hidevirtual)
+ CClass_CheckHideVirtual(tree, tree);
+
+ if (tclass->flags & CLASS_FLAGS_8000)
+ CClass_CheckVirtualBaseOverrides(tree, tree, 0);
+
+ objlist = NULL;
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (object->datatype == DVFUNC) {
+ CError_ASSERT(2175, IS_TYPE_FUNC(object->type));
+ if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_400000)
+ objlist = CClass_DeclareCovariantFuncs(objlist, object, tclass);
+ }
+ }
+
+ while (objlist) {
+ CScope_AddObject(tclass->nspace, objlist->object->name, OBJ_BASE(objlist->object));
+ objlist = objlist->next;
+ }
+
+ for (base = tclass->bases; base; base = base->next) {
+ base->offset = 0;
+ base->voffset = 0;
+ }
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ vbase->offset = 0;
+ vbase->voffset = 0;
+ }
+}
+
+static void CClass_FindDominator(TypeClass *tclass1, SInt32 offset1, Object *object1, TypeClass *tclass2, SInt32 offset2, TypeClass *tclass3) {
+ Object *object;
+ ClassList *base;
+ CScopeObjectIterator iter;
+
+ CScope_InitObjectIterator(&iter, tclass1->nspace);
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (
+ object->name == cclass_dominator_vobject->name &&
+ object->datatype == DVFUNC &&
+ CClass_GetOverrideKind(TYPE_FUNC(cclass_dominator_vobject->type), TYPE_FUNC(object->type), 0)
+ )
+ {
+ if (object == cclass_dominator_vobject && offset1 == cclass_dominator_voffset) {
+ if (object1) {
+ if (cclass_dominator_oobject && cclass_dominator_ooffset != offset2) {
+ if (CClass_ClassDominates(cclass_dominator_oclass, tclass2))
+ return;
+ if (!CClass_ClassDominates(tclass2, cclass_dominator_oclass)) {
+ cclass_dominator_eobject = object1;
+ cclass_vbase = tclass3;
+ return;
+ }
+ }
+
+ cclass_dominator_oobject = object1;
+ cclass_dominator_ooffset = offset2;
+ cclass_dominator_oclass = tclass2;
+ cclass_dominator_eobject = NULL;
+ cclass_vbase = tclass3;
+ }
+ return;
+ } else {
+ if (!object1) {
+ object1 = object;
+ tclass2 = tclass1;
+ offset2 = offset1;
+ }
+ break;
+ }
+ }
+ }
+
+ for (base = tclass1->bases; base; base = base->next) {
+ if (base->base->vtable) {
+ if (!base->is_virtual) {
+ CClass_FindDominator(base->base, offset1 + base->offset, object1, tclass2, offset2, tclass3);
+ } else {
+ SInt32 vboffset = CClass_VirtualBaseOffset(main_class, base->base);
+ CClass_FindDominator(base->base, vboffset, object1, tclass2, offset2, base->base);
+ }
+ }
+ }
+}
+
+static void CClass_ConstructVTable(TypeClass *tclass, SInt32 voffset, SInt32 offset, TypeClass *baseclass) {
+ Object *object;
+ Object *thunkobject;
+ SInt32 newoffset;
+ SInt32 newvoffset;
+ ClassList *base;
+ SInt32 thunkoffset;
+ OLinkList *olink;
+ CScopeObjectIterator iter;
+
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (object->datatype == DVFUNC) {
+ newoffset = voffset + TYPE_METHOD(object->type)->vtbl_index + CABI_GetVTableOffset(tclass);
+ CError_ASSERT(2288, newoffset < vtable_data_size);
+
+ if (!vtable_object_data[newoffset]) {
+ cclass_dominator_vobject = object;
+ cclass_dominator_voffset = offset;
+ cclass_dominator_oobject = NULL;
+ cclass_dominator_ooffset = offset;
+ CClass_FindDominator(main_class, 0, NULL, NULL, 0, NULL);
+
+ if (cclass_dominator_oobject) {
+ if (cclass_dominator_eobject)
+ CError_Error(CErrorStr251, main_class, 0, cclass_dominator_vobject, cclass_dominator_oobject, cclass_dominator_eobject);
+ } else {
+ cclass_dominator_oobject = object;
+ cclass_vbase = NULL;
+ }
+
+ vtable_object_data[newoffset] = 1;
+
+ if (!(TYPE_FUNC(cclass_dominator_oobject->type)->flags & FUNC_PURE)) {
+ if (!check_pures) {
+ thunkobject = cclass_dominator_oobject;
+ if ((thunkoffset = cclass_dominator_ooffset - offset)) {
+ if (cclass_vbase && (main_class->flags & CLASS_FLAGS_8000)) {
+ thunkobject = CClass_ThunkObject(cclass_dominator_oobject, thunkoffset, 0,
+ CABI_GetCtorOffsetOffset(cclass_vbase, tclass));
+ } else {
+ thunkobject = CClass_ThunkObject(cclass_dominator_oobject, thunkoffset, 0, -1);
+ }
+ }
+
+ olink = lalloc(sizeof(OLinkList));
+ olink->next = vtable_object_links;
+ olink->obj = thunkobject;
+ olink->offset = newoffset;
+ olink->somevalue = 0;
+ vtable_object_links = olink;
+ }
+ } else {
+ found_pure = cclass_dominator_oobject;
+ }
+ }
+ }
+ }
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (base->base->vtable) {
+ if (base->is_virtual) {
+ newoffset = CClass_VirtualBaseOffset(main_class, base->base);
+ newvoffset = CClass_VirtualBaseVTableOffset(main_class, base->base);
+ CClass_ConstructVTable(
+ base->base,
+ newvoffset,
+ newoffset,
+ base->base
+ );
+ } else {
+ CClass_ConstructVTable(
+ base->base,
+ voffset + base->voffset,
+ offset + base->offset,
+ baseclass
+ );
+ }
+ }
+ }
+}
+
+void CClass_ClassDefaultFuncAction(TypeClass *tclass) {
+}
+
+void CClass_ClassAction(TypeClass *tclass) {
+ if (tclass->sominfo) {
+ CSOM_GenerateClassStructures(tclass);
+ } else if (tclass->vtable) {
+ vtable_data_size = tclass->vtable->size;
+ vtable_object_data = lalloc(vtable_data_size);
+ memclrw(vtable_object_data, vtable_data_size);
+
+ main_class = tclass;
+ vtable_object_links = NULL;
+ found_pure = NULL;
+ check_pures = 0;
+
+ CClass_AllocVTable(tclass);
+
+ memclrw(vtable_object_data, vtable_data_size);
+ if (copts.RTTI && !(tclass->flags & (CLASS_SINGLE_OBJECT | CLASS_COM_OBJECT)))
+ vtable_object_links = CRTTI_ConstructVTableHeaders(tclass, vtable_object_data, vtable_object_links);
+
+ CError_ASSERT(2492, tclass->vtable->object->type->size == tclass->vtable->size);
+ CInit_DeclareData(tclass->vtable->object, vtable_object_data, vtable_object_links, tclass->vtable->size);
+ }
+}
+
+void CClass_MakeStaticActionClass(TypeClass *tclass) {
+ if (tclass->vtable) {
+ tclass->vtable->object->sclass = TK_STATIC;
+ tclass->vtable->object->qual |= Q_20000;
+ if (!(tclass->vtable->object->flags & OBJECT_FLAGS_2)) {
+ CParser_NewCallBackAction(tclass->vtable->object, tclass);
+ } else if (cparamblkptr->precompile != 1) {
+ CParser_NewClassAction(tclass);
+ }
+ }
+}
+
+Object *CClass_CheckPures(TypeClass *tclass) {
+ return CClass_CheckVirtuals(tclass);
+}
+
+void CClass_MemberDef(Object *obj, TypeClass *tclass) {
+ switch (tclass->action) {
+ case CLASS_ACTION_0:
+ break;
+ case CLASS_ACTION_1:
+ if (IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_FLAGS_4)) {
+ if (obj->qual & Q_INLINE) {
+ if (tclass->sominfo)
+ CError_Error(CErrorStr280);
+ tclass->action = CLASS_ACTION_0;
+ CClass_MakeStaticActionClass(tclass);
+ } else if (cparamblkptr->precompile != 1) {
+ CParser_NewClassAction(tclass);
+ }
+ }
+ break;
+ case CLASS_ACTION_2:
+ CError_FATAL(2682);
+ break;
+ case CLASS_ACTION_3:
+ break;
+ default:
+ CError_FATAL(2701);
+ }
+}
+
+Object *CClass_ThisSelfObject(void) {
+ ObjectList *list;
+
+ if (cscope_currentfunc && cscope_currentclass) {
+ if (cscope_currentclass->objcinfo) {
+ for (list = arguments; list; list = list->next) {
+ if (list->object->name == self_name_node)
+ return list->object;
+ }
+ CError_Error(CErrorStr301);
+ } else {
+ if (cscope_is_member_func) {
+ for (list = arguments; list; list = list->next) {
+ if (list->object->name == this_name_node)
+ return list->object;
+ }
+ }
+ CError_Error(CErrorStr189);
+ }
+ }
+
+ CError_Error(copts.cplusplus ? CErrorStr189 : CErrorStr301);
+ return NULL;
+}
+
+ENode *CClass_CreateThisSelfExpr(void) {
+ Object *object;
+ ENode *expr;
+
+ if (!(object = CClass_ThisSelfObject()))
+ return NULL;
+
+ expr = create_objectrefnode(object);
+ expr->rtype = CDecl_NewPointerType(TYPE(cscope_currentclass));
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype);
+
+ return expr;
+}
+
+static AccessType CClass_BaseMemberAccess(BClassList *path, AccessType access) {
+ ClassList *base;
+
+ if (path->next) {
+ access = CClass_BaseMemberAccess(path->next, access);
+ switch (access) {
+ case ACCESSPRIVATE:
+ case ACCESSNONE:
+ return ACCESSNONE;
+ }
+
+ for (base = TYPE_CLASS(path->type)->bases; ; base = base->next) {
+ if (!base)
+ return ACCESSNONE;
+
+ if (base->base == TYPE_CLASS(path->next->type)) {
+ switch (base->access) {
+ case ACCESSNONE:
+ access = ACCESSNONE;
+ break;
+ case ACCESSPROTECTED:
+ if (access == ACCESSPUBLIC)
+ access = ACCESSPROTECTED;
+ break;
+ case ACCESSPRIVATE:
+ if (access == ACCESSPRIVATE)
+ access = ACCESSNONE;
+ else
+ access = ACCESSPRIVATE;
+ break;
+ case ACCESSPUBLIC:
+ break;
+ }
+ break;
+ }
+ }
+ }
+
+ return access;
+}
+
+static Boolean CClass_CanAccess(BClassList *path, AccessType access) {
+ AccessType access2;
+ BClassList *scan;
+ BClassList *next;
+ TypeClass *prevclass;
+ TypeClass *tclass;
+ ClassList *base;
+ ClassFriend *cfriend;
+
+ tclass = TYPE_CLASS(path->type);
+ access2 = access;
+ if ((scan = path->next)) {
+ if (access2 != ACCESSPRIVATE) {
+ prevclass = tclass;
+ while (scan) {
+ for (base = prevclass->bases; base; base = base->next) {
+ if (base->base == TYPE_CLASS(scan->type))
+ break;
+ }
+
+ if (!base)
+ return 0;
+
+ switch (base->access) {
+ case ACCESSNONE:
+ access2 = ACCESSNONE;
+ break;
+ case ACCESSPROTECTED:
+ if (access2 == ACCESSPUBLIC)
+ access2 = ACCESSPROTECTED;
+ break;
+ case ACCESSPRIVATE:
+ if (access2 == ACCESSPRIVATE)
+ access2 = ACCESSNONE;
+ else
+ access2 = ACCESSPRIVATE;
+ break;
+ case ACCESSPUBLIC:
+ break;
+ }
+
+ prevclass = TYPE_CLASS(scan->type);
+ scan = scan->next;
+ }
+ } else {
+ access2 = ACCESSNONE;
+ }
+ }
+
+ if (access2 == ACCESSPUBLIC)
+ return 1;
+
+ if (access2 != ACCESSNONE) {
+ if (cscope_currentclass == tclass)
+ return 1;
+ if (cobjc_currentclass == tclass)
+ return 1;
+
+ for (cfriend = tclass->friends; cfriend; cfriend = cfriend->next) {
+ if (cfriend->isclass) {
+ if (cfriend->u.theclass == cscope_currentclass)
+ return 1;
+ } else {
+ if (cfriend->u.obj == cscope_currentfunc)
+ return 1;
+ }
+ }
+ }
+
+ for (scan = path; scan->next; scan = scan->next) {
+ if (CClass_CanAccess(scan->next, access)) {
+ if ((next = scan->next->next) || access != ACCESSPUBLIC) {
+ scan->next->next = NULL;
+ if (CClass_CanAccess(path, ACCESSPUBLIC)) {
+ scan->next->next = next;
+ return 1;
+ }
+ scan->next->next = next;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void CClass_CheckPathAccess(BClassList *path, Object *obj, AccessType access) {
+ if (!CClass_CanAccess(path, access)) {
+ if (path && obj)
+ CError_Error(CErrorStr381, path->type, 0, obj);
+ else
+ CError_Error(CErrorStr187);
+ }
+}
+
+static BClassList *CClass_PathCleanup(BClassList *path, TypeClass *tclass) {
+ BClassList *first;
+ ClassList *base;
+
+ first = path;
+
+ while (1) {
+ if (!path->next) {
+ if (!tclass)
+ return first;
+ if (path->type == TYPE(tclass))
+ return first;
+ return NULL;
+ }
+
+ if (path->type != path->next->type) {
+ for (base = TYPE_CLASS(path->type)->bases; base; base = base->next) {
+ if (base->base == TYPE_CLASS(path->next->type))
+ break;
+ }
+
+ if (base) {
+ path = path->next;
+ } else {
+ first = path = path->next;
+ }
+ } else {
+ path->next = path->next->next;
+ }
+ }
+}
+
+void CClass_CheckStaticAccess(BClassList *path, TypeClass *tclass, AccessType access) {
+ ClassFriend *cfriend;
+
+ if (path) {
+ path = CClass_PathCleanup(path, tclass);
+ if (path && path->next) {
+ if (!CClass_CanAccess(path, access))
+ CError_Error(CErrorStr187);
+ return;
+ }
+ }
+
+ switch (access) {
+ case ACCESSPUBLIC:
+ return;
+ case ACCESSPRIVATE:
+ case ACCESSPROTECTED:
+ if (tclass == cscope_currentclass)
+ return;
+
+ for (cfriend = tclass->friends; cfriend; cfriend = cfriend->next) {
+ if (cfriend->isclass) {
+ if (cfriend->u.theclass == cscope_currentclass)
+ return;
+ } else {
+ if (cfriend->u.obj == cscope_currentfunc)
+ return;
+ }
+ }
+ case ACCESSNONE:
+ CError_Warning(CErrorStr187);
+ return;
+ default:
+ CError_FATAL(3013);
+ }
+}
+
+void CClass_CheckObjectAccess(BClassList *path, Object *obj) {
+ short depth;
+ Boolean isambigbase;
+
+ if (obj->nspace && obj->nspace->theclass) {
+ if (!path && cscope_currentclass)
+ path = CClass_GetBasePath(cscope_currentclass, obj->nspace->theclass, &depth, &isambigbase);
+
+ CClass_CheckStaticAccess(path, obj->nspace->theclass, obj->access);
+ }
+}
+
+void CClass_CheckEnumAccess(BClassList *path, ObjEnumConst *objec) {
+ if (path) {
+ if ((path = CClass_PathCleanup(path, NULL))) {
+ if (!CClass_CanAccess(path, objec->access))
+ CError_Error(CErrorStr187);
+ return;
+ }
+ }
+
+ if (
+ objec->access != ACCESSPUBLIC &&
+ IS_TYPE_ENUM(objec->type) &&
+ TYPE_ENUM(objec->type)->nspace &&
+ TYPE_ENUM(objec->type)->nspace->theclass
+ )
+ CClass_CheckStaticAccess(NULL, TYPE_ENUM(objec->type)->nspace->theclass, objec->access);
+}
+
+static Type *CClass_PointerTypeCopy(Type *type) {
+ Type *copy;
+
+ switch (type->type) {
+ case TYPEPOINTER:
+ case TYPEARRAY:
+ copy = galloc(sizeof(TypePointer));
+ *TYPE_POINTER(copy) = *TYPE_POINTER(type);
+ TPTR_TARGET(copy) = CClass_PointerTypeCopy(TPTR_TARGET(copy));
+ return copy;
+ case TYPEMEMBERPOINTER:
+ copy = galloc(sizeof(TypeMemberPointer));
+ *TYPE_MEMBER_POINTER(copy) = *TYPE_MEMBER_POINTER(type);
+ return copy;
+ default:
+ return type;
+ }
+}
+
+Type *CClass_CombineClassAccessQualifiers(Type *type, UInt32 qual1, UInt32 qual2, UInt32 *outflags) {
+ Type *inner;
+
+ qual2 = qual2 & (Q_CONST | Q_VOLATILE);
+ if (qual1 & Q_MUTABLE)
+ qual2 &= ~Q_CONST;
+ qual1 = qual1 & (Q_CONST | Q_VOLATILE);
+
+ inner = type;
+ while (IS_TYPE_ARRAY(inner))
+ inner = TPTR_TARGET(inner);
+
+ switch (inner->type) {
+ case TYPEMEMBERPOINTER:
+ case TYPEPOINTER:
+ if (qual2) {
+ type = CClass_PointerTypeCopy(type);
+ inner = type;
+ while (IS_TYPE_ARRAY(inner))
+ inner = TPTR_TARGET(inner);
+
+ switch (inner->type) {
+ case TYPEPOINTER:
+ TPTR_QUAL(inner) |= qual2;
+ break;
+ case TYPEMEMBERPOINTER:
+ TYPE_MEMBER_POINTER(inner)->qual |= qual2;
+ break;
+ default:
+ CError_FATAL(3125);
+ }
+ }
+ break;
+ default:
+ qual1 |= qual2;
+ }
+
+ *outflags = qual1;
+ return type;
+}
+
+static void CClass_OptimizeBitFieldAccess(Type **ptype, SInt32 *poffset) {
+ Type *innertype;
+ TypeBitfield *newtype;
+ short i;
+
+ innertype = TYPE_BITFIELD(*ptype)->bitfieldtype;
+ if (TYPE_BITFIELD(*ptype)->bitlength == 8) {
+ switch (TYPE_BITFIELD(*ptype)->offset) {
+ case 0:
+ i = 0;
+ break;
+ case 8:
+ i = 1;
+ break;
+ case 16:
+ i = 2;
+ break;
+ case 24:
+ i = 3;
+ break;
+ default:
+ i = -1;
+ break;
+ }
+
+ if (i >= 0) {
+ if (innertype->size != 1) {
+ if (is_unsigned(TYPE_BITFIELD(*ptype)->bitfieldtype))
+ *ptype = TYPE(&stunsignedchar);
+ else
+ *ptype = TYPE(&stsignedchar);
+ } else {
+ *ptype = innertype;
+ }
+ *poffset += i;
+ return;
+ }
+ }
+
+ if (TYPE_BITFIELD(*ptype)->bitlength == 16) {
+ switch (TYPE_BITFIELD(*ptype)->offset) {
+ case 0:
+ i = 0;
+ break;
+ case 16:
+ i = 2;
+ break;
+ default:
+ i = -1;
+ break;
+ }
+
+ if (i >= 0) {
+ if (innertype->size != stsignedshort.size) {
+ if (is_unsigned(innertype))
+ *ptype = TYPE(&stunsignedshort);
+ else
+ *ptype = TYPE(&stsignedshort);
+ } else {
+ *ptype = innertype;
+ }
+ *poffset += i;
+ return;
+ }
+ }
+
+ if (TYPE_BITFIELD(*ptype)->bitlength == 32 && TYPE_BITFIELD(*ptype)->offset == 0) {
+ if (innertype->size != stsignedlong.size) {
+ if (is_unsigned(innertype))
+ *ptype = TYPE(&stunsignedlong);
+ else
+ *ptype = TYPE(&stsignedlong);
+ } else {
+ *ptype = innertype;
+ }
+ return;
+ }
+
+ if ((*ptype)->size != stsignedchar.size) {
+ i = TYPE_BITFIELD(*ptype)->offset + TYPE_BITFIELD(*ptype)->bitlength - 1;
+
+ if (TYPE_BITFIELD(*ptype)->bitlength < 8 && (TYPE_BITFIELD(*ptype)->offset & 0xFFF8) == (i & 0xFFF8)) {
+ newtype = galloc(sizeof(TypeBitfield));
+ *newtype = *TYPE_BITFIELD(*ptype);
+ *ptype = TYPE(newtype);
+
+ i = 0;
+ if (newtype->offset >= 8)
+ i = 1;
+ if (newtype->offset >= 16)
+ i = 2;
+ if (newtype->offset >= 24)
+ i = 3;
+ *poffset += i;
+ newtype->offset -= 8 * i;
+
+ newtype->bitfieldtype = is_unsigned(innertype) ? TYPE(&stunsignedchar) : TYPE(&stsignedchar);
+ newtype->size = newtype->bitfieldtype->size;
+ return;
+ }
+
+ if ((*ptype)->size != stsignedshort.size) {
+ if (TYPE_BITFIELD(*ptype)->bitlength < 16 && (TYPE_BITFIELD(*ptype)->offset & 0xFFF0) == (i & 0xFFF0)) {
+ newtype = galloc(sizeof(TypeBitfield));
+ *newtype = *TYPE_BITFIELD(*ptype);
+ *ptype = TYPE(newtype);
+
+ i = 0;
+ if (newtype->offset >= 16)
+ i = stsignedshort.size;
+ *poffset += i;
+ newtype->offset -= 8 * i;
+
+ newtype->bitfieldtype = is_unsigned(innertype) ? TYPE(&stunsignedshort) : TYPE(&stsignedshort);
+ newtype->size = newtype->bitfieldtype->size;
+ return;
+ }
+ }
+ }
+}
+
+ENode *CClass_AccessMember(ENode *classexpr, Type *type, UInt32 qual, SInt32 offset) {
+ Type *innertype;
+ UInt32 flags;
+
+ innertype = NULL;
+
+ if (IS_TYPE_CLASS(classexpr->rtype) && (TYPE_CLASS(classexpr->rtype)->flags & CLASS_HANDLEOBJECT)) {
+ classexpr = makemonadicnode(classexpr, EINDIRECT);
+ classexpr->data.monadic->rtype = CDecl_NewPointerType(classexpr->rtype);
+ }
+
+ if (IS_TYPE_BITFIELD(type)) {
+ innertype = TYPE_BITFIELD(type)->bitfieldtype;
+ CClass_OptimizeBitFieldAccess(&type, &offset);
+ }
+
+ if (offset && !canadd(classexpr->data.monadic, offset)) {
+ classexpr->data.monadic = makediadicnode(
+ classexpr->data.monadic,
+ intconstnode(TYPE(&stunsignedlong), offset),
+ EADD);
+ optimizecomm(classexpr->data.monadic);
+ }
+
+ if (innertype) {
+ if (IS_TYPE_BITFIELD(type)) {
+ classexpr->data.monadic = makemonadicnode(classexpr->data.monadic, EBITFIELD);
+ classexpr->data.monadic->rtype = type;
+ classexpr->rtype = TYPE_BITFIELD(type)->bitfieldtype;
+ } else {
+ classexpr->rtype = type;
+ }
+ } else {
+ classexpr->rtype = type;
+ }
+
+ classexpr->rtype = CClass_CombineClassAccessQualifiers(classexpr->rtype, qual, ENODE_QUALS(classexpr), &flags);
+ classexpr->flags = flags;
+ return classexpr;
+}
diff --git a/compiler_and_linker/FrontEnd/C/CDecl.c b/compiler_and_linker/FrontEnd/C/CDecl.c
new file mode 100644
index 0000000..43ca92e
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CDecl.c
@@ -0,0 +1,4845 @@
+#include "compiler/CDecl.h"
+#include "compiler/CABI.h"
+#include "compiler/CBrowse.h"
+#include "compiler/CClass.h"
+#include "compiler/CError.h"
+#include "compiler/CException.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInit.h"
+#include "compiler/CInline.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CObjC.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CSOM.h"
+#include "compiler/CTemplateClass.h"
+#include "compiler/CTemplateFunc.h"
+#include "compiler/CTemplateNew.h"
+#include "compiler/CTemplateTools.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/templates.h"
+#include "compiler/tokens.h"
+
+AccessType global_access;
+FileOffsetInfo member_fileoffset;
+
+// forward declarations
+static void scandirectdecl1(DeclInfo *declinfo);
+
+Type *CDecl_NewStructType(SInt32 size, SInt16 align) {
+ TypeStruct *tstruct = galloc(sizeof(TypeStruct));
+ memclrw(tstruct, sizeof(TypeStruct));
+
+ tstruct->type = TYPESTRUCT;
+ tstruct->size = size;
+ tstruct->align = align;
+ tstruct->stype = STRUCT_TYPE_STRUCT;
+
+ return (Type *) tstruct;
+}
+
+Type *CDecl_NewArrayType(Type *type, SInt32 size) {
+ TypePointer *tarray = galloc(sizeof(TypePointer));
+ memclrw(tarray, sizeof(TypePointer));
+
+ tarray->type = TYPEARRAY;
+ tarray->size = size;
+ tarray->target = type;
+ tarray->qual = 0;
+
+ return (Type *) tarray;
+}
+
+Type *CDecl_NewPointerType(Type *type) {
+ TypePointer *tptr = galloc(sizeof(TypePointer));
+ memclrw(tptr, sizeof(TypePointer));
+
+ tptr->type = TYPEPOINTER;
+ tptr->size = 4;
+ tptr->target = type;
+
+ return (Type *) tptr;
+}
+
+Type *CDecl_NewRefPointerType(Type *type) {
+ TypePointer *tptr = galloc(sizeof(TypePointer));
+ memclrw(tptr, sizeof(TypePointer));
+
+ tptr->type = TYPEPOINTER;
+ tptr->size = 4;
+ tptr->target = type;
+ tptr->qual = Q_REFERENCE;
+
+ return (Type *) tptr;
+}
+
+Type *CDecl_NewTemplDepType(TypeTemplDepType tdt) {
+ TypeTemplDep *t = galloc(sizeof(TypeTemplDep));
+ memclrw(t, sizeof(TypeTemplDep));
+
+ t->type = TYPETEMPLATE;
+ t->size = 1;
+ t->dtype = tdt;
+
+ return (Type *) t;
+}
+
+void CDecl_SetResultReg(TypeFunc *tfunc) {
+}
+
+static void CDecl_SetFuncResultReg(TypeFunc *tfunc) {
+}
+
+void CDecl_SetFuncFlags(TypeFunc *tfunc, UInt32 flags) {
+ CDecl_SetResultReg(tfunc);
+}
+
+static void CDecl_ParseCPPFuncDecl(TypeFunc *tfunc) {
+ for (;;) {
+ if (tk == TK_CONST) {
+ if (tfunc->flags & FUNC_CONST)
+ CError_Warning(CErrorStr313, "const");
+ tfunc->flags |= FUNC_CONST;
+ tk = lex();
+ } else if (tk == TK_VOLATILE) {
+ if (tfunc->flags & FUNC_VOLATILE)
+ CError_Warning(CErrorStr313, "volatile");
+ tfunc->flags |= FUNC_VOLATILE;
+ tk = lex();
+ } else {
+ break;
+ }
+ }
+
+ if (tk == TK_THROW)
+ CExcept_ScanExceptionSpecification(tfunc);
+}
+
+void CDecl_NewConvFuncType(DeclInfo *declinfo) {
+ TypeFunc *tfunc;
+
+ if (tk != '(')
+ CError_Error(CErrorStr114);
+ else
+ tk = lex();
+
+ if (tk == TK_VOID)
+ tk = lex();
+
+ if (tk != ')')
+ CError_Error(CErrorStr115);
+ else
+ tk = lex();
+
+ tfunc = galloc(sizeof(TypeFunc));
+ memclrw(tfunc, sizeof(TypeFunc));
+ declinfo->name = CMangler_ConversionFuncName(declinfo->thetype, declinfo->qual);
+ tfunc->type = TYPEFUNC;
+ tfunc->functype = declinfo->thetype;
+ tfunc->qual = declinfo->qual & (Q_CONST | Q_VOLATILE);
+ tfunc->flags = FUNC_CONVERSION;
+ declinfo->x49 = 0;
+ CDecl_SetFuncFlags(tfunc, 1);
+ CDecl_ParseCPPFuncDecl(tfunc);
+
+ declinfo->thetype = (Type *) tfunc;
+ declinfo->qual &= ~(Q_CONST | Q_VOLATILE);
+ declinfo->storageclass = 0;
+}
+
+void CDecl_CompleteType(Type *type) {
+ switch (type->type) {
+ case TYPEPOINTER:
+ if ((TYPE_POINTER(type)->qual & Q_REFERENCE) && IS_TYPE_CLASS(TYPE_POINTER(type)->target)) {
+ type = TYPE_POINTER(type)->target;
+ break;
+ }
+ return;
+ case TYPEARRAY:
+ do {
+ type = TYPE_POINTER(type)->target;
+ } while (IS_TYPE_ARRAY(type));
+ if (IS_TYPE_CLASS(type))
+ break;
+ return;
+ case TYPECLASS:
+ break;
+ default:
+ return;
+ }
+
+ if ((TYPE_CLASS(type)->flags & (CLASS_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST)
+ CTempl_InstantiateTemplateClass(TYPE_CLASS(type));
+}
+
+Boolean IsCompleteType(Type *type) {
+ switch (type->type) {
+ case TYPEVOID:
+ CError_Error(CErrorStr126);
+ return 0;
+ case TYPEFUNC:
+ CError_Error(CErrorStr146);
+ return 0;
+ case TYPESTRUCT:
+ if (!type->size) {
+ CError_Error(CErrorStr136, type, 0);
+ return 0;
+ }
+ return 1;
+ case TYPECLASS:
+ if (
+ !(TYPE_CLASS(type)->flags & CLASS_COMPLETED) &&
+ (
+ !(TYPE_CLASS(type)->flags & CLASS_IS_TEMPL_INST) ||
+ !CTempl_InstantiateTemplateClass(TYPE_CLASS(type))
+ )
+ )
+ {
+ CError_Error(CErrorStr136, type, 0);
+ return 0;
+ }
+ return 1;
+ default:
+ if (!type->size) {
+ CError_Error(CErrorStr145);
+ return 0;
+ }
+ return 1;
+ }
+}
+
+Boolean CanAllocObject(Type *type) {
+ switch (type->type) {
+ case TYPEVOID:
+ CError_Error(CErrorStr126);
+ return 0;
+ case TYPEFUNC:
+ CError_Error(CErrorStr146);
+ return 0;
+ case TYPECLASS:
+ if (TYPE_CLASS(type)->flags & CLASS_ABSTRACT) {
+ CError_AbstractClassError(TYPE_CLASS(type));
+ return 0;
+ }
+ default:
+ return 1;
+ }
+}
+
+Boolean CanCreateObject(Type *type) {
+ if (!CanAllocObject(type))
+ return 0;
+
+ if (IS_TYPE_CLASS(type)) {
+ if (TYPE_CLASS(type)->flags & CLASS_HANDLEOBJECT) {
+ CError_Error(CErrorStr191);
+ return 0;
+ }
+ if (TYPE_CLASS(type)->objcinfo) {
+ CError_Error(CErrorStr307);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static Boolean CanCreateHandleMemberObject(Type *type) {
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+
+ if (!CanCreateObject(type))
+ return 0;
+
+ if (IS_TYPE_CLASS(type)) {
+ if (CClass_Destructor(TYPE_CLASS(type)) || CClass_Constructor(TYPE_CLASS(type))) {
+ CError_Error(CErrorStr191);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+void makethetypepointer(DeclInfo *declinfo, UInt32 qual) {
+ declinfo->thetype = CDecl_NewPointerType(declinfo->thetype);
+ TYPE_POINTER(declinfo->thetype)->qual = qual;
+}
+
+void CDecl_AddThisPointerArgument(TypeFunc *tfunc, TypeClass *tclass) {
+ Type *ptype;
+ FuncArg *arg;
+
+ ptype = CDecl_NewPointerType(!tclass->sominfo ? (Type *) tclass : &stvoid);
+ TYPE_POINTER(ptype)->qual = Q_CONST;
+
+ arg = CParser_NewFuncArg();
+ arg->name = this_name_node;
+ arg->type = ptype;
+ if (tfunc->flags & FUNC_CONST)
+ arg->qual |= Q_CONST;
+ if (tfunc->flags & FUNC_VOLATILE)
+ arg->qual |= Q_VOLATILE;
+ arg->next = tfunc->args;
+ tfunc->args = arg;
+}
+
+void CDecl_MakePTMFuncType(TypeFunc *tfunc) {
+ Type *cvoidp;
+ FuncArg *arg1;
+ FuncArg *arg2;
+
+ cvoidp = CDecl_NewPointerType(&stvoid);
+ TYPE_POINTER(cvoidp)->qual = Q_CONST;
+
+ arg1 = CParser_NewFuncArg();
+ arg1->name = this_name_node;
+ arg1->type = cvoidp;
+ if (tfunc->flags & FUNC_CONST)
+ arg1->qual |= Q_CONST;
+ if (tfunc->flags & FUNC_VOLATILE)
+ arg1->qual |= Q_VOLATILE;
+
+ arg2 = CParser_NewFuncArg();
+ arg2->name = this_name_node;
+ arg2->type = cvoidp;
+ arg2->qual = Q_CONST;
+
+ arg1->next = tfunc->args;
+ arg2->next = arg1;
+ tfunc->args = arg2;
+ tfunc->flags |= FUNC_FLAGS_80;
+}
+
+void CDecl_AddArgument(TypeFunc *tfunc, Type *argtype) {
+ FuncArg *arg = CParser_NewFuncArg();
+ arg->type = argtype;
+
+ arg->next = tfunc->args;
+ tfunc->args = arg;
+
+ if (arg->next && arg->next->type == &stvoid)
+ arg->next = NULL;
+}
+
+Boolean CDecl_CheckArrayIntegr(Type *type) {
+ if (!IsCompleteType(type))
+ return 0;
+
+ if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo) {
+ CError_Error(CErrorStr289);
+ return 0;
+ }
+
+ if (IS_TYPE_REFERENCE(type)) {
+ CError_Error(CErrorStr196);
+ return 0;
+ }
+
+ return CanCreateObject(type);
+}
+
+static Boolean checkfuncintegr(Type *type) {
+ if (IS_TYPE_VOID(type))
+ return 1;
+
+ if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo) {
+ CError_Error(CErrorStr283);
+ return 0;
+ }
+
+ return CanCreateObject(type);
+}
+
+void CDecl_ParseDirectFuncDecl(DeclInfo *declinfo) {
+ FuncArg *list;
+ TypeFunc *tfunc;
+
+ if (tk == ')') {
+ if (copts.cplusplus)
+ list = NULL;
+ else
+ list = &oldstyle;
+ tk = lex();
+ } else {
+ list = parameter_type_list(declinfo);
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+ }
+
+ tfunc = galloc(sizeof(TypeFunc));
+ memclrw(tfunc, sizeof(TypeFunc));
+ tfunc->type = TYPEFUNC;
+ tfunc->args = list;
+ if (declinfo->qual & Q_PASCAL) {
+ declinfo->qual &= ~Q_PASCAL;
+ tfunc->flags = FUNC_PASCAL;
+ }
+
+ if (copts.cplusplus) {
+ CDecl_ParseCPPFuncDecl(tfunc);
+ if (declinfo->storageclass == TK_TYPEDEF && tfunc->exspecs)
+ CError_Error(CErrorStr264);
+ }
+
+ scandirectdecl1(declinfo);
+ if (!checkfuncintegr(declinfo->thetype))
+ declinfo->thetype = &stvoid;
+
+ tfunc->functype = declinfo->thetype;
+ tfunc->qual = declinfo->qual & (Q_CONST | Q_VOLATILE);
+ declinfo->thetype = (Type *) tfunc;
+ declinfo->qual &= ~(Q_CONST | Q_VOLATILE);
+ declinfo->x49 = 0;
+}
+
+static void scandirectdecl1(DeclInfo *declinfo) {
+ Boolean flag;
+ CInt64 len;
+ ENode *expr;
+ TypeTemplDep *ttempl;
+
+ flag = 0;
+ if (tk == '[') {
+ if ((tk = lex()) == ']') {
+ len = cint64_zero;
+ tk = lex();
+ flag = 1;
+ } else {
+ if (!declinfo->x46 || declinfo->x47) {
+ expr = CExpr_IntegralConstOrDepExpr();
+ if (!ENODE_IS(expr, EINTCONST)) {
+ if (tk != ']')
+ CError_ErrorSkip(CErrorStr125);
+ else
+ tk = lex();
+ declinfo->x47 = 1;
+ scandirectdecl1(declinfo);
+ if (!CDecl_CheckArrayIntegr(declinfo->thetype))
+ declinfo->thetype = (Type *) &stsignedchar;
+ ttempl = (TypeTemplDep *) CDecl_NewTemplDepType(TEMPLDEP_ARRAY);
+ ttempl->u.array.type = declinfo->thetype;
+ ttempl->u.array.index = CInline_CopyExpression(expr, CopyMode1);
+ declinfo->thetype = (Type *) ttempl;
+ return;
+ }
+ len = expr->data.intval;
+ if (CInt64_IsNegative(&len)) {
+ CError_Error(CErrorStr124);
+ len = cint64_one;
+ } else if (CInt64_IsZero(&len)) {
+ if (!copts.ANSIstrict && declinfo->x50) {
+ flag = 1;
+ } else {
+ CError_Error(CErrorStr124);
+ len = cint64_one;
+ }
+ }
+ } else {
+ len = cint64_one;
+ expr = expression();
+ if (IS_TYPE_INT(expr->rtype)) {
+ if (!ENODE_IS(expr, EINTCONST))
+ declinfo->x24 = expr;
+ else
+ len = expr->data.intval;
+ } else {
+ CError_Error(CErrorStr124);
+ }
+ }
+
+ if (tk != ']')
+ CError_ErrorSkip(CErrorStr125);
+ else
+ tk = lex();
+ }
+
+ declinfo->x47 = 1;
+ scandirectdecl1(declinfo);
+
+ if (!flag && !CDecl_CheckArrayIntegr(declinfo->thetype))
+ declinfo->thetype = (Type *) &stsignedchar;
+
+ if (!declinfo->thetype->size && CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype)) {
+ ttempl = (TypeTemplDep *) CDecl_NewTemplDepType(TEMPLDEP_ARRAY);
+ ttempl->u.array.type = declinfo->thetype;
+ ttempl->u.array.index = CInline_CopyExpression(intconstnode((Type *) &stsignedint, CInt64_GetULong(&len)), CopyMode1);
+ declinfo->thetype = (Type *) ttempl;
+ } else {
+ declinfo->thetype = CDecl_NewArrayType(declinfo->thetype, declinfo->thetype->size * CInt64_GetULong(&len));
+ }
+ } else if (tk == '(') {
+ if (!copts.cplusplus || !declinfo->name || IS_TYPE_VOID(declinfo->thetype) || CParser_TryParamList(!IS_TYPE_CLASS(declinfo->thetype))) {
+ tk = lex();
+ CDecl_ParseDirectFuncDecl(declinfo);
+ }
+ }
+}
+
+static void substitute_type(Type *type1, Type *type2) {
+ SInt32 oldsize;
+
+ while (1) {
+ switch (type1->type) {
+ case TYPEPOINTER:
+ if (TYPE_POINTER(type1)->target == &stillegal) {
+ TYPE_POINTER(type1)->target = type2;
+ type1->size = 4;
+ return;
+ }
+ type1 = TYPE_POINTER(type1)->target;
+ break;
+ case TYPEMEMBERPOINTER:
+ if (TYPE_MEMBER_POINTER(type1)->ty1 == &stillegal) {
+ TYPE_MEMBER_POINTER(type1)->ty1 = type2;
+ if (IS_TYPE_FUNC(type2)) {
+ CDecl_MakePTMFuncType(TYPE_FUNC(type2));
+ type1->size = 12;
+ } else {
+ type1->size = 4;
+ }
+ return;
+ }
+ type1 = TYPE_MEMBER_POINTER(type1)->ty1;
+ break;
+ case TYPEARRAY:
+ if (TYPE_POINTER(type1)->target == &stillegal) {
+ if (!CDecl_CheckArrayIntegr(type2))
+ type2 = (Type *) &stsignedchar;
+ type1->size *= type2->size;
+ TYPE_POINTER(type1)->target = type2;
+ return;
+ }
+ oldsize = TYPE_POINTER(type1)->target->size;
+ substitute_type(TYPE_POINTER(type1)->target, type2);
+ if (oldsize != TYPE_POINTER(type1)->target->size && oldsize != 0)
+ type1->size = TYPE_POINTER(type1)->target->size * (type1->size / oldsize);
+ return;
+ case TYPEFUNC:
+ if (TYPE_FUNC(type1)->functype == &stillegal) {
+ if (!checkfuncintegr(type2))
+ type2 = &stvoid;
+ TYPE_FUNC(type1)->functype = type2;
+ CDecl_SetFuncResultReg((TypeFunc *) type1);
+ return;
+ }
+ type1 = TYPE_FUNC(type1)->functype;
+ break;
+ case TYPETEMPLATE:
+ if (TYPE_TEMPLATE(type1)->dtype == TEMPLDEP_ARRAY) {
+ if (TYPE_TEMPLATE(type1)->u.array.type == &stillegal) {
+ if (!CDecl_CheckArrayIntegr(type2))
+ type2 = (Type *) &stsignedchar;
+ TYPE_TEMPLATE(type1)->u.array.type = type2;
+ return;
+ }
+ type1 = TYPE_TEMPLATE(type1)->u.array.type;
+ } else {
+ CError_Error(CErrorStr146);
+ return;
+ }
+ break;
+ default:
+ CError_Error(CErrorStr121);
+ return;
+ }
+ }
+}
+
+static void scandecl(DeclInfo *declinfo) {
+ Type *oldtype;
+ Type *newtype;
+
+ oldtype = declinfo->thetype;
+ declinfo->thetype = &stillegal;
+ scandeclarator(declinfo);
+
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+
+ newtype = declinfo->thetype;
+ if (newtype == &stillegal) {
+ declinfo->thetype = oldtype;
+ scandirectdecl1(declinfo);
+ } else {
+ declinfo->thetype = oldtype;
+ scandirectdecl1(declinfo);
+ substitute_type(newtype, declinfo->thetype);
+ declinfo->thetype = newtype;
+ }
+}
+
+static Boolean CDecl_ParseOperatorDecl(DeclInfo *declinfo) {
+ if (declinfo->operator_token) {
+ CError_Error(CErrorStr121);
+ return 0;
+ }
+
+ declinfo->operator_token = 0;
+ if (!CParser_ParseOperatorName(&declinfo->operator_token, declinfo->x4A && cscope_current->theclass, 0))
+ return 0;
+
+ if (!declinfo->operator_token) {
+ conversion_type_name(declinfo);
+ tkidentifier = CMangler_ConversionFuncName(declinfo->thetype, declinfo->qual);
+ declinfo->x54 = 1;
+ }
+ return 1;
+}
+
+static Boolean CDecl_IsEnumClassTypeOrRef(Type *type) {
+ if (IS_TYPE_CLASS(type) || IS_TYPE_ENUM(type))
+ return 1;
+ if (!IS_TYPE_REFERENCE(type))
+ return 0;
+ type = TYPE_POINTER(type)->target;
+ return IS_TYPE_CLASS(type) || IS_TYPE_ENUM(type);
+}
+
+static Boolean CDecl_CheckOperatorType(DeclInfo *declinfo, Boolean flag) {
+ FuncArg *args;
+ FuncArg *secondarg;
+ Type *functype;
+ short argCount;
+ Boolean isMethod;
+
+ if (!IS_TYPE_FUNC(declinfo->thetype)) {
+ CError_Error(CErrorStr193);
+ return 0;
+ }
+
+ functype = TYPE_FUNC(declinfo->thetype)->functype;
+ args = TYPE_FUNC(declinfo->thetype)->args;
+ if (args) {
+ if (args != &elipsis && args != &oldstyle) {
+ argCount = 1;
+ if (args->dexpr) {
+ switch (declinfo->operator_token) {
+ case TK_NEW:
+ case TK_DELETE:
+ case TK_NEW_ARRAY:
+ case TK_DELETE_ARRAY:
+ break;
+ default:
+ CError_Error(CErrorStr205);
+ }
+ }
+
+ secondarg = args->next;
+ if (secondarg) {
+ argCount = ((secondarg != &elipsis && !secondarg->next) != 0) ? 2 : 3;
+ if (secondarg->dexpr) {
+ switch (declinfo->operator_token) {
+ case '(':
+ case TK_NEW:
+ case TK_DELETE:
+ case TK_NEW_ARRAY:
+ case TK_DELETE_ARRAY:
+ break;
+ default:
+ CError_Error(CErrorStr205);
+ }
+ }
+ }
+ } else {
+ argCount = 3;
+ }
+ } else {
+ CError_Error(CErrorStr193);
+ return 0;
+ }
+
+ isMethod = flag &&
+ IS_TYPEFUNC_METHOD(TYPE_FUNC(declinfo->thetype)) &&
+ !TYPE_METHOD(declinfo->thetype)->is_static;
+
+ switch (declinfo->operator_token) {
+ case TK_NEW:
+ case TK_NEW_ARRAY:
+ if (isMethod || !is_typesame(functype, TYPE(&void_ptr)) || argCount < 1 || args->type != CABI_GetSizeTType()) {
+ CError_Error(CErrorStr193);
+ return 0;
+ }
+ return 1;
+ case TK_DELETE:
+ case TK_DELETE_ARRAY:
+ if (isMethod || !IS_TYPE_VOID(functype) || argCount < 1 || !is_typesame(args->type, TYPE(&void_ptr))) {
+ CError_Error(CErrorStr193);
+ return 0;
+ }
+ return 1;
+ case '=':
+ if (!isMethod) {
+ CError_Error(CErrorStr193);
+ return 0;
+ }
+ break;
+ case '(':
+ if (!isMethod) {
+ CError_Error(CErrorStr193);
+ return 0;
+ }
+ return 1;
+ case '[':
+ if (!isMethod) {
+ CError_Error(CErrorStr193);
+ return 0;
+ }
+ break;
+ case TK_ARROW:
+ if (argCount != 1 || isMethod == 0) {
+ CError_Error(CErrorStr193);
+ return 0;
+ }
+ return 1;
+ case TK_INCREMENT:
+ case TK_DECREMENT:
+ if (argCount == 2 && secondarg->type != TYPE(&stsignedint)) {
+ CError_Error(CErrorStr193);
+ return 0;
+ }
+ break;
+ }
+
+ if (flag && !isMethod) {
+ CError_Error(CErrorStr193);
+ return 0;
+ }
+
+ switch (declinfo->operator_token) {
+ case '&':
+ case '*':
+ case '+':
+ case '-':
+ case TK_INCREMENT:
+ case TK_DECREMENT:
+ if (argCount != 1)
+ goto whatever;
+ case '!':
+ case '~':
+ if (argCount == 1) {
+ if (flag || CDecl_IsEnumClassTypeOrRef(args->type))
+ return 1;
+ }
+ break;
+ case '%':
+ case ',':
+ case '/':
+ case '<':
+ case '=':
+ case '>':
+ case '[':
+ case '^':
+ case '|':
+ case TK_MULT_ASSIGN:
+ case TK_DIV_ASSIGN:
+ case TK_MOD_ASSIGN:
+ case TK_ADD_ASSIGN:
+ case TK_SUB_ASSIGN:
+ case TK_SHL_ASSIGN:
+ case TK_SHR_ASSIGN:
+ case TK_AND_ASSIGN:
+ case TK_XOR_ASSIGN:
+ case TK_OR_ASSIGN:
+ case TK_LOGICAL_OR:
+ case TK_LOGICAL_AND:
+ case TK_LOGICAL_EQ:
+ case TK_LOGICAL_NE:
+ case TK_LESS_EQUAL:
+ case TK_GREATER_EQUAL:
+ case TK_SHL:
+ case TK_SHR:
+ case TK_ARROW:
+ case TK_DOT_STAR:
+ case TK_ARROW_STAR:
+ whatever:
+ if (argCount == 2) {
+ if (flag || CDecl_IsEnumClassTypeOrRef(args->type) || CDecl_IsEnumClassTypeOrRef(secondarg->type))
+ return 1;
+ }
+ break;
+ }
+
+ CError_Error(CErrorStr193);
+ return 0;
+}
+
+static void scandirectdeclarator(DeclInfo *declinfo, NameSpace *nspace) {
+ HashNameNode *saveident;
+ CScopeSave scopesave;
+ Boolean flag;
+
+ if (nspace)
+ CScope_SetNameSpaceScope(nspace, &scopesave);
+
+ if (tk == '(') {
+ if ((tk = lex()) == ')') {
+ if (declinfo->x55) {
+ CDecl_ParseDirectFuncDecl(declinfo);
+ if (nspace)
+ CScope_RestoreScope(&scopesave);
+ return;
+ } else {
+ CError_Error(CErrorStr121);
+ if (nspace)
+ CScope_RestoreScope(&scopesave);
+ return;
+ }
+ }
+
+ if (!(tk >= TK_AUTO && tk <= TK_BYREF)) {
+ if (!(tk == TK_IDENTIFIER && CScope_PossibleTypeName(tkidentifier))) {
+ scandecl(declinfo);
+ if (nspace)
+ CScope_RestoreScope(&scopesave);
+ return;
+ } else {
+ saveident = tkidentifier;
+ switch (lookahead()) {
+ case ')':
+ case ',':
+ break;
+ default:
+ tkidentifier = saveident;
+ scandecl(declinfo);
+ if (nspace)
+ CScope_RestoreScope(&scopesave);
+ return;
+ }
+ }
+ }
+
+ if (declinfo->name)
+ CError_Error(CErrorStr121);
+
+ CDecl_ParseDirectFuncDecl(declinfo);
+ if (nspace)
+ CScope_RestoreScope(&scopesave);
+ return;
+ }
+
+ if (nspace) {
+ if (tk == TK_OPERATOR) {
+ if (!CDecl_ParseOperatorDecl(declinfo)) {
+ CScope_RestoreScope(&scopesave);
+ return;
+ }
+
+ if (declinfo->x54) {
+ declinfo->nspace = nspace;
+ declinfo->name = tkidentifier;
+ if (nspace)
+ CScope_RestoreScope(&scopesave);
+
+ if (tk == '(') {
+ tk = lex();
+ CDecl_ParseDirectFuncDecl(declinfo);
+ if (IS_TYPE_FUNC(declinfo->thetype))
+ TYPE_FUNC(declinfo->thetype)->flags |= FUNC_CONVERSION;
+ else
+ CError_Error(CErrorStr121);
+ } else {
+ CError_Error(CErrorStr114);
+ }
+ return;
+ }
+
+ flag = 1;
+ } else if (tk != TK_IDENTIFIER) {
+ CError_Error(CErrorStr107);
+ CScope_RestoreScope(&scopesave);
+ return;
+ } else {
+ flag = 0;
+ }
+
+ if (declinfo->name) {
+ CError_Error(CErrorStr121);
+ CScope_RestoreScope(&scopesave);
+ return;
+ }
+
+ declinfo->nspace = nspace;
+ declinfo->name = tkidentifier;
+ if (!flag)
+ tk = lex();
+ } else if (tk == TK_IDENTIFIER) {
+ if (declinfo->name)
+ CError_Error(CErrorStr121);
+ declinfo->name = tkidentifier;
+ tk = lex();
+ } else if (tk == TK_OPERATOR) {
+ if (!CDecl_ParseOperatorDecl(declinfo))
+ return;
+ declinfo->name = tkidentifier;
+ }
+
+ if (tk == '<' && declinfo->x51) {
+ declinfo->expltargs = CTempl_ParseUncheckTemplArgs(NULL, 0);
+ declinfo->has_expltargs = 1;
+ declinfo->x51 = 0;
+ tk = lex();
+ }
+
+ scandirectdecl1(declinfo);
+
+ if (nspace)
+ CScope_RestoreScope(&scopesave);
+}
+
+void makememberpointertype(DeclInfo *declinfo, TypeClass *tclass, UInt32 qual) {
+ TypeMemberPointer *tmemp;
+ TypeFunc *tfunc;
+
+ if (tclass->flags & CLASS_HANDLEOBJECT) {
+ CError_Error(CErrorStr191);
+ declinfo->thetype = (Type *) &stsignedint;
+ return;
+ }
+ if (tclass->sominfo) {
+ CError_Error(CErrorStr290);
+ declinfo->thetype = (Type *) &stsignedint;
+ return;
+ }
+
+ tmemp = galloc(sizeof(TypeMemberPointer));
+ memclrw(tmemp, sizeof(TypeMemberPointer));
+ tmemp->type = TYPEMEMBERPOINTER;
+ tmemp->ty2 = (Type *) tclass;
+ tmemp->qual = qual;
+
+ if (IS_TYPE_FUNC(declinfo->thetype)) {
+ tfunc = galloc(sizeof(TypeFunc));
+ *tfunc = *TYPE_FUNC(declinfo->thetype);
+ tmemp->ty1 = (Type *) tfunc;
+ tmemp->size = 12;
+ CDecl_MakePTMFuncType(tfunc);
+ } else {
+ tmemp->size = 4;
+ tmemp->ty1 = declinfo->thetype;
+ }
+ declinfo->thetype = (Type *) tmemp;
+}
+
+void CDecl_ScanPointer(DeclInfo *declinfo, NameSpace *nspace, Boolean flag) {
+ NameResult pr;
+ UInt32 qual;
+
+ while (1) {
+ qual = (tk == '&') ? Q_REFERENCE : 0;
+
+ for (tk = lex(); ; tk = lex()) {
+ switch (tk) {
+ case TK_CONST:
+ if (qual & Q_CONST)
+ CError_Error(CErrorStr121);
+ qual |= Q_CONST;
+ continue;
+ case TK_VOLATILE:
+ if (qual & Q_VOLATILE)
+ CError_Error(CErrorStr121);
+ qual |= Q_VOLATILE;
+ continue;
+ case TK_RESTRICT:
+ if (qual & Q_RESTRICT)
+ CError_Error(CErrorStr121);
+ qual |= Q_RESTRICT;
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (IS_TYPE_REFERENCE(declinfo->thetype) || ((qual & Q_REFERENCE) && IS_TYPE_VOID(declinfo->thetype))) {
+ CError_Error(CErrorStr196);
+ return;
+ }
+
+ if (nspace) {
+ makememberpointertype(declinfo, nspace->theclass, qual);
+ nspace = NULL;
+ } else {
+ makethetypepointer(declinfo, qual);
+ }
+
+ switch (tk) {
+ case '*':
+ continue;
+ case '&':
+ if (!copts.cplusplus) {
+ if (flag)
+ scandirectdeclarator(declinfo, NULL);
+ return;
+ }
+ continue;
+ case TK_IDENTIFIER:
+ if (!copts.cplusplus)
+ break;
+ if (copts.cpp_extensions && cscope_current->theclass && cscope_current->theclass->classname == tkidentifier && lookahead() == TK_COLON_COLON) {
+ tk = lex();
+ tk = lex();
+ break;
+ }
+ case TK_COLON_COLON:
+ if (CScope_ParseQualifiedNameSpace(&pr, 1, 0)) {
+ if ((nspace = pr.nspace_0)) {
+ if (nspace->theclass && tk == '*')
+ continue;
+ } else {
+ if (pr.type && IS_TYPE_TEMPLATE(pr.type) && declinfo->x30) {
+ if (CTempl_IsQualifiedMember(declinfo, pr.type, &nspace))
+ scandirectdeclarator(declinfo, nspace);
+ else
+ declinfo->x20 = pr.type;
+ return;
+ }
+ CError_Error(CErrorStr121);
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ if (flag)
+ scandirectdeclarator(declinfo, nspace);
+}
+
+static void CDecl_TemplatePTM(DeclInfo *declinfo, Type *type) {
+ TypeMemberPointer *tmemp = galloc(sizeof(TypeMemberPointer));
+ tmemp->type = TYPEMEMBERPOINTER;
+ if (IS_TYPE_FUNC(declinfo->thetype)) {
+ CDecl_MakePTMFuncType((TypeFunc *) declinfo->thetype);
+ tmemp->size = 12;
+ } else {
+ tmemp->size = 4;
+ }
+
+ tmemp->ty1 = declinfo->thetype;
+ tmemp->ty2 = type;
+ tmemp->qual = 0;
+ declinfo->thetype = (Type *) tmemp;
+}
+
+void scandeclarator(DeclInfo *declinfo) {
+ NameResult pr;
+ NameSpace *nspace;
+
+ switch (tk) {
+ case '&':
+ if (!copts.cplusplus)
+ break;
+ case '*':
+ CDecl_ScanPointer(declinfo, NULL, 1);
+ if (tk == TK_UU_ATTRIBUTE_UU)
+ CParser_ParseAttribute(NULL, declinfo);
+ return;
+ case TK_IDENTIFIER:
+ if (!copts.cplusplus)
+ break;
+ case TK_COLON_COLON:
+ if (CScope_ParseQualifiedNameSpace(&pr, 1, 0)) {
+ nspace = pr.nspace_0;
+ if (nspace) {
+ if (nspace->theclass && tk == '*')
+ CDecl_ScanPointer(declinfo, nspace, 1);
+ else
+ scandirectdeclarator(declinfo, nspace);
+ return;
+ }
+ if (pr.type && IS_TYPE_TEMPLATE(pr.type)) {
+ if (declinfo->x30 && CTempl_IsQualifiedMember(declinfo, pr.type, &nspace)) {
+ scandirectdeclarator(declinfo, nspace);
+ return;
+ } else if (declinfo->x30 && tk == TK_OPERATOR) {
+ declinfo->x20 = pr.type;
+ return;
+ } else if ((tk = lex()) == TK_COLON_COLON && (tk = lex()) == '*') {
+ CDecl_TemplatePTM(declinfo, pr.type);
+ tk = lex();
+ break;
+ } else if (declinfo->x30) {
+ declinfo->x20 = pr.type;
+ return;
+ }
+ }
+ CError_Error(CErrorStr121);
+ }
+ break;
+ }
+
+ scandirectdeclarator(declinfo, NULL);
+ if (tk == TK_UU_ATTRIBUTE_UU)
+ CParser_ParseAttribute(NULL, declinfo);
+}
+
+void conversion_type_name(DeclInfo *declinfo) {
+ NameResult pr;
+ DeclInfo subdeclinfo;
+
+ memclrw(&subdeclinfo, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(&subdeclinfo, 0);
+
+ switch (tk) {
+ case '&':
+ case '*':
+ CDecl_ScanPointer(&subdeclinfo, NULL, 0);
+ break;
+ case TK_IDENTIFIER:
+ case TK_COLON_COLON:
+ if (CScope_ParseQualifiedNameSpace(&pr, 0, 0)) {
+ if (pr.nspace_0 && pr.nspace_0->theclass && tk == '*')
+ CDecl_ScanPointer(&subdeclinfo, pr.nspace_0, 0);
+ else
+ CError_Error(CErrorStr121);
+ }
+ break;
+ }
+
+ declinfo->name = subdeclinfo.name;
+ declinfo->thetype = subdeclinfo.thetype;
+ declinfo->qual |= subdeclinfo.qual;
+}
+
+static void scaninlinefunc(Object *obj) {
+ short array[256];
+ short r29;
+ CInt64 val;
+
+ if (tk == '{') {
+ tk = lex();
+ r29 = 0;
+ while (1) {
+ if (r29 >= 256) {
+ CError_Error(CErrorStr127);
+ r29 = 255;
+ }
+ val = CExpr_IntegralConstExpr();
+ array[r29++] = CInt64_GetULong(&val);
+ if (tk != '}') {
+ if (tk != ',')
+ CError_Error(CErrorStr116);
+ tk = lex();
+ } else {
+ tk = lex();
+ break;
+ }
+ }
+ } else {
+ val = CExpr_IntegralConstExpr();
+ array[0] = CInt64_GetULong(&val);
+ r29 = 1;
+ }
+
+ obj->datatype = DINLINEFUNC;
+ obj->u.ifunc.size = r29 * 2;
+ obj->u.ifunc.data = galloc(obj->u.ifunc.size);
+ obj->u.ifunc.xrefs = NULL;
+ memcpy(obj->u.ifunc.data, array, obj->u.ifunc.size);
+
+ if (tk != ';')
+ CError_Error(CErrorStr123);
+}
+
+typedef enum {
+ OverloadMode0,
+ OverloadMode1,
+ OverloadMode2,
+ OverloadMode3
+} OverloadMode;
+
+static Object *CDecl_OverloadFunctionObject(NameSpaceObjectList *list, DeclInfo *declinfo, Boolean *outflag, OverloadMode mode, Boolean flag2) {
+ TypeFunc *scanfunc;
+ NameSpaceObjectList *scan;
+ TypeFunc *tfunc;
+ FuncArg *args;
+ FuncArg *scanargs;
+ Object *obj;
+ Boolean r24;
+ short compareresult;
+
+ if (outflag)
+ *outflag = 0;
+
+ tfunc = (TypeFunc *) declinfo->thetype;
+ args = tfunc->args;
+ r24 = 0;
+ for (scan = list; scan; scan = scan->next) {
+ obj = OBJECT(scan->object);
+ if (obj->otype != OT_OBJECT)
+ continue;
+
+ scanfunc = TYPE_FUNC(obj->type);
+ if (!IS_TYPE_FUNC(scanfunc))
+ continue;
+
+ scanargs = scanfunc->args;
+ if (scanfunc->flags & FUNC_IS_TEMPL)
+ r24 = 1;
+
+ if (IS_TYPEFUNC_METHOD(scanfunc)) {
+ switch (mode) {
+ case OverloadMode0:
+ CError_Error(CErrorStr197);
+ break;
+ case OverloadMode1:
+ if (!TYPE_METHOD(scanfunc)->is_static)
+ continue;
+ break;
+ case OverloadMode2:
+ if (TYPE_METHOD(scanfunc)->is_static)
+ continue;
+ break;
+ case OverloadMode3:
+ if (!TYPE_METHOD(scanfunc)->is_static) {
+ if (scanargs->qual & Q_CV)
+ continue;
+ scanargs = scanargs->next;
+ }
+ break;
+ }
+ } else {
+ if (mode)
+ CError_Error(CErrorStr197);
+ }
+
+ compareresult = CParser_CompareArgLists(args, scanargs);
+ if (compareresult == 1) {
+ if (scanfunc->flags & FUNC_CONVERSION) {
+ if (!(tfunc->flags & FUNC_CONVERSION)) {
+ CError_Error(CErrorStr197);
+ break;
+ }
+ if (!is_typesame(tfunc->functype, scanfunc->functype))
+ continue;
+ if ((tfunc->qual & Q_CV) != (scanfunc->qual & Q_CV))
+ continue;
+ if ((tfunc->flags & FUNC_CALL_CONV_MASK) != (scanfunc->flags & FUNC_CALL_CONV_MASK)) {
+ CError_Error(CErrorStr197);
+ break;
+ }
+ if (tfunc->exspecs || scanfunc->exspecs)
+ CExcept_CompareSpecifications(tfunc->exspecs, scanfunc->exspecs);
+ return obj;
+ }
+
+ if (tfunc->flags & FUNC_CONVERSION) {
+ CError_Error(CErrorStr197);
+ break;
+ }
+
+ if (
+ !is_typesame(tfunc->functype, scanfunc->functype) ||
+ ((tfunc->qual & (Q_CONST | Q_PASCAL)) != (scanfunc->qual & (Q_CONST | Q_PASCAL))) ||
+ ((tfunc->flags & FUNC_CALL_CONV_MASK) != (scanfunc->flags & FUNC_CALL_CONV_MASK))
+ )
+ {
+ CError_Error(CErrorStr197);
+ break;
+ }
+
+ if (tfunc->exspecs || scanfunc->exspecs) {
+ if (obj->name != newp_fobj->name && obj->name != newa_fobj->name && obj->name != delp_fobj->name && obj->name != dela_fobj->name)
+ CExcept_CompareSpecifications(tfunc->exspecs, scanfunc->exspecs);
+ }
+
+ return obj;
+ } else if (compareresult == 2) {
+ CError_Error(CErrorStr197);
+ break;
+ }
+ }
+
+ if (r24 && (flag2 || declinfo->x3C)) {
+ if ((obj = CTempl_TemplateFunctionCheck(declinfo, list)))
+ return obj;
+ }
+
+ if (!outflag) {
+ CError_Error(CErrorStr197);
+ return NULL;
+ }
+
+ if (declinfo->nspace)
+ CError_Error(CErrorStr336);
+
+ *outflag = 1;
+ obj = CParser_NewFunctionObject(declinfo);
+ CheckDefaultArgs(TYPE_FUNC(obj->type)->args);
+
+ if (tfunc->flags & FUNC_PASCAL) {
+ for (scan = list; scan; scan = scan->next) {
+ if (scan->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(scan->object)->type)) {
+ if (TYPE_FUNC(OBJECT(scan->object)->type)->flags & FUNC_PASCAL)
+ CError_Error(CErrorStr226);
+ }
+ }
+ }
+
+ if (copts.cplusplus && declinfo->is_extern_c) {
+ for (scan = list; scan; scan = scan->next) {
+ if (scan->object->otype == OT_OBJECT && !(OBJECT(scan->object)->qual & Q_MANGLE_NAME))
+ CError_Error(CErrorStr197);
+ }
+ }
+
+ CScope_AddObject(cscope_current, declinfo->name, OBJ_BASE(obj));
+ if (cscope_current->theclass && (cscope_current->theclass->flags & CLASS_IS_TEMPL) &&
+ CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype))
+ CTemplClass_RegisterObjectDef(TEMPL_CLASS(cscope_current->theclass), OBJ_BASE(obj));
+
+ return obj;
+}
+
+void MergeDefaultArgs(FuncArg *a, FuncArg *b) {
+ FuncArg *scan_a;
+ FuncArg *scan_b;
+
+ if (a == &oldstyle || b == &oldstyle)
+ return;
+
+ scan_a = a;
+ scan_b = b;
+ while (scan_a && scan_b) {
+ if (scan_a->dexpr) {
+ while (scan_b) {
+ if (scan_b->dexpr) {
+ while (a) {
+ a->dexpr = NULL;
+ a = a->next;
+ }
+ while (b) {
+ b->dexpr = NULL;
+ b = b->next;
+ }
+ CError_Error(CErrorStr205);
+ return;
+ }
+ scan_b = scan_b->next;
+ }
+ break;
+ } else if (scan_b->dexpr) {
+ do {
+ scan_a = scan_a->next;
+ scan_b = scan_b->next;
+ if (!scan_a) goto secondpart;
+ if (scan_a == &elipsis) goto secondpart;
+ if (scan_a->dexpr && scan_b->dexpr) break;
+ } while (scan_a->dexpr || scan_b->dexpr);
+
+ while (a) {
+ a->dexpr = NULL;
+ a = a->next;
+ }
+ while (b) {
+ b->dexpr = NULL;
+ b = b->next;
+ }
+ CError_Error(CErrorStr205);
+ return;
+ } else {
+ scan_a = scan_a->next;
+ scan_b = scan_b->next;
+ }
+ }
+
+secondpart:
+ while (a && b) {
+ if (b->dexpr)
+ a->dexpr = b->dexpr;
+ else
+ b->dexpr = a->dexpr;
+ a = a->next;
+ b = b->next;
+ }
+}
+
+void CheckDefaultArgs(FuncArg *args) {
+ FuncArg *scan;
+
+ scan = args;
+ while (scan && !scan->dexpr)
+ scan = scan->next;
+
+ while (scan && scan != &elipsis && scan != &oldstyle) {
+ if (!scan->dexpr) {
+ while (args) {
+ args->dexpr = NULL;
+ args = args->next;
+ }
+ CError_Error(CErrorStr205);
+ return;
+ }
+ scan = scan->next;
+ }
+}
+
+static void CDecl_FuncRedeclCheck(Object *obj, DeclInfo *declinfo, Boolean flag) {
+ if (declinfo->storageclass == TK_STATIC && obj->sclass != TK_STATIC) {
+ if (copts.cplusplus)
+ CError_Error(CErrorStr260);
+ else
+ obj->sclass = TK_STATIC;
+ }
+
+ obj->qual |= declinfo->qual;
+ if (flag)
+ CheckDefaultArgs(TYPE_FUNC(obj->type)->args);
+ else
+ MergeDefaultArgs(TYPE_FUNC(obj->type)->args, TYPE_FUNC(declinfo->thetype)->args);
+
+ if (!declinfo->x45)
+ TYPE_FUNC(obj->type)->args = TYPE_FUNC(declinfo->thetype)->args;
+}
+
+Object *CDecl_GetFunctionObject(DeclInfo *declinfo, NameSpace *nspace, Boolean *pflag, Boolean someotherflag) {
+ NameSpace *nspace2;
+ Type *type;
+ Object *obj;
+ NameSpaceObjectList *list;
+ TypeMemberFunc tmp;
+ Boolean r27;
+ Boolean outflag;
+
+ r27 = 0;
+ if (pflag)
+ *pflag = 0;
+
+ nspace2 = declinfo->nspace;
+ if (!nspace2)
+ nspace2 = cscope_current;
+
+ CError_QualifierCheck(declinfo->qual & ~(Q_ALIGNED_MASK | Q_WEAK | Q_20000 | Q_INLINE | Q_PASCAL | Q_ASM | Q_VOLATILE | Q_CONST));
+ switch (TYPE_FUNC(declinfo->thetype)->functype->type) {
+ case TYPEFUNC:
+ case TYPEARRAY:
+ CError_Error(CErrorStr128);
+ TYPE_FUNC(declinfo->thetype)->functype = TYPE(&stsignedint);
+ break;
+ }
+
+ if (nspace2->theclass) {
+ CError_ASSERT(1969, declinfo->name);
+ if (!nspace2->theclass->size)
+ CDecl_CompleteType(TYPE(nspace2->theclass));
+ if (!(list = CScope_GetLocalObject(nspace2, declinfo->name))) {
+ CError_Error(CErrorStr140, declinfo->name->name);
+ return NULL;
+ }
+
+ obj = OBJECT(list->object);
+ type = obj->type;
+ if (!IS_TYPE_FUNC(type)) {
+ CError_Error(CErrorStr249, CError_GetObjectName(obj), type, obj->qual, declinfo->thetype, declinfo->qual);
+ return NULL;
+ }
+
+ if (declinfo->has_expltargs)
+ return CTempl_TemplateFunctionCheck(declinfo, list);
+
+ if (declinfo->x3C || (list->next && list->next->object->otype == OT_OBJECT)) {
+ if (TYPE_FUNC(declinfo->thetype)->flags & (FUNC_CONST | FUNC_VOLATILE)) {
+ CDecl_AddThisPointerArgument(TYPE_FUNC(declinfo->thetype), nspace2->theclass);
+ obj = CDecl_OverloadFunctionObject(list, declinfo, NULL, OverloadMode2, someotherflag);
+ if (!obj)
+ return NULL;
+ } else {
+ obj = CDecl_OverloadFunctionObject(list, declinfo, NULL, OverloadMode3, someotherflag);
+ if (!obj)
+ return NULL;
+ if (!TYPE_METHOD(obj->type)->is_static)
+ CDecl_AddThisPointerArgument(TYPE_FUNC(declinfo->thetype), nspace2->theclass);
+ }
+ } else {
+ if (TYPE_METHOD(type)->is_static) {
+ if (nspace2->theclass->sominfo)
+ CSOM_FixNewDeleteFunctype(TYPE_FUNC(declinfo->thetype));
+ } else {
+ CDecl_AddThisPointerArgument(TYPE_FUNC(declinfo->thetype), nspace2->theclass);
+ }
+
+ if (copts.cpp_extensions) {
+ declinfo->qual |= obj->qual & (Q_PASCAL | Q_CONST);
+ TYPE_FUNC(declinfo->thetype)->qual |= TYPE_FUNC(obj->type)->qual & (Q_PASCAL | Q_CONST);
+ TYPE_FUNC(declinfo->thetype)->flags |= TYPE_FUNC(obj->type)->flags & (FUNC_FLAGS_4000000 | FUNC_FLAGS_10000000);
+ }
+
+ if (!is_typesame(declinfo->thetype, obj->type) || (declinfo->qual & (Q_PASCAL | Q_CONST)) != (obj->qual & (Q_PASCAL | Q_CONST))) {
+ tmp = *TYPE_METHOD(obj->type);
+ *(TYPE_FUNC(&tmp)) = *TYPE_FUNC(declinfo->thetype);
+ tmp.flags |= FUNC_METHOD;
+ CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, &tmp, declinfo->qual);
+ }
+
+ if (TYPE_FUNC(declinfo->thetype)->exspecs || TYPE_FUNC(obj->type)->exspecs)
+ CExcept_CompareSpecifications(TYPE_FUNC(declinfo->thetype)->exspecs, TYPE_FUNC(obj->type)->exspecs);
+ }
+
+ CDecl_FuncRedeclCheck(obj, declinfo, 0);
+ if (declinfo->x3C) {
+ if (obj->nspace->theclass && !(obj->nspace->theclass->flags & CLASS_IS_TEMPL_INST))
+ CError_Error(CErrorStr335);
+ declinfo->x3C = 0;
+ }
+ } else {
+ if (TYPE_FUNC(declinfo->thetype)->flags & (FUNC_VOLATILE | FUNC_CONST))
+ CError_Error(CErrorStr384);
+
+ if (declinfo->operator_token && !CDecl_CheckOperatorType(declinfo, 0))
+ return NULL;
+
+ list = CScope_GetLocalObject(nspace2, declinfo->name);
+ if (declinfo->has_expltargs)
+ return CTempl_TemplateFunctionCheck(declinfo, list);
+
+ if (list) {
+ if (copts.cplusplus) {
+ obj = CDecl_OverloadFunctionObject(list, declinfo, &outflag, OverloadMode0, someotherflag);
+ if (!obj)
+ return NULL;
+ if (pflag)
+ *pflag = outflag;
+ if (nspace)
+ obj->nspace = nspace;
+ } else {
+ obj = OBJECT(list->object);
+ if (!is_typesame(declinfo->thetype, obj->type) || (declinfo->qual & (Q_CONST | Q_PASCAL)) != (obj->qual & (Q_CONST | Q_PASCAL))) {
+ CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, declinfo->thetype, declinfo->qual);
+ r27 = 1;
+ if (!IS_TYPE_FUNC(obj->type))
+ return NULL;
+ }
+ }
+
+ if (!r27 && pflag)
+ CDecl_FuncRedeclCheck(obj, declinfo, *pflag);
+ } else {
+ if (declinfo->nspace)
+ CError_Error(CErrorStr336);
+
+ if (declinfo->has_expltargs) {
+ if (declinfo->name)
+ CError_Error(CErrorStr140, declinfo->name->name);
+ else
+ CError_Error(CErrorStr127);
+ }
+
+ obj = CParser_NewFunctionObject(declinfo);
+ if (nspace)
+ obj->nspace = nspace;
+ if (pflag)
+ *pflag = 1;
+ else
+ CError_Error(CErrorStr127);
+
+ CheckDefaultArgs(TYPE_FUNC(obj->type)->args);
+ CScope_AddObject(nspace2, declinfo->name, OBJ_BASE(obj));
+ }
+ }
+
+ return obj;
+}
+
+void CDecl_TypedefDeclarator(DeclInfo *declinfo) {
+ NameSpace *nspace;
+ NameSpaceObjectList *list;
+ ObjType *objt;
+
+ nspace = declinfo->nspace;
+ if (!nspace)
+ nspace = cscope_current;
+
+ CError_QualifierCheck(declinfo->qual & ~(Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST));
+ if (declinfo->x48 || declinfo->x44)
+ CError_Error(CErrorStr121);
+ if (declinfo->operator_token)
+ CError_Error(CErrorStr193);
+
+ objt = NULL;
+ list = CScope_FindName(nspace, declinfo->name);
+ if (list) {
+ switch (list->object->otype) {
+ case OT_TYPE:
+ objt = OBJ_TYPE(list->object);
+ break;
+ case OT_TYPETAG:
+ break;
+ case OT_NAMESPACE:
+ CError_Error(CErrorStr321);
+ return;
+ case OT_ENUMCONST:
+ case OT_OBJECT:
+ CError_Error(CErrorStr322);
+ return;
+ default:
+ CError_FATAL(2156);
+ }
+ }
+
+ if (objt) {
+ const UInt32 mask = Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST;
+ if (!is_typesame(objt->type, declinfo->thetype) || (objt->qual & mask) != (declinfo->qual & mask)) {
+ CError_Error(CErrorStr249, declinfo->name->name, objt->type, objt->qual, declinfo->thetype, declinfo->qual);
+ } else if (!copts.cplusplus && (copts.pedantic || copts.ANSIstrict)) {
+ if (copts.pedantic)
+ CError_Warning(CErrorStr122, declinfo->name->name);
+ else
+ CError_Error(CErrorStr122, declinfo->name->name);
+ }
+ return;
+ }
+
+ objt = galloc(sizeof(ObjType));
+ memclrw(objt, sizeof(ObjType));
+ objt->otype = OT_TYPE;
+ objt->access = ACCESSPUBLIC;
+ objt->type = declinfo->thetype;
+ objt->qual = declinfo->qual;
+ CScope_AddObject(nspace, declinfo->name, OBJ_BASE(objt));
+
+ if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL) &&
+ CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype))
+ CTemplClass_RegisterObjectDef(TEMPL_CLASS(nspace->theclass), OBJ_BASE(objt));
+
+ if (copts.cplusplus) {
+ if (IS_TYPE_CLASS(declinfo->thetype) && IsTempName(TYPE_CLASS(declinfo->thetype)->classname)) {
+ TYPE_CLASS(declinfo->thetype)->classname = declinfo->name;
+ TYPE_CLASS(declinfo->thetype)->nspace->name = declinfo->name;
+ }
+ if (IS_TYPE_ENUM(declinfo->thetype) && IsTempName(TYPE_ENUM(declinfo->thetype)->enumname)) {
+ TYPE_ENUM(declinfo->thetype)->enumname = declinfo->name;
+ }
+ }
+
+ if (cparamblkptr->browseoptions.recordTypedefs && declinfo->file->recordbrowseinfo)
+ CBrowse_NewTypedef(nspace, declinfo->name, declinfo->file, declinfo->file2, declinfo->sourceoffset, CPrep_BrowserFileOffset());
+}
+
+static void CDecl_DataDeclarator(DeclInfo *declinfo, AccessType access, Boolean flag) {
+ NameSpaceObjectList *list;
+ Object *obj;
+ NameSpace *nspace;
+ Boolean tmpflag;
+ ENode *expr;
+
+ nspace = declinfo->nspace;
+ if (!nspace)
+ nspace = cscope_current;
+
+ CError_QualifierCheck(declinfo->qual & ~(Q_ALIGNED_MASK | Q_WEAK | Q_20000 | Q_PASCAL | Q_VOLATILE | Q_CONST));
+ if (declinfo->x48 || declinfo->x44)
+ CError_Error(CErrorStr121);
+ if (declinfo->operator_token)
+ CError_Error(CErrorStr193);
+
+ obj = NULL;
+ list = CScope_FindName(nspace, declinfo->name);
+ if (list) {
+ switch (list->object->otype) {
+ case OT_OBJECT:
+ obj = OBJECT(list->object);
+ if (flag)
+ CError_Error(CErrorStr122, declinfo->name->name);
+ break;
+ case OT_TYPETAG:
+ break;
+ case OT_NAMESPACE:
+ CError_Error(CErrorStr321);
+ return;
+ case OT_ENUMCONST:
+ case OT_TYPE:
+ CError_Error(CErrorStr322);
+ break;
+ case OT_MEMBERVAR:
+ CError_Error(CErrorStr221);
+ break;
+ default:
+ CError_FATAL(2281);
+ }
+ }
+
+ if (copts.cplusplus) {
+ if (!flag)
+ CDecl_CompleteType(declinfo->thetype);
+ switch (declinfo->storageclass) {
+ case TK_EXTERN:
+ if (tk == '=' || tk == '(')
+ declinfo->storageclass = 0;
+ break;
+ case 0:
+ if (CParser_IsConst(declinfo->thetype, declinfo->qual)) {
+ if ((!obj && !nspace->theclass) || (obj && obj->sclass != TK_EXTERN && !obj->nspace->theclass))
+ declinfo->storageclass = TK_STATIC;
+ }
+ break;
+ }
+ } else {
+ if (declinfo->storageclass == TK_EXTERN && tk == '=')
+ declinfo->storageclass = 0;
+ }
+
+ if (IS_TYPE_ARRAY(declinfo->thetype) && !declinfo->thetype->size && !declinfo->storageclass && tk != '=')
+ declinfo->storageclass = TK_EXTERN;
+
+ if (obj) {
+ if ((!obj->type->size || !declinfo->thetype->size) && IS_TYPE_ARRAY(declinfo->thetype) && IS_TYPE_ARRAY(obj->type))
+ tmpflag = is_typesame(TYPE_POINTER(declinfo->thetype)->target, TYPE_POINTER(obj->type)->target);
+ else
+ tmpflag = is_typesame(declinfo->thetype, obj->type);
+
+ if (!tmpflag || (obj->qual & (Q_PASCAL | Q_VOLATILE | Q_CONST)) != (declinfo->qual & (Q_PASCAL | Q_VOLATILE | Q_CONST)))
+ CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, declinfo->thetype, declinfo->qual);
+
+ if (obj->qual & Q_INLINE_DATA) {
+ if (tk == ',' || tk == ';')
+ return;
+ CError_Error(CErrorStr333, obj);
+ }
+
+ if (declinfo->storageclass != TK_EXTERN) {
+ if (obj->sclass != TK_EXTERN && declinfo->storageclass && obj->sclass != declinfo->storageclass)
+ CError_Error(CErrorStr333, obj);
+
+ if (tmpflag) {
+ obj->sclass = declinfo->storageclass;
+ obj->qual |= declinfo->qual;
+ if (declinfo->thetype->size)
+ obj->type = declinfo->thetype;
+ }
+
+ CParser_UpdateObject(obj, declinfo);
+ } else {
+ flag = 1;
+ }
+ } else {
+ if (declinfo->nspace)
+ CError_Error(CErrorStr336);
+ if (IS_TYPE_CLASS(declinfo->thetype) && TYPE_CLASS(declinfo->thetype)->sominfo)
+ CError_Error(CErrorStr288);
+ if (!CanCreateObject(declinfo->thetype))
+ declinfo->thetype = TYPE(&stsignedint);
+
+ obj = CParser_NewGlobalDataObject(declinfo);
+ obj->access = access;
+ CScope_AddObject(nspace, declinfo->name, OBJ_BASE(obj));
+
+ if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL) &&
+ CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype))
+ CTemplClass_RegisterObjectDef(TEMPL_CLASS(nspace->theclass), OBJ_BASE(obj));
+
+ if (flag && nspace->theclass && cparamblkptr->browseoptions.recordClasses)
+ CBrowse_AddClassMemberData(obj, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset());
+ }
+
+ if (!flag) {
+ if (declinfo->nspace) {
+ CScopeSave save;
+ CScope_SetNameSpaceScope(declinfo->nspace, &save);
+ CInit_InitializeData(obj);
+ CScope_RestoreScope(&save);
+
+ if (declinfo->x3C && obj->nspace->theclass && (TYPE_CLASS(obj->nspace->theclass)->flags & CLASS_IS_TEMPL_INST))
+ declinfo->x3C = 0;
+ } else {
+ CInit_InitializeData(obj);
+ }
+
+ if (declinfo->file->recordbrowseinfo && obj->sclass != TK_EXTERN)
+ CBrowse_NewData(obj, declinfo->file, declinfo->file2, declinfo->sourceoffset, CPrep_BrowserFileOffset());
+ } else if (tk == '=') {
+ tk = lex();
+ expr = CExpr_IntegralConstOrDepExpr();
+ if (IS_TYPE_TEMPLATE(obj->type) || !ENODE_IS(expr, EINTCONST)) {
+ CError_ASSERT(2426, nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL));
+ CTemplClass_RegisterObjectInit(TEMPL_CLASS(nspace->theclass), obj, expr);
+ } else if ((obj->qual & Q_CONST) && IS_TYPE_INT_OR_ENUM(obj->type)) {
+ obj->u.data.u.intconst = expr->data.intval;
+ obj->qual |= Q_INLINE_DATA | Q_20000;
+ } else {
+ CError_Error(CErrorStr354, obj->name->name);
+ }
+ }
+}
+
+Boolean CDecl_FunctionDeclarator(DeclInfo *declinfo, NameSpace *nspace, Boolean flag, Boolean flag2) {
+ Object *obj;
+ Boolean pflag;
+
+ obj = CDecl_GetFunctionObject(declinfo, nspace, &pflag, 0);
+ if (obj) {
+ if (declinfo->x44 || tk == '{' || tk == TK_TRY || (declinfo->x4B && tk == ':') || (!copts.cplusplus && isdeclaration(0, 0, 0, 0))) {
+ if (!flag || cscope_currentfunc) {
+ CError_Error(CErrorStr127);
+ if (cscope_currentfunc)
+ return 0;
+ }
+
+ if (obj->nspace == cscope_root && !strcmp(obj->name->name, "main")) {
+ if (obj->sclass == TK_STATIC || (copts.ANSIstrict && TYPE_FUNC(obj->type)->functype != (Type *) &stsignedint))
+ CError_Error(CErrorStr334);
+ } else if (copts.checkprotos && (pflag || declinfo->x64)) {
+ if (obj->sclass != TK_STATIC && !(obj->qual & Q_INLINE) && !obj->nspace->is_unnamed)
+ CError_Warning(CErrorStr178);
+ }
+
+ CFunc_ParseFuncDef(obj, declinfo, NULL, 0, 0, NULL);
+ if (declinfo->file->recordbrowseinfo)
+ CBrowse_NewFunction(
+ obj,
+ declinfo->file,
+ declinfo->file2,
+ declinfo->sourceoffset,
+ CPrep_BrowserFileOffset());
+
+ if (copts.cplusplus && lookahead() == ';')
+ tk = lex();
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void CDecl_ParseSpecialMember(DeclInfo *declinfo, Boolean flag) {
+ Object *r28;
+ NameSpace *r25;
+
+ if (!(r28 = declinfo->x10)) {
+ CError_ASSERT(2544, declinfo->x14);
+ r28 = OBJECT(declinfo->x14->object);
+ CError_ASSERT(2546, r28->otype == OT_OBJECT);
+ }
+
+ if (!r28->nspace->theclass) {
+ CError_Error(CErrorStr121);
+ return;
+ }
+
+ if (IS_TYPE_FUNC(r28->type)) {
+ if (TYPE_FUNC(r28->type)->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR)) {
+ if (r28->nspace->theclass->sominfo)
+ declinfo->thetype = TYPE(&stvoid);
+ else
+ declinfo->thetype = TYPE(&void_ptr);
+ declinfo->nspace = r28->nspace;
+ declinfo->name = r28->name;
+ if (TYPE_FUNC(r28->type)->flags & FUNC_IS_CTOR)
+ declinfo->x4B = 1;
+
+ if ((tk = lex()) == '(') {
+ tk = lex();
+
+ r25 = cscope_current;
+ cscope_current = r28->nspace;
+ CDecl_ParseDirectFuncDecl(declinfo);
+ cscope_current = r25;
+
+ if (IS_TYPE_FUNC(declinfo->thetype)) {
+ if (TYPE_FUNC(r28->type)->flags & FUNC_IS_CTOR) {
+ if ((r28->nspace->theclass->flags & CLASS_HAS_VBASES) && !r28->nspace->theclass->sominfo)
+ CDecl_AddArgument(TYPE_FUNC(declinfo->thetype), TYPE(&stsignedshort));
+ } else {
+ if (!r28->nspace->theclass->sominfo)
+ CDecl_AddArgument(TYPE_FUNC(declinfo->thetype), TYPE(&stsignedshort));
+ }
+ if (flag)
+ CDecl_FunctionDeclarator(declinfo, NULL, 1, 1);
+ } else {
+ CError_Error(CErrorStr121);
+ }
+ } else {
+ CError_Error(CErrorStr114);
+ }
+ return;
+ } else if (TYPE_FUNC(r28->type)->flags & FUNC_CONVERSION) {
+ CError_FATAL(2603);
+
+ declinfo->thetype = TYPE_FUNC(r28->type)->functype;
+ declinfo->qual |= TYPE_FUNC(r28->type)->qual;
+ declinfo->nspace = r28->nspace;
+ declinfo->name = r28->name;
+
+ if ((tk = lex()) == '(') {
+ tk = lex();
+ CDecl_ParseDirectFuncDecl(declinfo);
+ if (IS_TYPE_FUNC(declinfo->thetype)) {
+ TYPE_FUNC(declinfo->thetype)->flags |= FUNC_CONVERSION;
+ if (flag)
+ CDecl_FunctionDeclarator(declinfo, NULL, 1, 1);
+ } else {
+ CError_Error(CErrorStr121);
+ }
+ } else {
+ CError_Error(CErrorStr114);
+ }
+ return;
+ } else {
+ declinfo->thetype = TYPE(&stsignedint);
+ declinfo->nspace = r28->nspace;
+ declinfo->name = r28->name;
+
+ if ((tk = lex()) == '(') {
+ tk = lex();
+
+ r25 = cscope_current;
+ cscope_current = r28->nspace;
+ CDecl_ParseDirectFuncDecl(declinfo);
+ cscope_current = r25;
+
+ if (IS_TYPE_FUNC(declinfo->thetype)) {
+ if (flag)
+ CDecl_FunctionDeclarator(declinfo, NULL, 1, 1);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr114);
+ }
+ }
+ }
+
+ CError_Error(CErrorStr121);
+}
+
+void CDecl_ScanDeclarator(DeclInfo *declinfo) {
+ if (declinfo->x14 || declinfo->x10) {
+ CDecl_ParseSpecialMember(declinfo, 0);
+ CDecl_GetFunctionObject(declinfo, NULL, NULL, 1);
+ return;
+ }
+
+ if (IS_TYPE_FUNC(declinfo->thetype)) {
+ TypeFunc *copy = galloc(sizeof(TypeFunc));
+ *copy = *TYPE_FUNC(declinfo->thetype);
+ declinfo->thetype = TYPE(copy);
+ }
+ scandeclarator(declinfo);
+ if (!declinfo->name) {
+ CError_Error(CErrorStr121);
+ return;
+ }
+
+ if (declinfo->storageclass && declinfo->storageclass != TK_EXTERN)
+ CError_Error(CErrorStr177);
+
+ if (IS_TYPE_FUNC(declinfo->thetype)) {
+ CDecl_GetFunctionObject(declinfo, NULL, NULL, 1);
+ return;
+ }
+
+ if (declinfo->x48 || declinfo->x44)
+ CError_Error(CErrorStr121);
+
+ if (declinfo->operator_token)
+ CError_Error(CErrorStr193);
+
+ if (
+ (declinfo->qual & ~(Q_ALIGNED_MASK | Q_WEAK | Q_20000 | Q_PASCAL | Q_VOLATILE | Q_CONST)) ||
+ (declinfo->storageclass == TK_TYPEDEF && (declinfo->qual & ~(Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST)))
+ )
+ CError_Error(CErrorStr176);
+}
+
+void scandeclaratorlist(DeclInfo *declinfo) {
+ CScopeSave savescope;
+ Type *r30;
+ UInt32 r29;
+ Boolean r28;
+
+ if (declinfo->x14 || declinfo->x10) {
+ CDecl_ParseSpecialMember(declinfo, 1);
+ return;
+ }
+
+ CScope_GetScope(&savescope);
+ CError_ASSERT(2707, declinfo->thetype);
+
+ r28 = 1;
+ while (1) {
+ r30 = declinfo->thetype;
+ r29 = declinfo->qual;
+ declinfo->nspace = NULL;
+ declinfo->operator_token = 0;
+ if (IS_TYPE_FUNC(r30)) {
+ declinfo->thetype = galloc(sizeof(TypeFunc));
+ *TYPE_FUNC(declinfo->thetype) = *TYPE_FUNC(r30);
+ }
+ declinfo->name = NULL;
+ scandeclarator(declinfo);
+ if (!declinfo->name) {
+ CError_Error(CErrorStr121);
+ break;
+ }
+
+ if (declinfo->storageclass != TK_TYPEDEF) {
+ if (IS_TYPE_FUNC(declinfo->thetype)) {
+ if (!CDecl_FunctionDeclarator(declinfo, NULL, r28, 1))
+ return;
+ } else {
+ CDecl_DataDeclarator(declinfo, ACCESSPUBLIC, 0);
+ }
+ } else {
+ CDecl_TypedefDeclarator(declinfo);
+ }
+
+ CScope_RestoreScope(&savescope);
+ declinfo->thetype = r30;
+ declinfo->qual = r29;
+
+ if (tk != ',')
+ break;
+ tk = lex();
+ r28 = 0;
+ }
+
+ if (tk != ';')
+ CError_Error(CErrorStr123);
+}
+
+static TypeIntegral *CDecl_FindSignedType(short size) {
+ if (stsignedchar.size == size)
+ return &stsignedchar;
+ if (stsignedshort.size == size)
+ return &stsignedshort;
+ if (stsignedint.size == size)
+ return &stsignedint;
+ if (stsignedlong.size == size)
+ return &stsignedlong;
+ if (copts.longlong && copts.longlong_enums && stsignedlonglong.size == size)
+ return &stsignedlonglong;
+ return &stsignedlong;
+}
+
+static TypeIntegral *CDecl_FindUnsignedType(short size) {
+ if (stunsignedchar.size == size)
+ return &stunsignedchar;
+ if (stunsignedshort.size == size)
+ return &stunsignedshort;
+ if (stunsignedint.size == size)
+ return &stunsignedint;
+ if (stunsignedlong.size == size)
+ return &stunsignedlong;
+ if (copts.longlong && copts.longlong_enums && stunsignedlonglong.size == size)
+ return &stunsignedlonglong;
+ return &stunsignedlong;
+}
+
+static TypeIntegral *CDecl_IterateIntegralEnumType(int *t) {
+ switch (*t) {
+ case 0:
+ *t = 1;
+ return &stsignedchar;
+ case 1:
+ if (stsignedshort.size > stsignedchar.size) {
+ *t = 2;
+ return &stsignedshort;
+ }
+ case 2:
+ if (stsignedint.size > stsignedshort.size) {
+ *t = 3;
+ return &stsignedint;
+ }
+ case 3:
+ if (stsignedlong.size > stsignedint.size) {
+ *t = 4;
+ return &stsignedlong;
+ }
+ case 4:
+ *t = 5;
+ if (stsignedlonglong.size > stsignedlong.size && copts.longlong && copts.longlong_enums)
+ return &stsignedlonglong;
+ default:
+ return NULL;
+ }
+}
+
+static TypeIntegral *CDecl_IterateUIntegralEnumType(int *t) {
+ switch (*t) {
+ case 0:
+ *t = 1;
+ return &stunsignedchar;
+ case 1:
+ if (stunsignedshort.size > stunsignedchar.size) {
+ *t = 2;
+ return &stunsignedshort;
+ }
+ case 2:
+ if (stunsignedint.size > stunsignedshort.size) {
+ *t = 3;
+ return &stunsignedint;
+ }
+ case 3:
+ if (stunsignedlong.size > stunsignedint.size) {
+ *t = 4;
+ return &stunsignedlong;
+ }
+ case 4:
+ *t = 5;
+ if (stunsignedlonglong.size > stunsignedlong.size && copts.longlong && copts.longlong_enums)
+ return &stunsignedlonglong;
+ default:
+ return NULL;
+ }
+}
+
+static TypeEnum *CDecl_OldParseEnumList(TypeEnum *tenum, HashNameNode *name) {
+ AccessType access;
+ Boolean has_template_value;
+ Boolean r24;
+ Boolean r23;
+ ObjEnumConst *oec;
+ ObjEnumConst *last;
+ Boolean overflowed;
+ CInt64 val;
+ CInt64 minimum;
+ CInt64 maximum;
+ CInt64 var_74;
+ CInt64 unused;
+ Type *basetype;
+ Type *basetype2;
+ CPrepFileInfo *fileinfo;
+ SInt32 offset;
+ ENode *expr;
+ Type *tmp;
+
+ if (!tenum) {
+ tenum = galloc(sizeof(TypeEnum));
+ memclrw(tenum, sizeof(TypeEnum));
+ tenum->type = TYPEENUM;
+ tenum->nspace = cscope_current;
+
+ if (name) {
+ tenum->enumname = name;
+ CScope_DefineTypeTag(cscope_current, name, TYPE(tenum));
+ }
+
+ if (!cscope_current->is_global) {
+ do {
+ tenum->nspace = tenum->nspace->parent;
+ } while (!tenum->nspace->is_global);
+ if (tenum->enumname)
+ tenum->enumname = CParser_AppendUniqueNameFile(tenum->enumname->name);
+ }
+ }
+
+ if (cscope_current->theclass && (cscope_current->theclass->flags & CLASS_IS_TEMPL)) {
+ CTemplClass_RegisterEnumType(TEMPL_CLASS(cscope_current->theclass), tenum);
+ }
+
+ access = cscope_current->theclass ? global_access : ACCESSPUBLIC;
+ last = NULL;
+ unused = cint64_zero;
+ val = cint64_zero;
+ minimum = cint64_zero;
+ maximum = cint64_zero;
+ r23 = 0;
+ if (copts.enumsalwaysint) {
+ basetype = TYPE(&stsignedint);
+ r24 = 1;
+ } else {
+ basetype = TYPE(&stunsignedchar);
+ r24 = 0;
+ }
+
+ tk = lex();
+ if (!copts.cplusplus || tk != '}') {
+ do {
+ if (tk != TK_IDENTIFIER) {
+ if (tk == '}') {
+ if (copts.cpp_extensions)
+ break;
+ if (!copts.warn_extracomma)
+ break;
+ }
+ CError_Warning(CErrorStr107);
+ break;
+ }
+
+ oec = galloc(sizeof(ObjEnumConst));
+ memclrw(oec, sizeof(ObjEnumConst));
+ oec->otype = OT_ENUMCONST;
+ oec->access = access;
+ oec->type = TYPE(tenum);
+ oec->name = tkidentifier;
+ CPrep_BrowserFilePosition(&fileinfo, &offset);
+ overflowed = 0;
+ if ((tk = lex()) == '=') {
+ tk = lex();
+ val = CExpr_IntegralConstExprType(&basetype2);
+ if (!CInt64_IsNegative(&val) || is_unsigned(basetype2)) {
+ if (CInt64_GreaterU(val, minimum)) {
+ minimum = val;
+ overflowed = 1;
+ }
+ } else {
+ if (CInt64_Less(val, maximum)) {
+ maximum = val;
+ overflowed = 1;
+ }
+ if (!r24) {
+ basetype = TYPE(&stsignedchar);
+ r24 = 1;
+ }
+ }
+ r23 = 0;
+ } else {
+ if (r23)
+ CError_Error(CErrorStr154);
+
+ if (!r24 || !CInt64_IsNegative(&val)) {
+ if (CInt64_GreaterU(val, minimum)) {
+ minimum = val;
+ overflowed = 1;
+ }
+ } else {
+ if (CInt64_Less(val, maximum)) {
+ maximum = val;
+ overflowed = 1;
+ }
+ }
+ }
+
+ if (copts.enumsalwaysint) {
+ if (copts.ANSIstrict) {
+ if (!CInt64_IsInRange(val, stsignedint.size))
+ CError_Error(CErrorStr154);
+ } else {
+ if (!CInt64_IsInRange(val, stsignedint.size) && !CInt64_IsInURange(val, stunsignedint.size))
+ CError_Error(CErrorStr154);
+ }
+ } else if (r24) {
+ switch (basetype->size) {
+ case 1:
+ if (CInt64_IsInRange(minimum, 1) && CInt64_IsInRange(maximum, 1))
+ break;
+ basetype = TYPE(CDecl_FindSignedType(2));
+ case 2:
+ if (CInt64_IsInRange(minimum, 2) && CInt64_IsInRange(maximum, 2))
+ break;
+ basetype = TYPE(CDecl_FindSignedType(4));
+ case 4:
+ if (CInt64_IsInRange(minimum, 4) && CInt64_IsInRange(maximum, 4))
+ break;
+ basetype = TYPE(CDecl_FindSignedType(8));
+ if (basetype->size != 8) {
+ if (!copts.ANSIstrict && CInt64_IsInRange(maximum, 4) && CInt64_IsInURange(minimum, 4))
+ break;
+ if (overflowed)
+ CError_Error(CErrorStr154);
+ break;
+ }
+ case 8:
+ if (CInt64_Equal(val, minimum) && CInt64_IsNegative(&val))
+ CError_Error(CErrorStr154);
+ break;
+ default:
+ CError_FATAL(3071);
+ }
+ } else {
+ switch (basetype->size) {
+ case 1:
+ if (CInt64_IsInURange(minimum, 1))
+ break;
+ basetype = TYPE(CDecl_FindUnsignedType(2));
+ case 2:
+ if (CInt64_IsInURange(minimum, 2))
+ break;
+ basetype = TYPE(CDecl_FindUnsignedType(4));
+ case 4:
+ if (CInt64_IsInURange(minimum, 4))
+ break;
+ basetype = TYPE(CDecl_FindUnsignedType(8));
+ if (basetype->size != 8) {
+ if (overflowed)
+ CError_Error(CErrorStr154);
+ break;
+ }
+ case 8:
+ break;
+ default:
+ CError_FATAL(3099);
+ }
+ }
+
+ tenum->size = basetype->size;
+ tenum->enumtype = basetype;
+ oec->val = val;
+ CScope_AddObject(cscope_current, oec->name, OBJ_BASE(oec));
+
+ if (last) {
+ last->next = oec;
+ last = oec;
+ } else {
+ last = oec;
+ tenum->enumlist = oec;
+ }
+
+ if (cparamblkptr->browseoptions.recordEnums) {
+ CPrepFileInfo *f = CPrep_BrowserCurrentFile();
+ if (f->recordbrowseinfo) {
+ CBrowse_NewEnumConstant(cscope_current, oec->name, f, fileinfo, offset, CPrep_BrowserFileOffset());
+ }
+ }
+
+ var_74 = CInt64_Add(val, cint64_one);
+ if (r24) {
+ if (CInt64_IsNegative(&var_74) && !CInt64_IsNegative(&val))
+ r23 = 1;
+ } else {
+ if (CInt64_IsZero(&var_74))
+ r23 = 1;
+ }
+ val = var_74;
+
+ if (tk != ',')
+ break;
+ tk = lex();
+ } while (1);
+ }
+
+ tenum->size = basetype->size;
+ tenum->enumtype = basetype;
+
+ for (oec = tenum->enumlist; oec; oec = oec->next)
+ oec->type = TYPE(tenum);
+
+ if (tk != '}')
+ CError_ErrorSkip(CErrorStr130);
+ else
+ tk = lex();
+
+ return tenum;
+}
+
+static Type *CDecl_MaxType(Type *a, Type *b) {
+ if (a->size > b->size)
+ return a;
+ if (b->size > a->size)
+ return b;
+ if (is_unsigned(b))
+ return b;
+ else
+ return a;
+}
+
+void CDecl_ComputeUnderlyingEnumType(TypeEnum *tenum) {
+ ObjEnumConst *oec;
+ ObjEnumConst *oec2;
+ Type *r26;
+ int t;
+
+ if (!copts.enumsalwaysint) {
+ for (oec2 = tenum->enumlist; oec2; oec2 = oec2->next) {
+ if (CInt64_IsNegative(&oec2->val) && !is_unsigned(oec2->type))
+ break;
+ }
+
+ if (oec2) {
+ CInt64 unused = cint64_zero;
+ CInt64 minimum = cint64_zero;
+ CInt64 maximum = cint64_zero;
+ for (oec = tenum->enumlist; oec; oec = oec->next) {
+ if (CInt64_IsNegative(&oec->val) && !is_unsigned(oec->type)) {
+ if (CInt64_Less(oec->val, minimum))
+ minimum = oec->val;
+ } else {
+ if (CInt64_GreaterU(oec->val, maximum))
+ maximum = oec->val;
+ }
+ }
+
+ if (CInt64_IsNegative(&maximum))
+ CError_Error(CErrorStr154);
+
+ t = 0;
+ do {
+ r26 = TYPE(CDecl_IterateIntegralEnumType(&t));
+ if (!r26) {
+ r26 = TYPE(&stsignedlong);
+ CError_Error(CErrorStr154);
+ break;
+ }
+
+ if (CInt64_IsInRange(maximum, r26->size) && CInt64_IsInRange(minimum, r26->size))
+ break;
+ if (r26->size == stsignedlong.size && !copts.ANSIstrict && CInt64_IsInRange(minimum, r26->size) && CInt64_IsInURange(maximum, r26->size))
+ break;
+ } while (1);
+ } else {
+ CInt64 val = cint64_zero;
+
+ for (oec = tenum->enumlist; oec; oec = oec->next) {
+ if (CInt64_GreaterU(oec->val, val))
+ val = oec->val;
+ }
+
+ t = 0;
+ do {
+ r26 = TYPE(CDecl_IterateUIntegralEnumType(&t));
+ if (!r26) {
+ r26 = TYPE(&stunsignedlong);
+ CError_Error(CErrorStr154);
+ break;
+ }
+ if (CInt64_IsInURange(val, r26->size))
+ break;
+ } while (1);
+ }
+ } else {
+ r26 = TYPE(&stsignedint);
+ }
+
+ tenum->size = r26->size;
+ tenum->enumtype = r26;
+ for (oec = tenum->enumlist; oec; oec = oec->next)
+ oec->type = TYPE(tenum);
+}
+
+static Type *CDecl_FindUnderlyingType(short size, CInt64 *a, CInt64 *b) {
+ if (CInt64_IsZero(a)) {
+ if (size <= stsignedchar.size && CInt64_IsInURange(*b, stunsignedchar.size))
+ return TYPE(&stunsignedchar);
+ if (size <= stsignedshort.size && CInt64_IsInURange(*b, stunsignedshort.size))
+ return TYPE(&stunsignedshort);
+ if (size <= stsignedint.size && CInt64_IsInURange(*b, stunsignedint.size))
+ return TYPE(&stunsignedint);
+ if (size <= stsignedlong.size && CInt64_IsInURange(*b, stunsignedlong.size))
+ return TYPE(&stunsignedlong);
+ if (size <= stsignedlonglong.size && copts.longlong && copts.longlong_enums && CInt64_IsInURange(*b, stunsignedlonglong.size))
+ return TYPE(&stunsignedlonglong);
+ } else {
+ if (size <= stsignedchar.size && CInt64_IsInRange(*a, stsignedchar.size) && CInt64_IsInRange(*b, stsignedchar.size))
+ return TYPE(&stsignedchar);
+ if (size <= stsignedshort.size && CInt64_IsInRange(*a, stsignedshort.size) && CInt64_IsInRange(*b, stsignedshort.size))
+ return TYPE(&stsignedshort);
+ if (size <= stsignedint.size && CInt64_IsInRange(*a, stsignedint.size) && CInt64_IsInRange(*b, stsignedint.size))
+ return TYPE(&stsignedint);
+ if (size <= stsignedlong.size && CInt64_IsInRange(*a, stsignedlong.size) && CInt64_IsInRange(*b, stsignedlong.size))
+ return TYPE(&stsignedlong);
+ if (size <= stsignedlonglong.size && copts.longlong && copts.longlong_enums && CInt64_IsInRange(*a, stsignedlonglong.size) && CInt64_IsInRange(*b, stsignedlonglong.size))
+ return TYPE(&stsignedlonglong);
+ if (!copts.ANSIstrict && size <= stsignedlong.size && CInt64_IsInRange(*a, stsignedlong.size) && CInt64_IsInURange(*b, stunsignedlong.size))
+ return TYPE(&stsignedlong);
+ }
+
+ return NULL;
+}
+
+static TypeEnum *CDecl_ParseEnumList(TypeEnum *tenum, HashNameNode *name) {
+ AccessType access;
+ TemplClass *tmclass;
+ ObjEnumConst *oec;
+ Boolean has_template_value;
+ Boolean overflowed;
+ Boolean is_first;
+ CInt64 val;
+ CInt64 minimum;
+ CInt64 maximum;
+ CInt64 unused;
+ Type *basetype;
+ CPrepFileInfo *fileinfo;
+ SInt32 offset;
+ ENode *expr;
+ Type *tmp;
+ ObjEnumConst *last;
+
+ if (!tenum) {
+ tenum = galloc(sizeof(TypeEnum));
+ memclrw(tenum, sizeof(TypeEnum));
+ tenum->type = TYPEENUM;
+ tenum->nspace = cscope_current;
+
+ if (name) {
+ tenum->enumname = name;
+ CScope_DefineTypeTag(cscope_current, name, TYPE(tenum));
+ }
+
+ if (!cscope_current->is_global) {
+ do {
+ tenum->nspace = tenum->nspace->parent;
+ } while (!tenum->nspace->is_global);
+ if (tenum->enumname)
+ tenum->enumname = CParser_AppendUniqueNameFile(tenum->enumname->name);
+ }
+ }
+
+ if (cscope_current->theclass && (cscope_current->theclass->flags & CLASS_IS_TEMPL)) {
+ tmclass = TEMPL_CLASS(cscope_current->theclass);
+ CTemplClass_RegisterEnumType(tmclass, tenum);
+ } else {
+ tmclass = NULL;
+ }
+
+ access = cscope_current->theclass ? global_access : ACCESSPUBLIC;
+ last = NULL;
+ is_first = 1;
+ has_template_value = 0;
+ unused = cint64_zero;
+ val = cint64_zero;
+ minimum = cint64_zero;
+ maximum = cint64_zero;
+ basetype = copts.enumsalwaysint ? TYPE(&stsignedint) : TYPE(&stsignedchar);
+ tenum->size = basetype->size;
+ tenum->enumtype = basetype;
+
+ do {
+ if ((tk = lex()) != TK_IDENTIFIER) {
+ if (tk == '}') {
+ if (is_first) {
+ if (copts.cplusplus)
+ break;
+ } else {
+ if (!copts.warn_extracomma)
+ break;
+ if (copts.c9x)
+ break;
+ if (copts.cpp_extensions)
+ break;
+ }
+ CError_Warning(CErrorStr107);
+ } else {
+ CError_Error(CErrorStr107);
+ }
+ break;
+ }
+
+ oec = galloc(sizeof(ObjEnumConst));
+ memclrw(oec, sizeof(ObjEnumConst));
+ oec->otype = OT_ENUMCONST;
+ oec->access = access;
+ oec->name = tkidentifier;
+ CPrep_BrowserFilePosition(&fileinfo, &offset);
+ overflowed = 0;
+ if ((tk = lex()) == '=') {
+ tk = lex();
+ if (tmclass) {
+ expr = CExpr_IntegralConstOrDepExpr();
+ if (ENODE_IS(expr, EINTCONST)) {
+ val = expr->data.intval;
+ basetype = expr->rtype;
+ has_template_value = 0;
+ } else {
+ val = cint64_zero;
+ basetype = TYPE(tenum);
+ CTemplClass_RegisterEnumerator(tmclass, oec, expr);
+ has_template_value = 1;
+ }
+ } else {
+ val = CExpr_IntegralConstExprType(&basetype);
+ has_template_value = 0;
+ }
+ } else if (has_template_value) {
+ CTemplClass_RegisterEnumerator(tmclass, oec, NULL);
+ } else if (!is_first) {
+ if (is_unsigned(basetype)) {
+ val = CInt64_Add(val, cint64_one);
+ if (CInt64_IsZero(&val))
+ overflowed = 1;
+ } else if (!CInt64_IsNegative(&val)) {
+ val = CInt64_Add(val, cint64_one);
+ if (CInt64_IsNegative(&val))
+ overflowed = 1;
+ } else {
+ val = CInt64_Add(val, cint64_one);
+ }
+ }
+
+ if (!has_template_value) {
+ if (copts.enumsalwaysint) {
+ if (!CInt64_IsInRange(val, stsignedint.size) && (copts.ANSIstrict || !CInt64_IsInURange(val, stunsignedint.size)))
+ overflowed = 1;
+ basetype = TYPE(&stsignedint);
+ } else if (CInt64_IsNegative(&val) && !is_unsigned(basetype)) {
+ if (CInt64_Less(val, minimum)) {
+ minimum = val;
+ if ((tmp = CDecl_FindUnderlyingType(tenum->size, &minimum, &maximum))) {
+ tenum->size = tmp->size;
+ tenum->enumtype = tmp;
+ } else {
+ overflowed = 1;
+ }
+ }
+ } else {
+ if (CInt64_GreaterU(val, maximum)) {
+ maximum = val;
+ if ((tmp = CDecl_FindUnderlyingType(tenum->size, &minimum, &maximum))) {
+ tenum->size = tmp->size;
+ tenum->enumtype = tmp;
+ } else {
+ overflowed = 1;
+ }
+ }
+ }
+ }
+
+ if (overflowed)
+ CError_Error(CErrorStr154);
+
+ oec->val = val;
+ oec->type = basetype;
+ CScope_AddObject(cscope_current, oec->name, OBJ_BASE(oec));
+
+ if (last) {
+ last->next = oec;
+ last = oec;
+ } else {
+ last = oec;
+ tenum->enumlist = oec;
+ }
+
+ if (cparamblkptr->browseoptions.recordEnums) {
+ CPrepFileInfo *f = CPrep_BrowserCurrentFile();
+ if (f->recordbrowseinfo) {
+ CBrowse_NewEnumConstant(cscope_current, oec->name, f, fileinfo, offset, CPrep_BrowserFileOffset());
+ }
+ }
+
+ is_first = 0;
+ } while (tk == ',');
+
+ for (oec = tenum->enumlist; oec; oec = oec->next)
+ oec->type = TYPE(tenum);
+
+ if (tk != '}')
+ CError_ErrorSkip(CErrorStr130);
+ else
+ tk = lex();
+
+ return tenum;
+}
+
+void scanenum(DeclInfo *declinfo) {
+ HashNameNode *name;
+ Type *type;
+ NameResult pr;
+
+ if (tk == '{') {
+ declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, NULL));
+ TYPE_ENUM(declinfo->thetype)->enumname = CParser_AppendUniqueNameFile("@enum");
+ return;
+ }
+
+ if (tk == TK_IDENTIFIER) {
+ name = tkidentifier;
+ if (lookahead() == '{') {
+ type = CScope_GetLocalTagType(cscope_current, name);
+ if (type) {
+ lex();
+ do_shit:
+ if (type->size || !IS_TYPE_ENUM(type)) {
+ CError_Error(CErrorStr122, name->name);
+ declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, NULL));
+ return;
+ }
+ declinfo->thetype = TYPE(CDecl_ParseEnumList(TYPE_ENUM(type), NULL));
+ } else {
+ lex();
+ declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, name));
+ }
+
+ if (cparamblkptr->browseoptions.recordEnums && declinfo->file->recordbrowseinfo)
+ CBrowse_NewEnum(
+ cscope_current,
+ TYPE_ENUM(declinfo->thetype)->enumname,
+ declinfo->file,
+ declinfo->file2,
+ declinfo->sourceoffset,
+ CPrep_BrowserFileOffset());
+ return;
+ } else {
+ CError_ASSERT(3851, !copts.cplusplus || tk != ';');
+ tkidentifier = name;
+ }
+ }
+
+ if (CScope_ParseElaborateName(&pr)) {
+ if ((type = pr.type)) {
+ if (!IS_TYPE_ENUM(type))
+ CError_Error(CErrorStr121);
+ if ((tk = lex()) == '{')
+ goto do_shit;
+ declinfo->thetype = type;
+ return;
+ } else {
+ CError_ASSERT(3865, pr.name_4);
+ if ((tk = lex()) == '{') {
+ declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, pr.name_4));
+ return;
+ } else {
+ CError_Error(CErrorStr140, pr.name_4->name);
+ }
+ }
+ } else {
+ CError_Error(CErrorStr121);
+ }
+
+ declinfo->thetype = TYPE(&stsignedint);
+}
+
+void CDecl_ScanStructDeclarator(BigDeclInfo *bde) {
+ ENode *expr;
+ short val;
+ short bits;
+ Boolean is_bitfield;
+ TypeTemplDep *ttempl;
+ TypeBitfield *tbitfield;
+ Type *type;
+
+ bde->declinfo2 = bde->declinfo;
+ bde->declinfo2.name = NULL;
+ bde->declinfo2.operator_token = 0;
+ bde->xCD = 0;
+ is_bitfield = 0;
+
+ if (tk == ':') {
+ bde->declinfo2.name = no_name_node;
+ is_bitfield = 1;
+ } else {
+ bde->declinfo2.x50 = 1;
+ scandeclarator(&bde->declinfo2);
+ if (!bde->declinfo2.name) {
+ CError_Error(CErrorStr131);
+ return;
+ }
+
+ if ((!copts.ANSIstrict || copts.c9x) && !bde->declinfo2.thetype->size && IS_TYPE_ARRAY(bde->declinfo2.thetype)) {
+ if (bde->declinfo2.storageclass != TK_STATIC && bde->declinfo2.storageclass != TK_TYPEDEF) {
+ type = TYPE_POINTER(bde->declinfo2.thetype)->target;
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+ if (!IsCompleteType(type))
+ return;
+ if (tk != ';' || lookahead() != '}') {
+ CError_Error(CErrorStr145);
+ return;
+ }
+ }
+ } else {
+ if (bde->declinfo2.storageclass != TK_STATIC && bde->declinfo2.storageclass != TK_TYPEDEF) {
+ if (!IS_TYPE_FUNC(bde->declinfo2.thetype) && !IsCompleteType(bde->declinfo2.thetype))
+ return;
+ }
+ }
+
+ if (IS_TYPE_CLASS(bde->declinfo2.thetype) && TYPE_CLASS(bde->declinfo2.thetype)->sominfo) {
+ CError_Error(CErrorStr287);
+ return;
+ }
+
+ if (tk != ':')
+ goto not_a_bitfield;
+ }
+
+ if (!IS_TYPE_INT_OR_ENUM(bde->declinfo2.thetype)) {
+ if (CTemplTool_IsTemplateArgumentDependentType(bde->declinfo2.thetype))
+ goto fuckup;
+ CError_Error(CErrorStr138);
+ bde->declinfo2.thetype = TYPE(&stunsignedint);
+ } else if (copts.ANSIstrict && !copts.cplusplus) {
+ if (bde->declinfo2.thetype != TYPE(&stsignedint) && bde->declinfo2.thetype != TYPE(&stunsignedint)) {
+ CError_Error(CErrorStr138);
+ bde->declinfo2.thetype = TYPE(&stunsignedint);
+ }
+ }
+
+ switch (bde->declinfo2.thetype->size) {
+ case 1:
+ bits = 8;
+ break;
+ case 2:
+ bits = 16;
+ break;
+ case 4:
+ bits = 32;
+ break;
+ default:
+ CError_Error(CErrorStr138);
+ return;
+ }
+fuckup:
+ tk = lex();
+ expr = CExpr_IntegralConstOrDepExpr();
+ if (!ENODE_IS(expr, EINTCONST)) {
+ ttempl = TYPE_TEMPLATE(CDecl_NewTemplDepType(TEMPLDEP_BITFIELD));
+ ttempl->u.bitfield.type = bde->declinfo2.thetype;
+ ttempl->u.bitfield.size = CInline_CopyExpression(expr, CopyMode1);
+ bde->declinfo2.thetype = TYPE(ttempl);
+ bde->xCD = 1;
+ return;
+ }
+ val = CInt64_GetULong(&expr->data.intval);
+ if (is_bitfield) {
+ if (val < 0 || val > bits) {
+ CError_Error(CErrorStr138);
+ return;
+ }
+ } else {
+ if (val <= 0 || val > bits) {
+ CError_Error(CErrorStr138);
+ return;
+ }
+ }
+
+ tbitfield = galloc(sizeof(TypeBitfield));
+ memclrw(tbitfield, sizeof(TypeBitfield));
+ tbitfield->type = TYPEBITFIELD;
+ tbitfield->size = bde->declinfo2.thetype->size;
+ tbitfield->bitfieldtype = bde->declinfo2.thetype;
+ tbitfield->bitlength = val;
+ bde->declinfo2.thetype = TYPE(tbitfield);
+
+ if (tk == TK_UU_ATTRIBUTE_UU)
+ CParser_ParseAttribute(NULL, &bde->declinfo2);
+
+not_a_bitfield:
+ bde->xCD = 1;
+}
+
+static void CDecl_LayoutStruct(TypeStruct *tstruct) {
+ StructMember *member;
+ SInt32 r28;
+ StructMember *innermember;
+ SInt32 innerbase;
+ StructMember *newmember;
+ StructMember **memberp;
+ TypeBitfield *bf;
+ SInt32 r24;
+ Boolean r23;
+ SInt32 tmp;
+
+ r28 = 0;
+ r23 = 0;
+ CMach_StructLayoutInitOffset(0);
+ for (member = tstruct->members; member; member = member->next) {
+ if (tstruct->stype == STRUCT_TYPE_UNION)
+ CMach_StructLayoutInitOffset(0);
+
+ if (IS_TYPE_BITFIELD(member->type))
+ member->offset = CMach_StructLayoutBitfield(TYPE_BITFIELD(member->type), member->qual);
+ else
+ member->offset = CMach_StructLayoutGetOffset(member->type, member->qual);
+
+ if (tstruct->stype == STRUCT_TYPE_UNION) {
+ tmp = CMach_StructLayoutGetCurSize();
+ if (tmp > r28)
+ r28 = tmp;
+ }
+
+ if (member->name == no_name_node)
+ r23 = 1;
+
+ if (!member->name) {
+ CError_ASSERT(4064, IS_TYPE_STRUCT(member->type));
+ innerbase = member->offset;
+ innermember = TYPE_STRUCT(member->type)->members;
+ r23 = 1;
+ while (innermember) {
+ if (ismember(tstruct, innermember->name))
+ CError_Error(CErrorStr133, innermember->name->name);
+ if (r23) {
+ member->type = innermember->type;
+ member->name = innermember->name;
+ member->qual = innermember->qual;
+ member->offset = innerbase + innermember->offset;
+ } else {
+ newmember = galloc(sizeof(StructMember));
+ memclrw(newmember, sizeof(StructMember));
+ newmember->next = member->next;
+ newmember->type = innermember->type;
+ newmember->name = innermember->name;
+ newmember->qual = innermember->qual | Q_WEAK;
+ newmember->offset = innerbase + innermember->offset;
+ member->next = newmember;
+ member = newmember;
+ }
+ if (copts.reverse_bitfields && IS_TYPE_BITFIELD(member->type)) {
+ bf = galloc(sizeof(TypeBitfield));
+ *bf = *TYPE_BITFIELD(member->type);
+ CABI_ReverseBitField(bf);
+ member->type = TYPE(bf);
+ }
+ r23 = 0;
+ innermember = innermember->next;
+ }
+ r23 = 1;
+ }
+ }
+
+ if (r23) {
+ memberp = &tstruct->members;
+ while (*memberp) {
+ if ((*memberp)->name == no_name_node || !(*memberp)->name)
+ *memberp = (*memberp)->next;
+ else
+ memberp = &(*memberp)->next;
+ }
+ }
+
+ if (tstruct->stype == STRUCT_TYPE_UNION)
+ r24 = r28;
+ else
+ r24 = CMach_StructLayoutGetCurSize();
+ tstruct->size = r24;
+ tstruct->align = CMach_GetStructAlign(tstruct);
+ tstruct->size = r24 + CABI_StructSizeAlignValue(TYPE(tstruct), r24);
+
+ if (copts.reverse_bitfields) {
+ for (member = tstruct->members; member; member = member->next) {
+ if (IS_TYPE_BITFIELD(member->type))
+ CABI_ReverseBitField(TYPE_BITFIELD(member->type));
+ }
+ }
+
+ if (copts.warn_padding && tstruct->stype != STRUCT_TYPE_UNION) {
+ StructMember *prev;
+
+ member = tstruct->members;
+ prev = NULL;
+ while (member) {
+ if (prev && (prev->offset + prev->type->size) < member->offset) {
+ CError_Warning(CErrorStr350, member->offset - (prev->offset + prev->type->size), prev->name->name);
+ }
+ prev = member;
+ member = member->next;
+ }
+
+ if (prev && (prev->offset + prev->type->size) < tstruct->size) {
+ CError_Warning(CErrorStr350, tstruct->size - (prev->offset + prev->type->size), prev->name->name);
+ }
+ }
+}
+
+static SInt32 scanstructdeclarationlist(TypeStruct *tstruct, Boolean flag) {
+ SInt32 offset;
+ StructMember *member;
+ BigDeclInfo bde;
+
+ offset = -1;
+ memclrw(&bde, sizeof(BigDeclInfo));
+
+ if (tk == TK_AT_DEFS) {
+ CPrep_NewFileOffsetInfo(&member_fileoffset, NULL);
+ CObjC_ParseDefs(tstruct);
+ if ((tk = lex()) != '}')
+ CError_Error(CErrorStr130);
+ } else {
+ do {
+ CPrep_NewFileOffsetInfo(&member_fileoffset, NULL);
+ memclrw(&bde.declinfo, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(&bde.declinfo, 0);
+ if (bde.declinfo.storageclass || bde.declinfo.x44) {
+ CError_Error(CErrorStr131);
+ tstruct->members = NULL;
+ return -1;
+ }
+
+ if (tk != ';') {
+ while (1) {
+ CDecl_ScanStructDeclarator(&bde);
+ if (!CanCreateObject(bde.declinfo2.thetype)) {
+ CError_Error(CErrorStr131);
+ bde.xCD = 0;
+ }
+
+ if (bde.declinfo2.operator_token) {
+ CError_Error(CErrorStr131);
+ bde.xCD = 0;
+ }
+
+ if (bde.xCD) {
+ if (bde.declinfo2.name == no_name_node || !ismember(tstruct, bde.declinfo2.name)) {
+ member = galloc(sizeof(StructMember));
+ memclrw(member, sizeof(StructMember));
+ member->type = bde.declinfo2.thetype;
+ member->name = bde.declinfo2.name;
+ member->qual = bde.declinfo2.qual;
+ appendmember(tstruct, member);
+
+ if (flag) {
+ CBrowse_AddStructMember(member, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset());
+ }
+ } else {
+ CError_Error(CErrorStr133, bde.declinfo2.name->name);
+ }
+ }
+
+ if (tk != ',')
+ break;
+ tk = lex();
+ }
+ } else if (!copts.ANSIstrict && IS_TYPE_STRUCT(bde.declinfo.thetype)) {
+ member = galloc(sizeof(StructMember));
+ memclrw(member, sizeof(StructMember));
+ member->type = bde.declinfo.thetype;
+ appendmember(tstruct, member);
+ } else {
+ CError_Error(CErrorStr131);
+ }
+
+ if (tk != ';') {
+ tstruct->members = NULL;
+ CError_Error(CErrorStr123);
+ return -1;
+ }
+
+ CPrep_TokenStreamFlush();
+ } while ((tk = lex()) != '}');
+ CDecl_LayoutStruct(tstruct);
+ }
+
+ if (flag) {
+ offset = CPrep_BrowserFileOffset();
+ if (tk == ';')
+ offset++;
+ }
+
+ tk = lex();
+ return offset;
+}
+
+static TypeStruct *CDecl_DefineStruct(HashNameNode *name, short stype) {
+ TypeStruct *tstruct;
+
+ tstruct = galloc(sizeof(TypeStruct));
+ memclrw(tstruct, sizeof(TypeStruct));
+
+ tstruct->type = TYPESTRUCT;
+ tstruct->align = 1;
+ tstruct->stype = stype;
+ if (name) {
+ tstruct->name = name;
+ CScope_DefineTypeTag((in_func_arglist && !copts.cplusplus) ? cscope_root : cscope_current, name, (Type *) tstruct);
+ }
+
+ return tstruct;
+}
+
+void scanstruct(DeclInfo *declinfo, short structtype) {
+ Type *type;
+ HashNameNode *name;
+ TypeStruct typecopy;
+ Boolean add_to_browse;
+ GList gl;
+ SInt32 offset;
+
+ if (copts.cplusplus) {
+ CDecl_ParseClass(declinfo, structtype, 1, 0);
+ return;
+ }
+
+ if (tk == TK_IDENTIFIER) {
+ name = tkidentifier;
+ type = CScope_GetTagType(cscope_current, name);
+ if (type) {
+ if (IS_TYPE_CLASS(type)) {
+ CDecl_ParseClass(declinfo, structtype, 1, 0);
+ return;
+ }
+
+ tk = lex();
+ if (!CScope_GetLocalTagType(cscope_current, name) && (tk == ';' || tk == '{'))
+ type = (Type *) CDecl_DefineStruct(name, structtype);
+
+ if (!IS_TYPE_STRUCT(type) || TYPE_STRUCT(type)->stype != structtype) {
+ CError_Error(CErrorStr132, name->name);
+ declinfo->thetype = type;
+ return;
+ }
+
+ if (tk != '{') {
+ declinfo->thetype = type;
+ return;
+ }
+
+ if (type->size) {
+ CError_Error(CErrorStr132, name->name);
+ type = (Type *) CDecl_DefineStruct(NULL, structtype);
+ }
+ } else {
+ type = (Type *) CDecl_DefineStruct(name, structtype);
+ if ((tk = lex()) != '{') {
+ declinfo->thetype = type;
+ return;
+ }
+ }
+ } else if (tk != '{') {
+ CError_Error(CErrorStr131);
+ declinfo->thetype = (Type *) &stsignedint;
+ return;
+ } else {
+ type = (Type *) CDecl_DefineStruct(NULL, structtype);
+ }
+
+ if ((add_to_browse = cparamblkptr->browseoptions.recordClasses && declinfo->file->recordbrowseinfo))
+ CBrowse_BeginStruct(declinfo, TYPE_STRUCT(type), &gl);
+
+ typecopy = *TYPE_STRUCT(type);
+ tk = lex();
+ offset = scanstructdeclarationlist(&typecopy, add_to_browse);
+ *TYPE_STRUCT(type) = typecopy;
+ declinfo->thetype = type;
+
+ if (add_to_browse)
+ CBrowse_EndStruct(offset, &gl);
+}
+
+static void InlineFunctionObject(Object *obj, TypeClass *tclass) {
+ TokenStream stream;
+ CPrepFileInfo *file;
+
+ obj->qual |= Q_INLINE;
+ TYPE_FUNC(obj->type)->flags |= FUNC_DEFINED;
+
+ CPrep_StreamGetBlock(&stream, NULL, 1);
+ if (stream.tokens) {
+ if (IS_TYPEFUNC_METHOD(TYPE_FUNC(obj->type)) && (TYPE_METHOD(obj->type)->theclass->flags & CLASS_IS_TEMPL)) {
+ TYPE_FUNC(obj->type)->flags |= FUNC_IS_TEMPL_INSTANCE;
+ CTemplClass_DefineMember(TEMPL_CLASS(TYPE_METHOD(obj->type)->theclass), obj, &member_fileoffset, &stream);
+ } else {
+ CInline_AddInlineFunctionAction(obj, tclass, &member_fileoffset, &stream, 0);
+ }
+ }
+
+ file = CPrep_BrowserCurrentFile();
+ if (file->recordbrowseinfo) {
+ CBrowse_NewFunction(
+ obj, file,
+ member_fileoffset.file,
+ CPrep_BrowserTokenOffset(&member_fileoffset) + 1,
+ CPrep_BrowserFileOffset());
+ }
+
+ if (lookahead() == ';')
+ tk = lex();
+ else
+ tk = ';';
+}
+
+void CDecl_ExtractClassExportFlags(DeclInfo *declinfo, UInt8 flags) {
+ if (flags & CLASS_EFLAGS_INTERNAL)
+ declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_INTERNAL;
+ if (flags & CLASS_EFLAGS_IMPORT)
+ declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_IMPORT;
+ if (flags & CLASS_EFLAGS_EXPORT)
+ declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_EXPORT;
+}
+
+TypeMemberFunc *CDecl_MakeTypeMemberFunc(TypeFunc *tfunc, TypeClass *tclass, Boolean flag) {
+ TypeMemberFunc *method;
+
+ method = galloc(sizeof(TypeMemberFunc));
+ memclrw(method, sizeof(TypeMemberFunc));
+ *TYPE_FUNC(method) = *tfunc;
+ method->theclass = tclass;
+ method->is_static = flag;
+ method->flags |= FUNC_METHOD;
+ if (!flag)
+ CDecl_AddThisPointerArgument(TYPE_FUNC(method), tclass);
+
+ if ((flag || (tfunc->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR))) && (tfunc->flags & (FUNC_CONST | FUNC_VOLATILE)))
+ CError_Error(CErrorStr384);
+
+ return method;
+}
+
+static void CDecl_MakeFunctionVirtual(TypeClass *tclass, Object *func) {
+ if (is_pascal_object(func))
+ CError_Error(CErrorStr219);
+ if (tclass->mode == CLASS_MODE_UNION)
+ CError_Error(CErrorStr352, func);
+ func->datatype = DVFUNC;
+}
+
+static void CDecl_AddFunctionMember(ClassLayout *decle, TypeClass *tclass, DeclInfo *declinfo, AccessType access, Boolean flag1, Boolean flag2, Boolean flag3, Boolean flag4) {
+ NameSpaceObjectList *list; // r20
+ Object *obj; // also r20
+ TypeMemberFunc *tfunc; // r19
+ Boolean r31;
+ Boolean outflag;
+
+ if (IS_TYPE_ARRAY(TYPE_FUNC(declinfo->thetype)->functype) || IS_TYPE_FUNC(TYPE_FUNC(declinfo->thetype)->functype)) {
+ CError_Error(CErrorStr128);
+ TYPE_FUNC(declinfo->thetype)->functype = (Type *) &stsignedint;
+ }
+
+ if (tclass->sominfo)
+ CSOM_CheckFuncType(TYPE_FUNC(declinfo->thetype));
+
+ r31 = 0;
+ if (declinfo->qual & Q_VIRTUAL) {
+ declinfo->qual &= ~Q_VIRTUAL;
+ r31 = 1;
+ flag1 = 1;
+ }
+
+ if ((list = CScope_FindName(tclass->nspace, declinfo->name))) {
+ if (list->object->otype != OT_TYPETAG) {
+ if (list->object->otype != OT_OBJECT || !IS_TYPE_FUNC(OBJECT(list->object)->type))
+ CError_Error(CErrorStr133, declinfo->name->name);
+ } else {
+ list = NULL;
+ }
+ }
+
+ if (!IS_TYPEFUNC_METHOD(TYPE_FUNC(declinfo->thetype))) {
+ tfunc = CDecl_MakeTypeMemberFunc(TYPE_FUNC(declinfo->thetype), tclass, flag4);
+ declinfo->thetype = (Type *) tfunc;
+ } else {
+ tfunc = TYPE_METHOD(declinfo->thetype);
+ CError_ASSERT(4579, !tclass->sominfo);
+ }
+
+ CDecl_ExtractClassExportFlags(declinfo, tclass->eflags);
+
+ CError_ASSERT(4597, cscope_current == tclass->nspace);
+
+ if (list) {
+ obj = CDecl_OverloadFunctionObject(list, declinfo, &outflag, flag4 ? OverloadMode1 : OverloadMode2, 0);
+ if (!obj)
+ return;
+ if (outflag)
+ tfunc->vtbl_index = ++decle->lex_order_count;
+ else
+ CError_Error(CErrorStr133, CError_GetObjectName(obj));
+ } else {
+ tfunc->vtbl_index = ++decle->lex_order_count;
+ obj = CParser_NewFunctionObject(declinfo);
+ if ((tclass->flags & CLASS_IS_TEMPL) && CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype))
+ CTemplClass_RegisterObjectDef(TEMPL_CLASS(tclass), OBJ_BASE(obj));
+ CScope_AddObject(tclass->nspace, declinfo->name, OBJ_BASE(obj));
+ }
+
+ obj->access = access;
+ CheckDefaultArgs(TYPE_FUNC(obj->type)->args);
+
+ if (flag2) {
+ tfunc->flags |= FUNC_CONVERSION;
+ tclass->flags = tclass->flags | CLASS_IS_CONVERTIBLE;
+ }
+
+ if (r31) {
+ CDecl_MakeFunctionVirtual(tclass, obj);
+ decle->has_vtable = 1;
+ }
+
+ if ((flag1 || r31) && flag3 && (tk == '=')) {
+ if ((tk = lex()) == TK_INTCONST) {
+ if (!CInt64_IsZero(&tkintconst))
+ CError_Error(CErrorStr121);
+ tfunc->flags |= FUNC_PURE;
+ tclass->flags = tclass->flags | CLASS_ABSTRACT;
+ tk = lex();
+ } else {
+ CError_Error(CErrorStr121);
+ }
+ }
+
+ if (flag3 && ((tk == '{') || (tk == TK_TRY) || ((tk == ':') && CClass_IsConstructor(obj)))) {
+ if (declinfo->x49)
+ CError_Error(CErrorStr127);
+ InlineFunctionObject(obj, NULL);
+ }
+
+ if (cparamblkptr->browseoptions.recordClasses)
+ CBrowse_AddClassMemberFunction(obj, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset());
+}
+
+static Boolean CDecl_IsAccessDeclaration(TypeClass *tclass, AccessType access) {
+ SInt32 state;
+ Boolean flag;
+
+ CPrep_TokenStreamGetState(&state);
+ flag = 0;
+
+restart:
+ switch (tk) {
+ case TK_IDENTIFIER:
+ if ((tk = lex()) != ';')
+ break;
+ case TK_OPERATOR:
+ CPrep_TokenStreamSetCurState(&state);
+ if (flag) {
+ CScope_ParseUsingDeclaration(tclass->nspace, access, 1);
+ return 1;
+ }
+ return 0;
+ default:
+ CPrep_TokenStreamSetCurState(&state);
+ return 0;
+ }
+
+ switch (tk) {
+ case TK_COLON_COLON:
+ flag = 1;
+ tk = lex();
+ goto restart;
+ case '<':
+ tk = lex();
+ while (1) {
+ switch (tk) {
+ case 0:
+ case ';':
+ case '{':
+ case '}':
+ CPrep_TokenStreamSetCurState(&state);
+ return 0;
+ case '>':
+ if ((tk = lex()) == TK_COLON_COLON) {
+ flag = 1;
+ tk = lex();
+ goto restart;
+ }
+ default:
+ tk = lex();
+ }
+ }
+ }
+
+ CPrep_TokenStreamSetCurState(&state);
+ return 0;
+}
+
+void CDecl_PackDeclInfo(PackedDeclInfo *packed, DeclInfo *declinfo) {
+ packed->thetype = declinfo->thetype;
+ packed->qual = declinfo->qual;
+ packed->nspace = declinfo->nspace;
+ packed->name = declinfo->name;
+ packed->expltargs = CTemplTool_MakeGlobalTemplArgCopy(declinfo->expltargs);
+ packed->storageclass = declinfo->storageclass;
+ packed->section = declinfo->section;
+ packed->exportflags = declinfo->exportflags;
+ packed->has_expltargs = declinfo->has_expltargs;
+}
+
+void CDecl_UnpackDeclInfo(DeclInfo *declinfo, PackedDeclInfo *packed) {
+ memclrw(declinfo, sizeof(DeclInfo));
+ declinfo->thetype = packed->thetype;
+ declinfo->qual = packed->qual;
+ declinfo->nspace = packed->nspace;
+ declinfo->name = packed->name;
+ declinfo->expltargs = packed->expltargs;
+ declinfo->storageclass = packed->storageclass;
+ declinfo->section = packed->section;
+ declinfo->exportflags = packed->exportflags;
+ declinfo->has_expltargs = packed->has_expltargs;
+}
+
+void CDecl_AddFriend(TypeClass *tclass, Object *friendfunc, TypeClass *friendclass) {
+ ClassFriend *scan;
+ ClassFriend *newfriend;
+
+ if (friendfunc) {
+ for (scan = tclass->friends; scan; scan = scan->next) {
+ if (!scan->isclass && scan->u.obj == friendfunc)
+ break;
+ }
+ if (!scan) {
+ newfriend = galloc(sizeof(ClassFriend));
+ memclrw(newfriend, sizeof(ClassFriend));
+ newfriend->next = tclass->friends;
+ tclass->friends = newfriend;
+ newfriend->u.obj = friendfunc;
+ newfriend->isclass = 0;
+ }
+ }
+
+ if (friendclass) {
+ for (scan = tclass->friends; scan; scan = scan->next) {
+ if (scan->isclass && scan->u.theclass == friendclass)
+ break;
+ }
+ if (!scan) {
+ newfriend = galloc(sizeof(ClassFriend));
+ memclrw(newfriend, sizeof(ClassFriend));
+ newfriend->next = tclass->friends;
+ tclass->friends = newfriend;
+ newfriend->u.theclass = friendclass;
+ newfriend->isclass = 1;
+ }
+ }
+}
+
+static void CDecl_ParseFriendDecl(TypeClass *tclass) {
+ DeclInfo declinfo;
+ DeclInfo declinfo_copy;
+ Boolean is_templ;
+ Boolean r27;
+ Boolean pflag;
+ CScopeSave save;
+ Object *obj;
+ NameSpace *nspace;
+
+ is_templ = (tclass->flags & CLASS_IS_TEMPL) != 0;
+ r27 = (tk == TK_CLASS || tk == TK_STRUCT || tk == TK_UNION);
+ memclrw(&declinfo, sizeof(DeclInfo));
+
+ declinfo.in_friend_decl = 1;
+ CParser_GetDeclSpecs(&declinfo, 1);
+ if (declinfo.storageclass) {
+ CError_Error(CErrorStr177);
+ declinfo.storageclass = 0;
+ }
+ declinfo.in_friend_decl = 0;
+
+ if (tk == ';') {
+ if (!r27)
+ CError_Error(CErrorStr201);
+
+ if (IS_TYPE_CLASS(declinfo.thetype)) {
+ if (!(TYPE_CLASS(declinfo.thetype)->flags & CLASS_IS_TEMPL) || CParser_CheckTemplateClassUsage(TEMPL_CLASS(declinfo.thetype), 1)) {
+ if (!is_templ)
+ CDecl_AddFriend(tclass, NULL, TYPE_CLASS(declinfo.thetype));
+ else
+ CTemplClass_RegisterFriend(TEMPL_CLASS(tclass), &declinfo);
+ }
+ } else {
+ if (IS_TYPE_TEMPLATE(declinfo.thetype) && is_templ)
+ CTemplClass_RegisterFriend(TEMPL_CLASS(tclass), &declinfo);
+ else
+ CError_Error(CErrorStr201);
+ }
+ } else {
+ if (declinfo.x14 || declinfo.x10) {
+ CDecl_ParseSpecialMember(&declinfo, 0);
+ if (declinfo.name) {
+ obj = CDecl_GetFunctionObject(&declinfo, NULL, &pflag, 0);
+ if (obj)
+ CDecl_AddFriend(tclass, obj, NULL);
+ if (tk != ';')
+ CError_Error(CErrorStr123);
+ else
+ tk = lex();
+ }
+ return;
+ } else {
+ nspace = CScope_FindGlobalNS(cscope_current);
+ declinfo_copy = declinfo;
+ while (1) {
+ declinfo = declinfo_copy;
+ declinfo.x4D = 1;
+ declinfo.x51 = 1;
+ scandeclarator(&declinfo);
+
+ if (IS_TYPE_FUNC(declinfo.thetype)) {
+ if (!is_templ) {
+ CScope_SetNameSpaceScope(nspace, &save);
+ obj = CDecl_GetFunctionObject(&declinfo, NULL, &pflag, 0);
+ CScope_RestoreScope(&save);
+
+ if (obj) {
+ CDecl_AddFriend(tclass, obj, NULL);
+ if (!declinfo.nspace && tk == '{') {
+ InlineFunctionObject(obj, tclass);
+ } else {
+ if (!obj->sclass)
+ obj->sclass = TK_EXTERN;
+ }
+ }
+ } else {
+ CTemplClass_RegisterFriend(TEMPL_CLASS(tclass), &declinfo);
+ }
+ } else {
+ CError_Error(CErrorStr201);
+ }
+
+ if (tk != ',')
+ break;
+ tk = lex();
+ }
+ }
+ }
+
+ if (tk == ';')
+ tk = lex();
+ else
+ CError_Error(CErrorStr123);
+}
+
+static ObjMemberVar *CDecl_InstanceDataDeclarator(ClassLayout *decle, TypeClass *tclass, Type *type, UInt32 qual, HashNameNode *name, AccessType access) {
+ NameSpaceObjectList *list;
+ ObjMemberVar *ivar;
+ ObjMemberVar *scan;
+
+ if (name && (list = CScope_FindName(tclass->nspace, name))) {
+ switch (list->object->otype) {
+ case OT_NAMESPACE:
+ CError_Error(CErrorStr321);
+ return NULL;
+ case OT_ENUMCONST:
+ case OT_TYPE:
+ case OT_OBJECT:
+ CError_Error(CErrorStr322);
+ return NULL;
+ case OT_MEMBERVAR:
+ CError_Error(CErrorStr122, name->name);
+ return NULL;
+ case OT_TYPETAG:
+ break;
+ default:
+ CError_FATAL(4989);
+ }
+ }
+
+ ivar = galloc(sizeof(ObjMemberVar));
+ memclrw(ivar, sizeof(ObjMemberVar));
+ ivar->otype = OT_MEMBERVAR;
+ ivar->access = access;
+ ivar->name = name;
+ ivar->type = type;
+ ivar->qual = qual;
+ if (!tclass->sominfo)
+ decle->lex_order_count++;
+
+ if ((scan = tclass->ivars)) {
+ while (scan->next)
+ scan = scan->next;
+ scan->next = ivar;
+ } else {
+ tclass->ivars = ivar;
+ }
+
+ if (name && name != no_name_node) {
+ CScope_AddObject(tclass->nspace, name, OBJ_BASE(ivar));
+ if ((tclass->flags & CLASS_IS_TEMPL) && CTemplTool_IsTemplateArgumentDependentType(type))
+ CTemplClass_RegisterObjectDef(TEMPL_CLASS(tclass), OBJ_BASE(ivar));
+ if (cparamblkptr->browseoptions.recordClasses)
+ CBrowse_AddClassMemberVar(ivar, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset());
+ }
+
+ return ivar;
+}
+
+void CDecl_CheckCtorIntegrity(FuncArg *args, TypeClass *tclass) {
+ if (args && args->type == TYPE(tclass)) {
+ if (!args->next || args->next->dexpr) {
+ CError_Error(CErrorStr239);
+ args->type = &stvoid;
+ }
+ }
+}
+
+static void CDecl_ParseClassMembers(ClassLayout *decle, TypeClass *tclass, short mode) {
+ AccessType access;
+ Boolean r17;
+ BigDeclInfo bde;
+ DeclInfo declinfo;
+ //Type *newtype
+ ObjMemberVar *ivar;
+ ObjMemberVar *scanivar;
+ Type *tmptype;
+ UInt32 r22;
+ UInt32 r21;
+ UInt8 r20;
+ UInt8 r18;
+ Boolean r19;
+ short t;
+
+ r17 = (tclass->flags & CLASS_IS_TEMPL) && TEMPL_CLASS(tclass)->pspec_owner;
+ memclrw(&bde, sizeof(BigDeclInfo));
+
+ access = (mode == CLASS_MODE_CLASS) ? ACCESSPRIVATE : ACCESSPUBLIC;
+ global_access = access;
+
+ restart:
+ while (tk != '}') {
+ CPrep_NewFileOffsetInfo(&member_fileoffset, NULL);
+ r21 = 0;
+ r22 = 0;
+ r20 = 0;
+ r18 = 0;
+
+ if (tk == TK_TEMPLATE) {
+ NameSpace *nspace = cscope_current;
+ TemplClass *tmclass;
+
+ if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL)) {
+ tmclass = TEMPL_CLASS(nspace->theclass);
+ } else {
+ for (; nspace; nspace = nspace->parent) {
+ if (!nspace->name && !nspace->theclass && nspace->parent && !nspace->is_templ) {
+ CError_Error(CErrorStr347);
+ break;
+ }
+ }
+ }
+
+ CTempl_Parse(TEMPL_CLASS(tclass), access);
+ tk = lex();
+ continue;
+ }
+
+ restart2:
+ r19 = 0;
+ switch (tk) {
+ case TK_UU_DECLSPEC:
+ if ((tk = lex()) != '(')
+ CError_Error(CErrorStr114);
+ memclrw(&declinfo, sizeof(DeclInfo));
+ CParser_ParseDeclSpec(&declinfo, 1);
+ r21 |= declinfo.qual;
+ r20 |= declinfo.exportflags;
+ r18 = declinfo.section;
+ if ((tk = lex()) != ')')
+ CError_Error(CErrorStr115);
+ tk = lex();
+ goto restart2;
+ case TK_PRIVATE:
+ global_access = access = ACCESSPRIVATE;
+ goto check_access;
+ case TK_PROTECTED:
+ global_access = access = ACCESSPROTECTED;
+ goto check_access;
+ case TK_PUBLIC:
+ global_access = access = ACCESSPUBLIC;
+ check_access:
+ if (r22 || r20)
+ CError_Error(CErrorStr121);
+ if ((tk = lex()) != ':')
+ CError_Error(CErrorStr170);
+ else
+ tk = lex();
+ goto restart;
+ case TK_EXPLICIT:
+ CError_QualifierCheck(r22 & Q_EXPLICIT);
+ r22 |= Q_EXPLICIT;
+ tk = lex();
+ goto restart2;
+ case TK_INLINE:
+ CError_QualifierCheck(r22 & Q_INLINE);
+ r22 |= Q_INLINE;
+ tk = lex();
+ goto restart2;
+ case TK_ASM:
+ CError_QualifierCheck(r22 & Q_ASM);
+ r22 |= Q_ASM;
+ tk = lex();
+ goto restart2;
+ case TK_VIRTUAL:
+ CError_QualifierCheck(r22 & Q_VIRTUAL);
+ r22 |= Q_VIRTUAL;
+ tk = lex();
+ goto restart2;
+ case TK_IDENTIFIER:
+ while (1) {
+ if (tkidentifier == tclass->classname) {
+ t = lookahead();
+ tkidentifier = tclass->classname;
+ r19 = 1;
+ if (copts.cpp_extensions && t == TK_COLON_COLON) {
+ lex();
+ tk = lex();
+ if (tk == TK_IDENTIFIER)
+ continue;
+ if (tk == '~')
+ goto restart2;
+ CError_Error(CErrorStr107);
+ }
+
+ if (t == '(') {
+ redo_thing:
+ CError_QualifierCheck(r22 & ~(Q_EXPLICIT | Q_INLINE | Q_ASM));
+ memclrw(&bde.declinfo2, sizeof(DeclInfo));
+ if (tclass->sominfo)
+ bde.declinfo2.thetype = &stvoid;
+ else
+ bde.declinfo2.thetype = TYPE(&void_ptr);
+
+ bde.declinfo2.qual = r22;
+ bde.declinfo2.exportflags = r20;
+ bde.declinfo2.section = r18;
+ bde.declinfo2.x4B = 1;
+ scandeclarator(&bde.declinfo2);
+ if (IS_TYPE_FUNC(bde.declinfo2.thetype)) {
+ if (r17)
+ bde.declinfo2.thetype = CTemplTool_ResolveMemberSelfRefs(TEMPL_CLASS(tclass), bde.declinfo2.thetype, &bde.declinfo2.qual);
+ if (tclass->sominfo) {
+ if (TYPE_FUNC(bde.declinfo2.thetype)->args)
+ CError_Error(CErrorStr272);
+ bde.declinfo2.qual |= Q_VIRTUAL;
+ } else {
+ CDecl_CheckCtorIntegrity(TYPE_FUNC(bde.declinfo2.thetype)->args, tclass);
+ if (tclass->flags & CLASS_HAS_VBASES)
+ CDecl_AddArgument(TYPE_FUNC(bde.declinfo2.thetype), TYPE(&stsignedshort));
+ bde.declinfo2.qual &= ~Q_VIRTUAL;
+ }
+ TYPE_FUNC(bde.declinfo2.thetype)->flags |= FUNC_IS_CTOR;
+ bde.declinfo2.name = constructor_name_node;
+ bde.declinfo2.qual |= r21;
+ CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 0, 0, 1, 0);
+ } else {
+ CError_Error(CErrorStr241);
+ }
+ if (tk == ';')
+ tk = lex();
+ else
+ CError_Error(CErrorStr123);
+ goto restart;
+ }
+ }
+ // 6F8D8
+ if (!r22 && CDecl_IsAccessDeclaration(tclass, access)) {
+ tk = lex();
+ goto restart;
+ }
+ break;
+ }
+ break;
+ case TK_USING:
+ CError_QualifierCheck(r22);
+ tk = lex();
+ CScope_ParseUsingDeclaration(tclass->nspace, access, 0);
+ tk = lex();
+ goto restart;
+ case '~':
+ if ((tk = lex()) != TK_IDENTIFIER || tkidentifier != tclass->classname) {
+ CError_Error(CErrorStr241);
+ goto restart;
+ }
+ CError_QualifierCheck(r22 & ~(Q_VIRTUAL | Q_INLINE | Q_ASM));
+ if (tclass->flags & CLASS_IS_TEMPL_ANY) {
+ t = lookahead();
+ tkidentifier = tclass->classname;
+ if (t == '<') {
+ memclrw(&bde.declinfo, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(&bde.declinfo, 0);
+ if (tk != '(' || bde.declinfo.thetype != TYPE(tclass) || bde.declinfo.nspace) {
+ CError_Error(CErrorStr241);
+ goto restart;
+ }
+ CPrep_UnLex();
+ tk = TK_IDENTIFIER;
+ tkidentifier = tclass->classname;
+ }
+ }
+ memclrw(&bde.declinfo2, sizeof(DeclInfo));
+ bde.declinfo2.qual = r22;
+ bde.declinfo2.exportflags = r20;
+ bde.declinfo2.section = r18;
+ if (tclass->sominfo)
+ bde.declinfo2.thetype = &stvoid;
+ else
+ bde.declinfo2.thetype = TYPE(&void_ptr);
+ scandeclarator(&bde.declinfo2);
+ if (IS_TYPE_FUNC(bde.declinfo2.thetype) && !TYPE_FUNC(bde.declinfo2.thetype)->args) {
+ if (!CScope_FindName(tclass->nspace, destructor_name_node)) {
+ if (tclass->sominfo)
+ bde.declinfo2.qual |= Q_VIRTUAL;
+ else
+ CDecl_AddArgument(TYPE_FUNC(bde.declinfo2.thetype), TYPE(&stsignedshort));
+ bde.declinfo2.name = destructor_name_node;
+ TYPE_FUNC(bde.declinfo2.thetype)->flags |= FUNC_IS_DTOR;
+ bde.declinfo2.qual |= r21;
+ CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 1, 0, 1, 0);
+ } else {
+ CError_Error(CErrorStr133, CError_GetFunctionName(tclass->nspace, destructor_name_node, NULL));
+ }
+ } else {
+ CError_Error(CErrorStr146);
+ }
+ if (tk == ';')
+ tk = lex();
+ else
+ CError_Error(CErrorStr123);
+ goto restart;
+ case TK_OPERATOR:
+ if (CMangler_OperatorName(lookahead())) {
+ memclrw(&bde.declinfo, sizeof(DeclInfo));
+ bde.declinfo.thetype = TYPE(&stsignedint);
+ goto after_various_things;
+ } else {
+ tk = lex();
+ CError_QualifierCheck(r22 & ~(Q_VIRTUAL | Q_INLINE | Q_ASM));
+ memclrw(&bde.declinfo2, sizeof(DeclInfo));
+ bde.declinfo2.qual = r22;
+ bde.declinfo2.exportflags = r20;
+ bde.declinfo2.section = r18;
+ conversion_type_name(&bde.declinfo2);
+ bde.declinfo2.qual |= r21;
+ tmptype = bde.declinfo2.thetype;
+ CDecl_NewConvFuncType(&bde.declinfo2);
+ if ((tclass->flags & CLASS_IS_TEMPL) && CTemplTool_IsTemplateArgumentDependentType(tmptype))
+ bde.declinfo2.name = CParser_GetUniqueName();
+ CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 1, 1, 1, 0);
+ if (tk == ';')
+ tk = lex();
+ else
+ CError_Error(CErrorStr123);
+ goto restart;
+ }
+ case TK_FRIEND:
+ tk = lex();
+ CDecl_ParseFriendDecl(tclass);
+ goto restart;
+ }
+
+ CError_QualifierCheck(r22 & Q_EXPLICIT);
+ global_access = access;
+ memclrw(&bde.declinfo, sizeof(DeclInfo));
+ bde.declinfo.qual = r22;
+ bde.declinfo.exportflags = r20;
+ bde.declinfo.section = r18;
+ CParser_GetDeclSpecs(&bde.declinfo, 0);
+
+ if (r19 && tk == '(' && (tclass->flags & CLASS_IS_TEMPL_ANY) && bde.declinfo.thetype == TYPE(tclass) && !bde.declinfo.nspace) {
+ CPrep_UnLex();
+ tk = TK_IDENTIFIER;
+ tkidentifier = tclass->classname;
+ r22 = bde.declinfo.qual;
+ goto redo_thing;
+ }
+
+ after_various_things:
+ switch (bde.declinfo.storageclass) {
+ case 0:
+ case TK_STATIC:
+ case TK_TYPEDEF:
+ case TK_MUTABLE:
+ break;
+ default:
+ CError_Error(CErrorStr177);
+ bde.declinfo.storageclass = 0;
+ }
+
+ if (tk != ';') {
+ while (1) {
+ CDecl_ScanStructDeclarator(&bde);
+ if (r17)
+ bde.declinfo2.thetype = CTemplTool_ResolveMemberSelfRefs(TEMPL_CLASS(tclass), bde.declinfo2.thetype, &bde.declinfo2.qual);
+ if (bde.declinfo2.nspace)
+ CError_Error(CErrorStr200);
+ if (bde.declinfo2.operator_token) {
+ if (bde.declinfo.storageclass == TK_MUTABLE)
+ CError_QualifierCheck(Q_MUTABLE);
+ r19 = 0;
+ switch (bde.declinfo2.operator_token) {
+ case TK_NEW:
+ case TK_NEW_ARRAY:
+ CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL);
+ r19 = 1;
+ break;
+ case TK_DELETE:
+ case TK_DELETE_ARRAY:
+ CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL);
+ r19 = 1;
+ break;
+ default:
+ if (bde.declinfo2.storageclass == TK_STATIC)
+ CError_Error(CErrorStr193);
+ if (tclass->sominfo)
+ CError_Error(CErrorStr193);
+ }
+
+ bde.declinfo2.storageclass = 0;
+ if (IS_TYPE_FUNC(bde.declinfo2.thetype)) {
+ bde.declinfo2.qual |= r21;
+ CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, r19 == 0, 0, 1, r19);
+ CDecl_CheckOperatorType(&bde.declinfo2, 1);
+ if (tclass->sominfo)
+ CSOM_FixNewDeleteFunctype(TYPE_FUNC(bde.declinfo2.thetype));
+ } else {
+ CError_Error(CErrorStr121);
+ }
+ } else if (bde.xCD) {
+ if (bde.declinfo2.name == constructor_name_node || bde.declinfo2.name == destructor_name_node)
+ CError_Error(CErrorStr241);
+ switch (bde.declinfo2.storageclass) {
+ case TK_TYPEDEF:
+ CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL);
+ CDecl_TypedefDeclarator(&bde.declinfo2);
+ break;
+ case TK_STATIC:
+ CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL);
+ if (tclass->sominfo)
+ CError_Error(CErrorStr271);
+ if (IS_TYPE_FUNC(bde.declinfo2.thetype)) {
+ bde.declinfo2.qual |= r21;
+ bde.declinfo2.storageclass = 0;
+ if (bde.declinfo2.name == tclass->classname)
+ CError_Error(CErrorStr241);
+ CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 0, 0, 1, 1);
+ } else {
+ CDecl_ExtractClassExportFlags(&bde.declinfo2, tclass->eflags);
+ bde.declinfo2.storageclass = 0;
+ CDecl_DataDeclarator(&bde.declinfo2, access, 1);
+ }
+ break;
+ case 0:
+ case TK_MUTABLE:
+ if (IS_TYPE_FUNC(bde.declinfo2.thetype)) {
+ if (bde.declinfo2.name == tclass->classname)
+ CError_Error(CErrorStr241);
+ if (bde.declinfo.storageclass == TK_MUTABLE)
+ CError_QualifierCheck(Q_MUTABLE);
+ bde.declinfo2.qual |= r21;
+ CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 1, 0, 1, 0);
+ } else {
+ CDecl_CompleteType(bde.declinfo2.thetype);
+ CanCreateObject(bde.declinfo2.thetype);
+ CError_QualifierCheck(bde.declinfo2.qual & (Q_VIRTUAL | Q_INLINE));
+ if (bde.declinfo2.storageclass == TK_MUTABLE)
+ bde.declinfo2.qual |= Q_MUTABLE;
+ CDecl_InstanceDataDeclarator(decle, tclass, bde.declinfo2.thetype, bde.declinfo2.qual, bde.declinfo2.name, access);
+ }
+ break;
+ default:
+ CError_Error(CErrorStr177);
+ }
+ }
+
+ // this should be 70058
+ if (tk != ',')
+ break; // goes to 70148
+ tk = lex();
+ }
+ } else if (CParser_IsAnonymousUnion(&bde.declinfo, 1)) {
+ if ((ivar = CDecl_InstanceDataDeclarator(decle, tclass, bde.declinfo.thetype, 0, NULL, access)))
+ ivar->anonunion = 1;
+ for (scanivar = TYPE_CLASS(bde.declinfo.thetype)->ivars; scanivar; scanivar = scanivar->next) {
+ tmptype = scanivar->type;
+ if (IS_TYPE_BITFIELD(tmptype) && copts.reverse_bitfields) {
+ TypeBitfield *newtype = galloc(sizeof(TypeBitfield));
+ *newtype = *TYPE_BITFIELD(tmptype);
+ CABI_ReverseBitField(newtype);
+ tmptype = TYPE(newtype);
+ }
+ if ((ivar = CDecl_InstanceDataDeclarator(decle, tclass, tmptype, scanivar->qual, scanivar->name, access)))
+ ivar->offset = scanivar->offset | 0x80000000;
+ }
+ }
+
+ // this should be 70148 i think
+ if (tk != ';') {
+ CError_Error(CErrorStr123);
+ return;
+ }
+ CPrep_TokenStreamFlush();
+ tk = lex();
+ }
+}
+
+static VClassList *AddVBaseToList(TypeClass *tclass, TypeClass *baseclass) {
+ VClassList *scan;
+ VClassList *vbase;
+
+ for (scan = tclass->vbases; scan; scan = scan->next) {
+ if (scan->base == baseclass)
+ return NULL;
+ }
+
+ vbase = galloc(sizeof(VClassList));
+ memclrw(vbase, sizeof(VClassList));
+ vbase->base = baseclass;
+
+ if ((scan = tclass->vbases)) {
+ while (scan->next)
+ scan = scan->next;
+ scan->next = vbase;
+ } else {
+ tclass->vbases = vbase;
+ }
+
+ return vbase;
+}
+
+void CDecl_MakeVBaseList(TypeClass *tclass) {
+ ClassList *base;
+ VClassList *vbase;
+ VClassList *new_vbase;
+ SInt32 offset;
+
+ if (copts.vbase_ctor_offset)
+ tclass->flags = tclass->flags | CLASS_FLAGS_8000;
+
+ for (base = tclass->bases, offset = tclass->size; base; base = base->next) {
+ for (vbase = base->base->vbases; vbase; vbase = vbase->next) {
+ if ((new_vbase = AddVBaseToList(tclass, vbase->base))) {
+ new_vbase->offset = offset + CMach_MemberAlignValue(TYPE(vbase->base), offset);
+ offset = new_vbase->offset + vbase->base->size;
+ }
+ }
+
+ if (base->is_virtual && (new_vbase = AddVBaseToList(tclass, base->base))) {
+ new_vbase->offset = offset + CMach_MemberAlignValue(TYPE(base->base), offset);
+ offset = new_vbase->offset + base->base->size;
+ }
+ }
+}
+
+Boolean CDecl_CheckNewBase(TypeClass *tclass, TypeClass *baseclass, Boolean is_virtual) {
+ ClassList *scan;
+
+ if (tclass == baseclass) {
+ CError_Error(CErrorStr131);
+ return 0;
+ }
+
+ if (!(baseclass->flags & CLASS_COMPLETED)) {
+ CError_Error(CErrorStr136, baseclass, 0);
+ return 0;
+ }
+
+ if (baseclass->flags & CLASS_SINGLE_OBJECT) {
+ if (is_virtual || tclass->bases) {
+ CError_Error(CErrorStr191);
+ return 0;
+ }
+ tclass->flags = tclass->flags | CLASS_SINGLE_OBJECT;
+ }
+
+ if (baseclass->flags & CLASS_HANDLEOBJECT) {
+ if (is_virtual || tclass->bases) {
+ CError_Error(CErrorStr191);
+ return 0;
+ }
+ tclass->flags = tclass->flags | CLASS_HANDLEOBJECT;
+ }
+
+ if (baseclass->sominfo) {
+ if (!is_virtual)
+ CError_Error(CErrorStr268);
+ CSOM_MakeSOMClass(tclass);
+ } else if (tclass->sominfo) {
+ CError_Error(CErrorStr267);
+ }
+
+ if (tclass->bases && (tclass->flags & CLASS_SINGLE_OBJECT) && (tclass->flags & CLASS_SINGLE_OBJECT)) {
+ CError_Error(CErrorStr131);
+ return 0;
+ }
+
+ if (copts.ecplusplus && (is_virtual || tclass->bases)) {
+ CError_Error(CErrorStr339);
+ return 0;
+ }
+
+ for (scan = tclass->bases; scan; scan = scan->next) {
+ if (scan->base == baseclass) {
+ CError_Error(CErrorStr131);
+ return 0;
+ }
+ }
+
+ if (baseclass->flags & CLASS_COM_OBJECT)
+ tclass->flags = tclass->flags | CLASS_COM_OBJECT;
+ if (baseclass->flags & CLASS_IS_CONVERTIBLE)
+ tclass->flags = tclass->flags | CLASS_IS_CONVERTIBLE;
+ if (baseclass->flags & CLASS_HAS_VBASES)
+ tclass->flags = tclass->flags | CLASS_HAS_VBASES;
+
+ if (is_virtual)
+ tclass->flags = tclass->flags | CLASS_HAS_VBASES;
+
+ return 1;
+}
+
+static void CDecl_ParseBaseClassList(TypeClass *tclass, short mode, Boolean is_templ) {
+ Boolean is_virtual;
+ AccessType access;
+ NameResult pr;
+ ObjType *inherited_type;
+ ClassList *base;
+ ClassList *scan;
+ TypeClass *baseclass;
+
+ do {
+ if (mode == CLASS_MODE_CLASS)
+ access = ACCESSPRIVATE;
+ else
+ access = ACCESSPUBLIC;
+
+ is_virtual = 0;
+ if ((tk = lex()) == TK_VIRTUAL) {
+ tk = lex();
+ is_virtual = 1;
+ }
+
+ switch (tk) {
+ case TK_PRIVATE:
+ access = ACCESSPRIVATE;
+ tk = lex();
+ break;
+ case TK_PUBLIC:
+ access = ACCESSPUBLIC;
+ tk = lex();
+ break;
+ case TK_PROTECTED:
+ if (!copts.ARMconform) {
+ access = ACCESSPROTECTED;
+ tk = lex();
+ }
+ break;
+ }
+
+ if (tk == TK_VIRTUAL) {
+ if (is_virtual)
+ CError_Error(CErrorStr121);
+ is_virtual = 1;
+ tk = lex();
+ }
+
+ if (CScope_ParseDeclName(&pr)) {
+ if (!pr.type) {
+ if (!pr.name_4) {
+ CError_Error(CErrorStr121);
+ } else if (tk == TK_IDENTIFIER && pr.name_4 == tkidentifier) {
+ goto special_parsing;
+ }
+ CError_Error(CErrorStr140, tkidentifier->name);
+ continue;
+ }
+
+ CDecl_CompleteType(pr.type);
+ if (is_templ && CTemplTool_IsTemplateArgumentDependentType(pr.type)) {
+ if (!IS_TYPE_CLASS(pr.type) || !(TYPE_CLASS(pr.type)->flags & CLASS_IS_TEMPL) ||
+ CParser_CheckTemplateClassUsage(TEMPL_CLASS(pr.type), 1)) {
+ CTemplClass_RegisterBaseClass(TEMPL_CLASS(tclass), pr.type, access, is_virtual);
+ if (is_virtual)
+ tclass->flags = tclass->flags | CLASS_HAS_VBASES;
+ }
+ continue;
+ }
+
+ if (!IS_TYPE_CLASS(pr.type) || (TYPE_CLASS(pr.type)->flags & CLASS_IS_TEMPL)) {
+ CError_Error(CErrorStr131);
+ continue;
+ }
+ baseclass = TYPE_CLASS(pr.type);
+ } else {
+ special_parsing:
+ if (!strcmp(tkidentifier->name, "HandleObject")) {
+ if (tclass->bases)
+ CError_Error(CErrorStr191);
+ tclass->flags |= CLASS_SINGLE_OBJECT | CLASS_HANDLEOBJECT;
+ tk = lex();
+ break;
+ }
+ if (!strcmp(tkidentifier->name, "SingleObject") || !strcmp(tkidentifier->name, "SingleInheritance")) {
+ if (tclass->bases)
+ CError_Error(CErrorStr191);
+ tclass->flags = tclass->flags | CLASS_SINGLE_OBJECT;
+ tk = lex();
+ break;
+ }
+ if (!strcmp(tkidentifier->name, "__comobject")) {
+ tclass->flags = tclass->flags | CLASS_COM_OBJECT;
+ tk = lex();
+ break;
+ }
+ if (!strcmp(tkidentifier->name, "__somobject")) {
+ if (!is_virtual)
+ CError_Error(CErrorStr268);
+ CSOM_MakeSOMClass(tclass);
+ tk = lex();
+ break;
+ }
+ if (!strcmp(tkidentifier->name, "__javaobject")) {
+ tk = lex();
+ tclass->action = CLASS_ACTION_3;
+ break;
+ }
+
+ CError_Error(CErrorStr140, tkidentifier->name);
+ continue;
+ }
+
+ if (CDecl_CheckNewBase(tclass, baseclass, is_virtual)) {
+ base = galloc(sizeof(ClassList));
+ memclrw(base, sizeof(ClassList));
+ base->base = baseclass;
+ base->access = access;
+ base->is_virtual = is_virtual;
+ if ((scan = tclass->bases)) {
+ while (scan->next)
+ scan = scan->next;
+ scan->next = base;
+ } else {
+ tclass->bases = base;
+ }
+ }
+ } while ((tk = lex()) == ',');
+
+ if (tclass->flags & CLASS_HAS_VBASES)
+ CDecl_MakeVBaseList(tclass);
+
+ if (copts.def_inherited && tclass->bases && !tclass->bases->next) {
+ inherited_type = galloc(sizeof(ObjType));
+ memclrw(inherited_type, sizeof(ObjType));
+ inherited_type->otype = OT_TYPE;
+ inherited_type->access = ACCESSPUBLIC;
+ inherited_type->type = TYPE(tclass->bases->base);
+ CScope_AddObject(tclass->nspace, GetHashNameNodeExport("inherited"), OBJ_BASE(inherited_type));
+ }
+}
+
+static AccessType getaccesstype(AccessType a, AccessType b, AccessType c) {
+ if (a == ACCESSNONE || b == ACCESSNONE || b == ACCESSPRIVATE)
+ return ACCESSNONE;
+
+ if (c == ACCESSPUBLIC && b != ACCESSPUBLIC)
+ return ACCESSNONE;
+
+ return ACCESSPUBLIC;
+}
+
+static TypeMemberFunc *CDecl_MakeDefaultCtorType(TypeClass *tclass) {
+ TypeMemberFunc *tmeth = galloc(sizeof(TypeMemberFunc));
+ memclrw(tmeth, sizeof(TypeMemberFunc));
+ tmeth->type = TYPEFUNC;
+ tmeth->functype = TYPE(&void_ptr);
+ tmeth->flags = FUNC_IS_CTOR | FUNC_AUTO_GENERATED | FUNC_METHOD;
+ tmeth->theclass = tclass;
+ CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1);
+
+ if (tclass->flags & CLASS_HAS_VBASES)
+ CDecl_AddArgument(TYPE_FUNC(tmeth), TYPE(&stsignedshort));
+
+ CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass);
+ return tmeth;
+}
+
+static void CDecl_AddDefArgConstructor(TypeClass *tclass) {
+ // empty
+}
+
+static void CDecl_AddMemberFunctionObject(TypeClass *tclass, HashNameNode *name, TypeMemberFunc *tmeth, AccessType access) {
+ Object *obj = CParser_NewCompilerDefFunctionObject();
+ obj->name = name;
+ obj->type = TYPE(tmeth);
+ obj->qual = Q_MANGLE_NAME;
+ obj->access = access;
+ obj->nspace = tclass->nspace;
+ obj->qual = obj->qual | Q_INLINE;
+ CScope_AddObject(tclass->nspace, obj->name, OBJ_BASE(obj));
+}
+
+static void CDecl_AddDefaultConstructor(ClassLayout *decle, TypeClass *tclass) {
+ ClassList *base;
+ ObjMemberVar *ivar;
+ Object *obj;
+ Boolean has_ctor;
+
+ if (CClass_Constructor(tclass)) {
+ CDecl_AddDefArgConstructor(tclass);
+ return;
+ }
+
+ has_ctor = 0;
+
+ if (tclass->flags & CLASS_HAS_VBASES)
+ has_ctor = 1;
+ if (decle->has_vtable)
+ has_ctor = 1;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (CClass_Constructor(base->base))
+ has_ctor = 1;
+ }
+
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ Type *type = ivar->type;
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+ if (IS_TYPE_CLASS(type) && CClass_Constructor(TYPE_CLASS(type)))
+ has_ctor = 1;
+ }
+
+ if (has_ctor) {
+ CDecl_AddMemberFunctionObject(
+ tclass,
+ constructor_name_node,
+ CDecl_MakeDefaultCtorType(tclass),
+ ACCESSPUBLIC
+ );
+ }
+}
+
+static TypeMemberFunc *CDecl_MakeCopyCtorType(TypeClass *tclass, Boolean is_const) {
+ FuncArg *arg;
+ TypeMemberFunc *tmeth = galloc(sizeof(TypeMemberFunc));
+ memclrw(tmeth, sizeof(TypeMemberFunc));
+ tmeth->type = TYPEFUNC;
+ tmeth->functype = TYPE(&void_ptr);
+ tmeth->flags = FUNC_IS_CTOR | FUNC_AUTO_GENERATED | FUNC_METHOD;
+ tmeth->theclass = tclass;
+ CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1);
+
+ arg = CParser_NewFuncArg();
+ if (is_const)
+ arg->qual = Q_CONST;
+ arg->type = CDecl_NewRefPointerType(TYPE(tclass));
+ tmeth->args = arg;
+
+ if (tclass->flags & CLASS_HAS_VBASES)
+ CDecl_AddArgument(TYPE_FUNC(tmeth), TYPE(&stsignedshort));
+
+ CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass);
+ return tmeth;
+}
+
+static void CDecl_AddDefaultCopyConstructor(ClassLayout *decle, TypeClass *tclass) {
+ ClassList *base;
+ ObjMemberVar *ivar;
+ Object *obj;
+ AccessType access;
+ Boolean has_copyctor;
+ Boolean is_const;
+ FuncArg *arg;
+
+ if (CClass_CopyConstructor(tclass))
+ return;
+
+ access = ACCESSPUBLIC;
+ is_const = 1;
+ has_copyctor = 0;
+
+ if (CClass_Constructor(tclass))
+ has_copyctor = 1;
+ if ((tclass->flags & CLASS_HAS_VBASES) || decle->has_vtable)
+ has_copyctor = 1;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if ((obj = CClass_CopyConstructor(base->base))) {
+ has_copyctor = 1;
+ access = getaccesstype(access, obj->access, ACCESSPRIVATE);
+ arg = TYPE_FUNC(obj->type)->args->next;
+ if (base->base->flags & CLASS_HAS_VBASES)
+ arg = arg->next;
+ if (!(arg->qual & Q_CONST))
+ is_const = 0;
+ }
+ }
+
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ Type *type = ivar->type;
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+ if (IS_TYPE_CLASS(type) && (obj = CClass_CopyConstructor(TYPE_CLASS(type)))) {
+ has_copyctor = 1;
+ access = getaccesstype(access, obj->access, ACCESSPUBLIC);
+ arg = TYPE_FUNC(obj->type)->args->next;
+ if (TYPE_CLASS(type)->flags & CLASS_HAS_VBASES)
+ arg = arg->next;
+ if (!(arg->qual & Q_CONST))
+ is_const = 0;
+ }
+ }
+
+ if (has_copyctor) {
+ CDecl_AddMemberFunctionObject(
+ tclass,
+ constructor_name_node,
+ CDecl_MakeCopyCtorType(tclass, is_const),
+ access
+ );
+ }
+}
+
+static TypeMemberFunc *CDecl_MakeAssignmentOperatorType(TypeClass *tclass, Boolean is_const) {
+ FuncArg *arg;
+ TypeMemberFunc *tmeth = galloc(sizeof(TypeMemberFunc));
+ memclrw(tmeth, sizeof(TypeMemberFunc));
+ tmeth->type = TYPEFUNC;
+ tmeth->functype = CDecl_NewRefPointerType(TYPE(tclass));
+ tmeth->flags = FUNC_AUTO_GENERATED | FUNC_METHOD;
+ tmeth->theclass = tclass;
+ CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1);
+
+ arg = CParser_NewFuncArg();
+ if (is_const)
+ arg->qual = Q_CONST;
+ arg->type = CDecl_NewRefPointerType(TYPE(tclass));
+ tmeth->args = arg;
+
+ CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass);
+ return tmeth;
+}
+
+static void CDecl_AddDefaultAssignmentOperator(ClassLayout *decle, TypeClass *tclass) {
+ ClassList *base;
+ ObjMemberVar *ivar;
+ Object *obj;
+ AccessType access;
+ Boolean is_const;
+ Boolean has_ass;
+ DeclInfo declinfo;
+
+ is_const = 1;
+ has_ass = 0;
+ access = ACCESSPUBLIC;
+
+ if (!CClass_AssignmentOperator(tclass)) {
+ if (!copts.old_argmatch)
+ has_ass = 1;
+
+ if ((tclass->flags & CLASS_HAS_VBASES) || decle->has_vtable || CClass_MemberObject(tclass, asop_name_node))
+ has_ass = 1;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if ((obj = CClass_AssignmentOperator(base->base))) {
+ has_ass = 1;
+ access = getaccesstype(access, obj->access, ACCESSPRIVATE);
+ if (!(TYPE_FUNC(obj->type)->args->next->qual & Q_CONST))
+ is_const = 0;
+ }
+ }
+
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ Type *type = ivar->type;
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+ if (IS_TYPE_CLASS(type) && (obj = CClass_AssignmentOperator(TYPE_CLASS(type)))) {
+ has_ass = 1;
+ access = getaccesstype(access, obj->access, ACCESSPUBLIC);
+ if (!(TYPE_FUNC(obj->type)->args->next->qual & Q_CONST))
+ is_const = 0;
+ }
+ }
+ }
+
+ if (has_ass) {
+ memclrw(&declinfo, sizeof(DeclInfo));
+ declinfo.qual |= Q_INLINE;
+ declinfo.thetype = (Type *) CDecl_MakeAssignmentOperatorType(tclass, is_const);
+ declinfo.name = asop_name_node;
+ CDecl_AddFunctionMember(decle, tclass, &declinfo, access, 1, 0, 0, 0);
+ }
+}
+
+TypeMemberFunc *CDecl_MakeDefaultDtorType(TypeClass *tclass, Boolean is_virtual) {
+ TypeMemberFunc *tmeth = galloc(sizeof(TypeMemberFunc));
+ memclrw(tmeth, sizeof(TypeMemberFunc));
+ tmeth->type = TYPEFUNC;
+ tmeth->functype = (Type *) &void_ptr;
+ tmeth->flags = FUNC_IS_DTOR | FUNC_AUTO_GENERATED | FUNC_METHOD;
+ tmeth->theclass = tclass;
+ CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1);
+ if (is_virtual)
+ CDecl_AddArgument(TYPE_FUNC(tmeth), TYPE(&stsignedshort));
+ CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass);
+ return tmeth;
+}
+
+static void CDecl_AddDefaultDestructor(ClassLayout *decle, TypeClass *tclass) {
+ ClassList *base;
+ ObjMemberVar *ivar;
+ Object *obj;
+ AccessType access;
+ Boolean has_dtor;
+ Boolean is_virtual;
+ DeclInfo declinfo;
+
+ if (CClass_Destructor(tclass))
+ return;
+
+ has_dtor = 0;
+ is_virtual = 0;
+ access = ACCESSPUBLIC;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if ((obj = CClass_Destructor(base->base))) {
+ has_dtor = 1;
+ if (obj->datatype == DVFUNC)
+ is_virtual = 1;
+ access = getaccesstype(access, obj->access, ACCESSPRIVATE);
+ }
+ }
+
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ Type *type = ivar->type;
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+ if (IS_TYPE_CLASS(type) && (obj = CClass_Destructor(TYPE_CLASS(type)))) {
+ has_dtor = 1;
+ access = getaccesstype(access, obj->access, ACCESSPUBLIC);
+ }
+ }
+
+ if (has_dtor) {
+ memclrw(&declinfo, sizeof(DeclInfo));
+ declinfo.qual |= Q_INLINE;
+ if (is_virtual)
+ declinfo.qual |= Q_VIRTUAL;
+
+ declinfo.thetype = (Type *) CDecl_MakeDefaultDtorType(tclass, 1);
+ declinfo.name = destructor_name_node;
+ CDecl_AddFunctionMember(decle, tclass, &declinfo, access, 1, 0, 0, 0);
+ }
+}
+
+static void CDecl_SetupClassLayout(ClassLayout *decle, TypeClass *tclass, ObjBase **objbuf) {
+ SInt32 index;
+ SInt32 i;
+ Object *obj;
+ CScopeObjectIterator iter;
+ ObjMemberVar *ivar;
+ SInt32 bufsize;
+
+ if (decle->lex_order_count > 32) {
+ bufsize = decle->lex_order_count * sizeof(ObjBase *);
+ objbuf = lalloc(bufsize);
+ } else {
+ bufsize = 32 * sizeof(ObjBase *);
+ }
+ memclrw(objbuf, bufsize);
+ decle->objlist = objbuf;
+
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ index = 0;
+ while (1) {
+ obj = OBJECT(CScope_NextObjectIteratorObject(&iter));
+ if (!obj) break;
+
+ if (!IS_TYPE_FUNC(obj->type))
+ continue;
+ if (!IS_TYPEFUNC_METHOD(TYPE_FUNC(obj->type)))
+ continue;
+ if (obj->datatype == DALIAS)
+ continue;
+
+ i = TYPE_METHOD(obj->type)->vtbl_index;
+ if (i > 0) {
+ CError_ASSERT(6363, (i - 1) < decle->lex_order_count && !objbuf[(int) (i - 1)]);
+ objbuf[(int) (i - 1)] = OBJ_BASE(obj);
+ index++;
+ if (obj->datatype != DVFUNC && !TYPE_METHOD(obj->type)->is_static && CClass_OverridesBaseMember(tclass, obj->name, obj))
+ CDecl_MakeFunctionVirtual(tclass, obj);
+
+ if (obj->datatype == DVFUNC) {
+ decle->has_vtable = 1;
+ if (!tclass->vtable) {
+ CABI_AddVTable(tclass);
+ decle->xA = i - 1;
+ } else {
+ if ((i - 1) < decle->xA)
+ decle->xA = i - 1;
+ }
+ } else if (TYPE_FUNC(obj->type)->flags & FUNC_PURE) {
+ CError_Error(CErrorStr351, obj);
+ TYPE_FUNC(obj->type)->flags &= ~FUNC_PURE;
+ }
+ } else {
+ CError_ASSERT(6412, i == 0);
+ }
+
+ if (!tclass->sominfo)
+ TYPE_METHOD(obj->type)->vtbl_index = 0;
+ }
+
+ if (!tclass->action) {
+ for (i = 0; i < decle->lex_order_count; i++) {
+ Object *obj2 = OBJECT(objbuf[i]);
+ if (obj2 && obj2->datatype == DVFUNC && !(obj2->qual & Q_INLINE) && !(TYPE_FUNC(obj2->type)->flags & FUNC_PURE)) {
+ tclass->action = CLASS_ACTION_1;
+ TYPE_FUNC(obj2->type)->flags |= FUNC_FLAGS_4;
+ break;
+ }
+ }
+ }
+
+ if (!tclass->sominfo) {
+ for (i = 0, ivar = tclass->ivars; i < decle->lex_order_count; i++) {
+ if (!objbuf[i]) {
+ CError_ASSERT(6449, ivar);
+ objbuf[i] = OBJ_BASE(ivar);
+ ivar = ivar->next;
+ index++;
+ }
+ }
+ CError_ASSERT(6455, ivar == NULL);
+ }
+
+ CError_ASSERT(6458, index == decle->lex_order_count);
+}
+
+void CDecl_CompleteClass(ClassLayout *decle, TypeClass *tclass) {
+ ClassList *base;
+ ObjBase *buf[32];
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (base->base->vtable)
+ decle->has_vtable = 1;
+ }
+
+ if (!tclass->sominfo) {
+ CDecl_AddDefaultDestructor(decle, tclass);
+ CDecl_AddDefaultAssignmentOperator(decle, tclass);
+ CDecl_AddDefaultConstructor(decle, tclass);
+ CDecl_AddDefaultCopyConstructor(decle, tclass);
+ }
+
+ CDecl_SetupClassLayout(decle, tclass, buf);
+ if (decle->has_vtable)
+ CClass_CheckOverrides(tclass);
+ CABI_LayoutClass(decle, tclass);
+ if (tclass->sominfo)
+ CSOM_ClassComplete(tclass);
+
+ if ((tclass->flags & CLASS_IS_TEMPL_INST) && !TEMPL_CLASS_INST(tclass)->is_specialized)
+ tclass->action = CLASS_ACTION_0;
+
+ if (!tclass->action)
+ CClass_MakeStaticActionClass(tclass);
+ CClass_ClassDefaultFuncAction(tclass);
+}
+
+TypeClass *CDecl_DefineClass(NameSpace *nspace, HashNameNode *name, TypeClass *tclass, short mode, Boolean flag2, Boolean flag3) {
+ NameSpace *mynspace;
+ ObjType *objtype;
+
+ if (!tclass && nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL)) {
+ CError_ASSERT(6556, !flag2);
+ return TYPE_CLASS(CTemplClass_DefineNestedClass(TEMPL_CLASS(nspace->theclass), name, mode));
+ }
+
+ mynspace = CScope_NewListNameSpace(name, 1);
+ if (!tclass) {
+ tclass = galloc(sizeof(TypeClass));
+ memclrw(tclass, sizeof(TypeClass));
+ }
+
+ tclass->type = TYPECLASS;
+ tclass->align = 1;
+ tclass->mode = mode;
+ tclass->action = CLASS_ACTION_0;
+ if (name) {
+ tclass->classname = name;
+ if (flag3) {
+ if (flag2) {
+ objtype = galloc(sizeof(ObjType));
+ memclrw(objtype, sizeof(ObjType));
+ objtype->otype = OT_TYPE;
+ objtype->access = ACCESSPUBLIC;
+ objtype->type = (Type *) tclass;
+ CScope_AddObject(nspace, name, OBJ_BASE(objtype));
+ } else {
+ CScope_DefineTypeTag(nspace, name, (Type *) tclass);
+ }
+ }
+ CScope_DefineTypeTag(mynspace, name, (Type *) tclass);
+
+ if (cscope_currentfunc)
+ mynspace->name = CParser_AppendUniqueNameFile(name->name);
+
+ if (copts.direct_to_som && nspace == cscope_root && !strcmp(name->name, "SOMObject"))
+ CSOM_MakeSOMClass(tclass);
+ } else {
+ tclass->classname = CParser_AppendUniqueNameFile("@class");
+ mynspace->name = tclass->classname;
+ }
+
+ tclass->nspace = mynspace;
+ mynspace->theclass = tclass;
+ mynspace->parent = nspace;
+ if (!nspace->is_global)
+ CParser_RegisterNonGlobalClass(tclass);
+
+ return tclass;
+}
+
+void CDecl_ParseClassDeclSpec(UInt8 *declspec) {
+ DeclInfo declinfo;
+
+ if ((tk = lex()) == '(') {
+ memclrw(&declinfo, sizeof(DeclInfo));
+ CParser_ParseDeclSpec(&declinfo, 1);
+ if (declinfo.exportflags & EXPORT_FLAGS_INTERNAL)
+ *declspec = *declspec | CLASS_EFLAGS_INTERNAL;
+ if (declinfo.exportflags & EXPORT_FLAGS_IMPORT)
+ *declspec = *declspec | CLASS_EFLAGS_IMPORT;
+ if (declinfo.exportflags & EXPORT_FLAGS_EXPORT)
+ *declspec = *declspec | CLASS_EFLAGS_EXPORT;
+ if ((tk = lex()) != ')')
+ CError_Error(CErrorStr115);
+ else
+ tk = lex();
+ } else {
+ CError_Error(CErrorStr114);
+ }
+}
+
+static TemplClass *CDecl_SpecializeTemplateClass(TemplClass *tmclass) {
+ tmclass->theclass.nspace->names = 0;
+ tmclass->theclass.nspace->data.list = NULL;
+ tmclass->theclass.ivars = NULL;
+ tmclass->theclass.bases = NULL;
+ tmclass->theclass.vbases = NULL;
+ tmclass->theclass.friends = NULL;
+ tmclass->theclass.vtable = NULL;
+ tmclass->members = NULL;
+ tmclass->instances = NULL;
+ tmclass->pspec_owner = NULL;
+ tmclass->pspecs = NULL;
+ tmclass->actions = NULL;
+ tmclass->lex_order_count = 0;
+ tmclass->align = 0;
+ tmclass->flags = TEMPLCLASS_FLAGS_2;
+ return tmclass;
+}
+
+void CDecl_ParseClass(DeclInfo *declinfo, short mode, Boolean flag1, UInt8 class_declspec) {
+ ClassLayout decle;
+ TypeClass *tclass;
+ HashNameNode *classname;
+ Type *search;
+ short t;
+ NameSpace *nspace;
+ NameResult pr;
+ CScopeSave scopesave;
+ GList gl;
+ FileOffsetInfo offsetsave;
+ SInt32 offset;
+ Boolean is_templ;
+ Boolean add_to_browse;
+
+ memclrw(&decle, sizeof(ClassLayout));
+ if (declinfo->x28) {
+ tclass = TYPE_CLASS(declinfo->x28);
+ } else {
+ if (tk == TK_UU_DECLSPEC)
+ CDecl_ParseClassDeclSpec(&class_declspec);
+
+ switch (tk) {
+ case ':':
+ case '{':
+ tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1);
+ tclass->eflags |= class_declspec;
+ break;
+ case TK_IDENTIFIER:
+ classname = tkidentifier;
+ if (!declinfo->in_friend_decl && !declinfo->x4F && ((t = lookahead()) == ':' || t == ';' || t == '{')) {
+ tk = lex();
+ search = CScope_GetLocalTagType(cscope_current, classname);
+ if (search) {
+ tagtype_search:
+ if (!IS_TYPE_CLASS(search)) {
+ if ((IS_TYPE_TEMPLATE(search) || IS_TYPE_STRUCT(search)) && tk != '{' && tk != ':') {
+ declinfo->thetype = search;
+ return;
+ }
+ if (!IS_TYPE_TEMPLATE(search) || !(tclass = TYPE_CLASS(CTemplTool_GetSelfRefTemplate(search)))) {
+ CError_Error(CErrorStr132, classname->name);
+ tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1);
+ break;
+ }
+ } else {
+ tclass = TYPE_CLASS(search);
+ }
+ if (tclass->mode != mode) {
+ if (
+ (mode == CLASS_MODE_CLASS && tclass->mode == CLASS_MODE_STRUCT) ||
+ (mode == CLASS_MODE_STRUCT && tclass->mode == CLASS_MODE_CLASS)
+ )
+ {
+ if (copts.warn_structclass)
+ CError_Warning(CErrorStr343);
+ } else {
+ CError_Error(CErrorStr132, classname);
+ }
+ }
+ tclass->eflags |= class_declspec;
+ break;
+ } else {
+ tclass = CDecl_DefineClass(cscope_current, classname, NULL, mode, 0, 1);
+ tclass->eflags |= class_declspec;
+ break;
+ }
+ } else {
+ tkidentifier = classname;
+ }
+ default:
+ if (!CScope_ParseElaborateName(&pr)) {
+ CError_Error(CErrorStr121);
+ declinfo->thetype = TYPE(&stsignedint);
+ return;
+ }
+
+ tk = lex();
+ if ((search = pr.type)) {
+ goto tagtype_search;
+ }
+
+ CError_ASSERT(6786, pr.name_4);
+
+ tclass = CDecl_DefineClass(CScope_FindNonClassNonFunctionNS(cscope_current), pr.name_4, NULL, mode, 0, 1);
+ tclass->eflags |= class_declspec;
+ }
+ }
+
+ declinfo->thetype = TYPE(tclass);
+ if (tk == ':' || tk == '{') {
+ if (declinfo->in_friend_decl)
+ CError_Error(CErrorStr201);
+
+ if (tclass->flags & CLASS_COMPLETED) {
+ if (
+ (tclass->flags & CLASS_IS_TEMPL) &&
+ !TEMPL_CLASS(tclass)->instances &&
+ !(TEMPL_CLASS(tclass)->flags & TEMPLCLASS_FLAGS_2)
+ )
+ {
+ tclass = TYPE_CLASS(CDecl_SpecializeTemplateClass(TEMPL_CLASS(tclass)));
+ } else {
+ CError_Error(CErrorStr132, tclass->classname->name);
+ tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1);
+ }
+ }
+
+ for (nspace = cscope_current; nspace; nspace = nspace->parent) {
+ if (nspace == tclass->nspace) {
+ CError_Error(CErrorStr132, tclass->classname->name);
+ tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1);
+ break;
+ }
+ }
+
+ is_templ = (tclass->flags & CLASS_IS_TEMPL) != 0;
+ if (tclass->flags & CLASS_IS_TEMPL_INST) {
+ TEMPL_CLASS_INST(tclass)->is_instantiated = 1;
+ if (!declinfo->x28)
+ TEMPL_CLASS_INST(tclass)->is_specialized = 1;
+ }
+
+ CError_ASSERT(6853, copts.structalignment >= 0 && copts.structalignment <= 14);
+
+ tclass->eflags = tclass->eflags | (((copts.structalignment + 1) << 4) & 0xF0);
+ if (tk == ':')
+ CDecl_ParseBaseClassList(tclass, mode, is_templ);
+
+ CScope_SetClassDefScope(tclass, &scopesave);
+ if (tk == '{') {
+ tk = lex();
+ if ((add_to_browse = cparamblkptr->browseoptions.recordClasses && declinfo->file->recordbrowseinfo)) {
+ offsetsave = member_fileoffset;
+ CBrowse_BeginClass(declinfo, &gl);
+ }
+ CDecl_ParseClassMembers(&decle, tclass, mode);
+ offset = CPrep_BrowserFileOffset();
+ if (flag1)
+ tk = lex();
+ if (add_to_browse) {
+ member_fileoffset = offsetsave;
+ if (flag1 && tk == ';')
+ CPrep_BrowserFileOffset();
+ CBrowse_EndClass(offset, &gl);
+ }
+ } else {
+ CError_Error(CErrorStr135);
+ }
+
+ if (is_templ)
+ CTemplClass_CompleteClass(TEMPL_CLASS(tclass), &decle);
+ else
+ CDecl_CompleteClass(&decle, tclass);
+ CScope_RestoreScope(&scopesave);
+ }
+}
diff --git a/compiler_and_linker/FrontEnd/C/CError.c b/compiler_and_linker/FrontEnd/C/CError.c
new file mode 100644
index 0000000..02265c3
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CError.c
@@ -0,0 +1,1098 @@
+#include "cos.h"
+#include "compiler/CClass.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CTemplateNew.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/Unmangle.h"
+#include "compiler/enode.h"
+#include "compiler/objc.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/templates.h"
+#include "compiler/tokens.h"
+
+TStreamElement *cerror_locktoken;
+static TStreamElement *cerror_token;
+static short cerror_errorcount;
+static SInt32 cerror_lasterrorline;
+char cerror_synchdata[32];
+short cerror_synchoffset;
+int CError_BreakPointcount;
+
+// forward decls
+static void CError_BufferAppendType(CErrorBuffer *eb, Type *ty, UInt32 qual);
+static void CError_AppendObjectName(CErrorBuffer *eb, Object *obj);
+
+void CError_Init(void) {
+ cerror_errorcount = 0;
+ cerror_lasterrorline = -1;
+ cerror_token = 0;
+ cerror_locktoken = 0;
+}
+
+void CError_SetErrorToken(TStreamElement *token) {
+ if (token && token->tokenfile)
+ cerror_token = token;
+}
+
+void CError_SetNullErrorToken(void) {
+ cerror_token = (TStreamElement *) -1;
+}
+
+void CError_LockErrorPos(TStreamElement *token, TStreamElement **saved) {
+ *saved = cerror_locktoken;
+ if (token && token->tokenfile)
+ cerror_locktoken = token;
+}
+
+void CError_UnlockErrorPos(TStreamElement **saved) {
+ cerror_locktoken = *saved;
+}
+
+void CError_ResetErrorSkip(void) {
+ cerror_lasterrorline = -1;
+}
+
+static void CError_GetErrorString(char *buf, short code) {
+ CError_ASSERT(142, code >= CErrorStr100 && code < CErrorStrMAX);
+ COS_GetString(buf, 10000, code - 99);
+}
+
+static void CError_BufferInit(CErrorBuffer *eb, char *buf, SInt32 bufSize) {
+ eb->start = eb->end = buf;
+ eb->size = eb->remaining = bufSize - 1;
+}
+
+static void CError_BufferGrow(CErrorBuffer *eb, SInt32 amount) {
+ char *newBuf;
+
+ newBuf = lalloc(eb->size + amount);
+ memcpy(newBuf, eb->start, eb->size);
+ eb->start = newBuf;
+ eb->end = newBuf + eb->size - eb->remaining;
+ eb->size += amount;
+ eb->remaining += amount;
+}
+
+static void CError_BufferAppendChar(CErrorBuffer *eb, char ch) {
+ if (eb) {
+ if (!eb->remaining)
+ CError_BufferGrow(eb, 256);
+ *(eb->end++) = ch;
+ eb->remaining--;
+ }
+}
+
+static void CError_BufferAppendString(CErrorBuffer *eb, const char *str) {
+ size_t len;
+
+ if (eb) {
+ len = strlen(str);
+ if (eb->remaining < len)
+ CError_BufferGrow(eb, len);
+ memcpy(eb->end, str, len);
+ eb->end += len;
+ eb->remaining -= len;
+ }
+}
+
+static void CError_BufferTerminate(CErrorBuffer *eb) {
+ if (eb->remaining == 0)
+ CError_BufferGrow(eb, 1);
+ *eb->end = 0;
+ eb->remaining = 0;
+}
+
+static void CError_BufferAppendQualifier(CErrorBuffer *eb, UInt32 qual) {
+ if (qual & Q_PASCAL)
+ CError_BufferAppendString(eb, "pascal ");
+ if (qual & Q_CONST)
+ CError_BufferAppendString(eb, "const ");
+ if (qual & Q_VOLATILE)
+ CError_BufferAppendString(eb, "volatile ");
+ if (qual & Q_EXPLICIT)
+ CError_BufferAppendString(eb, "explicit ");
+ if (qual & Q_RESTRICT)
+ CError_BufferAppendString(eb, "restrict ");
+}
+
+static void CError_BufferAppendTemplArgExpr(CErrorBuffer *eb, ENode *node) {
+ char buf[32];
+
+ if (node) {
+ switch (node->type) {
+ case EINTCONST:
+ CInt64_PrintDec(buf, node->data.intval);
+ CError_BufferAppendString(eb, buf);
+ return;
+ case EOBJREF:
+ CError_BufferAppendChar(eb, '&');
+ CError_AppendObjectName(eb, node->data.objref);
+ return;
+ }
+ }
+
+ CError_BufferAppendString(eb, "{targ_expr}");
+}
+
+static void CError_BufferAppendTemplArg(CErrorBuffer *eb, TemplArg *targ) {
+ switch (targ->pid.type) {
+ case TPT_TYPE:
+ CError_BufferAppendType(eb, targ->data.typeparam.type, targ->data.typeparam.qual);
+ break;
+ case TPT_NONTYPE:
+ CError_BufferAppendTemplArgExpr(eb, targ->data.paramdecl.expr);
+ break;
+ case TPT_TEMPLATE:
+ CError_BufferAppendType(eb, targ->data.ttargtype, 0);
+ break;
+ default:
+ CError_FATAL(300);
+ }
+}
+
+static void CError_BufferAppendTemplArgs(CErrorBuffer *eb, TemplArg *targs) {
+ if (targs) {
+ CError_BufferAppendChar(eb, '<');
+ while (targs) {
+ CError_BufferAppendTemplArg(eb, targs);
+ if (targs->next)
+ CError_BufferAppendString(eb, ", ");
+ targs = targs->next;
+ }
+ CError_BufferAppendChar(eb, '>');
+ }
+}
+
+static void CError_BufferAppendNameSpace(CErrorBuffer *eb, NameSpace *nspace) {
+ while (nspace) {
+ if (nspace->name) {
+ CError_BufferAppendNameSpace(eb, nspace->parent);
+ if (nspace->theclass) {
+ CError_BufferAppendString(eb, nspace->theclass->classname->name);
+ if (nspace->theclass->flags & CLASS_IS_TEMPL_INST)
+ CError_BufferAppendTemplArgs(
+ eb,
+ !TEMPL_CLASS_INST(nspace->theclass)->oargs ? TEMPL_CLASS_INST(nspace->theclass)->inst_args : TEMPL_CLASS_INST(nspace->theclass)->oargs
+ );
+ } else {
+ CError_BufferAppendString(eb, nspace->name->name);
+ }
+ CError_BufferAppendString(eb, "::");
+ return;
+ }
+ nspace = nspace->parent;
+ }
+}
+
+static void CError_BufferAppendPType(CErrorBuffer *eb, Type *ty) {
+ switch (ty->type) {
+ case TYPEPOINTER:
+ CError_BufferAppendPType(eb, TYPE_POINTER(ty)->target);
+ if (TYPE_POINTER(ty)->qual & Q_REFERENCE)
+ CError_BufferAppendString(eb, "&");
+ else
+ CError_BufferAppendString(eb, "*");
+ CError_BufferAppendQualifier(eb, TYPE_POINTER(ty)->qual);
+ break;
+ case TYPEMEMBERPOINTER:
+ CError_BufferAppendPType(eb, TYPE_MEMBER_POINTER(ty)->ty1);
+ CError_BufferAppendType(eb, TYPE_MEMBER_POINTER(ty)->ty2, 0);
+ CError_BufferAppendString(eb, "::*");
+ CError_BufferAppendQualifier(eb, TYPE_MEMBER_POINTER(ty)->qual);
+ break;
+ }
+}
+
+static void CError_BufferAppendTemplDepType(CErrorBuffer *eb, TypeTemplDep *type) {
+ char buf[64];
+ switch (type->dtype) {
+ case TEMPLDEP_ARGUMENT:
+ if (type->u.pid.nindex)
+ sprintf(buf, "T%" PRId32 "_%" PRId32, type->u.pid.nindex, type->u.pid.index);
+ else
+ sprintf(buf, "T%" PRId32, type->u.pid.index);
+ CError_BufferAppendString(eb, buf);
+ break;
+ case TEMPLDEP_QUALNAME:
+ CError_BufferAppendTemplDepType(eb, type->u.qual.type);
+ CError_BufferAppendString(eb, "::");
+ CError_BufferAppendString(eb, type->u.qual.name->name);
+ break;
+ case TEMPLDEP_TEMPLATE:
+ CError_BufferAppendType(eb, (Type *) type->u.templ.templ, 0);
+ CError_BufferAppendTemplArgs(eb, type->u.templ.args);
+ break;
+ case TEMPLDEP_ARRAY:
+ CError_BufferAppendType(eb, type->u.array.type, 0);
+ CError_BufferAppendChar(eb, '[');
+ CError_BufferAppendTemplArgExpr(eb, type->u.array.index);
+ CError_BufferAppendChar(eb, ']');
+ break;
+ case TEMPLDEP_QUALTEMPL:
+ CError_BufferAppendTemplDepType(eb, type->u.qualtempl.type);
+ CError_BufferAppendString(eb, "::");
+ CError_BufferAppendTemplArgs(eb, type->u.qualtempl.args);
+ break;
+ case TEMPLDEP_BITFIELD:
+ CError_BufferAppendType(eb, type->u.bitfield.type, 0);
+ CError_BufferAppendChar(eb, '[');
+ CError_BufferAppendTemplArgExpr(eb, type->u.bitfield.size);
+ CError_BufferAppendChar(eb, ']');
+ break;
+ default:
+ CError_FATAL(463);
+ }
+}
+
+static void CError_BufferAppendFuncArgs(CErrorBuffer *eb, TypeFunc *tfunc, Boolean isMethod) {
+ FuncArg *arg;
+ UInt32 qual;
+
+ qual = 0;
+ CError_BufferAppendChar(eb, '(');
+ if ((arg = tfunc->args)) {
+ if (isMethod) {
+ qual = arg->qual;
+ arg = arg->next;
+ if (arg)
+ arg = arg->next;
+ } else if ((tfunc->flags & FUNC_METHOD) && !TYPE_METHOD(tfunc)->is_static) {
+ qual = arg->qual;
+ arg = arg->next;
+ if (arg) {
+ if ((tfunc->flags & FUNC_IS_DTOR) || ((tfunc->flags & FUNC_IS_CTOR) && (TYPE_METHOD(tfunc)->theclass->flags & CLASS_HAS_VBASES)))
+ arg = arg->next;
+ }
+ }
+
+ while (arg) {
+ if (arg == &elipsis || arg == &oldstyle) {
+ CError_BufferAppendString(eb, "...");
+ break;
+ }
+
+ CError_BufferAppendType(eb, arg->type, arg->qual);
+
+ if ((arg = arg->next))
+ CError_BufferAppendString(eb, ", ");
+ else
+ break;
+ }
+ }
+ CError_BufferAppendChar(eb, ')');
+ if (qual)
+ CError_BufferAppendQualifier(eb, qual);
+}
+
+static void CError_BufferAppendType(CErrorBuffer *eb, Type *ty, UInt32 qual) {
+ // not matching - register issues
+ Type *scan;
+ Type *scan2;
+ char buf[16];
+
+ switch (ty->type) {
+ case TYPEVOID:
+ CError_BufferAppendQualifier(eb, qual);
+ CError_BufferAppendString(eb, "void");
+ return;
+ case TYPEINT:
+ case TYPEFLOAT:
+ CError_BufferAppendQualifier(eb, qual);
+ switch (TYPE_INTEGRAL(ty)->integral) {
+ case IT_BOOL:
+ CError_BufferAppendString(eb, "bool");
+ return;
+ case IT_CHAR:
+ CError_BufferAppendString(eb, "char");
+ return;
+ case IT_UCHAR:
+ CError_BufferAppendString(eb, "unsigned char");
+ return;
+ case IT_SCHAR:
+ CError_BufferAppendString(eb, "signed char");
+ return;
+ case IT_WCHAR_T:
+ CError_BufferAppendString(eb, "wchar_t");
+ return;
+ case IT_SHORT:
+ CError_BufferAppendString(eb, "short");
+ return;
+ case IT_USHORT:
+ CError_BufferAppendString(eb, "unsigned short");
+ return;
+ case IT_INT:
+ CError_BufferAppendString(eb, "int");
+ return;
+ case IT_UINT:
+ CError_BufferAppendString(eb, "unsigned int");
+ return;
+ case IT_LONG:
+ CError_BufferAppendString(eb, "long");
+ return;
+ case IT_ULONG:
+ CError_BufferAppendString(eb, "unsigned long");
+ return;
+ case IT_LONGLONG:
+ CError_BufferAppendString(eb, "long long");
+ return;
+ case IT_ULONGLONG:
+ CError_BufferAppendString(eb, "unsigned long long");
+ return;
+ case IT_FLOAT:
+ CError_BufferAppendString(eb, "float");
+ return;
+ case IT_SHORTDOUBLE:
+ CError_BufferAppendString(eb, "short double");
+ return;
+ case IT_DOUBLE:
+ CError_BufferAppendString(eb, "double");
+ return;
+ case IT_LONGDOUBLE:
+ CError_BufferAppendString(eb, "long double");
+ return;
+ default:
+ CError_FATAL(584);
+ }
+ case TYPEENUM:
+ CError_BufferAppendQualifier(eb, qual);
+ CError_BufferAppendNameSpace(eb, TYPE_ENUM(ty)->nspace);
+ if (TYPE_ENUM(ty)->enumname)
+ CError_BufferAppendString(eb, TYPE_ENUM(ty)->enumname->name);
+ else
+ CError_BufferAppendString(eb, "{unnamed-enum}");
+ return;
+ case TYPESTRUCT:
+ CError_BufferAppendQualifier(eb, qual);
+ switch (TYPE_STRUCT(ty)->stype) {
+ case STRUCT_TYPE_STRUCT:
+ CError_BufferAppendString(eb, "struct ");
+ break;
+ case STRUCT_TYPE_UNION:
+ CError_BufferAppendString(eb, "union ");
+ break;
+ case STRUCT_VECTOR_UCHAR:
+ case STRUCT_VECTOR_SCHAR:
+ case STRUCT_VECTOR_BCHAR:
+ case STRUCT_VECTOR_USHORT:
+ case STRUCT_VECTOR_SSHORT:
+ case STRUCT_VECTOR_BSHORT:
+ case STRUCT_VECTOR_UINT:
+ case STRUCT_VECTOR_SINT:
+ case STRUCT_VECTOR_BINT:
+ case STRUCT_VECTOR_FLOAT:
+ case STRUCT_VECTOR_PIXEL:
+ break;
+ default:
+ CError_FATAL(618);
+ }
+ if (TYPE_STRUCT(ty)->name)
+ CError_BufferAppendString(eb, TYPE_STRUCT(ty)->name->name);
+ return;
+ case TYPECLASS:
+ CError_BufferAppendQualifier(eb, qual);
+ CError_BufferAppendNameSpace(eb, TYPE_CLASS(ty)->nspace->parent);
+ if (TYPE_CLASS(ty)->classname) {
+ CError_BufferAppendString(eb, TYPE_CLASS(ty)->classname->name);
+ if (TYPE_CLASS(ty)->flags & CLASS_IS_TEMPL_INST)
+ CError_BufferAppendTemplArgs(
+ eb,
+ TEMPL_CLASS_INST(ty)->oargs ? TEMPL_CLASS_INST(ty)->oargs : TEMPL_CLASS_INST(ty)->inst_args
+ );
+ } else {
+ CError_BufferAppendString(eb, "{unnamed-class}");
+ }
+ return;
+ case TYPEPOINTER:
+ case TYPEMEMBERPOINTER:
+ scan = ty;
+ next_ptr:
+ switch (scan->type) {
+ case TYPEPOINTER:
+ scan = TYPE_POINTER(scan)->target;
+ goto next_ptr;
+ case TYPEMEMBERPOINTER:
+ scan = TYPE_MEMBER_POINTER(scan)->ty1;
+ goto next_ptr;
+ }
+
+ CError_BufferAppendQualifier(eb, qual);
+ switch (scan->type) {
+ case TYPEFUNC:
+ if (TYPE_FUNC(scan)->flags & FUNC_PASCAL)
+ CError_BufferAppendString(eb, "pascal ");
+ CError_BufferAppendType(eb, TYPE_FUNC(scan)->functype, 0);
+ CError_BufferAppendString(eb, " (");
+ CError_BufferAppendPType(eb, ty);
+ CError_BufferAppendChar(eb, ')');
+ CError_BufferAppendFuncArgs(eb, TYPE_FUNC(scan), ty->type == TYPEMEMBERPOINTER);
+ return;
+ case TYPEARRAY:
+ scan2 = scan;
+ while (scan->type == TYPEARRAY)
+ scan = TYPE_POINTER(scan)->target;
+ CError_BufferAppendType(eb, scan, 0);
+ CError_BufferAppendString(eb, " (");
+ CError_BufferAppendPType(eb, ty);
+ CError_BufferAppendChar(eb, ')');
+ ty = scan2;
+ goto append_array_lengths;
+ default:
+ CError_BufferAppendType(eb, scan, 0);
+ CError_BufferAppendChar(eb, ' ');
+ CError_BufferAppendPType(eb, ty);
+ return;
+ }
+ break;
+ case TYPEFUNC:
+ if (TYPE_FUNC(ty)->flags & FUNC_PASCAL)
+ CError_BufferAppendString(eb, "pascal ");
+ CError_BufferAppendQualifier(eb, qual);
+ CError_BufferAppendType(eb, TYPE_FUNC(ty)->functype, 0);
+ CError_BufferAppendChar(eb, ' ');
+ CError_BufferAppendFuncArgs(eb, TYPE_FUNC(ty), 0);
+ return;
+ case TYPEARRAY:
+ CError_BufferAppendQualifier(eb, qual);
+ scan = ty;
+ while (scan->type == TYPEARRAY)
+ scan = TYPE_POINTER(scan)->target;
+ CError_BufferAppendType(eb, scan, 0);
+ append_array_lengths:
+ while (ty->type == TYPEARRAY) {
+ CError_BufferAppendChar(eb, '[');
+ if (ty->size && TYPE_POINTER(ty)->target->size) {
+ sprintf(buf, "%" PRId32, ty->size / TYPE_POINTER(ty)->target->size);
+ CError_BufferAppendString(eb, buf);
+ }
+ CError_BufferAppendChar(eb, ']');
+ ty = TYPE_POINTER(ty)->target;
+ }
+ return;
+ case TYPETEMPLATE:
+ CError_BufferAppendQualifier(eb, qual);
+ CError_BufferAppendTemplDepType(eb, TYPE_TEMPLATE(ty));
+ return;
+ case TYPETEMPLDEPEXPR:
+ CError_BufferAppendString(eb, "T");
+ return;
+ case TYPEBITFIELD:
+ sprintf(buf, "bitfield:%" PRId32, TYPE_BITFIELD(ty)->bitlength);
+ CError_BufferAppendString(eb, buf);
+ return;
+ default:
+ CError_FATAL(752);
+ }
+}
+
+char *CError_GetTypeName(Type *ty, UInt32 qual, Boolean useGlobalHeap) {
+ CErrorBuffer eb;
+ char buf[256];
+ char *ptr;
+
+ CError_BufferInit(&eb, buf, sizeof(buf));
+ CError_BufferAppendType(&eb, ty, qual);
+ CError_BufferTerminate(&eb);
+
+ if (useGlobalHeap)
+ ptr = galloc(eb.size + 1);
+ else
+ ptr = lalloc(eb.size + 1);
+
+ return strcpy(ptr, eb.start);
+}
+
+static void CError_AppendUnqualFunctionName(CErrorBuffer *eb, NameSpace *nspace, HashNameNode *name, TypeFunc *tfunc) {
+ Boolean flag = 0;
+ char *opname;
+
+ if (nspace && nspace->theclass) {
+ if (name == constructor_name_node) {
+ CError_BufferAppendString(eb, nspace->theclass->classname->name);
+ flag = 1;
+ } else if (name == destructor_name_node) {
+ CError_BufferAppendChar(eb, '~');
+ CError_BufferAppendString(eb, nspace->theclass->classname->name);
+ flag = 1;
+ }
+ }
+
+ if (!flag) {
+ opname = CMangler_GetOperator(name);
+ if (!opname) {
+ if (tfunc && (tfunc->flags & FUNC_CONVERSION)) {
+ CError_BufferAppendString(eb, "operator ");
+ CError_BufferAppendType(eb, tfunc->functype, tfunc->qual);
+ } else {
+ CError_BufferAppendString(eb, name->name);
+ }
+ } else {
+ CError_BufferAppendString(eb, opname);
+ }
+ }
+}
+
+static void CError_AppendFunctionName(CErrorBuffer *eb, NameSpace *nspace, HashNameNode *name, TemplArg *templargs, TypeFunc *tfunc) {
+ while (nspace->is_templ && nspace->parent)
+ nspace = nspace->parent;
+
+ CError_BufferAppendNameSpace(eb, nspace);
+ CError_AppendUnqualFunctionName(eb, nspace, name, tfunc);
+ CError_BufferAppendTemplArgs(eb, templargs);
+ if (tfunc) {
+ if (!templargs && (tfunc->flags & FUNC_IS_TEMPL))
+ CError_BufferAppendString(eb, "<...>");
+ CError_BufferAppendFuncArgs(eb, tfunc, 0);
+ } else {
+ CError_BufferAppendString(eb, "()");
+ }
+}
+
+static void CError_AppendObjectName(CErrorBuffer *eb, Object *obj) {
+ if (obj->type->type == TYPEFUNC) {
+ CError_AppendFunctionName(eb, obj->nspace, obj->name, obj->u.func.inst ? obj->u.func.inst->args : NULL, TYPE_FUNC(obj->type));
+ } else {
+ CError_BufferAppendNameSpace(eb, obj->nspace);
+ CError_BufferAppendString(eb, obj->name->name);
+ }
+}
+
+static void CError_AppendMethodName(CErrorBuffer *eb, ObjCMethod *meth) {
+ ObjCMethodArg *arg;
+
+ CError_BufferAppendChar(eb, meth->is_class_method ? '+' : '-');
+ CError_BufferAppendChar(eb, '(');
+ CError_BufferAppendType(eb, meth->return_type, meth->return_qual);
+ CError_BufferAppendChar(eb, ')');
+ for (arg = meth->selector_args; arg; arg = arg->next) {
+ if (arg->selector)
+ CError_BufferAppendString(eb, arg->selector->name);
+ if (arg->type) {
+ CError_BufferAppendString(eb, ":(");
+ CError_BufferAppendType(eb, arg->type, arg->qual);
+ CError_BufferAppendChar(eb, ')');
+ }
+ }
+ if (meth->has_valist)
+ CError_BufferAppendString(eb, ",...");
+}
+
+char *CError_GetQualifiedName(NameSpace *nspace, HashNameNode *name) {
+ CErrorBuffer eb;
+ char buf[256];
+ char *ptr;
+
+ CError_BufferInit(&eb, buf, sizeof(buf));
+ CError_BufferAppendNameSpace(&eb, nspace);
+ CError_BufferAppendString(&eb, name->name);
+ CError_BufferTerminate(&eb);
+
+ ptr = lalloc(eb.size + 1);
+ return strcpy(ptr, eb.start);
+}
+
+char *CError_GetFunctionName(NameSpace *nspace, HashNameNode *name, TypeFunc *tfunc) {
+ CErrorBuffer eb;
+ char buf[256];
+ char *ptr;
+
+ CError_BufferInit(&eb, buf, sizeof(buf));
+ CError_AppendFunctionName(&eb, nspace, name, 0, tfunc);
+ CError_BufferTerminate(&eb);
+
+ ptr = lalloc(eb.size + 1);
+ return strcpy(ptr, eb.start);
+}
+
+char *CError_GetObjectName(Object *obj) {
+ CErrorBuffer eb;
+ char buf[256];
+ char *ptr;
+
+ CError_BufferInit(&eb, buf, sizeof(buf));
+ CError_AppendObjectName(&eb, obj);
+ CError_BufferTerminate(&eb);
+
+ ptr = lalloc(eb.size + 1);
+ return strcpy(ptr, eb.start);
+}
+
+char *CError_GetNameString(NameSpace *nspace, HashNameNode *operatorName) {
+ CErrorBuffer eb;
+ char buf[256];
+ char *ptr;
+ char *opStr;
+
+ CError_ASSERT(973, operatorName);
+
+ opStr = CMangler_GetOperator(operatorName);
+ if (!opStr)
+ opStr = operatorName->name;
+
+ if (nspace && nspace->name) {
+ CError_BufferInit(&eb, buf, sizeof(buf));
+ CError_BufferAppendNameSpace(&eb, nspace);
+ CError_BufferAppendString(&eb, opStr);
+ CError_BufferTerminate(&eb);
+ ptr = lalloc(eb.size + 1);
+ return strcpy(ptr, eb.start);
+ } else {
+ return opStr;
+ }
+}
+
+void CError_ErrorMessage(int errTable, char *str, Boolean flag1, Boolean flag2) {
+ TStreamElement *token;
+ short tokensize;
+ CPrepFileInfo *tokenfile;
+ CWMessageRef myref;
+ char buf[128];
+ CWMessageRef *ref;
+ unsigned char messagetype;
+
+ if (CWDisplayLines(cparamblkptr->context, lines) != cwNoErr)
+ CError_UserBreak();
+
+ if (!in_assembler && !flag1 && cerror_lasterrorline == lines) {
+ if (cerror_errorcount++ >= 50) {
+ if (cerror_errorcount > 60)
+ longjmp(errorreturn, 1);
+ tk = lex();
+ cerror_errorcount = 0;
+ if (tk == 0) {
+ CompilerGetCString(1, buf);
+ CWReportMessage(cparamblkptr->context, NULL, buf, NULL, messagetypeError, errTable);
+ longjmp(errorreturn, 1);
+ }
+ }
+ } else {
+ if (!flag2) {
+ cerror_lasterrorline = lines;
+ cerror_errorcount = 0;
+ }
+ if (copts.warningerrors)
+ flag2 = 0;
+
+ if (cerror_token)
+ token = cerror_token;
+ else if (cerror_locktoken)
+ token = cerror_locktoken;
+ else
+ token = NULL;
+ //token = cerror_token ? cerror_token : cerror_locktoken ? cerror_locktoken : NULL;
+ if ((SInt32) token == -1) {
+ ref = NULL;
+ } else {
+ CPrep_GetTokenContext(token, &tokenfile, &myref.selectionoffset, &tokensize, &myref.linenumber, buf, &myref.tokenoffset, &myref.tokenlength, cerror_synchdata, &cerror_synchoffset);
+ myref.selectionlength = tokensize;
+ myref.sourcefile = tokenfile->textfile;
+ ref = &myref;
+ }
+ messagetype = flag2 ? messagetypeWarning : messagetypeError;
+ if (!flag2) {
+ anyerrors = 1;
+ fatalerrors = 1;
+ }
+ if (CWReportMessage(cparamblkptr->context, ref, str, buf, messagetype, errTable) != cwNoErr)
+ longjmp(errorreturn, 1);
+ }
+
+ cerror_token = NULL;
+}
+
+static void CError_BufferAppendTemplateStack(CErrorBuffer *eb) {
+ TemplStack *stack[64];
+ TemplStack *scan;
+ int index;
+ int indent;
+ int count;
+
+ scan = ctempl_curinstance;
+ for (count = 0; scan && count < 64; count++) {
+ stack[count] = scan;
+ scan = scan->next;
+ }
+
+ for (index = count - 1; index >= 0; index--) {
+ CError_BufferAppendChar(eb, LF);
+ for (indent = index; indent < count; indent++)
+ CError_BufferAppendChar(eb, ' ');
+ CError_BufferAppendString(eb, "(instantiating: '");
+ if (stack[index]->is_func)
+ CError_AppendObjectName(eb, stack[index]->u.func);
+ else
+ CError_BufferAppendType(eb, (Type *) stack[index]->u.theclass, 0);
+ CError_BufferAppendString(eb, "')");
+ }
+
+ CError_BufferTerminate(eb);
+}
+
+void CError_ErrorMessageVA(int code, const char *format, va_list list, Boolean flag1, Boolean flag2) {
+ // register allocation is fucked, matches otherwise
+ CErrorBuffer eb;
+ char buf[256];
+ char unmangleBuf[256];
+ SInt32 moddate;
+ Type *type;
+ UInt32 qual;
+ const char *p;
+ CError_BufferInit(&eb, buf, sizeof(buf));
+
+ p = format;
+ do {
+ switch (p[0]) {
+ case 0:
+ break;
+ case '%':
+ switch (p[1]) {
+ case 'n':
+ MWUnmangle(va_arg(list, const char *), unmangleBuf, sizeof(unmangleBuf));
+ CError_BufferAppendString(&eb, unmangleBuf);
+ p += 2;
+ continue;
+ case 'u':
+ CError_BufferAppendString(&eb, va_arg(list, const char *));
+ p += 2;
+ continue;
+ case 'o':
+ CError_AppendObjectName(&eb, va_arg(list, Object *));
+ p += 2;
+ continue;
+ case 'm':
+ CError_AppendMethodName(&eb, va_arg(list, ObjCMethod *));
+ p += 2;
+ continue;
+ case 't':
+ type = va_arg(list, Type *);
+ qual = va_arg(list, UInt32);
+ CError_BufferAppendType(&eb, type, qual);
+ p += 2;
+ continue;
+ case '%':
+ CError_BufferAppendChar(&eb, '%');
+ p += 2;
+ continue;
+ case 'i':
+ sprintf(unmangleBuf, "%" PRId32, va_arg(list, SInt32));
+ CError_BufferAppendString(&eb, unmangleBuf);
+ p += 2;
+ continue;
+ case 'f':
+ CError_BufferAppendString(&eb, CTool_GetPathName(va_arg(list, FSSpec *), &moddate)->name);
+ p += 2;
+ continue;
+ default:
+ CError_FATAL(1174);
+ }
+ break;
+ default:
+ CError_BufferAppendChar(&eb, *(p++));
+ continue;
+ }
+ break;
+ } while (1);
+
+ CError_BufferAppendTemplateStack(&eb);
+ CError_ErrorMessage(code, eb.start, flag1, flag2);
+}
+
+static void CError_VAErrorMessage(int code, va_list list, Boolean flag1, Boolean flag2) {
+ char buf[256];
+
+ CError_GetErrorString(buf, code);
+ CError_ErrorMessageVA(code + 10000, buf, list, flag1, flag2);
+}
+
+void CError_Error(int code, ...) {
+ va_list va;
+
+ if (trychain)
+ longjmp(trychain->jmpbuf, 1);
+
+ va_start(va, code);
+ CError_VAErrorMessage(code, va, 0, 0);
+ va_end(va);
+
+ if (in_assembler && !preprocessing_only)
+ AssemblerError();
+}
+
+void CError_ErrorTerm(short code) {
+ CError_GetErrorString(string, code);
+ CError_ErrorMessage(code + 10000, string, 0, 0);
+ longjmp(errorreturn, 1);
+}
+
+void CError_ErrorSkip(int code, ...) {
+ va_list va;
+
+ if (trychain)
+ longjmp(trychain->jmpbuf, 1);
+
+ va_start(va, code);
+ CError_VAErrorMessage(code, va, 0, 0);
+ va_end(va);
+
+ if (tk != ';' && tk != ')' && tk != '}' && tk != ',' && tk != ']')
+ tk = lex();
+}
+
+void CError_ErrorFuncCall(short code, NameSpaceObjectList *args, ENodeList *argNodes) {
+ // does not match - one branch has loop weirdness
+ CErrorBuffer eb;
+ char buf[256];
+ char *p;
+ ENodeList *argscan;
+
+ if (trychain)
+ longjmp(trychain->jmpbuf, 1);
+
+ CError_GetErrorString(string, code);
+ CError_BufferInit(&eb, buf, sizeof(buf));
+
+ while (args && args->object->otype != OT_OBJECT)
+ args = args->next;
+ CError_ASSERT(1268, args);
+
+ p = string;
+ do {
+ switch (*p) {
+ case 0:
+ goto exit_main_loop;
+ case '*':
+ if (OBJECT(args->object)->type->type == TYPEFUNC) {
+ CError_AppendUnqualFunctionName(
+ &eb,
+ OBJECT(args->object)->nspace,
+ OBJECT(args->object)->name,
+ TYPE_FUNC(OBJECT(args->object)->type));
+ if (TYPE_FUNC(OBJECT(args->object)->type)->flags & FUNC_METHOD)
+ if (TYPE_FUNC(OBJECT(args->object)->type)->flags & FUNC_IS_CTOR)
+ if (TYPE_METHOD(OBJECT(args->object)->type)->theclass->flags & CLASS_HAS_VBASES)
+ if (argNodes)
+ argNodes = argNodes->next;
+ } else {
+ CError_BufferAppendString(&eb, OBJECT(args->object)->name->name);
+ }
+ CError_BufferAppendChar(&eb, '(');
+ argscan = argNodes;
+ while (argscan) {
+ CError_BufferAppendType(&eb, argscan->node->rtype, argscan->node->flags & ENODE_FLAG_QUALS);
+ if ((argscan = argscan->next))
+ CError_BufferAppendString(&eb, ", ");
+ else
+ break;
+ }
+ CError_BufferAppendChar(&eb, ')');
+ break;
+ default:
+ CError_BufferAppendChar(&eb, *p);
+ }
+ p++;
+ } while (1);
+
+exit_main_loop:
+ while (args) {
+ if (args->object->otype == OT_OBJECT) {
+ CError_BufferAppendChar(&eb, LF);
+ CError_BufferAppendChar(&eb, '\'');
+ CError_AppendObjectName(&eb, (Object *) args->object);
+ CError_BufferAppendChar(&eb, '\'');
+ }
+ args = args->next;
+ }
+
+ CError_BufferAppendTemplateStack(&eb);
+ CError_ErrorMessage(10000 + code, eb.start, 0, 0);
+}
+
+void CError_OverloadedFunctionError2(Object *obj, ObjectList *olst, ENodeList *argNodes) {
+ // not sure if the arg is actually ObjectList since it's never called lmao
+ NameSpaceObjectList first;
+ NameSpaceObjectList *current;
+
+ first.object = (ObjBase *) obj;
+ current = &first;
+ while (olst) {
+ current->next = lalloc(sizeof(NameSpaceObjectList));
+ current = current->next;
+ current->object = (ObjBase *) olst->object;
+ olst = olst->next;
+ }
+ current->next = NULL;
+
+ CError_ErrorFuncCall(CErrorStr392, &first, argNodes);
+}
+
+void CError_OverloadedFunctionError(Object *obj, ObjectList *olst) {
+ // not sure if this arg is ObjectList or NameSpaceObjectList
+ CErrorBuffer eb;
+ char buf[256];
+
+ if (trychain)
+ longjmp(trychain->jmpbuf, 1);
+
+ CError_GetErrorString(string, CErrorStr199);
+ CError_BufferInit(&eb, buf, sizeof(buf));
+ CError_BufferAppendString(&eb, string);
+
+ if (obj) {
+ CError_BufferAppendChar(&eb, LF);
+ CError_BufferAppendChar(&eb, '\'');
+ CError_AppendObjectName(&eb, obj);
+ CError_BufferAppendChar(&eb, '\'');
+ }
+ while (olst) {
+ CError_BufferAppendChar(&eb, LF);
+ CError_BufferAppendChar(&eb, '\'');
+ CError_AppendObjectName(&eb, olst->object);
+ CError_BufferAppendChar(&eb, '\'');
+ olst = olst->next;
+ }
+ CError_BufferAppendTemplateStack(&eb);
+ CError_ErrorMessage(10199, eb.start, 0, 0);
+}
+
+void CError_AbstractClassError(TypeClass *tclass) {
+ Object *result = CClass_CheckPures(tclass);
+ if (!result)
+ CError_Error(CErrorStr372, tclass, 0);
+ else
+ CError_Error(CErrorStr194, result);
+}
+
+void CError_Warning(int code, ...) {
+ va_list va;
+ if (trychain || copts.supress_warnings)
+ return;
+
+ va_start(va, code);
+ CError_VAErrorMessage(code, va, 0, 1);
+ va_end(va);
+}
+
+void CError_BreakPoint(const char *a, const char *b) {
+ if (!a || !strcmp(a, b))
+ CError_BreakPointcount++;
+}
+
+void CError_Internal(char *filename, int line) {
+ char tmp[128];
+ CompilerGetCString(5, tmp);
+ sprintf(string, tmp, filename, line);
+ CError_ErrorMessage(10001, string, 1, 0);
+ longjmp(errorreturn, 1);
+ CError_BreakPoint(0, 0);
+}
+
+void CError_ExpressionTooComplex(void) {
+ CompilerGetCString(6, string);
+ CError_ErrorMessage(10002, string, 1, 0);
+ longjmp(errorreturn, 1);
+}
+
+void CError_NoMem(void) {
+ cprep_nomem_exit = 1;
+ longjmp(errorreturn, 1);
+}
+
+void CError_UserBreak(void) {
+ CompilerGetCString(8, string);
+ longjmp(errorreturn, 1);
+}
+
+void CError_CannotOpen(void) {
+ CompilerGetCString(9, string);
+ CWReportMessage(cparamblkptr->context, NULL, string, NULL, messagetypeError, 0);
+ longjmp(errorreturn, 1);
+}
+
+void CError_QualifierCheck(UInt32 qual) {
+ if (qual) {
+ Boolean anything = 0;
+
+ if (qual & Q_CONST) {
+ CError_Error(CErrorStr313, "const");
+ anything = 1;
+ }
+ if (qual & Q_VOLATILE) {
+ CError_Error(CErrorStr313, "volatile");
+ anything = 1;
+ }
+ if (qual & Q_RESTRICT) {
+ CError_Error(CErrorStr313, "restrict");
+ anything = 1;
+ }
+ if (qual & Q_ASM) {
+ CError_Error(CErrorStr313, "asm");
+ anything = 1;
+ }
+ if (qual & Q_PASCAL) {
+ CError_Error(CErrorStr313, "pascal");
+ anything = 1;
+ }
+ if (qual & Q_INLINE) {
+ CError_Error(CErrorStr313, "inline");
+ anything = 1;
+ }
+ if (qual & Q_REFERENCE) {
+ CError_Error(CErrorStr313, "& reference type");
+ anything = 1;
+ }
+ if (qual & Q_EXPLICIT) {
+ CError_Error(CErrorStr313, "explicit");
+ anything = 1;
+ }
+ if (qual & Q_MUTABLE) {
+ CError_Error(CErrorStr313, "mutable");
+ anything = 1;
+ }
+ if (qual & Q_VIRTUAL) {
+ CError_Error(CErrorStr313, "virtual");
+ anything = 1;
+ }
+ if (qual & Q_FRIEND) {
+ CError_Error(CErrorStr313, "friend");
+ anything = 1;
+ }
+ if (qual & Q_IN) {
+ CError_Error(CErrorStr313, "in");
+ anything = 1;
+ }
+ if (qual & Q_OUT) {
+ CError_Error(CErrorStr313, "out");
+ anything = 1;
+ }
+ if (qual & Q_INOUT) {
+ CError_Error(CErrorStr313, "inout");
+ anything = 1;
+ }
+ if (qual & Q_BYCOPY) {
+ CError_Error(CErrorStr313, "bycopy");
+ anything = 1;
+ }
+ if (qual & Q_BYREF) {
+ CError_Error(CErrorStr313, "byref");
+ anything = 1;
+ }
+ if (qual & Q_ONEWAY) {
+ CError_Error(CErrorStr313, "oneway");
+ anything = 1;
+ }
+ if (qual & Q_ALIGNED_MASK) {
+ CError_Error(CErrorStr313, "__attribute__((aligned(?)))");
+ anything = 1;
+ }
+
+ if (!anything)
+ CError_Error(CErrorStr176);
+ }
+}
diff --git a/compiler_and_linker/FrontEnd/C/CException.c b/compiler_and_linker/FrontEnd/C/CException.c
new file mode 100644
index 0000000..d68ce13
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CException.c
@@ -0,0 +1,2183 @@
+#include "compiler/CException.h"
+#include "compiler/CABI.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInline.h"
+#include "compiler/CInit.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CScope.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/Exceptions.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/types.h"
+
+typedef struct UniqueObj {
+ struct UniqueObj *next;
+ Object *object;
+ SInt32 uniqueid;
+} UniqueObj;
+
+ExceptionAction *cexcept_dobjstack;
+Boolean cexcept_hasdobjects;
+Boolean cexcept_magic;
+static UniqueObj *cexcept_uniqueobjs;
+static Boolean cexcept_canthrow;
+static DtorTemp *cexcept_dtortemps;
+static Statement *cexcept_prevstmt;
+static ExceptionAction *cexcept_eabefore;
+static ExceptionAction *cexcept_eaafter;
+static Boolean cexcept_expandtrycatch;
+static Boolean cexcept_hastrycatch;
+static Boolean cexcept_serialize;
+
+// forward decls
+static ENode *CExcept_TempTransExprCond(ENode *expr);
+static ENode *CExcept_TempTransExpr(ENode *expr);
+
+void CExcept_Setup(void) {
+ cexcept_dobjstack = NULL;
+ cexcept_uniqueobjs = NULL;
+ cexcept_hasdobjects = 0;
+ cexcept_magic = 0;
+}
+
+Boolean CExcept_CanThrowException(Object *object, Boolean flag) {
+ if (copts.optEH && IS_TYPE_FUNC(object->type)) {
+ if (flag)
+ return 1;
+
+ if (TYPE_FUNC(object->type)->flags & FUNC_NOTHROW)
+ return 0;
+
+ if (
+ !flag &&
+ TYPE_FUNC(object->type)->exspecs &&
+ TYPE_FUNC(object->type)->exspecs &&
+ !TYPE_FUNC(object->type)->exspecs->type
+ )
+ return 0;
+
+ if (
+ copts.optEH2 &&
+ !(object->qual & Q_MANGLE_NAME) &&
+ object != rt_ptmf_call &&
+ object != rt_ptmf_scall &&
+ object != Rdync_func &&
+ object != rt_som_glue1 &&
+ object != rt_som_glue2 &&
+ object != rt_som_glue3 &&
+ object != carr_func &&
+ object != cnar_func &&
+ object != darr_func &&
+ object != dnar_func &&
+ object != dnar3_func &&
+ object != Xthrw_func
+ )
+ return 0;
+ }
+
+ return 1;
+}
+
+void CExcept_CheckStackRefs(ExceptionAction *actions) {
+ while (actions) {
+ switch (actions->type) {
+ case EAT_DESTROYLOCAL:
+ CInline_ObjectAddrRef(actions->data.destroy_local.dtor);
+ break;
+ case EAT_DESTROYLOCALCOND:
+ CInline_ObjectAddrRef(actions->data.destroy_local_cond.dtor);
+ break;
+ case EAT_DESTROYLOCALOFFSET:
+ CInline_ObjectAddrRef(actions->data.destroy_local_offset.dtor);
+ break;
+ case EAT_DESTROYLOCALPOINTER:
+ CInline_ObjectAddrRef(actions->data.destroy_local_pointer.dtor);
+ break;
+ case EAT_DESTROYLOCALARRAY:
+ CInline_ObjectAddrRef(actions->data.destroy_local_array.dtor);
+ break;
+ case EAT_DESTROYPARTIALARRAY:
+ CInline_ObjectAddrRef(actions->data.destroy_partial_array.dtor);
+ break;
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYBASE:
+ CInline_ObjectAddrRef(actions->data.destroy_member.dtor);
+ break;
+ case EAT_DESTROYMEMBERCOND:
+ CInline_ObjectAddrRef(actions->data.destroy_member_cond.dtor);
+ break;
+ case EAT_DESTROYMEMBERARRAY:
+ CInline_ObjectAddrRef(actions->data.destroy_member_array.dtor);
+ break;
+ case EAT_DELETEPOINTER:
+ case EAT_DELETELOCALPOINTER:
+ CInline_ObjectAddrRef(actions->data.delete_pointer.deletefunc);
+ break;
+ case EAT_DELETEPOINTERCOND:
+ CInline_ObjectAddrRef(actions->data.delete_pointer_cond.deletefunc);
+ break;
+ case EAT_CATCHBLOCK:
+ case EAT_ACTIVECATCHBLOCK:
+ case EAT_SPECIFICATION:
+ case EAT_TERMINATE:
+ break;
+ default:
+ CError_FATAL(192);
+ }
+ actions = actions->prev;
+ }
+}
+
+void CExcept_CompareSpecifications(ExceptSpecList *a, ExceptSpecList *b) {
+ ExceptSpecList *aa;
+ ExceptSpecList *bb;
+
+ aa = a;
+ bb = b;
+ while (1) {
+ if (!aa) {
+ if (!bb)
+ break;
+ CError_Error(CErrorStr265);
+ return;
+ }
+
+ if (!bb) {
+ CError_Error(CErrorStr265);
+ return;
+ }
+
+ aa = aa->next;
+ bb = bb->next;
+ }
+
+ if (a->type == NULL) {
+ if (b->type != NULL)
+ CError_Error(CErrorStr265);
+ } else if (b->type == NULL) {
+ CError_Error(CErrorStr265);
+ } else {
+ for (aa = a; aa; aa = aa->next) {
+ for (bb = b; bb; bb = bb->next) {
+ if (is_typesame(aa->type, bb->type) && aa->qual == bb->qual)
+ break;
+ }
+
+ if (bb == NULL) {
+ CError_Error(CErrorStr265);
+ return;
+ }
+ }
+ }
+}
+
+Boolean CExcept_ActionCompare(ExceptionAction *a, ExceptionAction *b) {
+ if (a->type == b->type) {
+ switch (a->type) {
+ case EAT_DESTROYLOCAL:
+ return a->data.destroy_local.local == b->data.destroy_local.local;
+ case EAT_DESTROYLOCALCOND:
+ return a->data.destroy_local_cond.local == b->data.destroy_local_cond.local;
+ case EAT_DESTROYLOCALOFFSET:
+ return a->data.destroy_local_offset.local == b->data.destroy_local_offset.local &&
+ a->data.destroy_local_offset.offset == b->data.destroy_local_offset.offset;
+ case EAT_DESTROYLOCALPOINTER:
+ return a->data.destroy_local_pointer.pointer == b->data.destroy_local_pointer.pointer;
+ case EAT_DESTROYLOCALARRAY:
+ return a->data.destroy_local_array.localarray == b->data.destroy_local_array.localarray;
+ case EAT_DESTROYPARTIALARRAY:
+ return a->data.destroy_partial_array.arraypointer == b->data.destroy_partial_array.arraypointer;
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYBASE:
+ return a->data.destroy_member.objectptr == b->data.destroy_member.objectptr &&
+ a->data.destroy_member.offset == b->data.destroy_member.offset;
+ case EAT_DESTROYMEMBERCOND:
+ return a->data.destroy_member_cond.objectptr == b->data.destroy_member_cond.objectptr &&
+ a->data.destroy_member_cond.offset == b->data.destroy_member_cond.offset;
+ case EAT_DESTROYMEMBERARRAY:
+ return a->data.destroy_member_array.objectptr == b->data.destroy_member_array.objectptr &&
+ a->data.destroy_member_array.offset == b->data.destroy_member_array.offset;
+ case EAT_DELETEPOINTER:
+ case EAT_DELETELOCALPOINTER:
+ return a->data.delete_pointer.pointerobject == b->data.delete_pointer.pointerobject &&
+ a->data.delete_pointer.deletefunc == b->data.delete_pointer.deletefunc;
+ case EAT_DELETEPOINTERCOND:
+ return a->data.delete_pointer_cond.cond == b->data.delete_pointer_cond.cond;
+ case EAT_CATCHBLOCK:
+ return a->data.catch_block.catch_label == b->data.catch_block.catch_label;
+ case EAT_ACTIVECATCHBLOCK:
+ return a->data.active_catch_block.catch_info_object == b->data.active_catch_block.catch_info_object;
+ case EAT_TERMINATE:
+ return 1;
+ case EAT_SPECIFICATION:
+ return a->data.specification.unexp_id == b->data.specification.unexp_id;
+ default:
+ CError_FATAL(314);
+ }
+ }
+
+ return 0;
+}
+
+int CExcept_IsSubList(ExceptionAction *a, ExceptionAction *b) {
+ int diff;
+ int i;
+ int count1;
+ int count2;
+ ExceptionAction *scan;
+
+ if (a == b)
+ return 0;
+
+ count1 = 0;
+ scan = a;
+ while (scan) {
+ scan = scan->prev;
+ count1++;
+ }
+
+ scan = b;
+ count2 = 0;
+ while (scan) {
+ scan = scan->prev;
+ count2++;
+ }
+
+ diff = count2 - count1;
+ if (diff < 0)
+ return -1;
+
+ for (i = 0; i < diff; i++)
+ b = b->prev;
+
+ while (a != b) {
+ if (!a || !b || !CExcept_ActionCompare(a, b))
+ return -1;
+ a = a->prev;
+ b = b->prev;
+ }
+
+ return diff;
+}
+
+Boolean CExcept_ActionNeedsDestruction(ExceptionAction *action) {
+ switch (action->type) {
+ case EAT_CATCHBLOCK:
+ return 0;
+ case EAT_DESTROYLOCAL:
+ case EAT_DESTROYLOCALOFFSET:
+ case EAT_DESTROYLOCALARRAY:
+ case EAT_DELETELOCALPOINTER:
+ case EAT_ACTIVECATCHBLOCK:
+ return 1;
+ case EAT_NOP:
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYMEMBERCOND:
+ case EAT_DESTROYMEMBERARRAY:
+ case EAT_DESTROYBASE:
+ break;
+ default:
+ CError_FATAL(363);
+ }
+
+ return 0;
+}
+
+ENode *CExcept_RegisterDestructorObject(Object *local, SInt32 offset, Object *dtor, Boolean flag) {
+ ExceptionAction *action;
+ ENode *expr;
+ Object *dtorObject;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ action->prev = cexcept_dobjstack;
+ cexcept_dobjstack = action;
+
+ expr = create_objectrefnode(local);
+ dtorObject = CABI_GetDestructorObject(dtor, CABIDestroy1);
+
+ if (offset == 0) {
+ action->type = EAT_DESTROYLOCAL;
+ action->data.destroy_local.local = local;
+ action->data.destroy_local.dtor = dtorObject;
+ } else {
+ action->type = EAT_DESTROYLOCALOFFSET;
+ action->data.destroy_local_offset.local = local;
+ action->data.destroy_local_offset.dtor = dtorObject;
+ action->data.destroy_local_offset.offset = offset;
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD);
+ }
+
+ cexcept_hasdobjects = 1;
+ return expr;
+}
+
+void CExcept_RegisterLocalArray(Statement *stmt, Object *localarray, Object *dtor, SInt32 elements, SInt32 element_size) {
+ ExceptionAction *action;
+ Object *dtorObject;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ action->prev = cexcept_dobjstack;
+ cexcept_dobjstack = action;
+
+ dtorObject = CABI_GetDestructorObject(dtor, CABIDestroy1);
+
+ action->type = EAT_DESTROYLOCALARRAY;
+ action->data.destroy_local_array.localarray = localarray;
+ action->data.destroy_local_array.dtor = dtorObject;
+ action->data.destroy_local_array.elements = elements;
+ action->data.destroy_local_array.element_size = element_size;
+
+ cexcept_hasdobjects = 1;
+}
+
+void CExcept_RegisterDeleteObject(Statement *stmt, Object *pointerobject, Object *deletefunc) {
+ ExceptionAction *action;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ action->prev = cexcept_dobjstack;
+ cexcept_dobjstack = action;
+
+ action->type = EAT_DELETELOCALPOINTER;
+ action->data.delete_pointer.pointerobject = pointerobject;
+ action->data.delete_pointer.deletefunc = deletefunc;
+
+ cexcept_hasdobjects = 1;
+}
+
+static void CExcept_PatchConstructorAction(Statement *stmt, ExceptionAction *actionArg) {
+ ExceptionAction *action30;
+ ExceptionAction *action;
+ ExceptionAction *scan;
+
+ for (action = stmt->dobjstack; action; action = action->prev) {
+ switch (action->type) {
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYMEMBERCOND:
+ case EAT_DESTROYMEMBERARRAY:
+ case EAT_SPECIFICATION:
+ case EAT_DESTROYBASE:
+ goto exitFirstLoop;
+ case EAT_CATCHBLOCK:
+ action30 = action;
+ while (1) {
+ if (!action30->prev)
+ goto exitFirstLoop;
+ action30 = action30->prev;
+ if (action30->type != EAT_CATCHBLOCK) {
+ CError_FATAL(481);
+ }
+ }
+ }
+ }
+ exitFirstLoop:
+ if (action == NULL) {
+ while (stmt) {
+ if ((scan = stmt->dobjstack)) {
+ while (1) {
+ if (scan == actionArg)
+ break;
+ if (scan->prev == NULL) {
+ scan->prev = actionArg;
+ break;
+ }
+ scan = scan->prev;
+ }
+ } else {
+ stmt->dobjstack = actionArg;
+ }
+ stmt = stmt->next;
+ }
+ } else {
+ actionArg->prev = action;
+ while (stmt) {
+ if (stmt->dobjstack != action) {
+ scan = stmt->dobjstack;
+ do {
+ if (scan == actionArg)
+ goto nextStmt;
+ if (scan->prev == action) {
+ scan->prev = actionArg;
+ goto nextStmt;
+ }
+ } while ((scan = scan->prev));
+
+ while (1) {
+ if (action->type == EAT_CATCHBLOCK && action->prev == NULL)
+ return;
+
+ action = action->prev;
+ if (!action)
+ CError_FATAL(531);
+ }
+ } else {
+ stmt->dobjstack = actionArg;
+ }
+ nextStmt:
+ stmt = stmt->next;
+ }
+ }
+}
+
+void CExcept_Terminate(void) {
+ ExceptionAction *action;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ action->type = EAT_TERMINATE;
+
+ action->prev = cexcept_dobjstack;
+ cexcept_dobjstack = action;
+}
+
+void CExcept_Magic(void) {
+ cexcept_magic = 1;
+}
+
+static Object *CExcept_FindLocalObject(char *name) {
+ NameResult result;
+ NameSpaceObjectList *list;
+
+ list = CScope_FindObjectList(&result, GetHashNameNodeExport(name));
+ if (list && list->object->otype == OT_OBJECT && OBJECT(list->object)->datatype == DLOCAL)
+ return OBJECT(list->object);
+
+ CError_FATAL(580);
+ return NULL;
+}
+
+void CExcept_ArrayInit(void) {
+ ExceptionAction *action;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ action->type = EAT_DESTROYPARTIALARRAY;
+ action->data.destroy_partial_array.arraypointer = CExcept_FindLocalObject("ptr");
+ action->data.destroy_partial_array.arraycounter = CExcept_FindLocalObject("i");
+ action->data.destroy_partial_array.dtor = CExcept_FindLocalObject("dtor");
+ action->data.destroy_partial_array.element_size = CExcept_FindLocalObject("size");
+
+ action->prev = cexcept_dobjstack;
+ cexcept_dobjstack = action;
+}
+
+void CExcept_RegisterMember(Statement *stmt, Object *objectptr, SInt32 offset, Object *dtor, Object *cond, Boolean isMember) {
+ ExceptionAction *action;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ if (cond == NULL) {
+ if (isMember) {
+ action->type = EAT_DESTROYMEMBER;
+ action->data.destroy_member.dtor = CABI_GetDestructorObject(dtor, CABIDestroy1);
+ } else {
+ action->type = EAT_DESTROYBASE;
+ action->data.destroy_member.dtor = CABI_GetDestructorObject(dtor, CABIDestroy0);
+ }
+ action->data.destroy_member.objectptr = objectptr;
+ action->data.destroy_member.offset = offset;
+ } else {
+ CError_ASSERT(632, cond->type == TYPE(&stsignedshort));
+ action->type = EAT_DESTROYMEMBERCOND;
+ action->data.destroy_member_cond.objectptr = objectptr;
+ action->data.destroy_member_cond.cond = cond;
+ action->data.destroy_member_cond.dtor = CABI_GetDestructorObject(dtor, CABIDestroy1);
+ action->data.destroy_member_cond.offset = offset;
+ }
+
+ CExcept_PatchConstructorAction(stmt, action);
+ stmt->flags |= StmtFlag_2;
+}
+
+void CExcept_RegisterMemberArray(Statement *stmt, Object *objectptr, SInt32 offset, Object *dtor, SInt32 elements, SInt32 element_size) {
+ ExceptionAction *action;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ action->type = EAT_DESTROYMEMBERARRAY;
+ action->data.destroy_member_array.objectptr = objectptr;
+ action->data.destroy_member_array.dtor = CABI_GetDestructorObject(dtor, CABIDestroy1);
+ action->data.destroy_member_array.offset = offset;
+ action->data.destroy_member_array.elements = elements;
+ action->data.destroy_member_array.element_size = element_size;
+
+ CExcept_PatchConstructorAction(stmt, action);
+ stmt->flags |= StmtFlag_2;
+}
+
+static Statement *CExcept_DestroyLocal(ExceptionAction *ea, Statement *stmt, Object *object, Object *dtor, SInt32 offset) {
+ ENode *expr;
+
+ expr = create_objectrefnode(object);
+ if (offset)
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD);
+
+ expr = CABI_DestroyObject(dtor, expr, CABIDestroy1, 1, 0);
+
+ CError_ASSERT(687, expr->type == EFUNCCALL && expr->data.funccall.funcref->type == EOBJREF);
+ if (expr->data.funccall.funcref->data.objref->datatype == DVFUNC)
+ expr->data.funccall.funcref->flags |= ENODE_FLAG_80;
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr;
+ stmt->dobjstack = ea->prev;
+ return stmt;
+}
+
+static Statement *CExcept_DestroyLocalPointer(ExceptionAction *ea, Statement *stmt, Object *object, Object *deletefunc) {
+ Statement *newStmt;
+
+ newStmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ newStmt->expr = funccallexpr(deletefunc, create_objectnode2(object), NULL, NULL, NULL);
+ newStmt->dobjstack = ea->prev;
+ return newStmt;
+}
+
+static Statement *CExcept_DestroyLocalArray(ExceptionAction *ea, Statement *stmt, Object *object, Object *dtor, SInt32 elements, SInt32 element_size) {
+ Statement *newStmt;
+ ENode *dtorExpr;
+
+ newStmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+
+ if (dtor)
+ dtorExpr = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1));
+ else
+ dtorExpr = nullnode();
+
+ newStmt->expr = funccallexpr(
+ darr_func,
+ create_objectrefnode(object),
+ dtorExpr,
+ intconstnode(TYPE(&stunsignedlong), element_size),
+ intconstnode(TYPE(&stunsignedlong), elements)
+ );
+
+ newStmt->dobjstack = ea->prev;
+ return newStmt;
+}
+
+static Statement *CExcept_EndCatch(ExceptionAction *ea, Statement *stmt) {
+ stmt = CFunc_InsertStatement(ST_ENDCATCHDTOR, stmt);
+ stmt->expr = create_objectrefnode(ea->data.active_catch_block.catch_info_object);
+ stmt->dobjstack = ea->prev;
+ if (!ea->data.active_catch_block.call_dtor)
+ stmt->type = ST_ENDCATCH;
+ return stmt;
+}
+
+Statement *CExcept_ActionCleanup(ExceptionAction *ea, Statement *stmt) {
+ switch (ea->type) {
+ case EAT_DESTROYLOCALCOND:
+ case EAT_DESTROYLOCALPOINTER:
+ case EAT_DESTROYPARTIALARRAY:
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYMEMBERCOND:
+ case EAT_DESTROYMEMBERARRAY:
+ case EAT_DELETEPOINTER:
+ case EAT_DELETEPOINTERCOND:
+ case EAT_CATCHBLOCK:
+ case EAT_SPECIFICATION:
+ case EAT_TERMINATE:
+ case EAT_DESTROYBASE:
+ break;
+ case EAT_DESTROYLOCAL:
+ stmt = CExcept_DestroyLocal(
+ ea, stmt,
+ ea->data.destroy_local.local,
+ ea->data.destroy_local.dtor,
+ 0);
+ break;
+ case EAT_DESTROYLOCALOFFSET:
+ stmt = CExcept_DestroyLocal(
+ ea, stmt,
+ ea->data.destroy_local.local,
+ ea->data.destroy_local.dtor,
+ ea->data.destroy_local_offset.offset);
+ break;
+ case EAT_DELETELOCALPOINTER:
+ stmt = CExcept_DestroyLocalPointer(
+ ea, stmt,
+ ea->data.delete_pointer.pointerobject,
+ ea->data.delete_pointer.deletefunc);
+ break;
+ case EAT_DESTROYLOCALARRAY:
+ stmt = CExcept_DestroyLocalArray(
+ ea, stmt,
+ ea->data.destroy_local_array.localarray,
+ ea->data.destroy_local_array.dtor,
+ ea->data.destroy_local_array.elements,
+ ea->data.destroy_local_array.element_size);
+ break;
+ case EAT_ACTIVECATCHBLOCK:
+ stmt = CExcept_EndCatch(ea, stmt);
+ break;
+ default:
+ CError_FATAL(827);
+ }
+
+ return stmt;
+}
+
+static void CExcept_MangleNameSpaceName(NameSpace *nspace) {
+ while (nspace) {
+ if (nspace->name) {
+ CExcept_MangleNameSpaceName(nspace->parent);
+ AppendGListName(&name_mangle_list, nspace->name->name);
+ AppendGListName(&name_mangle_list, "::");
+ break;
+ }
+ nspace = nspace->parent;
+ }
+}
+
+static void CExcept_MangleClassName(TypeClass *tclass) {
+ NameSpace *nspace;
+ char buf[64];
+
+ CExcept_MangleNameSpaceName(tclass->nspace->parent);
+ AppendGListName(&name_mangle_list, tclass->classname->name);
+
+ for (nspace = tclass->nspace->parent; nspace; nspace = nspace->parent) {
+ if (!nspace->is_global && !nspace->is_templ && !nspace->name) {
+ CError_ASSERT(868, cscope_currentfunc != NULL);
+
+ sprintf(buf, "*%" PRIxPTR "*%" PRIxPTR "*", &cscope_currentfunc, &nspace);
+ AppendGListName(&name_mangle_list, buf);
+ break;
+ }
+ }
+}
+
+typedef struct BCL {
+ struct BCL *next;
+ TypeClass *tclass;
+ SInt32 offset;
+ Boolean is_virtual;
+ Boolean is_public;
+ Boolean is_ambig;
+} BCL;
+
+static void CExcept_MakeBaseClassListAmbig(BCL *bcl, TypeClass *tclass) {
+ BCL *scan;
+ ClassList *list;
+
+ for (scan = bcl; scan; scan = scan->next) {
+ if (scan->tclass == tclass)
+ scan->is_ambig = 1;
+ }
+
+ for (list = tclass->bases; list; list = list->next)
+ CExcept_MakeBaseClassListAmbig(bcl, list->base);
+}
+
+static BCL *CExcept_GetBaseClassList(BCL *bcl, TypeClass *tclass1, TypeClass *tclass2, SInt32 offset, Boolean is_virtual, Boolean is_public) {
+ BCL *node;
+ ClassList *base;
+ Boolean new_is_public;
+
+ for (node = bcl; node; node = node->next) {
+ if (node->tclass == tclass2) {
+ if (is_virtual && node->is_virtual) {
+ if (is_public)
+ node->is_public = 1;
+ } else {
+ CExcept_MakeBaseClassListAmbig(bcl, tclass2);
+ }
+ return bcl;
+ }
+ }
+
+ node = lalloc(sizeof(BCL));
+ node->tclass = tclass2;
+ node->offset = offset;
+ node->is_virtual = is_virtual;
+ node->is_public = is_public;
+ node->is_ambig = 0;
+ node->next = bcl;
+ bcl = node;
+
+ for (base = tclass2->bases; base; base = base->next) {
+ new_is_public = is_public && (base->access == ACCESSPUBLIC);
+ bcl = base->is_virtual
+ ? CExcept_GetBaseClassList(bcl, tclass1, base->base, CClass_VirtualBaseOffset(tclass1, base->base), 1, new_is_public)
+ : CExcept_GetBaseClassList(bcl, tclass1, base->base, offset + base->offset, 0, new_is_public);
+ }
+
+ return bcl;
+}
+
+static void CExcept_MangleClass(TypeClass *tclass) {
+ BCL *bcl;
+ char buf[20];
+
+ for (bcl = CExcept_GetBaseClassList(NULL, tclass, tclass, 0, 0, 1); bcl; bcl = bcl->next) {
+ if (bcl->is_public && !bcl->is_ambig) {
+ CExcept_MangleClassName(bcl->tclass);
+ AppendGListByte(&name_mangle_list, '!');
+
+ if (bcl->offset) {
+ sprintf(buf, "%" PRId32 "!", bcl->offset);
+ AppendGListName(&name_mangle_list, buf);
+ } else {
+ AppendGListByte(&name_mangle_list, '!');
+ }
+ }
+ }
+}
+
+static ENode *CExcept_GetTypeID(Type *type, UInt32 qual, Boolean flag) {
+ ENode *expr;
+ TypePointer my_tptr;
+
+ if (IS_TYPE_REFERENCE(type))
+ type = TPTR_TARGET(type);
+
+ if (IS_TYPE_CLASS(type) || (IS_TYPE_POINTER_ONLY(type) && IS_TYPE_CLASS(TPTR_TARGET(type)))) {
+ name_mangle_list.size = 0;
+ if (IS_TYPE_POINTER_ONLY(type)) {
+ AppendGListByte(&name_mangle_list, '*');
+ type = TPTR_TARGET(type);
+ } else {
+ AppendGListByte(&name_mangle_list, '!');
+ }
+
+ if (flag) {
+ CExcept_MangleClass(TYPE_CLASS(type));
+ } else {
+ CExcept_MangleClassName(TYPE_CLASS(type));
+ AppendGListByte(&name_mangle_list, '!');
+ }
+ } else {
+ if (IS_TYPE_POINTER_ONLY(type)) {
+ if (TPTR_QUAL(type) & (Q_CONST | Q_VOLATILE)) {
+ my_tptr = *TYPE_POINTER(type);
+ my_tptr.qual = 0;
+ type = TYPE(&my_tptr);
+ }
+ } else {
+ qual = 0;
+ }
+ CMangler_MangleType(type, qual);
+ }
+
+ AppendGListByte(&name_mangle_list, 0);
+
+ expr = CExpr_NewENode(ESTRINGCONST);
+ expr->rtype = CDecl_NewPointerType(TYPE(&stchar));
+ expr->data.string.size = name_mangle_list.size;
+ expr->data.string.data = galloc(name_mangle_list.size);
+ memcpy(expr->data.string.data, *name_mangle_list.data, name_mangle_list.size);
+ return expr;
+}
+
+static Object *CExcept_TypeID(Type *type, UInt32 qual) {
+ ENode *expr = CExcept_GetTypeID(type, qual, 0);
+ CError_ASSERT(1086, expr->type == ESTRINGCONST);
+ return CInit_DeclareString(expr->data.string.data, expr->data.string.size, 0, 0);
+}
+
+void CExcept_ScanExceptionSpecification(TypeFunc *tfunc) {
+ ExceptSpecList *exspecs;
+ ExceptSpecList *exspec;
+ DeclInfo di;
+
+ exspecs = NULL;
+
+ if (lex() != '(') {
+ CError_Error(CErrorStr114);
+ return;
+ }
+
+ if ((tk = lex()) != ')') {
+ while (1) {
+ memclrw(&di, sizeof(di));
+ CParser_GetDeclSpecs(&di, 0);
+ if (di.storageclass)
+ CError_Error(CErrorStr177);
+
+ CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_ALIGNED_MASK));
+
+ scandeclarator(&di);
+ if (di.name)
+ CError_Error(CErrorStr146);
+
+ if (IS_TYPE_POINTER_ONLY(di.thetype)) {
+ if (TPTR_QUAL(di.thetype) & (Q_CONST | Q_VOLATILE)) {
+ TypePointer *newtype = galloc(sizeof(TypePointer));
+ *newtype = *TYPE_POINTER(di.thetype);
+ newtype->qual = 0;
+ di.thetype = TYPE(newtype);
+ }
+ } else {
+ di.qual = 0;
+ }
+
+ for (exspec = exspecs; exspec; exspec = exspec->next) {
+ if (is_typesame(exspec->type, di.thetype) && exspec->qual == di.qual)
+ break;
+ }
+
+ if (!exspec) {
+ exspec = galloc(sizeof(ExceptSpecList));
+ memclrw(exspec, sizeof(ExceptSpecList));
+ exspec->next = exspecs;
+ exspec->type = di.thetype;
+ exspec->qual = di.qual;
+ exspecs = exspec;
+ }
+
+ if (tk == ')')
+ break;
+
+ if (tk != ',') {
+ CError_Error(CErrorStr115);
+ break;
+ }
+
+ tk = lex();
+ }
+ }
+
+ if (!exspecs) {
+ exspecs = galloc(sizeof(ExceptSpecList));
+ memclrw(exspecs, sizeof(ExceptSpecList));
+ }
+ tfunc->exspecs = exspecs;
+ tk = lex();
+}
+
+static ENode *CExcept_CallCopyCtor(Object *object, Type *type, ENode *expr1, ENode *expr2) {
+ ENodeList *list;
+ ENode *expr;
+ FuncArg *arg;
+
+ if (
+ !IS_TYPE_FUNC(object->type) ||
+ !(arg = TYPE_FUNC(object->type)->args) ||
+ !(arg = arg->next)
+ )
+ CError_FATAL(1169);
+
+ expr = funccallexpr(object, expr1, NULL, NULL, NULL);
+ list = expr->data.funccall.args;
+
+ if (TYPE_CLASS(type)->flags & CLASS_HAS_VBASES) {
+ CError_ASSERT(1179, arg = arg->next);
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->next = NULL;
+ list->node = intconstnode(TYPE(&stsignedshort), 1);
+ }
+
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->next = NULL;
+ list->node = expr2;
+
+ while ((arg = arg->next)) {
+ CError_ASSERT(1195, arg->dexpr);
+
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->next = NULL;
+ list->node = CExpr_GetDefaultArgument(expr->data.funccall.funcref, arg);
+ }
+
+ return expr;
+}
+
+ENode *CExcept_ScanThrowExpression(void) {
+ ENode *expr;
+ Object *func;
+ ENode *resultExpr;
+ Object *obj;
+ ENode *thrownExpr;
+ ENode *tempExpr;
+
+ if (!copts.exceptions)
+ CError_Error(CErrorStr252);
+
+ switch ((tk = lex())) {
+ case ')':
+ case ',':
+ case ':':
+ case ';':
+ expr = funccallexpr(Xthrw_func, nullnode(), nullnode(), nullnode(), NULL);
+ break;
+ default:
+ thrownExpr = pointer_generation(assignment_expression());
+ obj = create_temp_object(thrownExpr->rtype);
+ if (!IS_TYPE_CLASS(thrownExpr->rtype) || !(resultExpr = CExpr_IsTempConstruction(thrownExpr, thrownExpr->rtype, &expr))) {
+ tempExpr = create_objectrefnode(obj);
+ if (IS_TYPE_CLASS(thrownExpr->rtype) && (func = CClass_CopyConstructor(TYPE_CLASS(thrownExpr->rtype)))) {
+ resultExpr = CExcept_CallCopyCtor(func, thrownExpr->rtype, tempExpr, getnodeaddress(thrownExpr, 0));
+ } else {
+ if (thrownExpr->rtype->size == 0)
+ CError_Error(CErrorStr146);
+
+ tempExpr = makemonadicnode(tempExpr, EINDIRECT);
+ tempExpr->rtype = thrownExpr->rtype;
+ resultExpr = makediadicnode(tempExpr, thrownExpr, EASS);
+ resultExpr = makediadicnode(resultExpr, create_objectrefnode(obj), ECOMMA);
+ resultExpr->rtype = TYPE(&void_ptr);
+ }
+ } else {
+ *expr = *create_objectrefnode(obj);
+ }
+
+ expr = CExcept_GetTypeID(thrownExpr->rtype, ENODE_QUALS(thrownExpr), 1);
+ if (IS_TYPE_CLASS(thrownExpr->rtype) && (func = CClass_Destructor(TYPE_CLASS(thrownExpr->rtype)))) {
+ expr = funccallexpr(
+ Xthrw_func,
+ expr,
+ resultExpr,
+ create_objectrefnode(CABI_GetDestructorObject(func, CABIDestroy1)),
+ NULL);
+ } else {
+ expr = funccallexpr(
+ Xthrw_func,
+ expr,
+ resultExpr,
+ nullnode(),
+ NULL);
+ }
+ }
+
+ expr->flags |= ENODE_FLAG_VOLATILE;
+ return expr;
+}
+
+static Boolean CExcept_MightNeedDtor(Type *type) {
+ if (type) {
+ if (IS_TYPE_CLASS(type)) {
+ if (!CClass_Destructor(TYPE_CLASS(type)))
+ return 0;
+ } else if (IS_TYPE_POINTER_ONLY(type)) {
+ if (!(TPTR_QUAL(type) & Q_REFERENCE) || !IS_TYPE_CLASS(TPTR_TARGET(type)))
+ return 0;
+ } else {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+typedef struct CatchBlock {
+ struct CatchBlock *next;
+ Object *catch_object;
+ Object *catch_info_object;
+ Statement *stmt;
+ Statement *anotherStmt;
+ Type *type;
+ UInt32 qual;
+} CatchBlock;
+
+static void CExcept_PatchDObjStack(Statement *beginCatchStmt, Statement *tryEndStmt, Statement *endStmt, CatchBlock *catchBlock) {
+ ExceptionAction *ea;
+ ExceptionAction *stackHead;
+ ExceptionAction *stackTail;
+ ExceptionAction *firstEA;
+ Statement *stmt;
+ Object *catch_info_object;
+ Boolean call_dtor;
+
+ catch_info_object = catchBlock->catch_info_object;
+ call_dtor = 0;
+ stackHead = stackTail = beginCatchStmt->dobjstack;
+ firstEA = NULL;
+
+ while (catchBlock) {
+ ea = lalloc(sizeof(ExceptionAction));
+ memclrw(ea, sizeof(ExceptionAction));
+
+ ea->prev = stackTail;
+ stackTail = ea;
+
+ if (!firstEA)
+ firstEA = ea;
+
+ ea->type = EAT_CATCHBLOCK;
+ ea->data.catch_block.catch_object = catchBlock->catch_object;
+ ea->data.catch_block.catch_label = catchBlock->stmt->label;
+ if (catchBlock->type)
+ ea->data.catch_block.catch_typeid = CExcept_TypeID(catchBlock->type, catchBlock->qual);
+ ea->data.catch_block.catch_info_object = catch_info_object;
+
+ if (!call_dtor && CExcept_MightNeedDtor(catchBlock->type))
+ call_dtor = 1;
+
+ ea->data.catch_block.catch_type = catchBlock->type;
+ ea->data.catch_block.catch_qual = catchBlock->qual;
+ catchBlock = catchBlock->next;
+ }
+
+ stmt = beginCatchStmt;
+ while (1) {
+ if ((ea = stmt->dobjstack) != stackHead) {
+ while (1) {
+ CError_ASSERT(1404, ea);
+ if (ea->prev == stackTail)
+ break;
+ if (ea->prev == stackHead) {
+ ea->prev = stackTail;
+ break;
+ }
+ ea = ea->prev;
+ }
+ } else {
+ stmt->dobjstack = stackTail;
+ }
+
+ if (stmt == endStmt)
+ break;
+
+ if (stmt == tryEndStmt) {
+ ea = lalloc(sizeof(ExceptionAction));
+ memclrw(ea, sizeof(ExceptionAction));
+ ea->prev = stackHead;
+ ea->type = EAT_ACTIVECATCHBLOCK;
+ ea->data.active_catch_block.catch_info_object = catch_info_object;
+ ea->data.active_catch_block.call_dtor = call_dtor;
+ stackTail = ea;
+ }
+
+ stmt = stmt->next;
+ CError_ASSERT(1426, stmt);
+ }
+
+ cexcept_hasdobjects = 1;
+}
+
+static void CExcept_CheckTryObjects(ENode *expr) {
+ if (expr->data.objref->datatype == DLOCAL && expr->data.objref->u.var.info)
+ expr->data.objref->u.var.info->noregister = 1;
+}
+
+static ENode *CExcept_CatchExpressionInit(DeclInfo *di, CatchBlock *catchBlock) {
+ Object *catch_object;
+ Object *copyCtor;
+ Object *dtor;
+ ENode *expr;
+
+ if (CScope_FindName(cscope_current, di->name))
+ CError_Error(CErrorStr122, di->name->name);
+
+ catch_object = CParser_NewLocalDataObject(di, 1);
+ CFunc_SetupLocalVarInfo(catch_object);
+ CScope_AddObject(cscope_current, di->name, OBJ_BASE(catch_object));
+ catchBlock->catch_object = catch_object;
+
+ expr = makediadicnode(
+ create_objectrefnode(catchBlock->catch_info_object),
+ intconstnode(TYPE(&stunsignedlong), 12),
+ EADD);
+ expr->rtype = CDecl_NewPointerType(CDecl_NewPointerType(di->thetype));
+
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = CDecl_NewPointerType(di->thetype);
+
+ if (IS_TYPE_REFERENCE(di->thetype))
+ return makediadicnode(create_objectnode2(catch_object), expr, EASS);
+
+ if (IS_TYPE_CLASS(di->thetype) && (copyCtor = CClass_CopyConstructor(TYPE_CLASS(di->thetype)))) {
+ dtor = CClass_Destructor(TYPE_CLASS(di->thetype));
+ return CExcept_CallCopyCtor(
+ copyCtor,
+ di->thetype,
+ (dtor == NULL) ? create_objectrefnode(catch_object) : CExcept_RegisterDestructorObject(catch_object, 0, dtor, 0),
+ expr);
+ }
+
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = di->thetype;
+ return makediadicnode(create_objectnode(catch_object), expr, EASS);
+}
+
+void CExcept_ScanTryBlock(DeclThing *dt, Boolean flag) {
+ Object *catch_info_object; // r27
+ Statement *beginCatchStmt; // r14
+ Statement *tryEndStmt; // r16
+ Statement *endStmt; // r17
+ Statement *stmt; // r14
+ CLabel *catchEndLabel; // r19
+ CLabel *endLabel; // r24
+ CatchBlock *catchStack; // r23
+ CatchBlock *catchBlock; // r22
+ DeclBlock *declBlock; // r20
+ DeclInfo di;
+
+ if (!copts.exceptions)
+ CError_Error(CErrorStr252);
+
+ catch_info_object = create_temp_object(TYPE(&catchinfostruct));
+ if (cexcept_magic) {
+ catch_info_object->name = GetHashNameNodeExport("__exception_magic");
+ CScope_AddObject(cscope_current, catch_info_object->name, OBJ_BASE(catch_info_object));
+ }
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->flags = StmtFlag_1;
+ stmt->label = newlabel();
+ stmt->label->stmt = stmt;
+
+ beginCatchStmt = CFunc_AppendStatement(ST_BEGINCATCH);
+ beginCatchStmt->expr = create_objectrefnode(catch_info_object);
+
+ if (tk != '{') {
+ CError_Error(CErrorStr135);
+ return;
+ }
+
+ CFunc_CompoundStatement(dt);
+
+ if (tk != TK_CATCH) {
+ CError_Error(CErrorStr242);
+ return;
+ }
+
+ stmt = CFunc_AppendStatement(ST_GOTO);
+ catchEndLabel = stmt->label = newlabel();
+ tryEndStmt = stmt;
+
+ endLabel = newlabel();
+ catchStack = NULL;
+
+ while (1) {
+ CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath);
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->flags = StmtFlag_1;
+ stmt->label = newlabel();
+ stmt->label->stmt = stmt;
+
+ declBlock = NULL;
+
+ catchBlock = lalloc(sizeof(ExceptionAction));
+ memclrw(catchBlock, sizeof(ExceptionAction));
+ catchBlock->next = catchStack;
+ catchStack = catchBlock;
+
+ catchBlock->stmt = stmt;
+ catchBlock->catch_info_object = catch_info_object;
+
+ if ((tk = lex()) != '(') {
+ CError_Error(CErrorStr114);
+ break;
+ }
+
+ if ((tk = lex()) == TK_ELLIPSIS) {
+ tk = lex();
+ } else {
+ memclrw(&di, sizeof(di));
+ CParser_GetDeclSpecs(&di, 0);
+
+ if (di.x48)
+ CError_Error(CErrorStr121);
+ if (di.storageclass)
+ CError_Error(CErrorStr177);
+
+ CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_ALIGNED_MASK));
+
+ scandeclarator(&di);
+
+ if (IS_TYPE_FUNC(di.thetype))
+ di.thetype = CDecl_NewPointerType(di.thetype);
+ else if (IS_TYPE_ARRAY(di.thetype))
+ di.thetype = CDecl_NewPointerType(TPTR_TARGET(di.thetype));
+
+ IsCompleteType(di.thetype);
+ if (IS_TYPE_CLASS(di.thetype) && (TYPE_CLASS(di.thetype)->flags & CLASS_ABSTRACT))
+ CError_AbstractClassError(TYPE_CLASS(di.thetype));
+
+ catchBlock->type = di.thetype;
+ catchBlock->qual = di.qual;
+
+ if (di.name) {
+ ENode *expr;
+ declBlock = CFunc_NewDeclBlock();
+ expr = CExcept_CatchExpressionInit(&di, catchBlock);
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = expr;
+ }
+ }
+
+ if (tk != ')') {
+ CError_Error(CErrorStr115);
+ break;
+ }
+
+ if ((tk = lex()) != '{') {
+ CError_Error(CErrorStr123);
+ break;
+ }
+
+ CFunc_CompoundStatement(dt);
+ if (flag) {
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = funccallexpr(Xthrw_func, nullnode(), nullnode(), nullnode(), NULL);
+ }
+
+ catchBlock->anotherStmt = stmt;
+
+ if (declBlock)
+ CFunc_RestoreBlock(declBlock);
+
+ if (tk != TK_CATCH)
+ break;
+
+ CFunc_AppendStatement(ST_GOTO)->label = endLabel;
+ }
+
+ endStmt = CFunc_AppendStatement(ST_LABEL);
+ endStmt->label = endLabel;
+ endLabel->stmt = endStmt;
+
+ CExcept_PatchDObjStack(beginCatchStmt, tryEndStmt, endStmt, catchBlock);
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = catchEndLabel;
+ catchEndLabel->stmt = stmt;
+}
+
+static Statement *CExcept_InsertPrevStatement(StatementType sttype) {
+ Statement *stmt = CFunc_InsertStatement(sttype, cexcept_prevstmt);
+ stmt->sourceoffset = stmt->next->sourceoffset;
+ stmt->sourcefilepath = stmt->next->sourcefilepath;
+ stmt->dobjstack = cexcept_eabefore;
+ return stmt;
+}
+
+static Object *CExcept_GetETEMPObject(ENode *expr) {
+ UniqueObj *uobj;
+ SInt32 id;
+
+ if ((id = expr->data.temp.uniqueid)) {
+ for (uobj = cexcept_uniqueobjs; uobj; uobj = uobj->next) {
+ if (uobj->uniqueid == id)
+ return uobj->object;
+ }
+
+ uobj = galloc(sizeof(UniqueObj));
+ uobj->next = cexcept_uniqueobjs;
+ cexcept_uniqueobjs = uobj;
+ uobj->uniqueid = id;
+ return (uobj->object = create_temp_object(expr->data.temp.type));
+ } else {
+ return create_temp_object(expr->data.temp.type);
+ }
+}
+
+static ENode *CExcept_TempTrans_ETEMP(ENode *expr) {
+ Object *object;
+ ExceptionAction *ea;
+ DtorTemp *dtorTemp;
+ Object *dtor;
+
+ object = CExcept_GetETEMPObject(expr);
+ if (expr->data.temp.needs_dtor) {
+ dtorTemp = lalloc(sizeof(DtorTemp));
+ dtorTemp->next = cexcept_dtortemps;
+ cexcept_dtortemps = dtorTemp;
+ dtorTemp->object = object;
+ dtorTemp->temp = NULL;
+
+ if (
+ !IS_TYPE_CLASS(expr->data.temp.type) ||
+ !(dtorTemp->dtor = CClass_Destructor(TYPE_CLASS(expr->data.temp.type)))
+ )
+ CError_FATAL(1749);
+
+ ea = lalloc(sizeof(ExceptionAction));
+ ea->prev = cexcept_eabefore;
+ cexcept_eabefore = ea;
+ ea->type = EAT_DESTROYLOCAL;
+ ea->data.destroy_local.local = dtorTemp->object;
+ ea->data.destroy_local.dtor = CABI_GetDestructorObject(dtorTemp->dtor, CABIDestroy1);
+
+ ea = lalloc(sizeof(ExceptionAction));
+ *ea = *cexcept_eabefore;
+ ea->prev = cexcept_eaafter;
+ cexcept_eaafter = ea;
+ }
+
+ expr->type = EOBJREF;
+ expr->data.objref = object;
+ return expr;
+}
+
+static ENode *CExcept_TransNewException(ENode *expr, Boolean isCond) {
+ Object *tempObj;
+ CLabel *label;
+ Boolean isArray;
+ Statement *stmt;
+ ExceptionAction *ea;
+ ENode *result;
+
+ isArray = expr->type == ENEWEXCEPTIONARRAY;
+
+ if (isCond) {
+ expr->data.newexception.initexpr = CExcept_TempTransExprCond(expr->data.newexception.initexpr);
+ expr->data.newexception.tryexpr = CExcept_TempTransExprCond(expr->data.newexception.tryexpr);
+ tempObj = create_temp_object(TYPE(&stchar));
+
+ stmt = CExcept_InsertPrevStatement(ST_EXPRESSION);
+ stmt->expr = makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 0), EASS);
+ cexcept_prevstmt = stmt;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ ea->prev = cexcept_eabefore;
+ cexcept_eabefore = ea;
+
+ ea->type = EAT_DELETEPOINTERCOND;
+ ea->data.delete_pointer_cond.pointerobject = expr->data.newexception.pointertemp;
+ ea->data.delete_pointer_cond.deletefunc = expr->data.newexception.deletefunc;
+ ea->data.delete_pointer_cond.cond = tempObj;
+
+ if (isArray) {
+ result = makediadicnode(
+ makediadicnode(
+ expr->data.newexception.initexpr,
+ makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 1), EASS),
+ ECOMMA
+ ),
+ expr->data.newexception.tryexpr,
+ ECOMMA
+ );
+
+ result = makediadicnode(
+ result,
+ makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 0), EASS),
+ ECOMMA
+ );
+
+ result = makediadicnode(
+ result,
+ create_objectnode(expr->data.newexception.pointertemp),
+ ECOMMA
+ );
+ } else {
+ result = makediadicnode(
+ makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 1), EASS),
+ expr->data.newexception.tryexpr,
+ ECOMMA
+ );
+
+ result = makediadicnode(
+ expr->data.newexception.initexpr,
+ makediadicnode(
+ result,
+ makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 0), EASS),
+ ECOMMA
+ ),
+ ELAND
+ );
+
+ result = makediadicnode(
+ result,
+ create_objectnode(expr->data.newexception.pointertemp),
+ ECOMMA
+ );
+ }
+ } else {
+ expr->data.newexception.initexpr = CExcept_TempTransExpr(expr->data.newexception.initexpr);
+ expr->data.newexception.tryexpr = CExcept_TempTransExpr(expr->data.newexception.tryexpr);
+
+ if (isArray) {
+ stmt = CExcept_InsertPrevStatement(ST_EXPRESSION);
+ stmt->expr = expr->data.newexception.initexpr;
+ } else {
+ stmt = CExcept_InsertPrevStatement(ST_IFNGOTO);
+ stmt->expr = expr->data.newexception.initexpr;
+ label = newlabel();
+ stmt->label = label;
+ }
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr->data.newexception.tryexpr;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ ea->prev = cexcept_eabefore;
+ ea->type = EAT_DELETEPOINTER;
+ ea->data.delete_pointer.pointerobject = expr->data.newexception.pointertemp;
+ ea->data.delete_pointer.deletefunc = expr->data.newexception.deletefunc;
+ stmt->dobjstack = ea;
+
+ if (!isArray) {
+ stmt = CFunc_InsertStatement(ST_LABEL, stmt);
+ stmt->label = label;
+ label->stmt = stmt;
+ stmt->dobjstack = cexcept_eabefore;
+ }
+
+ cexcept_prevstmt = stmt;
+ result = create_objectnode(expr->data.newexception.pointertemp);
+ }
+
+ result->rtype = expr->rtype;
+ return result;
+}
+
+static ENode *CExcept_TransInitTryCatch(ENode *expr, Boolean isCond) {
+ CLabel *label1;
+ CLabel *label2;
+ CLabel *label3;
+ Object *catch_info_object;
+ Statement *stmt;
+ ExceptionAction *ea;
+
+ cexcept_hastrycatch = 1;
+
+ if (isCond) {
+ CError_ASSERT(1877, !cexcept_expandtrycatch);
+
+ cexcept_serialize = 1;
+ expr->data.itc.initexpr = CExcept_TempTransExprCond(expr->data.itc.initexpr);
+ expr->data.itc.tryexpr = CExcept_TempTransExprCond(expr->data.itc.tryexpr);
+ expr->data.itc.catchexpr = CExcept_TempTransExprCond(expr->data.itc.catchexpr);
+ expr->data.itc.result = CExcept_TempTransExprCond(expr->data.itc.result);
+ return expr;
+ }
+
+ expr->data.itc.initexpr = CExcept_TempTransExpr(expr->data.itc.initexpr);
+ expr->data.itc.tryexpr = CExcept_TempTransExpr(expr->data.itc.tryexpr);
+ expr->data.itc.catchexpr = CExcept_TempTransExpr(expr->data.itc.catchexpr);
+ expr->data.itc.result = CExcept_TempTransExpr(expr->data.itc.result);
+
+ if (!cexcept_expandtrycatch)
+ return expr;
+
+ label1 = newlabel();
+ label2 = newlabel();
+ label3 = newlabel();
+
+ catch_info_object = create_temp_object(TYPE(&catchinfostruct));
+
+ stmt = CExcept_InsertPrevStatement(ST_IFNGOTO);
+ stmt->expr = expr->data.itc.initexpr;
+ stmt->label = label3;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ memclrw(ea, sizeof(ExceptionAction));
+ ea->type = EAT_CATCHBLOCK;
+ ea->data.catch_block.catch_label = label2;
+ ea->data.catch_block.catch_info_object = catch_info_object;
+ ea->prev = stmt->dobjstack;
+
+ stmt = CFunc_InsertStatement(ST_LABEL, stmt);
+ stmt->flags = StmtFlag_1;
+ stmt->label = label1;
+ label1->stmt = stmt;
+ stmt->dobjstack = ea;
+
+ stmt = CFunc_InsertStatement(ST_BEGINCATCH, stmt);
+ stmt->expr = create_objectrefnode(catch_info_object);
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr->data.itc.tryexpr;
+
+ stmt = CFunc_InsertStatement(ST_GOTO, stmt);
+ stmt->label = label3;
+
+ CError_ASSERT(1928, stmt->dobjstack == ea);
+
+ stmt->dobjstack = ea->prev;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ memclrw(ea, sizeof(ExceptionAction));
+ ea->type = EAT_ACTIVECATCHBLOCK;
+ ea->data.active_catch_block.catch_info_object = catch_info_object;
+ ea->prev = stmt->dobjstack;
+
+ stmt = CFunc_InsertStatement(ST_LABEL, stmt);
+ stmt->flags = StmtFlag_1;
+ stmt->label = label2;
+ label2->stmt = stmt;
+ stmt->dobjstack = ea;
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr->data.itc.catchexpr;
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = funccallexpr(Xthrw_func, nullnode(), nullnode(), nullnode(), NULL);
+
+ stmt = CFunc_InsertStatement(ST_LABEL, stmt);
+ stmt->label = label3;
+ label3->stmt = stmt;
+
+ CError_ASSERT(1968, stmt->dobjstack == ea);
+
+ stmt->dobjstack = ea->prev;
+
+ cexcept_prevstmt = stmt;
+ return expr->data.itc.result;
+}
+
+static ENode *CExcept_TempTransFuncCall(ENode *expr, Boolean isCond) {
+ ENodeList *tempArg;
+ ENodeList **argArray;
+ ENodeList *args;
+ ExceptionAction *ea;
+ Statement *stmt;
+ DtorTemp *dtorTemp;
+ ENode *tempNode;
+
+ tempArg = NULL;
+ if ((args = expr->data.funccall.args)) {
+ tempNode = args->node;
+ if (tempNode->type == ETEMP) {
+ if (tempNode->data.temp.needs_dtor)
+ tempArg = args;
+ } else if (args->next) {
+ tempNode = args->next->node;
+ if (tempNode->type == ETEMP) {
+ if (tempNode->data.temp.needs_dtor)
+ tempArg = args->next;
+ }
+ }
+ }
+
+ if (tempArg) {
+ if (isCond) {
+ ENodeList *arg = args;
+ SInt32 i = 0;
+ while (arg) {
+ arg = arg->next;
+ i++;
+ }
+
+ argArray = lalloc(sizeof(ENodeList *) * i);
+ for (args = expr->data.funccall.args, i = 0; args; args = args->next)
+ argArray[i++] = args;
+
+ while (i > 0) {
+ i--;
+ if (argArray[i] != tempArg)
+ argArray[i]->node = CExcept_TempTransExprCond(argArray[i]->node);
+ }
+ } else {
+ while (args) {
+ if (args != tempArg)
+ args->node = CExcept_TempTransExpr(args->node);
+ args = args->next;
+ }
+ }
+
+ dtorTemp = lalloc(sizeof(DtorTemp));
+ dtorTemp->next = cexcept_dtortemps;
+ cexcept_dtortemps = dtorTemp;
+
+ dtorTemp->object = CExcept_GetETEMPObject(tempNode);
+ dtorTemp->temp = NULL;
+
+ if (
+ !IS_TYPE_CLASS(tempNode->data.temp.type) ||
+ !(dtorTemp->dtor = CClass_Destructor(TYPE_CLASS(tempNode->data.temp.type)))
+ )
+ CError_FATAL(2046);
+
+ tempNode->type = EOBJREF;
+ tempNode->data.objref = dtorTemp->object;
+
+ if (isCond) {
+ Type *type24 = expr->rtype;
+ dtorTemp->temp = create_temp_object(TYPE(&stchar));
+
+ expr = makediadicnode(
+ expr,
+ makediadicnode(create_objectnode(dtorTemp->temp), intconstnode(TYPE(&stchar), 1), EASS),
+ ECOMMA
+ );
+
+ expr = makediadicnode(
+ expr,
+ create_objectrefnode(dtorTemp->object),
+ ECOMMA
+ );
+ expr->rtype = type24;
+
+ stmt = CExcept_InsertPrevStatement(ST_EXPRESSION);
+ stmt->expr = makediadicnode(
+ create_objectnode(dtorTemp->temp),
+ intconstnode(TYPE(&stchar), 0),
+ EASS
+ );
+ cexcept_prevstmt = stmt;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ ea->prev = cexcept_eabefore;
+ cexcept_eabefore = ea;
+
+ ea->type = EAT_DESTROYLOCALCOND;
+ ea->data.destroy_local_cond.local = dtorTemp->object;
+ ea->data.destroy_local_cond.dtor = CABI_GetDestructorObject(dtorTemp->dtor, CABIDestroy1);
+ ea->data.destroy_local_cond.cond = dtorTemp->temp;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ *ea = *cexcept_eabefore;
+ ea->prev = cexcept_eaafter;
+ cexcept_eaafter = ea;
+ } else {
+ stmt = CExcept_InsertPrevStatement(ST_EXPRESSION);
+ stmt->expr = expr;
+ cexcept_prevstmt = stmt;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ ea->prev = cexcept_eabefore;
+ cexcept_eabefore = ea;
+
+ ea->type = EAT_DESTROYLOCAL;
+ ea->data.destroy_local.local = dtorTemp->object;
+ ea->data.destroy_local.dtor = CABI_GetDestructorObject(dtorTemp->dtor, CABIDestroy1);
+
+ ea = lalloc(sizeof(ExceptionAction));
+ *ea = *cexcept_eabefore;
+ ea->prev = cexcept_eaafter;
+ cexcept_eaafter = ea;
+
+ expr = lalloc(sizeof(ENode));
+ *expr = *stmt->expr;
+ expr->type = EOBJREF;
+ expr->data.objref = tempArg->node->data.objref;
+ }
+ return expr;
+ } else {
+ if (isCond) {
+ SInt32 i = 0;
+ while (args) {
+ args = args->next;
+ i++;
+ }
+
+ argArray = lalloc(sizeof(ENodeList *) * i);
+ for (args = expr->data.funccall.args, i = 0; args; args = args->next)
+ argArray[i++] = args;
+
+ while (i > 0) {
+ i--;
+ argArray[i]->node = CExcept_TempTransExprCond(argArray[i]->node);
+ }
+
+ expr->data.funccall.funcref = CExcept_TempTransExprCond(expr->data.funccall.funcref);
+ } else {
+ while (args) {
+ args->node = CExcept_TempTransExpr(args->node);
+ args = args->next;
+ }
+
+ expr->data.funccall.funcref = CExcept_TempTransExpr(expr->data.funccall.funcref);
+ }
+
+ return expr;
+ }
+}
+
+static ENode *CExcept_TempTransExprCond(ENode *expr) {
+ switch (expr->type) {
+ case ETEMP:
+ return CExcept_TempTrans_ETEMP(expr);
+ case ENEWEXCEPTION:
+ case ENEWEXCEPTIONARRAY:
+ return CExcept_TransNewException(expr, 1);
+ case EINITTRYCATCH:
+ return CExcept_TransInitTryCatch(expr, 1);
+ case ENULLCHECK:
+ expr->data.nullcheck.nullcheckexpr = CExcept_TempTransExprCond(expr->data.nullcheck.nullcheckexpr);
+ expr->data.nullcheck.condexpr = CExcept_TempTransExprCond(expr->data.nullcheck.condexpr);
+ return expr;
+ case ECOND:
+ expr->data.cond.cond = CExcept_TempTransExprCond(expr->data.cond.cond);
+ expr->data.cond.expr1 = CExcept_TempTransExprCond(expr->data.cond.expr1);
+ expr->data.cond.expr2 = CExcept_TempTransExprCond(expr->data.cond.expr2);
+ return expr;
+ case ELAND:
+ case ELOR:
+ expr->data.diadic.left = CExcept_TempTransExprCond(expr->data.diadic.left);
+ expr->data.diadic.right = CExcept_TempTransExprCond(expr->data.diadic.right);
+ return expr;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ return CExcept_TempTransFuncCall(expr, 1);
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ 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 EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case ECOMMA:
+ case EROTL:
+ case EROTR:
+ expr->data.diadic.left = CExcept_TempTransExprCond(expr->data.diadic.left);
+ expr->data.diadic.right = CExcept_TempTransExprCond(expr->data.diadic.right);
+ return expr;
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EINDIRECT:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case ETYPCON:
+ case EBITFIELD:
+ expr->data.monadic = CExcept_TempTransExprCond(expr->data.monadic);
+ return expr;
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EPRECOMP:
+ case ELABEL:
+ case EINSTRUCTION:
+ case EVECTOR128CONST:
+ return expr;
+ default:
+ CError_FATAL(2236);
+ return expr;
+ }
+}
+
+static ENode *CExcept_TempTransExpr(ENode *expr) {
+ switch (expr->type) {
+ case ETEMP:
+ return CExcept_TempTrans_ETEMP(expr);
+ case ENEWEXCEPTION:
+ case ENEWEXCEPTIONARRAY:
+ return CExcept_TransNewException(expr, 0);
+ case EINITTRYCATCH:
+ return CExcept_TransInitTryCatch(expr, 0);
+ case ENULLCHECK:
+ expr->data.nullcheck.nullcheckexpr = CExcept_TempTransExpr(expr->data.nullcheck.nullcheckexpr);
+ expr->data.nullcheck.condexpr = CExcept_TempTransExprCond(expr->data.nullcheck.condexpr);
+ return expr;
+ case ECOND:
+ expr->data.cond.cond = CExcept_TempTransExpr(expr->data.cond.cond);
+ expr->data.cond.expr1 = CExcept_TempTransExprCond(expr->data.cond.expr1);
+ expr->data.cond.expr2 = CExcept_TempTransExprCond(expr->data.cond.expr2);
+ return expr;
+ case ELAND:
+ case ELOR:
+ case ECOMMA:
+ expr->data.diadic.left = CExcept_TempTransExpr(expr->data.diadic.left);
+ expr->data.diadic.right = CExcept_TempTransExprCond(expr->data.diadic.right);
+ return expr;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ return CExcept_TempTransFuncCall(expr, 0);
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ 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 EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case EROTL:
+ case EROTR:
+ expr->data.diadic.left = CExcept_TempTransExpr(expr->data.diadic.left);
+ expr->data.diadic.right = CExcept_TempTransExpr(expr->data.diadic.right);
+ return expr;
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EINDIRECT:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case ETYPCON:
+ case EBITFIELD:
+ expr->data.monadic = CExcept_TempTransExpr(expr->data.monadic);
+ return expr;
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EMFPOINTER:
+ case EPRECOMP:
+ case ELABEL:
+ case EOBJLIST:
+ case EMEMBER:
+ case EINSTRUCTION:
+ case EVECTOR128CONST:
+ return expr;
+ default:
+ CError_FATAL(2350);
+ return expr;
+ }
+}
+
+static Statement *CExcept_DtorTransform(Statement *stmt) {
+ DtorTemp *dtorTemp;
+ Statement *curStmt;
+ CLabel *lastLabel;
+
+ dtorTemp = cexcept_dtortemps;
+ curStmt = stmt;
+ while (dtorTemp) {
+ if (
+ cexcept_eaafter &&
+ (cexcept_eaafter->type == EAT_DESTROYLOCAL || cexcept_eaafter->type == EAT_DESTROYLOCALCOND) &&
+ cexcept_eaafter->data.destroy_local.local == dtorTemp->object
+ )
+ {
+ cexcept_eaafter = cexcept_eaafter->prev;
+ } else {
+ CError_FATAL(2374);
+ }
+
+ if (dtorTemp->temp) {
+ curStmt = CFunc_InsertStatement(ST_IFNGOTO, curStmt);
+ curStmt->expr = create_objectnode(dtorTemp->temp);
+ curStmt->dobjstack = cexcept_eaafter;
+ lastLabel = curStmt->label = newlabel();
+ }
+
+ curStmt = CFunc_InsertStatement(ST_EXPRESSION, curStmt);
+ curStmt->expr = CABI_DestroyObject(dtorTemp->dtor, create_objectrefnode(dtorTemp->object), CABIDestroy1, 1, 0);
+ curStmt->dobjstack = cexcept_eaafter;
+
+ if (dtorTemp->temp) {
+ curStmt = CFunc_InsertStatement(ST_LABEL, curStmt);
+ curStmt->label = lastLabel;
+ lastLabel->stmt = curStmt;
+ }
+
+ dtorTemp = dtorTemp->next;
+ }
+
+ return curStmt;
+}
+
+static void CExcept_TempTransform(Statement *stmt, Boolean flag1, Boolean flag2) {
+ Statement *prevStmt;
+ Statement *iter;
+ Statement copy;
+ Object *tempObj;
+
+ prevStmt = cexcept_prevstmt;
+ cexcept_dtortemps = NULL;
+ cexcept_serialize = 0;
+ cexcept_expandtrycatch = 0;
+ cexcept_hastrycatch = 0;
+ stmt->expr = CExcept_TempTransExpr(stmt->expr);
+
+ if (cexcept_hastrycatch) {
+ cexcept_expandtrycatch = 1;
+ if (cexcept_serialize) {
+ CInline_SerializeStatement(stmt);
+ cexcept_prevstmt = stmt;
+ } else {
+ cexcept_prevstmt = prevStmt;
+ }
+
+ iter = prevStmt;
+ while (1) {
+ CError_ASSERT(2425, iter);
+
+ switch (iter->type) {
+ case ST_RETURN:
+ CError_ASSERT(2429, iter->expr != NULL);
+ case ST_EXPRESSION:
+ case ST_SWITCH:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ iter->expr = CExcept_TempTransExpr(iter->expr);
+ }
+
+ if (iter == stmt)
+ break;
+ cexcept_prevstmt = iter;
+ iter = iter->next;
+ }
+ }
+
+ if (cexcept_dtortemps) {
+ if (!flag1) {
+ if (flag2) {
+ ENode *expr = stmt->expr;
+ CError_ASSERT(2456, !IS_TYPE_CLASS(expr->rtype) || !CClass_Destructor(TYPE_CLASS(expr->rtype)));
+
+ tempObj = create_temp_object(expr->rtype);
+ stmt->expr = makediadicnode(create_objectnode(tempObj), expr, EASS);
+ }
+
+ copy = *stmt;
+ stmt->type = ST_EXPRESSION;
+ stmt = CExcept_DtorTransform(stmt);
+ stmt = CFunc_InsertStatement(copy.type, stmt);
+ stmt->label = copy.label;
+
+ if (flag2)
+ stmt->expr = create_objectnode(tempObj);
+ else
+ stmt->expr = nullnode();
+ } else {
+ CExcept_DtorTransform(stmt);
+ }
+ }
+}
+
+static void CExcept_CleanupExceptionActions(Statement *stmt) {
+ Statement *iter;
+ ENode *expr;
+ ExceptionAction *ea;
+
+ cexcept_prevstmt = stmt;
+ for (iter = stmt; iter; iter = iter->next) {
+ cexcept_eabefore = cexcept_eaafter = ea = iter->dobjstack;
+
+ if (iter->flags & StmtFlag_2) {
+ cexcept_eabefore = ea->prev;
+ } else if (iter->type == ST_EXPRESSION) {
+ expr = iter->expr;
+ while (ENODE_IS(expr, ECOMMA))
+ expr = expr->data.diadic.left;
+ if (ENODE_IS(expr, EINDIRECT))
+ expr = expr->data.monadic;
+
+ if (
+ ENODE_IS(expr, EFUNCCALL) &&
+ ENODE_IS(expr->data.funccall.funcref, EOBJREF) &&
+ CClass_IsConstructor(expr->data.funccall.funcref->data.objref) &&
+ iter->dobjstack &&
+ iter->dobjstack->type == EAT_DESTROYLOCAL &&
+ expr->data.funccall.args &&
+ ENODE_IS(expr->data.funccall.args->node, EOBJREF) &&
+ expr->data.funccall.args->node->data.objref == iter->dobjstack->data.destroy_local.local
+ )
+ cexcept_eabefore = cexcept_eabefore->prev;
+ }
+
+ switch (iter->type) {
+ case ST_EXPRESSION:
+ CExcept_TempTransform(iter, 1, 0);
+ break;
+ case ST_SWITCH:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ CExcept_TempTransform(iter, 0, 1);
+ break;
+ case ST_RETURN:
+ if (iter->expr) {
+ CExcept_TempTransform(
+ iter,
+ 0,
+ CMach_GetFunctionResultClass(TYPE_FUNC(cscope_currentfunc->type)) != 1
+ );
+ }
+ break;
+ }
+
+ iter->dobjstack = cexcept_eabefore;
+ cexcept_prevstmt = iter;
+ }
+}
+
+static void CExcept_InsertSpecificationActions(Statement *stmt, ExceptSpecList *exspecs) {
+ Statement *iter;
+ Statement *last;
+ ExceptionAction *ea_spec;
+ ExceptionAction *ea;
+ ExceptSpecList *spec_iter;
+ SInt32 i;
+ Object *catch_info_object;
+ CLabel *label;
+
+ ea_spec = lalloc(sizeof(ExceptionAction));
+ memclrw(ea_spec, sizeof(ExceptionAction));
+ ea_spec->type = EAT_SPECIFICATION;
+
+ for (iter = stmt; iter; iter = iter->next) {
+ if ((ea = iter->dobjstack)) {
+ while (1) {
+ if (ea->type == EAT_SPECIFICATION)
+ break;
+ if (ea->prev == NULL) {
+ ea->prev = ea_spec;
+ break;
+ }
+ ea = ea->prev;
+ }
+ } else {
+ iter->dobjstack = ea_spec;
+ }
+ }
+
+ last = stmt;
+ while (last->next)
+ last = last->next;
+
+ if (last->type != ST_GOTO && last->type != ST_RETURN) {
+ last = CFunc_InsertStatement(ST_RETURN, last);
+ last->expr = NULL;
+ last->dobjstack = NULL;
+ if (TYPE_FUNC(cscope_currentfunc->type)->functype != &stvoid && (copts.pedantic || copts.cplusplus))
+ CError_Warning(CErrorStr184);
+ }
+
+ last = CFunc_InsertStatement(ST_LABEL, last);
+ last->label = newlabel();
+ last->label->stmt = last;
+ last->flags = StmtFlag_1;
+ last->dobjstack = NULL;
+
+ catch_info_object = create_temp_object(TYPE(&catchinfostruct));
+
+ if (!exspecs->type)
+ exspecs = NULL;
+
+ i = 0;
+ spec_iter = exspecs;
+ while (spec_iter) {
+ spec_iter = spec_iter->next;
+ i++;
+ }
+
+ ea_spec->data.specification.unexp_ids = i;
+ ea_spec->data.specification.unexp_id = galloc(sizeof(Object *) * i);
+ ea_spec->data.specification.unexp_label = last->label;
+ ea_spec->data.specification.unexp_info_object = catch_info_object;
+
+ i = 0;
+ while (exspecs) {
+ ea_spec->data.specification.unexp_id[i] = CExcept_TypeID(exspecs->type, exspecs->qual);
+ exspecs = exspecs->next;
+ i++;
+ }
+
+ last = CFunc_InsertStatement(ST_EXPRESSION, last);
+ last->expr = funccallexpr(Xunex_func, create_objectrefnode(catch_info_object), NULL, NULL, NULL);
+
+ ea = lalloc(sizeof(ExceptionAction));
+ memclrw(ea, sizeof(ExceptionAction));
+ ea->type = EAT_ACTIVECATCHBLOCK;
+ ea->data.active_catch_block.catch_info_object = catch_info_object;
+ ea->data.active_catch_block.call_dtor = 1;
+ last->dobjstack = ea;
+
+ last = CFunc_InsertStatement(ST_LABEL, last);
+ last->label = label = newlabel();
+ last->label->stmt = last;
+ last->dobjstack = NULL;
+
+ last = CFunc_InsertStatement(ST_GOTO, last);
+ last->label = label;
+}
+
+static void CExcept_HasFuncCallCallBack(ENode *expr) {
+ ENode *funcref = expr->data.funccall.funcref;
+ if (ENODE_IS(funcref, EOBJREF)) {
+ Object *func = funcref->data.objref;
+ if (CExcept_CanThrowException(func, func->datatype == DVFUNC && !(expr->flags & ENODE_FLAG_80)))
+ cexcept_canthrow = 1;
+ } else {
+ cexcept_canthrow = 1;
+ }
+}
+
+static Boolean CExcept_CanThrowCheck(Object *func, Statement *stmt) {
+ cexcept_canthrow = 0;
+
+ while (stmt) {
+ switch (stmt->type) {
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_GOTO:
+ case ST_ASM:
+ break;
+ case ST_RETURN:
+ if (!stmt->expr)
+ break;
+ case ST_EXPRESSION:
+ case ST_SWITCH:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_GOTOEXPR:
+ CExpr_SearchExprTree(stmt->expr, CExcept_HasFuncCallCallBack, 2, EFUNCCALL, EFUNCCALLP);
+ break;
+ default:
+ CError_FATAL(2687);
+ }
+ stmt = stmt->next;
+ }
+
+ if (!cexcept_canthrow) {
+ TYPE_FUNC(cscope_currentfunc->type)->flags |= FUNC_NOTHROW;
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+void CExcept_ExceptionTansform(Statement *stmt) {
+ cexcept_uniqueobjs = NULL;
+ CExcept_CleanupExceptionActions(stmt);
+
+ if (cscope_currentfunc && CExcept_CanThrowCheck(cscope_currentfunc, stmt)) {
+ CError_ASSERT(2716, IS_TYPE_FUNC(cscope_currentfunc->type));
+ if (TYPE_FUNC(cscope_currentfunc->type)->exspecs && copts.exceptions)
+ CExcept_InsertSpecificationActions(stmt, TYPE_FUNC(cscope_currentfunc->type)->exspecs);
+ }
+}
diff --git a/compiler_and_linker/FrontEnd/C/CExpr.c b/compiler_and_linker/FrontEnd/C/CExpr.c
new file mode 100644
index 0000000..484f56d
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CExpr.c
@@ -0,0 +1,4971 @@
+#include "compiler/CExpr.h"
+#include "compiler/CABI.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CException.h"
+#include "compiler/CInit.h"
+#include "compiler/CInline.h"
+#include "compiler/CIRTransform.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CInt64.h"
+#include "compiler/CObjC.h"
+#include "compiler/CObjCModern.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CRTTI.h"
+#include "compiler/CSOM.h"
+#include "compiler/CTemplateNew.h"
+#include "compiler/CTemplateTools.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/PPCError.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/templates.h"
+
+Boolean (*name_obj_check)(HashNameNode *, Object *);
+Boolean disallowgreaterthan;
+
+// forward declarations
+static ENode *makeaddnode(ENode *left, ENode *right);
+static ENode *makesubnode(ENode *left, ENode *right);
+
+ENode *CExpr_RewriteConst(ENode *expr) {
+ Object *obj;
+
+restart:
+ if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EOBJREF)) {
+ obj = expr->data.monadic->data.objref;
+ if (obj->datatype == DALIAS) {
+ CExpr_AliasTransform(expr->data.monadic);
+ goto restart;
+ }
+
+ if ((obj->qual & Q_INLINE_DATA) && expr->rtype == obj->type) {
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ case TYPEENUM:
+ expr->type = EINTCONST;
+ expr->data.intval = obj->u.data.u.intconst;
+ break;
+ case TYPEPOINTER:
+ expr->type = EINTCONST;
+ expr->data.intval = obj->u.data.u.intconst;
+ expr->rtype = TYPE(&stunsignedlong);
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = obj->type;
+ break;
+ case TYPEFLOAT:
+ expr->type = EFLOATCONST;
+ if (obj->u.data.u.floatconst)
+ expr->data.floatval = *obj->u.data.u.floatconst;
+ else
+ expr->data.floatval = CMach_CalcFloatConvertFromInt(TYPE(&stsignedlong), cint64_zero);
+ break;
+ default:
+ CError_FATAL(105);
+ }
+ }
+ }
+
+ return expr;
+}
+
+void optimizecomm(ENode *expr) {
+ ENode *right;
+ ENode *left;
+
+ if (ENODE_IS((right = expr->data.diadic.right), EINTCONST))
+ return;
+ if (ENODE_IS((left = expr->data.diadic.left), EINTCONST)) {
+ swap:
+ expr->data.diadic.right = left;
+ expr->data.diadic.left = right;
+ return;
+ }
+
+ if (ENODE_IS(left, EFLOATCONST))
+ return;
+ if (ENODE_IS(right, EFLOATCONST))
+ goto swap;
+
+ if (expr->rtype->type > TYPEFLOAT)
+ return;
+
+ if (left->cost > right->cost)
+ goto swap;
+}
+
+static void checkadditive(ENode *expr) {
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ if (expr->rtype == TYPE(&stbool))
+ break;
+ case TYPEFLOAT:
+ return;
+ case TYPEENUM:
+ if (copts.cplusplus)
+ break;
+ return;
+ case TYPEPOINTER:
+ if (TPTR_TARGET(expr->rtype)->size == 0)
+ CDecl_CompleteType(TPTR_TARGET(expr->rtype));
+ if (TPTR_TARGET(expr->rtype)->size == 0)
+ break;
+ return;
+ case TYPEARRAY:
+ if (ENODE_IS(expr, EOBJREF))
+ return;
+ }
+
+ CError_Error(CErrorStr376, expr->rtype, ENODE_QUALS(expr));
+}
+
+static void CExpr_CompareConvert(ENode **leftp, char *opname, ENode **rightp, Boolean flag) {
+ ENode *left;
+ ENode *right;
+ CInt64 val;
+
+ left = *leftp;
+ right = *rightp;
+
+ switch (left->rtype->type) {
+ case TYPEINT:
+ break;
+ case TYPEFLOAT:
+ if (left->rtype != right->rtype)
+ CExpr_ArithmeticConversion(leftp, rightp);
+ return;
+ case TYPEENUM:
+ left->rtype = TYPE_ENUM(left->rtype)->enumtype;
+ break;
+ default:
+ CError_Error(CErrorStr377,
+ left->rtype, ENODE_QUALS(left),
+ opname,
+ right->rtype, ENODE_QUALS(right));
+ left = nullnode();
+ }
+
+ switch (right->rtype->type) {
+ case TYPEINT:
+ break;
+ case TYPEFLOAT:
+ CExpr_ArithmeticConversion(leftp, rightp);
+ return;
+ case TYPEENUM:
+ right->rtype = TYPE_ENUM(right->rtype)->enumtype;
+ break;
+ default:
+ CError_Error(CErrorStr377,
+ left->rtype, ENODE_QUALS(left),
+ opname,
+ right->rtype, ENODE_QUALS(right));
+ right = nullnode();
+ }
+
+ if (left->rtype == right->rtype) {
+ *leftp = left;
+ *rightp = right;
+ return;
+ }
+
+ if (left->rtype->size == right->rtype->size) {
+ if (is_unsigned(left->rtype) == is_unsigned(right->rtype)) {
+ left->rtype = right->rtype;
+ *leftp = left;
+ *rightp = right;
+ return;
+ }
+ } else {
+ if (ENODE_IS(right, EINTCONST) && left->rtype->size <= right->rtype->size && (is_unsigned(left->rtype) == is_unsigned(right->rtype) || is_unsigned(left->rtype))) {
+ val = CMach_CalcIntDiadic(left->rtype, right->data.intval, '+', cint64_zero);
+ val = CMach_CalcIntDiadic(right->rtype, val, '+', cint64_zero);
+ if (CInt64_Equal(val, right->data.intval)) {
+ right->rtype = left->rtype;
+ *leftp = left;
+ *rightp = right;
+ return;
+ }
+ }
+
+ if (ENODE_IS(left, EINTCONST) && left->rtype->size >= right->rtype->size && (is_unsigned(left->rtype) == is_unsigned(right->rtype) || is_unsigned(right->rtype))) {
+ val = CMach_CalcIntDiadic(right->rtype, left->data.intval, '+', cint64_zero);
+ val = CMach_CalcIntDiadic(left->rtype, val, '+', cint64_zero);
+ if (CInt64_Equal(val, left->data.intval)) {
+ left->rtype = right->rtype;
+ *leftp = left;
+ *rightp = right;
+ return;
+ }
+ }
+ }
+
+ *leftp = left;
+ *rightp = right;
+ CExpr_ArithmeticConversion(leftp, rightp);
+}
+
+static ENode *CExpr_ConstResult(ENode *expr, SInt32 value) {
+ ENode *constnode;
+
+ if (IS_TYPE_FLOAT(expr->rtype)) {
+ constnode = intconstnode(TYPE(&stsignedint), value);
+ constnode->type = EFLOATCONST;
+ constnode->data.floatval = CMach_CalcFloatConvertFromInt(TYPE(&stsignedint), constnode->data.intval);
+ constnode->rtype = expr->rtype;
+ } else {
+ constnode = intconstnode(expr->rtype, value);
+ }
+
+ if (CInline_ExpressionHasSideEffect(expr))
+ return makediadicnode(expr, constnode, ECOMMA);
+ else
+ return constnode;
+}
+
+static ENode *makemultnode(ENode *left, ENode *right) {
+ CExpr_ArithmeticConversion(&left, &right);
+ if (iszero(left))
+ return CExpr_ConstResult(right, 0);
+ if (iszero(right))
+ return CExpr_ConstResult(left, 0);
+
+ if (CExpr_IsOne(right))
+ return left;
+ if (CExpr_IsOne(left))
+ return right;
+
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '*', right->data.intval);
+ return left;
+ }
+ if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
+ left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '*', right->data.floatval);
+ return left;
+ }
+
+ left = makediadicnode(left, right, EMUL);
+ optimizecomm(left);
+ if (IS_TYPE_INT(left->rtype) && left->rtype->size > 2) {
+ left->cost++;
+ if (left->cost > 200)
+ left->cost = 200;
+ }
+
+ if (IS_TYPE_FLOAT(left->rtype))
+ left = CExpr_BinaryFloatExpression(left);
+
+ return left;
+}
+
+static ENode *makedivnode(ENode *left, ENode *right, Boolean no_warning) {
+ CExpr_ArithmeticConversion(&left, &right);
+ if (iszero(right) && IS_TYPE_INT(right->rtype)) {
+ if (!no_warning)
+ CError_Warning(CErrorStr139);
+ return right;
+ }
+
+ if (CExpr_IsOne(right))
+ return left;
+
+ if (iszero(left) && IS_TYPE_INT(left->rtype))
+ return CExpr_ConstResult(right, 0);
+
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '/', right->data.intval);
+ return left;
+ }
+ if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
+ left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '/', right->data.floatval);
+ return left;
+ }
+
+ left = makediadicnode(left, right, EDIV);
+ if (IS_TYPE_FLOAT(left->rtype))
+ left = CExpr_BinaryFloatExpression(left);
+
+ return left;
+}
+
+static short canadd2(ENode *expr, CInt64 value) {
+ Float tmp;
+
+ if (CInt64_IsZero(&value))
+ return 1;
+
+ switch (expr->type) {
+ case EINTCONST:
+ expr->data.intval = CMach_CalcIntDiadic(expr->rtype, expr->data.intval, '+', value);
+ return 1;
+ case EFLOATCONST:
+ tmp = CMach_CalcFloatConvertFromInt(TYPE(&stsignedlong), value);
+ expr->data.floatval = CMach_CalcFloatDiadic(expr->rtype, expr->data.floatval, '+', tmp);
+ return 1;
+ case EADD:
+ if (canadd2(expr->data.diadic.left, value))
+ return 1;
+ if (canadd2(expr->data.diadic.right, value))
+ return 1;
+ return 0;
+ case ESUB:
+ if (canadd2(expr->data.diadic.left, value))
+ return 1;
+ if (canadd2(expr->data.diadic.right, CInt64_Neg(value)))
+ return 1;
+ return 0;
+ case ETYPCON:
+ if (IS_TYPE_POINTER_ONLY(expr->rtype) && ENODE_IS(expr->data.monadic, EINTCONST)) {
+ expr->data.monadic->data.intval = CMach_CalcIntDiadic(TYPE(&stunsignedlong), expr->data.monadic->data.intval, '+', value);
+ return 1;
+ }
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+short canadd(ENode *expr, SInt32 value) {
+ CInt64 value64;
+ CInt64_SetLong(&value64, value);
+ return canadd2(expr, value64);
+}
+
+static ENode *addconst(ENode *expr, SInt32 value) {
+ ENode *right;
+
+ if (canadd(expr, value))
+ return expr;
+
+ if (stsignedint.size < 4 && (value > 0x7FFF || value < -0x8000))
+ right = intconstnode(TYPE(&stsignedlong), value);
+ else
+ right = intconstnode(TYPE(&stsignedint), value);
+
+ CExpr_ArithmeticConversion(&expr, &right);
+ expr = makediadicnode(expr, right, EADD);
+ return expr;
+}
+
+static ENode *integralpointerpromote(ENode *expr) {
+ Boolean uns;
+ Type *type;
+
+ if (!IS_TYPE_INT(expr->rtype))
+ expr = forceintegral(expr);
+
+ if (expr->rtype->size != 4) {
+ type = TYPE(&stunsignedlong);
+ if (is_unsigned(type) != (uns = is_unsigned(expr->rtype))) {
+ if (uns) {
+ if (stunsignedlong.size == 4) {
+ type = TYPE(&stunsignedlong);
+ } else if (stunsignedint.size == 4) {
+ type = TYPE(&stunsignedint);
+ } else {
+ CError_FATAL(480);
+ }
+ } else {
+ if (stsignedlong.size == 4) {
+ type = TYPE(&stsignedlong);
+ } else if (stsignedint.size == 4) {
+ type = TYPE(&stsignedint);
+ } else {
+ CError_FATAL(486);
+ }
+ }
+ }
+
+ if (ENODE_IS(expr, EINTCONST))
+ expr->data.intval = CExpr_IntConstConvert(type, expr->rtype, expr->data.intval);
+ else
+ expr = makemonadicnode(expr, ETYPCON);
+
+ expr->rtype = type;
+ }
+
+ return expr;
+}
+
+static ENode *padd(ENode *left, ENode *right) {
+ Type *innertype;
+ SInt32 innersize;
+ ENode *expr;
+
+ right = integralpointerpromote(right);
+ innertype = TPTR_TARGET(left->rtype);
+ innersize = innertype->size;
+ if (innersize == 0) {
+ CDecl_CompleteType(innertype);
+ innersize = innertype->size;
+ if (innersize == 0) {
+ CError_Error(CErrorStr146);
+ return left;
+ }
+ }
+
+ expr = makemultnode(
+ right,
+ intconstnode((innersize > 0x7FFF) ? TYPE(&stsignedlong) : TYPE(&stsignedint), innersize));
+
+ if (ENODE_IS(expr, EINTCONST) && canadd2(left, expr->data.intval))
+ return left;
+
+ if (ENODE_IS(left, EADD) && ENODE_IS(left->data.diadic.right, EINTCONST)) {
+ left->data.diadic.left = makediadicnode(left->data.diadic.left, expr, EADD);
+ return left;
+ }
+
+ expr = makediadicnode(left, expr, EADD);
+ expr->rtype = left->rtype;
+ expr->flags = left->flags;
+ return expr;
+}
+
+static ENode *psub(ENode *left, ENode *right) {
+ Type *innertype;
+ SInt32 innersize;
+ ENode *expr;
+
+ if (IS_TYPE_POINTER(right->rtype)) {
+ innersize = TPTR_TARGET(left->rtype)->size;
+ if (innersize == 0) {
+ CDecl_CompleteType(TPTR_TARGET(left->rtype));
+ innersize = TPTR_TARGET(left->rtype)->size;
+ if (innersize == 0) {
+ CError_Error(CErrorStr146);
+ return left;
+ }
+ }
+
+ if (!is_typeequal(left->rtype, right->rtype)) {
+ CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right));
+ return left;
+ }
+
+ if (ENODE_IS(left, ETYPCON) && ENODE_IS(left->data.monadic, EINTCONST) && ENODE_IS(right, ETYPCON) && ENODE_IS(right->data.monadic, EINTCONST)) {
+ left->data.monadic->rtype = right->data.monadic->rtype = CABI_GetPtrDiffTType();
+ expr = makesubnode(left->data.monadic, right->data.monadic);
+ if (innersize > 1)
+ expr = makedivnode(expr, intconstnode(CABI_GetPtrDiffTType(), innersize), 11);
+ return expr;
+ }
+
+ expr = makediadicnode(left, right, ESUB);
+ expr->rtype = CABI_GetPtrDiffTType();
+ if (innersize > 1)
+ expr = makediadicnode(expr, intconstnode(CABI_GetPtrDiffTType(), innersize), EDIV);
+ return expr;
+ }
+
+ right = integralpointerpromote(right);
+ innertype = TPTR_TARGET(left->rtype);
+ innersize = innertype->size;
+ if (innersize == 0) {
+ CDecl_CompleteType(innertype);
+ innersize = innertype->size;
+ if (innersize == 0) {
+ CError_Error(CErrorStr146);
+ return left;
+ }
+ }
+
+ expr = makemultnode(right, intconstnode(CABI_GetPtrDiffTType(), innersize));
+ if (ENODE_IS(expr, EINTCONST) && canadd2(left, CInt64_Neg(expr->data.intval)))
+ return left;
+
+ expr = makediadicnode(left, expr, ESUB);
+ expr->rtype = left->rtype;
+ expr->flags = left->flags;
+ return expr;
+}
+
+static ENode *makeaddnode(ENode *left, ENode *right) {
+ if (IS_TYPE_POINTER(left->rtype))
+ return padd(left, right);
+ if (IS_TYPE_POINTER(right->rtype))
+ return padd(right, left);
+
+ CExpr_ArithmeticConversion(&left, &right);
+ if (iszero(right))
+ return left;
+ if (iszero(left))
+ return right;
+
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '+', right->data.intval);
+ return left;
+ }
+ if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
+ left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '+', right->data.floatval);
+ return left;
+ }
+
+ if (ENODE_IS(left, EINTCONST) && canadd2(right, left->data.intval))
+ return right;
+ if (ENODE_IS(right, EINTCONST) && canadd2(left, right->data.intval))
+ return left;
+
+ left = makediadicnode(left, right, EADD);
+ optimizecomm(left);
+ if (IS_TYPE_FLOAT(left->rtype))
+ left = CExpr_BinaryFloatExpression(left);
+ return left;
+}
+
+static ENode *makesubnode(ENode *left, ENode *right) {
+ if (ENODE_IS(right, EINTCONST) && !is_unsigned(right->rtype) && !IS_TYPE_FLOAT(left->rtype)) {
+ right->data.intval = CInt64_Neg(right->data.intval);
+ return makeaddnode(left, right);
+ }
+
+ if (IS_TYPE_POINTER(left->rtype))
+ return psub(left, right);
+
+ CExpr_ArithmeticConversion(&left, &right);
+ if (iszero(right))
+ return left;
+ if (iszero(left)) {
+ if (ENODE_IS(right, EINTCONST)) {
+ right->data.intval = CInt64_Neg(right->data.intval);
+ return right;
+ }
+ if (ENODE_IS(right, EFLOATCONST)) {
+ right->data.floatval = CMach_CalcFloatMonadic(right->rtype, '-', right->data.floatval);
+ return right;
+ }
+ return CExpr_UnaryFloatExpression(makemonadicnode(right, EMONMIN));
+ }
+
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '-', right->data.intval);
+ return left;
+ }
+ if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
+ left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '-', right->data.floatval);
+ return left;
+ }
+
+ if (ENODE_IS(right, EINTCONST) && canadd2(left, CInt64_Neg(right->data.intval)))
+ return left;
+
+ left = makediadicnode(left, right, ESUB);
+ if (IS_TYPE_FLOAT(left->rtype))
+ left = CExpr_BinaryFloatExpression(left);
+ return left;
+}
+
+ENode *checkreference(ENode *expr) {
+ if (!IS_TYPE_REFERENCE(expr->rtype))
+ return expr;
+
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TPTR_TARGET(expr->rtype);
+ return expr;
+}
+
+static ENode *pointer_generation2(ENode *expr) {
+ switch (expr->type) {
+ case EINDIRECT:
+ switch (expr->rtype->type) {
+ case TYPEARRAY:
+ switch (expr->data.monadic->type) {
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ expr->type = ETYPCON;
+ expr->rtype = CDecl_NewPointerType(TPTR_TARGET(expr->rtype));
+ return expr;
+ default:
+ expr->data.monadic->rtype = CDecl_NewPointerType(TPTR_TARGET(expr->rtype));
+ expr->data.monadic->flags = expr->flags;
+ return expr->data.monadic;
+ }
+ case TYPEFUNC:
+ expr = expr->data.monadic;
+ if (ENODE_IS(expr, EOBJREF) && expr->data.objref->datatype == DINLINEFUNC)
+ CError_Error(CErrorStr175);
+ return expr;
+ }
+ }
+ return expr;
+}
+
+ENode *pointer_generation(ENode *expr) {
+ return CExpr_RewriteConst(pointer_generation2(expr));
+}
+
+ENode *CExpr_PointerGeneration(ENode *expr) {
+ switch (expr->type) {
+ case EINDIRECT:
+ switch (expr->rtype->type) {
+ case TYPEARRAY:
+ expr->data.monadic->rtype = CDecl_NewPointerType(TPTR_TARGET(expr->rtype));
+ return expr->data.monadic;
+ case TYPEFUNC:
+ return expr->data.monadic;
+ }
+ }
+ return expr;
+}
+
+static void CExpr_ConstPointerCheck(ENode *expr, Type *type, short qual) {
+ Type *exprtype;
+ Type *b;
+ Type *a;
+ short exprqual;
+
+ exprtype = expr->rtype;
+ if (IS_TYPE_POINTER_ONLY(type) && IS_TYPE_POINTER_ONLY(exprtype)) {
+ exprqual = expr->flags;
+
+ if (TPTR_TARGET(type) == &stvoid) {
+ exprqual = CParser_GetCVTypeQualifiers(TPTR_TARGET(exprtype), exprqual);
+ } else {
+ a = TPTR_TARGET(type);
+ b = TPTR_TARGET(exprtype);
+ while (IS_TYPE_POINTER_ONLY(a) && IS_TYPE_POINTER_ONLY(b)) {
+ if (CParser_IsMoreCVQualified(TPTR_QUAL(b), TPTR_QUAL(a))) {
+ CError_Warning(CErrorStr220, expr->rtype, ENODE_QUALS(expr), type, qual);
+ return;
+ }
+ a = TPTR_TARGET(a);
+ b = TPTR_TARGET(b);
+ }
+ }
+
+ if (CParser_IsMoreCVQualified(exprqual, qual)) {
+ CError_Warning(CErrorStr220, expr->rtype, ENODE_QUALS(expr), type, (UInt32) qual);
+ }
+ }
+}
+
+ENode *oldassignmentpromotion(ENode *expr, Type *type, short qual, Boolean flag) {
+ Boolean is_ref;
+ UInt32 ref_qual;
+ short orig_qual;
+
+ is_ref = 0;
+ if (!IS_TYPE_MEMBERPOINTER(type)) {
+ if (IS_TYPE_REFERENCE(type)) {
+ if (ENODE_IS(expr, ECOND))
+ expr = CExpr_LValue(expr, 0, 0);
+ expr = pointer_generation2(expr);
+ ref_qual = CParser_GetCVTypeQualifiers(expr->rtype, expr->flags);
+ is_ref = 1;
+ } else {
+ expr = pointer_generation(expr);
+ }
+ }
+
+ if (ENODE_IS(expr, EMEMBER))
+ expr = getpointertomemberfunc(expr, type, 1);
+
+ if (!is_ref)
+ CExpr_ConstPointerCheck(expr, type, qual);
+ else
+ CExpr_ConstPointerCheck(expr, TPTR_TARGET(type), qual);
+
+ if (!(assign_check(expr, type, orig_qual = qual, 1, 0, flag)))
+ return expr;
+
+ if (is_ref) {
+ if (temp_reference_init) {
+ switch (TPTR_TARGET(type)->type) {
+ case TYPEPOINTER:
+ qual = TPTR_QUAL(TPTR_TARGET(type));
+ }
+ if (!(qual & Q_CONST))
+ CError_Warning(CErrorStr228);
+ } else {
+ if (ref_qual && ref_qual > CParser_GetCVTypeQualifiers(TPTR_TARGET(type), orig_qual))
+ CError_Warning(CErrorStr259);
+ }
+ }
+
+ return assign_node;
+}
+
+ENode *argumentpromotion(ENode *expr, Type *type, short qual, Boolean flag) {
+ ENode *tmp;
+ ENodeList *list;
+
+ if (IS_TYPE_CLASS(type) && CClass_ReferenceArgument(TYPE_CLASS(type))) {
+ if ((tmp = CExpr_IsTempConstruction(expr, type, NULL)))
+ return tmp;
+
+ list = lalloc(sizeof(ENodeList));
+ list->next = NULL;
+ list->node = expr;
+ tmp = CExpr_ConstructObject(
+ TYPE_CLASS(type),
+ create_temp_node(type),
+ list, 1, 1, 1, 1, 0);
+ return getnodeaddress(tmp, 0);
+ }
+
+ return CExpr_AssignmentPromotion(expr, type, qual, flag);
+}
+
+ENode *classargument(ENode *expr) {
+ ENodeList *list;
+
+ if (CClass_CopyConstructor(TYPE_CLASS(expr->rtype))) {
+ list = lalloc(sizeof(ENodeList));
+ list->next = NULL;
+ list->node = expr;
+ return CExpr_ConstructObject(
+ TYPE_CLASS(expr->rtype),
+ create_temp_node(expr->rtype),
+ list, 1, 1, 1, 1, 0);
+ }
+
+ return expr;
+}
+
+ENodeList *CExpr_ScanExpressionList(Boolean is_parens) {
+ ENodeList *list;
+ ENodeList *current;
+
+ if (is_parens && tk == ')')
+ return NULL;
+
+ list = current = lalloc(sizeof(ENodeList));
+
+ while (1) {
+ current->next = NULL;
+ current->node = assignment_expression();
+ if (copts.old_argmatch && !ENODE_IS(current->node, EMEMBER))
+ current->node = pointer_generation(current->node);
+
+ if (is_parens) {
+ if (tk == ')')
+ break;
+ } else {
+ if (tk == ']')
+ break;
+ }
+
+ if (tk != ',') {
+ CError_ErrorSkip(CErrorStr116);
+ break;
+ }
+
+ tk = lex();
+ current->next = lalloc(sizeof(ENodeList));
+ current = current->next;
+ }
+
+ return list;
+}
+
+static ENode *skipcommaexpr(ENode *expr) {
+ while (ENODE_IS(expr, ECOMMA))
+ expr = expr->data.diadic.right;
+ return expr;
+}
+
+ENode *CExpr_DoExplicitConversion(Type *type, UInt32 qual, ENodeList *list) {
+ Object *obj;
+ ENode *tmp;
+
+ if (!IS_TYPE_CLASS(type)) {
+ if (!list)
+ return do_typecast(nullnode(), type, qual);
+ if (list->next)
+ CError_Error(CErrorStr356);
+ return do_typecast(pointer_generation(list->node), type, qual);
+ }
+
+ CDecl_CompleteType(type);
+ if (!(TYPE_CLASS(type)->flags & CLASS_COMPLETED))
+ CError_Error(CErrorStr136, type, 0);
+
+ CanCreateObject(type);
+ if (!list && CClass_IsPODClass(TYPE_CLASS(type))) {
+ obj = CParser_NewGlobalDataObject(NULL);
+ obj->name = CParser_GetUniqueName();
+ obj->nspace = cscope_root;
+ obj->type = type;
+ obj->qual = qual;
+ obj->sclass = TK_STATIC;
+ CInit_DeclareData(obj, NULL, NULL, type->size);
+
+ tmp = makemonadicnode(create_temp_node(type), EINDIRECT);
+ tmp->rtype = type;
+ tmp->flags = qual & ENODE_FLAG_QUALS;
+ return makediadicnode(tmp, create_objectnode(obj), EASS);
+ }
+
+ return CExpr_ConstructObject(TYPE_CLASS(type), create_temp_node(type), list, 1, 1, 1, 1, 1);
+}
+
+static ENode *CExpr_TemplArgDepCast(Type *type, UInt32 qual, ENodeList *args) {
+ ENode *expr = CExpr_NewTemplDepENode(TDE_CAST);
+ expr->data.templdep.u.cast.args = args;
+ expr->data.templdep.u.cast.type = type;
+ expr->data.templdep.u.cast.qual = qual;
+ return expr;
+}
+
+static ENode *CExpr_ParseExplicitConversion(Type *type, UInt32 qual) {
+ ENodeList *args;
+ ENodeList *scan;
+
+ if (IS_TEMPL_CLASS(type) && !CParser_CheckTemplateClassUsage(TEMPL_CLASS(type), 1))
+ type = TYPE(&stsignedint);
+
+ if (tk == '(')
+ tk = lex();
+ else
+ CError_Error(CErrorStr114);
+
+ args = CExpr_ScanExpressionList(1);
+ if (tk != ')') {
+ CError_Error(CErrorStr115);
+ return nullnode();
+ }
+
+ tk = lex();
+ if (CTemplTool_IsTemplateArgumentDependentType(type))
+ return CExpr_TemplArgDepCast(type, qual, args);
+
+ for (scan = args; scan; scan = scan->next) {
+ if (CTemplTool_IsTemplateArgumentDependentExpression(scan->node))
+ return CExpr_TemplArgDepCast(type, qual, args);
+ }
+
+ return CExpr_DoExplicitConversion(type, qual, args);
+}
+
+static ENode *CExpr_MemberVarAccess(BClassList *path, ObjMemberVar *var, ENode *expr) {
+ ENode *accessnode;
+ BClassList *varpath;
+
+ CError_ASSERT(1152, path);
+
+ if (TYPE_CLASS(path->type)->sominfo)
+ return CSOM_MemberVarAccess(path, var, expr);
+
+ varpath = NULL;
+ if (var->has_path)
+ varpath = OBJ_MEMBER_VAR_PATH(var)->path;
+ accessnode = CExpr_GetClassAccessNode(path, varpath, expr, NULL, var->access, 1);
+ if (!accessnode)
+ return nullnode();
+
+ return CClass_AccessMember(accessnode, var->type, var->qual, var->offset);
+}
+
+static Boolean CExpr_IsTemplateFunc(Object *obj) {
+ return IS_TEMPL_FUNC(obj->type);
+}
+
+static ENode *CExpr_ExplicitTemplateArgCheck(NameResult *pr) {
+ NameSpaceObjectList *list;
+ NameSpaceObjectList *newhead;
+ NameSpaceObjectList *newlist;
+ ENode *expr;
+
+ if (pr->obj_10) {
+ if (pr->obj_10->otype != OT_OBJECT || !CExpr_IsTemplateFunc(OBJECT(pr->obj_10)))
+ return NULL;
+
+ list = lalloc(sizeof(NameSpaceObjectList));
+ memclrw(list, sizeof(NameSpaceObjectList));
+ list->object = pr->obj_10;
+ } else if (pr->nsol_14) {
+ for (list = pr->nsol_14; list; list = list->next) {
+ if (list->object->otype == OT_OBJECT && CExpr_IsTemplateFunc(OBJECT(list->object))) {
+ newhead = newlist = galloc(sizeof(NameSpaceObjectList));
+ *newlist = *list;
+ newlist->next = NULL;
+ while ((list = list->next)) {
+ if (list->object->otype == OT_OBJECT && CExpr_IsTemplateFunc(OBJECT(list->object))) {
+ newlist->next = galloc(sizeof(NameSpaceObjectList));
+ newlist = newlist->next;
+ *newlist = *list;
+ newlist->next = NULL;
+ }
+ }
+ list = newhead;
+ break;
+ }
+ }
+ if (!list)
+ return NULL;
+ } else {
+ return NULL;
+ }
+
+ expr = CExpr_NewENode(EOBJLIST);
+ expr->rtype = OBJECT(list->object)->type;
+ expr->data.objlist.list = list;
+ expr->data.objlist.templargs = CTempl_ParseUncheckTemplArgs(NULL, 0);
+
+ tk = lex();
+ return expr;
+}
+
+ENode *CExpr_MakeNameLookupResultExpr(NameResult *pr) {
+ ENode *expr;
+
+ if (pr->obj_10) {
+ switch (pr->obj_10->otype) {
+ case OT_OBJECT:
+ CClass_CheckObjectAccess(pr->bcl_18, OBJECT(pr->obj_10));
+ return create_objectnode(OBJECT(pr->obj_10));
+ case OT_ENUMCONST:
+ CClass_CheckEnumAccess(pr->bcl_18, OBJ_ENUM_CONST(pr->obj_10));
+ expr = lalloc(sizeof(ENode));
+ expr->type = EINTCONST;
+ expr->cost = 0;
+ expr->flags = 0;
+ expr->rtype = OBJ_ENUM_CONST(pr->obj_10)->type;
+ expr->data.intval = OBJ_ENUM_CONST(pr->obj_10)->val;
+ return expr;
+ case OT_MEMBERVAR:
+ CError_Error(CErrorStr221);
+ return nullnode();
+ default:
+ CError_FATAL(1268);
+ }
+ }
+
+ if (pr->nsol_14) {
+ expr = CExpr_NewENode(EOBJLIST);
+ expr->rtype = OBJECT(pr->nsol_14->object)->type;
+ expr->data.objlist.list = pr->nsol_14;
+ return expr;
+ }
+
+ CError_FATAL(1278);
+ return NULL;
+}
+
+static Type *CExpr_NewPTMType(EMemberInfo *member, Object *obj) {
+ TypeMemberPointer *ptm;
+ TypeMemberFunc *tmethod;
+ BClassList *path;
+
+ ptm = galloc(sizeof(TypeMemberPointer));
+ memclrw(ptm, sizeof(TypeMemberPointer));
+ ptm->type = TYPEMEMBERPOINTER;
+
+ if (member->list->object->otype == OT_MEMBERVAR) {
+ path = member->path;
+ while (path->next)
+ path = path->next;
+ ptm->size = 4;
+ ptm->ty2 = path->type;
+ ptm->ty1 = OBJ_MEMBER_VAR(member->list->object)->type;
+ } else {
+ if (!obj) {
+ CError_ASSERT(1306, member->list->object->otype == OT_OBJECT);
+ obj = OBJECT(member->list->object);
+ CError_ASSERT(1308, IS_TYPE_FUNC(obj->type));
+ }
+
+ tmethod = galloc(sizeof(TypeMemberFunc));
+ memclrw(tmethod, sizeof(TypeMemberFunc));
+ *tmethod = *TYPE_METHOD(obj->type);
+
+ CError_ASSERT(1312, tmethod->args);
+
+ tmethod->args = tmethod->args->next;
+ CDecl_MakePTMFuncType(TYPE_FUNC(tmethod));
+ tmethod->flags &= ~FUNC_DEFINED;
+
+ ptm->size = 12;
+ ptm->ty2 = TYPE(tmethod->theclass);
+ ptm->ty1 = TYPE(tmethod);
+ }
+
+ return TYPE(ptm);
+}
+
+static ENode *CExpr_ParseNameResultExpr(NameResult *pr, ENode *expr, Boolean flag1, Boolean flag2) {
+ ENode *result;
+ ENode *ta_expr;
+ ObjEnumConst *oec;
+ TemplateAction *act;
+ EMemberInfo *member;
+ NameSpaceObjectList *list;
+ Object *obj;
+ TypeFunc *tfunc;
+ SInt32 val;
+
+ if (pr->type) {
+ if (copts.cplusplus) {
+ if (IS_TYPE_TEMPLATE(pr->type)) {
+ if (TYPE_TEMPLATE(pr->type)->dtype == TEMPLDEP_ARGUMENT && TYPE_TEMPLATE(pr->type)->u.pid.type == TPT_NONTYPE) {
+ result = CExpr_NewTemplDepENode(TDE_PARAM);
+ result->data.templdep.u.pid = TYPE_TEMPLATE(pr->type)->u.pid;
+ tk = lex();
+ return result;
+ }
+ if (TYPE_TEMPLATE(pr->type)->dtype == TEMPLDEP_QUALNAME && !pr->x20) {
+ result = CExpr_NewTemplDepENode(TDE_QUALNAME);
+ result->data.templdep.u.qual.type = TYPE_TEMPLATE(pr->type)->u.qual.type;
+ result->data.templdep.u.qual.name = TYPE_TEMPLATE(pr->type)->u.qual.name;
+ tk = lex();
+ return result;
+ }
+ }
+ tk = lex();
+ return CExpr_ParseExplicitConversion(pr->type, pr->qual);
+ }
+ CError_ErrorSkip(CErrorStr141);
+ tk = lex();
+ return nullnode();
+ }
+
+ if (pr->obj_10) {
+ switch (pr->obj_10->otype) {
+ case OT_OBJECT:
+ if (OBJECT(pr->obj_10)->nspace && OBJECT(pr->obj_10)->nspace->theclass && (OBJECT(pr->obj_10)->nspace->theclass->flags & CLASS_IS_TEMPL)) {
+ result = CExpr_NewTemplDepENode(TDE_OBJ);
+ result->data.templdep.u.obj = OBJECT(pr->obj_10);
+ tk = lex();
+ return result;
+ }
+ if (!expr || !IS_TEMPL_FUNC(OBJECT(pr->obj_10)->type)) {
+ if (!IS_TYPE_NONSTATIC_METHOD(OBJECT(pr->obj_10)->type)) {
+ tk = lex();
+ if (tk == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr)))
+ return ta_expr;
+ if (OBJECT(pr->obj_10)->datatype == DLOCAL && OBJECT(pr->obj_10)->u.var.info->func != cscope_currentfunc) {
+ CError_Error(CErrorStr330);
+ return nullnode();
+ }
+ if (OBJECT(pr->obj_10)->datatype == DEXPR) {
+ result = CInline_CopyExpression(OBJECT(pr->obj_10)->u.expr, CopyMode0);
+ if (IS_TYPE_POINTER_ONLY(result->rtype) && ENODE_IS(result, EINTCONST)) {
+ result = makemonadicnode(result, ETYPCON);
+ result->data.monadic->rtype = TYPE(&stunsignedlong);
+ }
+ return result;
+ }
+ CClass_CheckObjectAccess(pr->bcl_18, OBJECT(pr->obj_10));
+ if (tk == '(' && flag2 && OBJECT(pr->obj_10)->datatype == DFUNC && copts.cplusplus && !pr->x1D && !IS_TYPEFUNC_METHOD(TYPE_FUNC(OBJECT(pr->obj_10)->type))) {
+ result = CExpr_NewENode(EOBJLIST);
+ result->rtype = OBJECT(pr->obj_10)->type;
+ result->data.objlist.list = galloc(sizeof(NameSpaceObjectList));
+ result->data.objlist.list->next = pr->nsol_14;
+ result->data.objlist.list->object = pr->obj_10;
+ result->data.objlist.name = OBJECT(pr->obj_10)->name;
+ return result;
+ }
+
+ result = create_objectnode(OBJECT(pr->obj_10));
+ if (expr) {
+ while (ENODE_IS(expr, EINDIRECT))
+ expr = expr->data.monadic;
+ switch (expr->type) {
+ case EINTCONST:
+ case EOBJREF:
+ case EOBJLIST:
+ break;
+ default:
+ result = makecommaexpression(expr, result);
+ }
+ }
+ return result;
+ }
+ if (CClass_IsDestructor(OBJECT(pr->obj_10))) {
+ if ((tk = lex()) != '(') {
+ CError_Error(CErrorStr114);
+ return nullnode();
+ }
+ if ((tk = lex()) != ')') {
+ CError_Error(CErrorStr115);
+ return nullnode();
+ }
+ if (!expr && (!cscope_currentfunc || !cscope_currentclass || !cscope_is_member_func)) {
+ CError_Error(CErrorStr221);
+ return nullnode();
+ }
+ if (pr->isambig)
+ CError_Error(CErrorStr188);
+
+ if ((expr = CExpr_GetClassAccessNode(pr->bcl_18, NULL, expr, OBJECT(pr->obj_10), pr->obj_10->access, 1))) {
+ tk = lex();
+ return CABI_DestroyObject(OBJECT(pr->obj_10), expr->data.monadic, 1, pr->x1D, 0);
+ }
+ }
+ }
+ break;
+ case OT_ENUMCONST:
+ CClass_CheckEnumAccess(pr->bcl_18, OBJ_ENUM_CONST(pr->obj_10));
+ oec = OBJ_ENUM_CONST(pr->obj_10);
+ if (CInt64_IsZero(&oec->val) && IS_TYPE_ENUM(oec->type) && TYPE_ENUM(oec->type)->nspace && TYPE_ENUM(oec->type)->nspace->theclass && (TYPE_ENUM(oec->type)->nspace->theclass->flags & CLASS_IS_TEMPL)) {
+ val = 0;
+ expr = NULL;
+ for (act = TEMPL_CLASS(TYPE_ENUM(oec->type)->nspace->theclass)->actions; act; act = act->next) {
+ if (act->type == TAT_ENUMERATOR) {
+ if (act->u.enumerator.initexpr) {
+ expr = act->u.enumerator.initexpr;
+ val = 0;
+ } else {
+ val++;
+ }
+ if (act->u.enumerator.objenumconst == oec) {
+ CError_ASSERT(1521, expr);
+ expr = CInline_CopyExpression(expr, CopyMode0);
+ if (val)
+ expr = makediadicnode(expr, intconstnode(TYPE(&stsignedlong), val), EADD);
+ tk = lex();
+ return expr;
+ }
+ }
+ }
+ }
+ result = lalloc(sizeof(ENode));
+ result->type = EINTCONST;
+ result->cost = 0;
+ result->flags = 0;
+ result->rtype = OBJ_ENUM_CONST(pr->obj_10)->type;
+ result->data.intval = OBJ_ENUM_CONST(pr->obj_10)->val;
+ tk = lex();
+ return result;
+ case OT_MEMBERVAR:
+ if (!flag1 || expr || !pr->x1D) {
+ if (pr->isambig)
+ CError_Error(CErrorStr188);
+ result = checkreference(CExpr_MemberVarAccess(pr->bcl_18, OBJ_MEMBER_VAR(pr->obj_10), expr));
+ tk = lex();
+ return result;
+ }
+ break;
+ default:
+ CError_FATAL(1552);
+ }
+
+ member = lalloc(sizeof(EMemberInfo));
+ memclrw(member, sizeof(EMemberInfo));
+ member->path = pr->bcl_18;
+ member->expr = expr;
+ member->pr_1D = pr->x1D;
+ member->isambig = pr->isambig;
+ if ((tk = lex()) == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr))) {
+ CError_ASSERT(1564, ENODE_IS(ta_expr, EOBJLIST));
+ member->list = ta_expr->data.objlist.list;
+ member->templargs = ta_expr->data.objlist.templargs;
+ } else {
+ member->list = galloc(sizeof(NameSpaceObjectList));
+ member->list->next = NULL;
+ member->list->object = pr->obj_10;
+ }
+
+ result = CExpr_NewENode(EMEMBER);
+ result->data.emember = member;
+ result->rtype = &stvoid;
+ return result;
+ }
+
+ if (pr->nsol_14) {
+ if ((tk = lex()) == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr))) {
+ CError_ASSERT(1591, ENODE_IS(ta_expr, EOBJLIST));
+ for (list = ta_expr->data.objlist.list; list; list = list->next) {
+ if (list->object->otype == OT_OBJECT && IS_TYPE_NONSTATIC_METHOD(OBJECT(list->object)->type)) {
+ member = lalloc(sizeof(EMemberInfo));
+ memclrw(member, sizeof(EMemberInfo));
+
+ member->path = pr->bcl_18;
+ member->expr = expr;
+ member->list = ta_expr->data.objlist.list;
+ member->templargs = ta_expr->data.objlist.templargs;
+ member->pr_1D = pr->x1D;
+ member->isambig = pr->isambig;
+
+ result = CExpr_NewENode(EMEMBER);
+ result->data.emember = member;
+ result->rtype = &stvoid;
+ return result;
+ }
+ }
+ return ta_expr;
+ }
+
+ for (list = pr->nsol_14; list; list = list->next) {
+ if (list->object->otype == OT_OBJECT && IS_TYPE_NONSTATIC_METHOD(OBJECT(list->object)->type)) {
+ member = lalloc(sizeof(EMemberInfo));
+ memclrw(member, sizeof(EMemberInfo));
+
+ member->path = pr->bcl_18;
+ member->expr = expr;
+ member->list = pr->nsol_14;
+ member->pr_1D = pr->x1D;
+ member->isambig = pr->isambig;
+
+ result = CExpr_NewENode(EMEMBER);
+ result->data.emember = member;
+ result->rtype = &stvoid;
+ return result;
+ }
+ }
+
+ if (tk == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr)))
+ return ta_expr;
+
+ result = CExpr_NewENode(EOBJLIST);
+ result->rtype = OBJECT(pr->nsol_14->object)->type;
+ result->data.objlist.list = pr->nsol_14;
+ if (tk == '(' && copts.cplusplus && flag2 && !pr->x1D && pr->nsol_14->object->otype == OT_OBJECT)
+ result->data.objlist.name = OBJECT(pr->nsol_14->object)->name;
+ return result;
+ }
+
+ if (pr->name_4) {
+ if (copts.cplusplus && flag2) {
+ if (lookahead() == '(') {
+ result = CExpr_NewENode(EOBJLIST);
+ result->rtype = &stvoid;
+ result->data.objlist.name = pr->name_4;
+ tk = lex();
+ return result;
+ }
+ CError_Error(CErrorStr140, pr->name_4->name);
+ tk = lex();
+ return nullnode();
+ }
+
+ if (lookahead() != '(') {
+ CError_Error(CErrorStr140, pr->name_4->name);
+ tk = lex();
+ return nullnode();
+ }
+
+ if (copts.checkprotos)
+ CError_Error(CErrorStr178);
+
+ tfunc = galloc(sizeof(TypeFunc));
+ memclrw(tfunc, sizeof(TypeFunc));
+ tfunc->type = TYPEFUNC;
+ tfunc->functype = TYPE(&stsignedint);
+ tfunc->args = &oldstyle;
+ CDecl_SetFuncFlags(tfunc, 0);
+
+ obj = CParser_NewFunctionObject(NULL);
+ obj->name = pr->name_4;
+ obj->sclass = TK_EXTERN;
+ obj->nspace = cscope_root;
+ obj->type = TYPE(tfunc);
+
+ CScope_AddGlobalObject(obj);
+ tk = lex();
+ return create_objectrefnode(obj);
+ }
+
+ CError_FATAL(1711);
+ return NULL;
+}
+
+static ENode *CExpr_ParseRotate(Boolean is_right) {
+ ENode *expr1;
+ ENode *expr2;
+
+ if (lex() != '(') {
+ CError_Error(CErrorStr114);
+ return nullnode();
+ }
+
+ tk = lex();
+ expr1 = assignment_expression();
+
+ if (tk != ',') {
+ CError_Error(CErrorStr116);
+ return nullnode();
+ }
+
+ tk = lex();
+ expr2 = assignment_expression();
+
+ if (tk != ')') {
+ CError_Error(CErrorStr115);
+ return nullnode();
+ }
+
+ if (!IS_TYPE_INT(expr1->rtype))
+ expr1 = forceintegral(expr1);
+ expr2 = integralpromote(expr2);
+
+ tk = lex();
+ if (iszero(expr1) || iszero(expr2))
+ return expr1;
+
+ return makediadicnode(expr1, expr2, is_right ? EROTR : EROTL);
+}
+
+static ENode *CExpr_ParseNextArg(void) {
+ NameSpaceObjectList *list;
+ NameResult pr;
+ ENode *expr;
+ SInt32 rounded_size;
+
+ if ((tk = lex()) != '(') {
+ CError_Error(CErrorStr114);
+ return nullnode();
+ }
+ if ((tk = lex()) != TK_IDENTIFIER) {
+ CError_Error(CErrorStr107);
+ return nullnode();
+ }
+
+ list = CScope_FindObjectList(&pr, tkidentifier);
+ if (!list) {
+ CError_Error(CErrorStr140, tkidentifier->name);
+ return nullnode();
+ }
+
+ if (list->object->otype != OT_OBJECT || OBJECT(list->object)->datatype != DLOCAL) {
+ CError_Error(CErrorStr140, tkidentifier->name);
+ return nullnode();
+ }
+
+ rounded_size = CMach_RoundedSizeOf(OBJECT(list->object));
+ expr = CExpr_MakeObjRefNode(OBJECT(list->object), 1);
+ expr = makediadicnode(expr, intconstnode(CABI_GetPtrDiffTType(), rounded_size), EADD);
+ expr->rtype = TYPE(&void_ptr);
+
+ if ((tk = lex()) != ')') {
+ CError_Error(CErrorStr115);
+ return expr;
+ } else {
+ tk = lex();
+ return expr;
+ }
+}
+
+static ENode *CExpr_ParseVecStep(void) {
+ ENode *expr;
+ Type *type;
+ SInt32 value;
+ DeclInfo di;
+
+ expr = intconstnode(TYPE(&stsignedint), 0);
+ if ((tk = lex()) == '(') {
+ if (tk == '(' && islookaheaddeclaration()) {
+ tk = lex();
+ memclrw(&di, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(&di, 0);
+ scandeclarator(&di);
+ if (di.name)
+ CError_Error(CErrorStr121);
+
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+
+ type = di.thetype;
+ if (IS_TYPE_REFERENCE(type))
+ type = TPTR_TARGET(type);
+ } else {
+ expr = unary_expression();
+ if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EBITFIELD))
+ CError_Error(CErrorStr144);
+ type = expr->rtype;
+ }
+
+ CDecl_CompleteType(type);
+ if (IS_TYPE_VECTOR(type)) {
+ switch (TYPE_STRUCT(type)->stype) {
+ case STRUCT_VECTOR_UCHAR:
+ case STRUCT_VECTOR_SCHAR:
+ case STRUCT_VECTOR_BCHAR:
+ value = 16;
+ break;
+ case STRUCT_VECTOR_USHORT:
+ case STRUCT_VECTOR_SSHORT:
+ case STRUCT_VECTOR_BSHORT:
+ case STRUCT_VECTOR_PIXEL:
+ value = 8;
+ break;
+ default:
+ value = 4;
+ }
+ expr = intconstnode(TYPE(&stsignedint), value);
+ } else {
+ PPCError_Error(PPCErrorStr104, "vec_step", "vec_step", type, 0);
+ }
+ } else {
+ CError_Error(CErrorStr114);
+ }
+
+ return expr;
+}
+
+static SInt32 CExpr_BuiltInComputeAlign(Type *type) {
+ return CMach_GetTypeAlign(type);
+}
+
+static SInt32 CExpr_AtomTypeID(IntegralType what) {
+ switch (what) {
+ case IT_BOOL: return 1;
+ case IT_CHAR: return 2;
+ case IT_SCHAR: return 3;
+ case IT_UCHAR: return 4;
+ case IT_WCHAR_T: return 5;
+ case IT_SHORT: return 6;
+ case IT_USHORT: return 7;
+ case IT_INT: return 8;
+ case IT_UINT: return 9;
+ case IT_LONG: return 10;
+ case IT_ULONG: return 10;
+ case IT_LONGLONG: return 12;
+ case IT_ULONGLONG: return 13;
+ case IT_FLOAT: return 14;
+ case IT_SHORTDOUBLE: return 15;
+ case IT_DOUBLE: return 16;
+ case IT_LONGDOUBLE: return 17;
+ case IT_17: return 32;
+ case IT_18: return 33;
+ case IT_19: return 34;
+ case IT_20: return 35;
+ case IT_21: return 36;
+ case IT_22: return 37;
+ case IT_23: return 38;
+ case IT_24: return 39;
+ default:
+ CError_FATAL(1976);
+ return 0;
+ }
+}
+
+static SInt32 CExpr_BuiltInComputeType(Type *type) {
+ switch (type->type) {
+ case TYPEINT:
+ return 0x100 | CExpr_AtomTypeID(TYPE_INTEGRAL(type)->integral);
+ case TYPEFLOAT:
+ return 0x200 | CExpr_AtomTypeID(TYPE_INTEGRAL(type)->integral);
+ case TYPEENUM:
+ return 0x400 | (CExpr_BuiltInComputeType(TYPE_ENUM(type)->enumtype) & 0xFF);
+ case TYPEPOINTER:
+ return 0x800;
+ case TYPEARRAY:
+ return 0x1000;
+ case TYPESTRUCT:
+ return 0x2000;
+ case TYPECLASS:
+ return 0x2000;
+ case TYPEMEMBERPOINTER:
+ return 0x4000;
+ case TYPEFUNC:
+ return 0x8000;
+ default:
+ CError_Error(CErrorStr146);
+ case TYPEVOID:
+ return 0;
+ }
+}
+
+static SInt32 CExpr_BuiltInClassifyType(Type *type) {
+ switch (type->type) {
+ case TYPEVOID: return 0;
+ case TYPEFUNC: return 10;
+ case TYPEENUM: return 3;
+ case TYPEINT: return 1;
+ case TYPEFLOAT: return 8;
+ case TYPEPOINTER: case TYPEMEMBERPOINTER: return 5;
+ case TYPEARRAY: return 14;
+ case TYPESTRUCT: return 12;
+ case TYPECLASS: return 12;
+ case TYPEBITFIELD: return -1;
+ case TYPETEMPLATE: return -1;
+ default: return -1;
+ }
+}
+
+static SInt32 CExpr_BuiltInComputeVArgType(Type *type) {
+ switch (type->type) {
+ case TYPEINT:
+ case TYPEENUM:
+ return 0;
+ case TYPEFLOAT:
+ return 1;
+ default:
+ return 2;
+ }
+}
+
+static Type *CExpr_ParseTypeExpression(Boolean *outflag) {
+ ENode *expr;
+ Type *type;
+ DeclInfo di;
+
+ tk = lex();
+ if (tk == '(' && islookaheaddeclaration()) {
+ tk = lex();
+ memclrw(&di, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(&di, 0);
+ scandeclarator(&di);
+ if (di.name)
+ CError_Error(CErrorStr121);
+
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+
+ type = di.thetype;
+ if (IS_TYPE_REFERENCE(type))
+ type = TPTR_TARGET(type);
+ } else {
+ expr = unary_expression();
+ if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EBITFIELD))
+ CError_Error(CErrorStr144);
+
+ if (outflag)
+ *outflag = ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval);
+
+ type = expr->rtype;
+ }
+
+ CDecl_CompleteType(type);
+ return type;
+}
+
+static ENode *CExpr_ParseBuiltin(SInt32 (*parser)(Type *)) {
+ ENode *expr;
+ expr = intconstnode(TYPE(&stsignedint), 0);
+ CInt64_SetLong(&expr->data.intval, parser(CExpr_ParseTypeExpression(NULL)));
+ return expr;
+}
+
+static ENode *CExpr_ParseBuiltin_isintconst(void) {
+ ENode *expr;
+ expr = intconstnode(TYPE(&stsignedint), 0);
+
+ tk = lex();
+ if (tk != '(')
+ CError_ErrorSkip(CErrorStr121);
+ else
+ tk = lex();
+
+ if (ENODE_IS(expression(), EINTCONST))
+ CInt64_SetLong(&expr->data.intval, 1);
+
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+
+ return expr;
+}
+
+static ENode *primary_expression(Boolean flag) {
+ NameResult pr;
+ ENode *expr;
+
+ switch (tk) {
+ case TK_TRUE:
+ expr = lalloc(sizeof(ENode));
+ expr->type = EINTCONST;
+ expr->cost = 0;
+ expr->flags = 0;
+ expr->rtype = TYPE(&stbool);
+ CInt64_SetULong(&expr->data.intval, 1);
+ tk = lex();
+ return expr;
+ case TK_FALSE:
+ expr = lalloc(sizeof(ENode));
+ expr->type = EINTCONST;
+ expr->cost = 0;
+ expr->flags = 0;
+ expr->rtype = TYPE(&stbool);
+ CInt64_SetULong(&expr->data.intval, 0);
+ tk = lex();
+ return expr;
+ case TK_INTCONST:
+ expr = lalloc(sizeof(ENode));
+ expr->type = EINTCONST;
+ expr->cost = 0;
+ expr->flags = 0;
+ expr->rtype = atomtype();
+ expr->data.intval = tkintconst;
+ tk = lex();
+ return expr;
+ case TK_FLOATCONST:
+ expr = lalloc(sizeof(ENode));
+ expr->type = EFLOATCONST;
+ expr->cost = 0;
+ expr->flags = 0;
+ expr->rtype = atomtype();
+ expr->data.floatval = tkfloatconst;
+ tk = lex();
+ return expr;
+ case TK_STRING:
+ expr = CExpr_NewENode(ESTRINGCONST);
+ expr->rtype = CDecl_NewArrayType(ispascalstring ? TYPE(&stunsignedchar) : TYPE(&stchar), tksize);
+ expr->data.string.size = tksize;
+ expr->data.string.data = tkstring;
+ expr->data.string.ispascal = ispascalstring;
+ if (copts.const_strings)
+ expr->flags = ENODE_FLAG_CONST;
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype);
+ tk = lex();
+ return expr;
+ case TK_STRING_WIDE:
+ expr = CExpr_NewENode(ESTRINGCONST);
+ expr->rtype = CDecl_NewArrayType(CParser_GetWCharType(), tksize);
+ expr->data.string.size = tksize;
+ expr->data.string.data = tkstring;
+ expr->data.string.ispascal = ispascalstring;
+ if (copts.const_strings)
+ expr->flags = ENODE_FLAG_CONST;
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype);
+ tk = lex();
+ return expr;
+ case TK_THIS:
+ case TK_SELF:
+ expr = CClass_CreateThisSelfExpr();
+ if (!expr)
+ expr = nullnode();
+ tk = lex();
+ return expr;
+ case TK_AT_SELECTOR:
+ return CObjC_ParseSelectorExpression();
+ case TK_AT_ENCODE:
+ return CObjC_ParseEncodeExpression();
+ case TK_AT_PROTOCOL:
+ return CObjC_ParseProtocolExpression();
+ case '@':
+ if (copts.objective_c)
+ return CObjC_ParseAtExpression();
+ break;
+ case '(':
+ tk = lex();
+ expr = s_expression();
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+ if (ENODE_IS(expr, EASS))
+ expr->flags = expr->flags | ENODE_FLAG_80;
+ return expr;
+ case '[':
+ if (copts.objective_c)
+ return CObjC_ParseMessageExpression();
+ break;
+ case TK_IDENTIFIER:
+ if (tkidentifier->name[0] == '_' && tkidentifier->name[1] == '_') {
+ if (!strcmp(tkidentifier->name, "__builtin_align"))
+ return CExpr_ParseBuiltin(CExpr_BuiltInComputeAlign);
+ if (!strcmp(tkidentifier->name, "__builtin_ntype"))
+ return CExpr_ParseBuiltin(CExpr_BuiltInComputeType);
+ if (!strcmp(tkidentifier->name, "__builtin_type") || !strcmp(tkidentifier->name, "__builtin_vargtype"))
+ return CExpr_ParseBuiltin(CExpr_BuiltInComputeVArgType);
+ if (!strcmp(tkidentifier->name, "__builtin_classify_type"))
+ return CExpr_ParseBuiltin(CExpr_BuiltInClassifyType);
+ if (!strcmp(tkidentifier->name, "__builtin_next_arg"))
+ return CExpr_ParseNextArg();
+ }
+ if (copts.altivec_model && !strcmp("vec_step", tkidentifier->name))
+ return CExpr_ParseVecStep();
+ case '~':
+ case TK_OPERATOR:
+ case TK_INHERITED:
+ case TK_COLON_COLON:
+ if (CScope_ParseExprName(&pr))
+ return CExpr_ParseNameResultExpr(&pr, NULL, flag, 1);
+ tk = lex();
+ return nullnode();
+ }
+
+ CError_ErrorSkip(CErrorStr141);
+ return nullnode();
+}
+
+static ENode *CExpr_SimpleExplicitConversion(void) {
+ DeclInfo di;
+
+ memclrw(&di, sizeof(DeclInfo));
+
+ if (!copts.cpp_extensions && tk != TK_UU_TYPEOF_UU && tk != TK_TYPENAME && lookahead() != '(')
+ CError_Error(CErrorStr114);
+
+ CParser_GetDeclSpecs(&di, 0);
+ return CExpr_ParseExplicitConversion(di.thetype, di.qual);
+}
+
+static ENode *CExpr_NewPTMFCall(void) {
+ tk = lex();
+ CExpr_ScanExpressionList(1);
+
+ if (tk != ')') {
+ CError_Error(CErrorStr115);
+ return nullnode();
+ } else {
+ CError_FATAL(2465);
+ return nullnode();
+ }
+}
+
+static ENode *call_ptmf(ENode *expr) {
+ Type *rettype;
+ ENodeList *args;
+ ENodeList *list1;
+ ENodeList *list2;
+ Object *callobj;
+
+ rettype = TYPE_FUNC(TPTR_TARGET(expr->data.mfpointer.mfpointer->rtype))->functype;
+ tk = lex();
+ args = CExpr_ScanExpressionList(1);
+
+ if (tk != ')') {
+ CError_Error(CErrorStr115);
+ return nullnode();
+ }
+
+ if (IS_TYPE_STRUCT(rettype) || IS_TYPE_CLASS(rettype) || IS_TYPE_12BYTES_MEMBERPOINTER(rettype))
+ callobj = rt_ptmf_scall4;
+ else
+ callobj = rt_ptmf_scall;
+
+ list1 = lalloc(sizeof(ENodeList));
+ list1->next = args;
+ list1->node = expr->data.mfpointer.accessnode->data.monadic;
+
+ list2 = lalloc(sizeof(ENodeList));
+ list2->next = list1;
+ list2->node = expr->data.mfpointer.mfpointer->data.monadic;
+
+ if (!copts.old_argmatch) {
+ CError_ASSERT(2568, IS_TYPE_POINTER_ONLY(list2->node->rtype));
+ list2->node->rtype = TYPE(&void_ptr);
+ }
+
+ expr = CExpr_GenericPtmfCall(
+ callobj,
+ TYPE_FUNC(TPTR_TARGET(expr->data.mfpointer.mfpointer->rtype)),
+ list2);
+ tk = lex();
+ return expr;
+}
+
+static ENode *CExpr_DummyDestr(ENode *expr) {
+ SInt32 state;
+ NameResult pr;
+ DeclInfo di;
+ NameSpace *nspace;
+
+ CPrep_TokenStreamGetState(&state);
+ nspace = cscope_current;
+ if ((tk = lex()) == TK_COLON_COLON) {
+ nspace = cscope_root;
+ tk = lex();
+ } else if (tk != '~' && tk != TK_IDENTIFIER && !(tk >= TK_AUTO && tk <= TK_BYREF)) {
+ CPrep_TokenStreamSetCurState(&state);
+ return NULL;
+ }
+
+loop:
+ if (tk == '~')
+ goto is_tilde;
+ if (tk == TK_IDENTIFIER) {
+ if (CScope_FindTypeName(nspace, tkidentifier, &pr)) {
+ tk = lex();
+ if (pr.nspace_0) {
+ if (tk == TK_COLON_COLON) {
+ tk = lex();
+ nspace = pr.nspace_0;
+ goto loop;
+ }
+ } else if (IS_TYPE_CLASS(pr.type) && tk == TK_COLON_COLON) {
+ tk = lex();
+ nspace = TYPE_CLASS(pr.type)->nspace;
+ goto loop;
+ } else {
+ if (!is_typesame(pr.type, expr->rtype))
+ CError_Error(CErrorStr146);
+ if (tk == TK_COLON_COLON && ((tk = lex()) == '~') && ((tk = lex()) == TK_IDENTIFIER)) {
+ parse_dtor:
+ if (CScope_FindTypeName(nspace, tkidentifier, &pr) && !pr.nspace_0) {
+ if (!is_typesame(pr.type, expr->rtype))
+ CError_Error(CErrorStr146);
+ tk = lex();
+ goto parsed;
+ }
+ }
+ }
+ }
+ } else if (tk >= TK_AUTO && tk <= TK_BYREF) {
+ memclrw(&di, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(&di, 0);
+ if (di.storageclass || di.qual || !is_typesame(di.thetype, expr->rtype))
+ CError_Error(CErrorStr146);
+ if (tk == TK_COLON_COLON && ((tk = lex()) == '~')) {
+ is_tilde:
+ if ((tk = lex()) == TK_IDENTIFIER)
+ goto parse_dtor;
+ memclrw(&di, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(&di, 0);
+ if (di.storageclass || !is_typesame(di.thetype, expr->rtype))
+ CError_Error(CErrorStr146);
+ goto parsed;
+ }
+ }
+
+ CError_Error(CErrorStr141);
+ return NULL;
+
+parsed:
+ if (tk == '(') {
+ if ((tk = lex()) != ')')
+ CError_Error(CErrorStr115);
+ else
+ tk = lex();
+ } else {
+ CError_Error(CErrorStr114);
+ }
+
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = &stvoid;
+ return expr;
+}
+
+static ENode *postfix_expression(Boolean flag) {
+ NameResult pr;
+ Conversion conv;
+ ENode *expr;
+ ENode *subexpr;
+ ENode *funcexpr;
+ ENodeList *args;
+ ENode *copy;
+ ENode *tmp;
+ StructMember *member;
+
+ if (copts.cplusplus) {
+ switch (tk) {
+ case TK_VOID:
+ case TK_CHAR:
+ case TK_SHORT:
+ case TK_INT:
+ case TK_LONG:
+ case TK_FLOAT:
+ case TK_DOUBLE:
+ case TK_SIGNED:
+ case TK_UNSIGNED:
+ case TK_UNK_113:
+ case TK_UNK_114:
+ case TK_UNK_115:
+ case TK_UNK_116:
+ case TK_UNK_117:
+ case TK_UNK_118:
+ case TK_UNK_119:
+ case TK_UNK_11A:
+ case TK_UU_TYPEOF_UU:
+ case TK_BOOL:
+ case TK_WCHAR_T:
+ case TK_TYPENAME:
+ expr = CExpr_SimpleExplicitConversion();
+ break;
+ default:
+ expr = primary_expression(flag);
+ break;
+ case TK_CONST_CAST:
+ expr = CRTTI_Parse_const_cast();
+ break;
+ case TK_DYNAMIC_CAST:
+ expr = CRTTI_Parse_dynamic_cast();
+ break;
+ case TK_REINTERPRET_CAST:
+ expr = CRTTI_Parse_reinterpret_cast();
+ break;
+ case TK_STATIC_CAST:
+ expr = CRTTI_Parse_static_cast();
+ break;
+ case TK_TYPEID:
+ expr = CRTTI_ParseTypeID();
+ break;
+ }
+ } else {
+ expr = primary_expression(flag);
+ }
+
+loop:
+ switch (tk) {
+ case '[':
+ expr = pointer_generation(expr);
+ tk = lex();
+ subexpr = expression();
+ if (copts.cplusplus && CExpr_CheckOperator('[', expr, subexpr, &conv)) {
+ if ((expr = conv.x0)) {
+ if (tk != ']')
+ CError_ErrorSkip(CErrorStr125);
+ else
+ tk = lex();
+ goto loop;
+ }
+
+ CError_ASSERT(2753, expr = conv.left);
+ CError_ASSERT(2754, subexpr = conv.right);
+ }
+
+ if (IS_TYPE_POINTER(expr->rtype)) {
+ expr = padd(expr, subexpr);
+ } else if (IS_TYPE_POINTER(subexpr->rtype)) {
+ expr = padd(subexpr, expr);
+ } else {
+ CError_Error(CErrorStr148);
+ goto dont_do_indirect;
+ }
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TPTR_TARGET(expr->rtype);
+ dont_do_indirect:
+ if (tk != ']')
+ CError_ErrorSkip(CErrorStr125);
+ else
+ tk = lex();
+ goto loop;
+
+ case '(':
+ funcexpr = CExpr_PointerGeneration(expr);
+ if (copts.cplusplus) {
+ if (CExpr_CheckOperator('(', funcexpr, NULL, &conv)) {
+ CError_ASSERT(2775, expr = conv.x0);
+ goto loop;
+ }
+ if (ENODE_IS(funcexpr, EMFPOINTER)) {
+ expr = checkreference(call_ptmf(funcexpr));
+ goto loop;
+ }
+ }
+
+ tk = lex();
+ args = CExpr_ScanExpressionList(1);
+ if (tk != ')')
+ CError_Error(CErrorStr115);
+
+ if (ENODE_IS(funcexpr, ETEMPLDEP)) {
+ expr = CExpr_NewENode(EFUNCCALL);
+ expr->rtype = &sttemplexpr;
+ expr->data.funccall.funcref = funcexpr;
+ expr->data.funccall.args = args;
+ expr->data.funccall.functype = &rt_func;
+ tk = lex();
+ } else {
+ expr = checkreference(CExpr_MakeFunctionCall(funcexpr, args));
+ tk = lex();
+ }
+ goto loop;
+
+ case TK_ARROW:
+ expr = pointer_generation(expr);
+ if (copts.cplusplus) {
+ while (IS_TYPE_CLASS(expr->rtype) && CExpr_CheckOperator(TK_ARROW, expr, NULL, &conv)) {
+ CError_ASSERT(2810, subexpr = conv.x0);
+ expr = pointer_generation(subexpr);
+ }
+ }
+
+ if (!IS_TYPE_POINTER(expr->rtype)) {
+ CError_ErrorSkip(CErrorStr148);
+ return expr;
+ }
+
+ if (copts.cplusplus && copts.objective_c && CObjC_IsType_id(expr->rtype)) {
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TPTR_TARGET(expr->rtype);
+ if ((subexpr = CObjC_CheckModernSendMessage(NULL, expr)))
+ return subexpr;
+ } else {
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TPTR_TARGET(expr->rtype);
+ }
+ case '.':
+ expr = pointer_generation(expr);
+ if (IS_TYPE_CLASS(expr->rtype)) {
+ CDecl_CompleteType(expr->rtype);
+ if (TYPE_CLASS(expr->rtype)->objcinfo && copts.cplusplus && (subexpr = CObjC_CheckModernSendMessage(TYPE_CLASS(expr->rtype), expr)))
+ return subexpr;
+
+ if (!(TYPE_CLASS(expr->rtype)->flags & CLASS_COMPLETED))
+ CError_Error(CErrorStr136, expr->rtype, 0);
+
+ if ((tk = lex()) == TK_TEMPLATE && (tk = lex()) != TK_IDENTIFIER)
+ CError_Error(CErrorStr107);
+
+ if (CScope_ParseMemberName(TYPE_CLASS(expr->rtype), &pr, 0)) {
+ if (pr.x1C) {
+ if ((tk = lex()) == '(') {
+ if ((tk = lex()) != ')')
+ CError_Error(CErrorStr115);
+ else
+ tk = lex();
+ } else {
+ CError_Error(CErrorStr114);
+ }
+
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = &stvoid;
+ } else {
+ expr = checkreference(CExpr_ParseNameResultExpr(&pr, expr, 0, 0));
+ }
+ }
+ goto loop;
+ }
+ if (!IS_TYPE_STRUCT(expr->rtype) || TYPE_STRUCT(expr->rtype)->stype > STRUCT_TYPE_MAX) {
+ if (copts.cplusplus && (subexpr = CExpr_DummyDestr(expr)))
+ return subexpr;
+ CError_ErrorSkip(CErrorStr149);
+ return expr;
+ }
+ if (!ENODE_IS(expr, EINDIRECT)) {
+ subexpr = CExpr_NewETEMPNode(expr->rtype, 1);
+ copy = lalloc(sizeof(ENode));
+ *copy = *subexpr;
+
+ tmp = makemonadicnode(subexpr, EINDIRECT);
+ tmp->rtype = expr->rtype;
+
+ tmp = makediadicnode(tmp, expr, EASS);
+ tmp = makediadicnode(tmp, copy, ECOMMA);
+ tmp->rtype = copy->rtype;
+
+ tmp = makemonadicnode(tmp, EINDIRECT);
+ tmp->rtype = expr->rtype;
+ expr = tmp;
+ }
+ if ((tk = lex()) != TK_IDENTIFIER) {
+ CError_Error(CErrorStr107);
+ return expr;
+ }
+
+ member = ismember(TYPE_STRUCT(expr->rtype), tkidentifier);
+ if (!member) {
+ if (!expr->rtype->size)
+ CError_Error(CErrorStr136, expr->rtype, 0);
+ else
+ CError_Error(CErrorStr150, tkidentifier->name);
+ return expr;
+ }
+
+ if (!IS_TYPE_POINTER(expr->data.monadic->rtype)) {
+ CError_ErrorSkip(CErrorStr149);
+ return expr;
+ }
+
+ expr = checkreference(CClass_AccessMember(expr, member->type, member->qual, member->offset));
+ tk = lex();
+ goto loop;
+
+ case TK_INCREMENT:
+ tmp = pointer_generation(expr);
+ if (copts.cplusplus && CExpr_CheckOperator(TK_INCREMENT, tmp, nullnode(), &conv)) {
+ if ((expr = conv.x0)) {
+ tk = lex();
+ goto loop;
+ }
+ CError_ASSERT(2952, tmp = conv.left);
+ }
+ tmp = CExpr_LValue(tmp, 1, 1);
+ if (tmp->rtype == TYPE(&stbool)) {
+ expr = CExpr_TempModifyExpr(tmp);
+ tk = lex();
+ } else {
+ checkadditive(tmp);
+ expr = makemonadicnode(tmp, EPOSTINC);
+ tk = lex();
+ }
+ goto loop;
+
+ case TK_DECREMENT:
+ tmp = pointer_generation(expr);
+ if (copts.cplusplus && CExpr_CheckOperator(TK_DECREMENT, tmp, nullnode(), &conv)) {
+ if ((expr = conv.x0)) {
+ tk = lex();
+ goto loop;
+ }
+ CError_ASSERT(2976, tmp = conv.left);
+ }
+ tmp = CExpr_LValue(tmp, 1, 1);
+ checkadditive(tmp);
+ expr = makemonadicnode(tmp, EPOSTDEC);
+ tk = lex();
+ goto loop;
+ }
+
+ return expr;
+}
+
+static ENode *CExpr_ParseSizeof(void) {
+ Type *type;
+ ENode *expr;
+
+ type = CExpr_ParseTypeExpression(NULL);
+ if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo)
+ CError_Error(CErrorStr286);
+
+ if (CTemplTool_IsTemplateArgumentDependentType(type)) {
+ expr = CExpr_NewTemplDepENode(TDE_SIZEOF);
+ expr->data.templdep.u.typeexpr.type = type;
+ return expr;
+ }
+
+ if (type->size == 0) {
+ if (copts.gcc_extensions && (IS_TYPE_FUNC(type) || IS_TYPE_VOID(type)))
+ return intconstnode(CABI_GetSizeTType(), 1);
+
+ if (IS_TYPE_CLASS(type) || IS_TYPE_STRUCT(type))
+ CError_Error(CErrorStr136, type, 0);
+ else
+ CError_Error(CErrorStr146);
+ }
+
+ return intconstnode(CABI_GetSizeTType(), type->size);
+}
+
+SInt32 scansizeof(void) {
+ ENode *expr;
+
+ expr = CExpr_ParseSizeof();
+ if (!ENODE_IS(expr, EINTCONST)) {
+ CError_Error(CErrorStr190);
+ return 0;
+ }
+
+ return CInt64_GetULong(&expr->data.intval);
+}
+
+static ENode *CExpr_ParseAlignof(void) {
+ Type *type;
+ ENode *expr;
+ SInt16 align;
+
+ type = CExpr_ParseTypeExpression(NULL);
+ if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo)
+ CError_Error(CErrorStr364);
+
+ if (CTemplTool_IsTemplateArgumentDependentType(type)) {
+ expr = CExpr_NewTemplDepENode(TDE_ALIGNOF);
+ expr->data.templdep.u.typeexpr.type = type;
+ return expr;
+ }
+
+ if (type->size == 0) {
+ if (IS_TYPE_CLASS(type) || IS_TYPE_STRUCT(type))
+ CError_Error(CErrorStr136, type, 0);
+ else
+ CError_Error(CErrorStr146);
+ }
+
+ align = CMach_GetTypeAlign(type);
+ if (align == 0)
+ align = 1;
+
+ return intconstnode(CABI_GetSizeTType(), align);
+}
+
+SInt32 scanalignof(void) {
+ ENode *expr;
+
+ expr = CExpr_ParseAlignof();
+ if (!ENODE_IS(expr, EINTCONST)) {
+ CError_Error(CErrorStr190);
+ return 0;
+ }
+
+ return CInt64_GetULong(&expr->data.intval);
+}
+
+static ENode *logicalexpression(ENode *expr) {
+ if (copts.cplusplus && copts.booltruefalse)
+ expr->rtype = TYPE(&stbool);
+ else
+ expr->rtype = TYPE(&stsignedint);
+ return expr;
+}
+
+ENode *getnodeaddress(ENode *expr, Boolean flag) {
+ ENode *result;
+ Object *obj;
+
+ if (!ENODE_IS(expr, EINDIRECT)) {
+ expr = CExpr_LValue(expr, flag, flag);
+ if (!ENODE_IS(expr, EINDIRECT)) {
+ if (!flag)
+ CError_Error(CErrorStr142);
+ return nullnode();
+ }
+ } else {
+ if (flag &&
+ ENODE_IS(expr->data.monadic, EOBJREF) &&
+ expr->data.monadic->data.objref->name == this_name_node &&
+ cscope_currentfunc &&
+ cscope_currentclass &&
+ expr->data.monadic->data.objref == CClass_ThisSelfObject())
+ CError_Error(CErrorStr189);
+ }
+
+ result = lalloc(sizeof(ENode));
+ *result = *expr;
+restart:
+ switch (result->data.monadic->type) {
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ result->type = ETYPCON;
+ if (IS_TYPE_POINTER_ONLY(result->rtype))
+ result->flags = TPTR_QUAL(result->rtype) & ENODE_FLAG_QUALS;
+ result->rtype = CDecl_NewPointerType(result->rtype);
+ return result;
+ case EOBJREF:
+ obj = result->data.monadic->data.objref;
+ if (obj->datatype == DALIAS) {
+ CExpr_AliasTransform(result->data.monadic);
+ goto restart;
+ }
+ if (obj->datatype == DINLINEFUNC)
+ CError_Error(CErrorStr175);
+ obj->flags = obj->flags | OBJECT_FLAGS_2;
+ if (flag && !copts.cplusplus && obj->sclass == TK_REGISTER)
+ CError_Error(CErrorStr163);
+ break;
+ case EFUNCCALL:
+ if (flag && !IS_TYPE_POINTER_ONLY(result->data.monadic->data.funccall.functype->functype))
+ CError_Warning(CErrorStr142);
+ break;
+ case EBITFIELD:
+ CError_Error(CErrorStr144);
+ return nullnode();
+ }
+
+ switch (result->rtype->type) {
+ case TYPEPOINTER:
+ result->data.monadic->rtype = CDecl_NewPointerType(result->rtype);
+ result->data.monadic->flags = result->flags;
+ break;
+ default:
+ result->data.monadic->rtype = CDecl_NewPointerType(result->rtype);
+ result->data.monadic->flags = result->flags;
+ }
+
+ return result->data.monadic;
+}
+
+static ENode *CExpr_MakeStaticMemberList(NameSpaceObjectList *list) {
+ NameSpaceObjectList *newlist;
+ NameSpaceObjectList *n;
+ ENode *result;
+
+ newlist = NULL;
+ while (list) {
+ if (list->object->otype == OT_OBJECT && IS_TYPE_STATIC_METHOD(OBJECT(list->object)->type)) {
+ n = galloc(sizeof(NameSpaceObjectList));
+ *n = *list;
+ n->next = newlist;
+ newlist = n;
+ }
+ list = list->next;
+ }
+
+ if (!newlist) {
+ CError_Warning(CErrorStr331);
+ return nullnode();
+ }
+
+ result = CExpr_NewENode(EOBJLIST);
+ result->rtype = OBJECT(newlist->object)->type;
+ result->data.objlist.list = newlist;
+ return result;
+}
+
+static ENode *CExpr_MakePTDM(ENode *expr) {
+ ENode *result;
+
+ CError_ASSERT(3414, ENODE_IS(expr, EMEMBER) && expr->data.emember->list->object->otype == OT_MEMBERVAR);
+
+ result = nullnode();
+ result->rtype = CExpr_NewPTMType(expr->data.emember, NULL);
+ CInt64_SetLong(&result->data.intval, OBJ_MEMBER_VAR(expr->data.emember->list->object)->offset + 1);
+ return result;
+}
+
+ENode *getpointertomemberfunc(ENode *expr, Type *type, Boolean flag) {
+ NameSpaceObjectList *list;
+ Object *obj;
+ Object *dataobj;
+ Type *ptmtype;
+ TypeMemberFunc *tmethod;
+ OLinkList *olist;
+ SInt32 data[3];
+
+ CError_ASSERT(3442, ENODE_IS(expr, EMEMBER));
+
+ if (expr->data.emember->expr && !copts.cpp_extensions)
+ CError_Error(CErrorStr141);
+
+ if (!copts.cpp_extensions) {
+ if (!(expr->data.emember->x11 && expr->data.emember->pr_1D)) {
+ if (type && IS_TYPE_MEMBERPOINTER(type))
+ CError_Warning(CErrorStr331);
+ }
+ }
+
+ if (expr->data.emember->list->next) {
+ if (type) {
+ if (IS_TYPE_MEMBERPOINTER(type)) {
+ type = TYPE_MEMBER_POINTER(type)->ty1;
+ for (list = expr->data.emember->list; list; list = list->next) {
+ if (list->object->otype == OT_OBJECT && is_memberpointerequal(OBJECT(list->object)->type, type)) {
+ obj = OBJECT(list->object);
+ break;
+ }
+ }
+ if (!list) {
+ CError_Error(CErrorStr146);
+ return nullnode();
+ }
+ } else {
+ return CExpr_MakeStaticMemberList(expr->data.emember->list);
+ }
+ } else {
+ obj = OBJECT(expr->data.emember->list->object);
+ }
+ } else {
+ obj = OBJECT(expr->data.emember->list->object);
+ }
+
+ while (obj->datatype == DALIAS)
+ obj = obj->u.alias.object;
+
+ CError_ASSERT(3503, obj->otype == OT_OBJECT && IS_TYPE_NONSTATIC_METHOD(obj->type));
+
+ if (TYPE_FUNC(obj->type)->flags & FUNC_IS_TEMPL)
+ CError_Error(CErrorStr190);
+
+ ptmtype = CExpr_NewPTMType(expr->data.emember, obj);
+ tmethod = TYPE_METHOD(obj->type);
+ dataobj = CParser_NewGlobalDataObject(NULL);
+ dataobj->name = CParser_GetUniqueName();
+ dataobj->nspace = cscope_root;
+ dataobj->type = ptmtype;
+ dataobj->sclass = TK_STATIC;
+
+ if (flag) {
+ data[0] = 0;
+ if (obj->datatype == DVFUNC) {
+ olist = NULL;
+ data[1] = tmethod->vtbl_index;
+ data[2] = tmethod->theclass->vtable->offset;
+ } else {
+ data[1] = -1;
+ data[2] = 0;
+ olist = galloc(sizeof(OLinkList));
+ olist->next = NULL;
+ olist->obj = obj;
+ olist->somevalue = 0;
+ olist->offset = 8;
+ }
+ CInit_DeclareData(dataobj, data, olist, dataobj->type->size);
+ }
+
+ return create_objectnode(dataobj);
+}
+
+static ENode *getpointertomember(ENode *expr) {
+ CError_ASSERT(3554, ENODE_IS(expr, EMEMBER));
+
+ if (expr->data.emember->expr)
+ CError_Error(CErrorStr141);
+
+ expr->data.emember->x11 = 1;
+ if (!expr->data.emember->list->next) {
+ if (expr->data.emember->list->object->otype == OT_MEMBERVAR)
+ return CExpr_MakePTDM(expr);
+ else
+ return getpointertomemberfunc(expr, NULL, 1);
+ }
+
+ return expr;
+}
+
+ENode *CExpr_New_ELOGNOT_Node(ENode *input) {
+ ENode *expr;
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(input->rtype))
+ return CTempl_MakeTemplDepExpr(NULL, ELOGNOT, input);
+
+ expr = pointer_generation(input);
+ if (copts.cplusplus && CExpr_CheckOperator('!', expr, NULL, &conv)) {
+ if ((input = conv.x0))
+ return input;
+ CError_ASSERT(3593, expr = conv.left);
+ }
+
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEPOINTER:
+ case TYPEARRAY:
+ break;
+ case TYPEENUM:
+ expr = forceintegral(expr);
+ break;
+ case TYPEMEMBERPOINTER:
+ expr = CExpr_ConvertToCondition(expr);
+ break;
+ default:
+ CError_Error(CErrorStr144);
+ return expr;
+ }
+
+ switch (expr->type) {
+ case EINTCONST:
+ expr->data.intval = CInt64_Not(expr->data.intval);
+ break;
+ case EFLOATCONST:
+ expr->type = EINTCONST;
+ CInt64_SetLong(&expr->data.intval, CMach_FloatIsZero(expr->data.floatval));
+ break;
+ default:
+ expr = makemonadicnode(expr, ELOGNOT);
+ }
+
+ return logicalexpression(expr);
+}
+
+ENode *CExpr_New_EMONMIN_Node(ENode *input) {
+ ENode *expr;
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(input->rtype))
+ return CTempl_MakeTemplDepExpr(NULL, EMONMIN, input);
+
+ expr = pointer_generation(input);
+ if (copts.cplusplus && CExpr_CheckOperator('-', expr, NULL, &conv)) {
+ if ((input = conv.x0))
+ return input;
+ CError_ASSERT(3652, expr = conv.left);
+ }
+
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ case TYPEENUM:
+ expr = integralpromote(expr);
+ if (ENODE_IS(expr, EINTCONST)) {
+ expr->data.intval = CMach_CalcIntMonadic(expr->rtype, '-', expr->data.intval);
+ return expr;
+ }
+ return makemonadicnode(expr, EMONMIN);
+ case TYPEFLOAT:
+ if (ENODE_IS(expr, EFLOATCONST)) {
+ expr->data.floatval = CMach_CalcFloatMonadic(expr->rtype, '-', expr->data.floatval);
+ return expr;
+ }
+ return CExpr_UnaryFloatExpression(makemonadicnode(expr, EMONMIN));
+ default:
+ CError_Error(CErrorStr144);
+ return expr;
+ }
+}
+
+ENode *CExpr_New_EBINNOT_Node(ENode *input) {
+ ENode *expr;
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(input->rtype))
+ return CTempl_MakeTemplDepExpr(NULL, EBINNOT, input);
+
+ expr = pointer_generation(input);
+ if (copts.cplusplus && CExpr_CheckOperator('~', expr, NULL, &conv)) {
+ if ((input = conv.x0))
+ return input;
+ CError_ASSERT(3702, expr = conv.left);
+ }
+
+ expr = integralpromote(expr);
+
+ if (ENODE_IS(expr, EINTCONST)) {
+ expr->data.intval = CMach_CalcIntMonadic(expr->rtype, '~', expr->data.intval);
+ return expr;
+ }
+ return makemonadicnode(expr, EBINNOT);
+}
+
+ENode *unary_expression(void) {
+ ENode *expr;
+ ENode *tmp;
+ Conversion conv;
+
+ switch (tk) {
+ case TK_COLON_COLON:
+ switch (lookahead()) {
+ case TK_NEW:
+ tk = lex();
+ return scannew(1);
+ case TK_DELETE:
+ tk = lex();
+ return scandelete(1);
+ }
+ return postfix_expression(0);
+
+ case TK_NEW:
+ return scannew(0);
+ case TK_DELETE:
+ return scandelete(0);
+ case TK_INCREMENT:
+ tk = lex();
+ if (copts.cplusplus) {
+ expr = pointer_generation(cast_expression());
+ if (CExpr_CheckOperator(TK_INCREMENT, expr, NULL, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(3748, expr = conv.left);
+ }
+ } else {
+ expr = pointer_generation(unary_expression());
+ }
+ expr = CExpr_LValue(expr, 1, 1);
+ if (expr->rtype == TYPE(&stbool)) {
+ tmp = nullnode();
+ tmp->rtype = TYPE(&stbool);
+ CInt64_SetLong(&tmp->data.intval, 1);
+ return makediadicnode(expr, tmp, EASS);
+ } else {
+ checkadditive(expr);
+ return makemonadicnode(expr, EPREINC);
+ }
+ case TK_DECREMENT:
+ tk = lex();
+ if (copts.cplusplus) {
+ expr = pointer_generation(cast_expression());
+ if (CExpr_CheckOperator(TK_DECREMENT, expr, NULL, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(3776, expr = conv.left);
+ }
+ } else {
+ expr = pointer_generation(unary_expression());
+ }
+ expr = CExpr_LValue(expr, 1, 1);
+ checkadditive(expr);
+ return makemonadicnode(expr, EPREDEC);
+
+ case '&':
+ if (copts.cplusplus) {
+ switch ((tk = lex())) {
+ case TK_IDENTIFIER:
+ case TK_INHERITED:
+ case TK_COLON_COLON:
+ expr = postfix_expression(1);
+ if (ENODE_IS(expr, EMEMBER))
+ return getpointertomember(expr);
+ break;
+ default:
+ expr = cast_expression();
+ }
+
+ if (CExpr_CheckOperator('&', expr, NULL, &conv)) {
+ CError_ASSERT(3809, conv.x0);
+ return conv.x0;
+ }
+ } else {
+ tk = lex();
+ expr = cast_expression();
+ }
+
+ if (copts.mpwc_relax && !copts.cplusplus && IS_TYPE_ARRAY(expr->rtype) && ENODE_IS(expr, EINDIRECT))
+ return pointer_generation(expr);
+ if (ENODE_IS(expr, EOBJLIST))
+ return expr;
+
+ if (IS_TYPE_TEMPLDEPEXPR(expr->rtype)) {
+ tmp = CExpr_NewTemplDepENode(TDE_ADDRESS_OF);
+ tmp->data.templdep.u.monadic = expr;
+ return tmp;
+ }
+
+ return getnodeaddress(expr, 1);
+
+ case '*':
+ tk = lex();
+ expr = pointer_generation(cast_expression());
+ if (copts.cplusplus && CExpr_CheckOperator('*', expr, NULL, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(3840, expr = conv.left);
+ }
+
+ if (!IS_TYPE_POINTER(expr->rtype)) {
+ CError_Error(CErrorStr148);
+ return expr;
+ }
+
+ tmp = makemonadicnode(expr, EINDIRECT);
+ CDecl_CompleteType(tmp->rtype = TPTR_TARGET(tmp->rtype));
+ return tmp;
+
+ case '+':
+ tk = lex();
+ expr = pointer_generation(cast_expression());
+ if (copts.cplusplus && CExpr_CheckOperator('+', expr, NULL, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(3852, expr = conv.left);
+ }
+
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ case TYPEENUM:
+ return integralpromote(expr);
+ case TYPEFLOAT:
+ case TYPEPOINTER:
+ case TYPEARRAY:
+ return expr;
+ default:
+ CError_Error(CErrorStr144);
+ return expr;
+ }
+
+ case '-':
+ tk = lex();
+ return CExpr_New_EMONMIN_Node(cast_expression());
+ case '~':
+ tk = lex();
+ return CExpr_New_EBINNOT_Node(cast_expression());
+ case '!':
+ tk = lex();
+ return CExpr_New_ELOGNOT_Node(cast_expression());
+
+ case TK_SIZEOF:
+ return CExpr_ParseSizeof();
+ case TK_UU_ALIGNOF_UU:
+ return CExpr_ParseAlignof();
+
+ case TK_LOGICAL_AND:
+ if (copts.ANSIstrict)
+ break;
+
+ if ((tk = lex()) != TK_IDENTIFIER) {
+ CError_Error(CErrorStr107);
+ return nullnode();
+ }
+
+ expr = lalloc(sizeof(ENode));
+ expr->type = ELABEL;
+ expr->cost = 0;
+ expr->flags = 0;
+ expr->rtype = TYPE(&void_ptr);
+ expr->data.label = findlabel();
+ if (!expr->data.label) {
+ expr->data.label = newlabel();
+ expr->data.label->name = tkidentifier;
+ expr->data.label->next = Labels;
+ Labels = expr->data.label;
+ }
+ tk = lex();
+ return expr;
+ }
+
+ return postfix_expression(0);
+}
+
+ENode *do_castnullcheck(ENode *condexpr, ENode *nullcheckexpr) {
+ ENode *result;
+
+ if (isnotzero(nullcheckexpr))
+ return condexpr;
+
+ result = lalloc(sizeof(ENode));
+ *result = *condexpr;
+ result->type = ENULLCHECK;
+ result->data.nullcheck.nullcheckexpr = lalloc(sizeof(ENode));
+ *result->data.nullcheck.nullcheckexpr = *nullcheckexpr;
+ result->data.nullcheck.condexpr = condexpr;
+ result->data.nullcheck.precompid = CParser_GetUniqueID();
+
+ nullcheckexpr->type = EPRECOMP;
+ nullcheckexpr->data.precompid = result->data.nullcheck.precompid;
+
+ return result;
+}
+
+ENode *CExpr_SafeClassPointerCast(ENode *expr, TypeClass *a, TypeClass *b, Boolean typconflag, Boolean pathcheckflag) {
+ ENode *result;
+
+ result = CClass_ClassPointerCast(expr, a, b, typconflag, 1, pathcheckflag);
+ if (result != expr) {
+ if (!(ENODE_IS(result, ETYPCON) && result->data.monadic == expr))
+ result = do_castnullcheck(result, expr);
+ }
+ return result;
+}
+
+ENode *PointerToMemberCast(ENode *expr, TypeMemberPointer *tm1, TypeMemberPointer *tm2, Boolean flag) {
+ BClassList *path;
+ Boolean negate;
+ short depth;
+ Boolean isambig;
+ SInt32 pathoffset;
+ CInt64 pathoffset64;
+ ENode *tmp;
+
+ CError_ASSERT(3984, IS_TYPE_CLASS(tm1->ty2));
+ CError_ASSERT(3985, IS_TYPE_CLASS(tm2->ty2));
+
+ if (tm1->ty2 == tm2->ty2) {
+ expr->rtype = TYPE(tm2);
+ return expr;
+ }
+
+ negate = 0;
+ path = CClass_GetBasePath(TYPE_CLASS(tm2->ty2), TYPE_CLASS(tm1->ty2), &depth, &isambig);
+ if (!path) {
+ path = CClass_GetBasePath(TYPE_CLASS(tm1->ty2), TYPE_CLASS(tm2->ty2), &depth, &isambig);
+ if (!path)
+ goto failed;
+ negate = 1;
+ }
+
+ if (isambig)
+ CError_Error(CErrorStr188);
+
+ if ((pathoffset = CClass_GetPathOffset(path)) < 0)
+ goto failed;
+ if (negate)
+ pathoffset = -pathoffset;
+
+ if (flag)
+ CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC);
+
+ if (tm1->size != tm2->size) {
+ failed:
+ CError_Error(CErrorStr247, tm1, 0, tm2, 0);
+ return nullnode();
+ }
+
+ if (!pathoffset) {
+ expr->rtype = TYPE(tm2);
+ return expr;
+ }
+
+ if (tm1->size == 4u) {
+ if (ENODE_IS(expr, EINTCONST)) {
+ if (!CInt64_IsZero(&expr->data.intval)) {
+ CInt64_SetLong(&pathoffset64, pathoffset);
+ expr->data.intval = CInt64_Add(expr->data.intval, pathoffset64);
+ }
+ expr->rtype = TYPE(tm2);
+ return expr;
+ } else {
+ expr->rtype = TYPE(&stunsignedlong);
+ tmp = intconstnode(TYPE(&stunsignedlong), pathoffset);
+ tmp = makediadicnode(expr, tmp, EADD);
+ tmp = makemonadicnode(tmp, ETYPCON);
+ tmp->rtype = TYPE(tm2);
+ return do_castnullcheck(tmp, expr);
+ }
+ } else {
+ tmp = create_temp_node(TYPE(&ptmstruct));
+ expr = getnodeaddress(expr, 0);
+ tmp = funccallexpr(rt_ptmf_cast, intconstnode(TYPE(&stsignedlong), pathoffset), expr, tmp, NULL);
+ tmp = makemonadicnode(tmp, EINDIRECT);
+ tmp->rtype = TYPE(tm2);
+ return tmp;
+ }
+}
+
+ENode *CExpr_MemberPointerConversion(ENode *expr, TypeMemberPointer *type, Boolean flag1) {
+ if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval)) {
+ if (IS_TYPE_FUNC(type->ty1))
+ expr = create_objectnode(rt_ptmf_null);
+ expr->rtype = TYPE(type);
+ } else if (ENODE_IS(expr, EMEMBER)) {
+ expr = getpointertomemberfunc(expr, TYPE(type), flag1);
+ }
+
+ return expr;
+}
+
+static ENode *CExpr_MemberPointerCast(ENode *expr, TypeMemberPointer *type, UInt32 qual) {
+ if (!IS_TYPE_MEMBERPOINTER(expr->rtype))
+ expr = CExpr_MemberPointerConversion(expr, type, 1);
+
+ if (!IS_TYPE_MEMBERPOINTER(expr->rtype)) {
+ CError_Error(CErrorStr164);
+ return nullnode();
+ }
+
+ expr = PointerToMemberCast(expr, TYPE_MEMBER_POINTER(expr->rtype), type, 0);
+ expr->flags = qual & ENODE_FLAG_QUALS;
+ return expr;
+}
+
+ENode *do_typecast(ENode *expr, Type *type, UInt32 qual) {
+ TypePointer *tptr;
+ ENode *tmp;
+ short flags;
+
+ if (!copts.old_argmatch)
+ return CExpr_Convert(expr, type, qual, 1, 0);
+
+ if (copts.cpp_extensions && is_typesame(expr->rtype, type) && !ENODE_IS(expr, EOBJLIST)) {
+ expr->rtype = type;
+ expr->flags &= ~ENODE_FLAG_QUALS;
+ expr->flags |= qual & ENODE_FLAG_QUALS;
+ return expr;
+ }
+
+ switch (type->type) {
+ case TYPEARRAY:
+ CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual);
+ return expr;
+ case TYPEMEMBERPOINTER:
+ if (!IS_TYPE_CLASS(expr->rtype))
+ return CExpr_MemberPointerCast(expr, TYPE_MEMBER_POINTER(type), qual);
+ }
+
+ flags = qual & ENODE_FLAG_QUALS;
+
+ if (ENODE_IS(expr, EOBJLIST))
+ return CExpr_AssignmentPromotion(expr, type, qual & ENODE_FLAG_QUALS, 1);
+
+ if (ENODE_IS(expr, EOBJREF) && IS_TYPE_NONSTATIC_METHOD(expr->data.objref->type)) {
+ CError_Error(CErrorStr221);
+ return nullnode();
+ }
+
+ if (type == &stvoid) {
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = type;
+ expr->flags = flags;
+ return expr;
+ }
+
+ if (IS_TYPE_REFERENCE(type)) {
+ tmp = getnodeaddress(expr, 0);
+ tptr = galloc(sizeof(TypePointer));
+ *tptr = *TYPE_POINTER(type);
+ tptr->qual &= ~Q_REFERENCE;
+
+ tmp = do_typecast(tmp, TYPE(tptr), qual);
+ tmp = makemonadicnode(tmp, EINDIRECT);
+ tmp->rtype = TPTR_TARGET(type);
+ tmp->flags = flags;
+ return tmp;
+ }
+
+ if (IS_TYPE_CLASS(expr->rtype) || IS_TYPE_CLASS(type)) {
+ if (expr->rtype->size == 0)
+ CDecl_CompleteType(expr->rtype);
+
+ if (expr->rtype == type && !CClass_CopyConstructor(TYPE_CLASS(type)))
+ return expr;
+
+ if (user_assign_check(expr, type, qual, 1, 1, 1)) {
+ assign_node->flags = flags;
+ return assign_node;
+ }
+
+ CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual);
+ return nullnode();
+ }
+
+ if (IS_TYPE_STRUCT(type) && copts.cplusplus && is_typesame(expr->rtype, type)) {
+ expr->rtype = type;
+ expr->flags = flags;
+ return expr;
+ }
+
+ if (type == TYPE(&stbool)) {
+ expr = CExpr_ConvertToBool(expr, 1);
+ expr->flags = flags;
+ return expr;
+ }
+
+ if (IS_TYPE_ENUM(type)) {
+ tmp = do_typecast(expr, TYPE_ENUM(type)->enumtype, qual);
+ if (!ENODE_IS(tmp, EINTCONST))
+ tmp = makemonadicnode(tmp, ETYPCON);
+ tmp->rtype = type;
+ tmp->flags = flags;
+ return tmp;
+ }
+
+ if (IS_TYPE_INT_OR_FLOAT(type)) {
+ if (ENODE_IS(expr, ETYPCON) && expr->rtype->type == type->type && expr->rtype->size == type->size) {
+ if (is_unsigned(expr->rtype) == is_unsigned(type) && ENODE_QUALS(expr) == qual) {
+ expr->rtype = type;
+ expr->flags = expr->flags | ENODE_FLAG_80;
+ return expr;
+ }
+ }
+
+ if (IS_TYPE_ENUM(expr->rtype))
+ expr = forceintegral(expr);
+
+ if (IS_TYPE_INT_OR_FLOAT(expr->rtype)) {
+ expr = promote(expr, type);
+ expr->flags = flags;
+ return expr;
+ }
+
+ if (!(IS_TYPE_POINTER_ONLY(expr->rtype) && !IS_TYPE_FLOAT(type)))
+ CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual);
+
+ if (ENODE_IS(expr, ETYPCON) && ENODE_IS(tmp = expr->data.monadic, EINTCONST)) {
+ tmp->rtype = type;
+ tmp->flags = flags;
+ tmp->data.intval = CExpr_IntConstConvert(type, TYPE(&stunsignedlong), tmp->data.intval);
+ return tmp;
+ }
+
+ if (type->size != 4) {
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = TYPE(&stunsignedlong);
+ }
+
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = type;
+ expr->flags = flags;
+ return expr;
+ }
+
+ if (IS_TYPE_POINTER(type)) {
+ if (IS_TYPE_POINTER(expr->rtype)) {
+ if (IS_TYPE_CLASS(TPTR_TARGET(expr->rtype)) && IS_TYPE_CLASS(TPTR_TARGET(type)))
+ expr = CExpr_SafeClassPointerCast(expr, TYPE_CLASS(TPTR_TARGET(expr->rtype)), TYPE_CLASS(TPTR_TARGET(type)), 1, 0);
+
+ if (!ENODE_IS(expr, ETYPCON))
+ expr = makemonadicnode(expr, ETYPCON);
+
+ expr->rtype = type;
+ expr->flags = flags;
+ return expr;
+ }
+
+ if (!IS_TYPE_INT(expr->rtype)) {
+ if (!IS_TYPE_ENUM(expr->rtype)) {
+ CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual);
+ return expr;
+ }
+ expr = forceintegral(expr);
+ }
+
+ if (expr->rtype->size != 4) {
+ if (!ENODE_IS(expr, EINTCONST))
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = TYPE(&stunsignedlong);
+ }
+
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = type;
+ expr->flags = flags;
+ return expr;
+ }
+
+ if ((tmp = CodeGen_HandleTypeCast(expr, type, qual)))
+ return tmp;
+
+ CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual);
+ return nullnode();
+}
+
+static Boolean isvectorconst(ENode *node) {
+ if (ENODE_IS3(node, ECOMMA, EINTCONST, EFLOATCONST))
+ return 1;
+ else
+ return 0;
+}
+
+ENode *cast_expression(void) {
+ ENode *expr;
+ ENode *tmp;
+ ENodeList *args;
+ MWVector128 vec;
+ DeclInfo di;
+
+ if (!(tk == '(' && islookaheaddeclaration()))
+ return unary_expression();
+ tk = lex();
+
+ memclrw(&di, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(&di, 0);
+ scandeclarator(&di);
+
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+
+ if (di.name)
+ CError_Error(CErrorStr164);
+
+ if (copts.altivec_model && tk == '(' && IS_TYPE_VECTOR(di.thetype)) {
+ tk = lex();
+ expr = s_expression();
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+
+ if (CodeGen_CollapseVectorExpression(expr, &vec, di.thetype)) {
+ tmp = lalloc(sizeof(ENode));
+ tmp->type = EVECTOR128CONST;
+ if ((tmp->cost = expr->cost) == 0)
+ tmp->cost = 1;
+ tmp->flags = ENODE_QUALS(expr);
+ tmp->rtype = di.thetype;
+ tmp->data.vector128val = vec;
+ } else {
+ tmp = makemonadicnode(expr, ETYPCON);
+ }
+ tmp->rtype = di.thetype;
+ tmp->flags = expr->flags;
+ return tmp;
+ }
+
+ if (tk == '{' && (!copts.ANSIstrict || copts.c9x) && !IS_TYPE_VECTOR(di.thetype))
+ return CInit_AutoObject(NULL, di.thetype, di.qual);
+
+ expr = cast_expression();
+ if (copts.cplusplus && (CTemplTool_IsTemplateArgumentDependentType(di.thetype) ||
+ CTemplTool_IsTemplateArgumentDependentExpression(expr))) {
+ args = lalloc(sizeof(ENodeList));
+ args->next = NULL;
+ args->node = expr;
+ return CExpr_TemplArgDepCast(di.thetype, di.qual, args);
+ }
+
+ if (!IS_TYPE_REFERENCE(di.thetype))
+ expr = pointer_generation(expr);
+ return do_typecast(expr, di.thetype, di.qual);
+}
+
+static ENode *pm_expression(void) {
+ ENode *left;
+ ENode *right;
+ ENode *tmp;
+ Type *type;
+ UInt32 qual;
+ short flags;
+ Conversion conv;
+
+ left = cast_expression();
+restart:
+ switch (tk) {
+ case TK_ARROW_STAR:
+ left = pointer_generation(left);
+ tk = lex();
+ right = pointer_generation(cast_expression());
+
+ if (CExpr_CheckOperator(TK_ARROW_STAR, left, right, &conv)) {
+ CError_ASSERT(4457, left = conv.x0);
+ goto restart;
+ }
+
+ if (!IS_TYPE_POINTER(left->rtype)) {
+ CError_Error(CErrorStr148);
+ return left;
+ }
+
+ left = makemonadicnode(left, EINDIRECT);
+ left->rtype = TPTR_TARGET(left->rtype);
+ goto common_part;
+ case TK_DOT_STAR:
+ left = pointer_generation(left);
+ tk = lex();
+ right = pointer_generation(cast_expression());
+ if (!ENODE_IS(left, EINDIRECT)) {
+ CError_Error(CErrorStr142);
+ return left;
+ }
+ common_part:
+ if (!IS_TYPE_CLASS(left->rtype)) {
+ CError_Error(CErrorStr149);
+ return left;
+ }
+ if (!IS_TYPE_MEMBERPOINTER(right->rtype)) {
+ CError_Error(CErrorStr144);
+ return left;
+ }
+ if (left->rtype != TYPE_MEMBER_POINTER(right->rtype)->ty2) {
+ if (CClass_IsBaseClass(TYPE_CLASS(left->rtype), TYPE_CLASS(TYPE_MEMBER_POINTER(right->rtype)->ty2), NULL, 1, 1)) {
+ left->data.monadic = CClass_ClassPointerCast(
+ left->data.monadic,
+ TYPE_CLASS(left->rtype),
+ TYPE_CLASS(TYPE_MEMBER_POINTER(right->rtype)->ty2),
+ 0, 1, 1);
+ left->rtype = TYPE_MEMBER_POINTER(right->rtype)->ty2;
+ } else {
+ CError_Error(CErrorStr146);
+ return left;
+ }
+ }
+ type = CClass_CombineClassAccessQualifiers(
+ TYPE_MEMBER_POINTER(right->rtype)->ty1,
+ ENODE_QUALS(right),
+ left->flags,
+ &qual);
+ flags = qual;
+ if (!IS_TYPE_FUNC(type)) {
+ if (!ENODE_IS(right, EINTCONST)) {
+ if (!canadd(left->data.monadic, -1)) {
+ left->data.monadic = makediadicnode(left->data.monadic, nullnode(), EADD);
+ CInt64_SetLong(&left->data.monadic->data.diadic.right->data.intval, -1);
+ optimizecomm(left->data.monadic);
+ }
+ right->rtype = TYPE(&stunsignedlong);
+ left->data.monadic = makediadicnode(left->data.monadic, right, EADD);
+ optimizecomm(left->data.monadic);
+ } else {
+ right->data.intval = CInt64_Sub(right->data.intval, cint64_one);
+ if (!canadd2(left->data.monadic, right->data.intval)) {
+ right->rtype = TYPE(&stunsignedlong);
+ left->data.monadic = makediadicnode(left->data.monadic, right, EADD);
+ optimizecomm(left->data.monadic);
+ }
+ }
+
+ if (IS_TYPE_BITFIELD(type)) {
+ left->data.monadic = makemonadicnode(left->data.monadic, EBITFIELD);
+ left->data.monadic->rtype = type;
+ left->rtype = TYPE_BITFIELD(type)->bitfieldtype;
+ } else {
+ left->rtype = type;
+ }
+ left->flags = flags;
+ left = checkreference(left);
+ goto restart;
+ } else {
+ CError_ASSERT(4535, ENODE_IS(right, EINDIRECT));
+ tmp = lalloc(sizeof(ENode));
+ tmp->type = EMFPOINTER;
+ tmp->cost = 4;
+ tmp->flags = 0;
+ tmp->rtype = &stvoid;
+ tmp->data.mfpointer.accessnode = left;
+ tmp->data.mfpointer.mfpointer = right;
+ return tmp;
+ }
+ default:
+ return left;
+ }
+}
+
+ENode *CExpr_New_EMUL_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, EMUL, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator('*', left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(4566, left = conv.left);
+ CError_ASSERT(4567, right = conv.right);
+ }
+
+ return makemultnode(left, right);
+}
+
+ENode *CExpr_New_EDIV_Node(ENode *left, ENode *right, Boolean no_warning) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, EDIV, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator('/', left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(4592, left = conv.left);
+ CError_ASSERT(4593, right = conv.right);
+ }
+
+ return makedivnode(left, right, no_warning);
+}
+
+ENode *CExpr_New_EMODULO_Node(ENode *left, ENode *right, Boolean no_warning) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, EMODULO, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator('%', left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(4618, left = conv.left);
+ CError_ASSERT(4619, right = conv.right);
+ }
+
+ left = integralpromote(left);
+ right = integralpromote(right);
+ CExpr_ArithmeticConversion(&left, &right);
+
+ if (iszero(right)) {
+ if (!no_warning)
+ CError_Warning(CErrorStr139);
+ return left;
+ }
+
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '%', right->data.intval);
+ return left;
+ }
+
+ if (iszero(left))
+ return makediadicnode(right, left, ECOMMA);
+
+ if (CExpr_IsOne(right)) {
+ right = nullnode();
+ right->rtype = left->rtype;
+ return makediadicnode(left, right, ECOMMA);
+ }
+
+ return makediadicnode(left, right, EMODULO);
+}
+
+ENode *CExpr_New_EADD_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, EADD, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator('+', left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(4665, left = conv.left);
+ CError_ASSERT(4666, right = conv.right);
+ }
+
+ return makeaddnode(left, right);
+}
+
+ENode *CExpr_New_ESUB_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, ESUB, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator('-', left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(4690, left = conv.left);
+ CError_ASSERT(4691, right = conv.right);
+ }
+
+ return makesubnode(left, right);
+}
+
+ENode *CExpr_New_ESHL_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, ESHL, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator(TK_SHL, left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(4715, left = conv.left);
+ CError_ASSERT(4716, right = conv.right);
+ }
+
+ left = integralpromote(left);
+ right = integralpromote(right);
+
+ if (iszero(left) || iszero(right)) {
+ return left;
+ }
+
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_SHL, right->data.intval);
+ return left;
+ }
+
+ return makediadicnode(left, right, ESHL);
+}
+
+ENode *CExpr_New_ESHR_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, ESHR, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator(TK_SHR, left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(4752, left = conv.left);
+ CError_ASSERT(4753, right = conv.right);
+ }
+
+ left = integralpromote(left);
+ right = integralpromote(right);
+
+ if (iszero(left) || iszero(right)) {
+ return left;
+ }
+
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_SHR, right->data.intval);
+ return left;
+ }
+
+ return makediadicnode(left, right, ESHR);
+}
+
+static ENode *pointercompare(ENodeType nt, ENode *left, ENode *right) {
+ Type *ltype;
+ Type *rtype;
+
+ ltype = left->rtype;
+ rtype = right->rtype;
+ if (IS_TYPE_POINTER_ONLY(ltype) && IS_TYPE_POINTER_ONLY(rtype)) {
+ ltype = TPTR_TARGET(left->rtype);
+ rtype = TPTR_TARGET(right->rtype);
+ if (IS_TYPE_CLASS(ltype) && IS_TYPE_CLASS(rtype)) {
+ if (ltype != rtype) {
+ if (ltype == TPTR_TARGET(left->rtype)) {
+ if (CClass_IsBaseClass(TYPE_CLASS(ltype), TYPE_CLASS(rtype), NULL, 0, 1)) {
+ left = CExpr_SafeClassPointerCast(left, TYPE_CLASS(ltype), TYPE_CLASS(rtype), 0, 1);
+ } else if (CClass_IsBaseClass(TYPE_CLASS(rtype), TYPE_CLASS(ltype), NULL, 0, 1)) {
+ right = CExpr_SafeClassPointerCast(right, TYPE_CLASS(rtype), TYPE_CLASS(ltype), 0, 1);
+ } else {
+ CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right));
+ }
+ } else {
+ CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right));
+ }
+ }
+ } else if (!is_typeequal(left->rtype, right->rtype)) {
+ if (!copts.objective_c || !CObjC_IsCompatibleType(left->rtype, right->rtype)) {
+ CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right));
+ }
+ }
+ } else if (nt == EEQU || nt == ENOTEQU) {
+ if (IS_TYPE_INT(ltype)) {
+ if (!(ENODE_IS(left, EINTCONST) && CInt64_IsZero(&left->data.intval)))
+ CError_Error(CErrorStr144);
+ CError_ASSERT(4847, IS_TYPE_POINTER_ONLY(rtype));
+ left->rtype = TYPE(&stunsignedlong);
+ } else if (IS_TYPE_INT(rtype)) {
+ if (!(ENODE_IS(right, EINTCONST) && CInt64_IsZero(&right->data.intval)))
+ CError_Error(CErrorStr144);
+ CError_ASSERT(4855, IS_TYPE_POINTER_ONLY(ltype));
+ right->rtype = TYPE(&stunsignedlong);
+ } else if (!is_typeequal(ltype, rtype)) {
+ CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right));
+ }
+ } else {
+ if (!is_typeequal(ltype, rtype))
+ CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right));
+ }
+
+ return logicalexpression(makediadicnode(left, right, nt));
+}
+
+static ENode *unsigncheck(ENode *expr, Boolean flag1, Boolean flag2) {
+ if (is_unsigned(expr->data.diadic.left->rtype)) {
+ if (ENODE_IS(expr->data.diadic.left, EINTCONST) && CInt64_IsZero(&expr->data.diadic.left->data.intval)) {
+ flag1 = !flag1;
+ } else if (!(ENODE_IS(expr->data.diadic.right, EINTCONST) && CInt64_IsZero(&expr->data.diadic.right->data.intval))) {
+ return logicalexpression(expr);
+ }
+
+ if (flag1 && flag2) {
+ expr->type = EEQU;
+ return logicalexpression(expr);
+ }
+ if (!flag1 && !flag2) {
+ expr->type = ENOTEQU;
+ return logicalexpression(expr);
+ }
+ return CExpr_ConstResult(logicalexpression(expr), !flag1);
+ }
+ return logicalexpression(expr);
+}
+
+ENode *CExpr_New_ELESS_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, ELESS, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator('<', left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(4929, left = conv.left);
+ CError_ASSERT(4930, right = conv.right);
+ }
+
+ if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype))
+ return pointercompare(ELESS, left, right);
+
+ CExpr_CompareConvert(&left, "<", &right, 0);
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '<', right->data.intval);
+ left->rtype = CParser_GetBoolType();
+ } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
+ CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, '<', right->data.floatval));
+ left->type = EINTCONST;
+ left->rtype = CParser_GetBoolType();
+ } else {
+ left = unsigncheck(makediadicnode(left, right, ELESS), 1, 0);
+ }
+
+ return left;
+}
+
+ENode *CExpr_New_ELESSEQU_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, ELESSEQU, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator(TK_LESS_EQUAL, left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(4976, left = conv.left);
+ CError_ASSERT(4977, right = conv.right);
+ }
+
+ if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype))
+ return pointercompare(ELESSEQU, left, right);
+
+ CExpr_CompareConvert(&left, "<=", &right, 0);
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_LESS_EQUAL, right->data.intval);
+ left->rtype = CParser_GetBoolType();
+ } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
+ CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_LESS_EQUAL, right->data.floatval));
+ left->type = EINTCONST;
+ left->rtype = CParser_GetBoolType();
+ } else {
+ left = unsigncheck(makediadicnode(left, right, ELESSEQU), 1, 1);
+ }
+
+ return left;
+}
+
+ENode *CExpr_New_EGREATER_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, EGREATER, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator('>', left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(5023, left = conv.left);
+ CError_ASSERT(5024, right = conv.right);
+ }
+
+ if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype))
+ return pointercompare(EGREATER, left, right);
+
+ CExpr_CompareConvert(&left, ">", &right, 0);
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '>', right->data.intval);
+ left->rtype = CParser_GetBoolType();
+ } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
+ CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, '>', right->data.floatval));
+ left->type = EINTCONST;
+ left->rtype = CParser_GetBoolType();
+ } else {
+ left = unsigncheck(makediadicnode(left, right, EGREATER), 0, 0);
+ }
+
+ return left;
+}
+
+ENode *CExpr_New_EGREATEREQU_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, EGREATEREQU, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator(TK_GREATER_EQUAL, left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(5070, left = conv.left);
+ CError_ASSERT(5071, right = conv.right);
+ }
+
+ if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype))
+ return pointercompare(EGREATEREQU, left, right);
+
+ CExpr_CompareConvert(&left, ">=", &right, 0);
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_GREATER_EQUAL, right->data.intval);
+ left->rtype = CParser_GetBoolType();
+ } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
+ CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_GREATER_EQUAL, right->data.floatval));
+ left->type = EINTCONST;
+ left->rtype = CParser_GetBoolType();
+ } else {
+ left = unsigncheck(makediadicnode(left, right, EGREATEREQU), 0, 1);
+ }
+
+ return left;
+}
+
+ENode *memberpointercompare(ENodeType nt, ENode *left, ENode *right) {
+ Object *func;
+ ENodeList *arg;
+
+ if (!IS_TYPE_MEMBERPOINTER(left->rtype)) {
+ if (!(IS_TYPE_INT(left->rtype) && ENODE_IS(left, EINTCONST) && CInt64_IsZero(&left->data.intval))) {
+ CError_Error(CErrorStr144);
+ return nullnode();
+ }
+ } else if (!IS_TYPE_MEMBERPOINTER(right->rtype)) {
+ if (!(IS_TYPE_INT(right->rtype) && ENODE_IS(right, EINTCONST) && CInt64_IsZero(&right->data.intval))) {
+ CError_Error(CErrorStr144);
+ return nullnode();
+ }
+ } else if (!is_typeequal(left->rtype, right->rtype)) {
+ left = PointerToMemberCast(left, TYPE_MEMBER_POINTER(left->rtype), TYPE_MEMBER_POINTER(right->rtype), 1);
+ }
+
+ if ((ENODE_IS(left, EINTCONST) || !IS_TYPE_FUNC(TYPE_MEMBER_POINTER(left->rtype)->ty1)) && (ENODE_IS(right, EINTCONST) || !IS_TYPE_FUNC(TYPE_MEMBER_POINTER(right->rtype)->ty1))) {
+ left->rtype = TYPE(&stunsignedlong);
+ right->rtype = TYPE(&stunsignedlong);
+ return logicalexpression(makediadicnode(left, right, nt));
+ }
+
+ arg = lalloc(sizeof(ENodeList));
+ if (ENODE_IS(left, EINTCONST) || ENODE_IS(right, EINTCONST)) {
+ func = rt_ptmf_test;
+ if (ENODE_IS(left, EINTCONST))
+ arg->node = getnodeaddress(right, 0);
+ else
+ arg->node = getnodeaddress(left, 0);
+ arg->next = NULL;
+ } else {
+ func = rt_ptmf_cmpr;
+ arg->next = lalloc(sizeof(ENodeList));
+ arg->node = getnodeaddress(left, 0);
+ arg->next->node = getnodeaddress(right, 0);
+ arg->next->next = NULL;
+ }
+
+ left = lalloc(sizeof(ENode));
+ left->type = EFUNCCALL;
+ left->rtype = TYPE(&stsignedlong);
+ left->cost = 4;
+ left->data.funccall.funcref = create_objectrefnode(func);
+ left->data.funccall.args = arg;
+ left->data.funccall.functype = TYPE_FUNC(func->type);
+ left->flags = TYPE_FUNC(func->type)->qual & ENODE_FLAG_QUALS;
+
+ if (nt == EEQU)
+ left = makemonadicnode(left, ELOGNOT);
+
+ return left;
+}
+
+ENode *CExpr_New_EEQU_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, EEQU, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_EQ, left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(5201, left = conv.left);
+ CError_ASSERT(5202, right = conv.right);
+ }
+
+ if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype))
+ return pointercompare(EEQU, left, right);
+ if (IS_TYPE_MEMBERPOINTER(left->rtype) || IS_TYPE_MEMBERPOINTER(right->rtype))
+ return memberpointercompare(EEQU, left, right);
+
+ CExpr_CompareConvert(&left, "==", &right, 1);
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_LOGICAL_EQ, right->data.intval);
+ left->rtype = CParser_GetBoolType();
+ } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
+ left->type = EINTCONST;
+ CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_LOGICAL_EQ, right->data.floatval));
+ left->type = EINTCONST;
+ left->rtype = CParser_GetBoolType();
+ } else {
+ left = makediadicnode(left, right, EEQU);
+ optimizecomm(left);
+ }
+
+ return logicalexpression(left);
+}
+
+ENode *CExpr_New_ENOTEQU_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, ENOTEQU, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_NE, left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(5261, left = conv.left);
+ CError_ASSERT(5262, right = conv.right);
+ }
+
+ if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype))
+ return pointercompare(ENOTEQU, left, right);
+ if (IS_TYPE_MEMBERPOINTER(left->rtype) || IS_TYPE_MEMBERPOINTER(right->rtype))
+ return memberpointercompare(ENOTEQU, left, right);
+
+ CExpr_CompareConvert(&left, "!=", &right, 1);
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_LOGICAL_NE, right->data.intval);
+ left->rtype = CParser_GetBoolType();
+ } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) {
+ CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_LOGICAL_NE, right->data.floatval));
+ left->type = EINTCONST;
+ left->rtype = CParser_GetBoolType();
+ } else {
+ left = makediadicnode(left, right, ENOTEQU);
+ optimizecomm(left);
+ }
+
+ return logicalexpression(left);
+}
+
+ENode *CExpr_New_EAND_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, EAND, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator('&', left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(5321, left = conv.left);
+ CError_ASSERT(5322, right = conv.right);
+ }
+
+ left = integralpromote(left);
+ right = integralpromote(right);
+ CExpr_ArithmeticConversion(&left, &right);
+
+ if (iszero(left) || CExpr_AllBitsSet(right))
+ return left;
+ if (iszero(right) || CExpr_AllBitsSet(left))
+ return right;
+
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '&', right->data.intval);
+ return left;
+ }
+
+ left = makediadicnode(left, right, EAND);
+ optimizecomm(left);
+ return left;
+}
+
+ENode *CExpr_New_EXOR_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, EXOR, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator('^', left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(5360, left = conv.left);
+ CError_ASSERT(5361, right = conv.right);
+ }
+
+ left = integralpromote(left);
+ right = integralpromote(right);
+ CExpr_ArithmeticConversion(&left, &right);
+
+ if (iszero(right))
+ return left;
+ if (iszero(left))
+ return right;
+
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '^', right->data.intval);
+ return left;
+ }
+
+ left = makediadicnode(left, right, EXOR);
+ optimizecomm(left);
+ return left;
+}
+
+ENode *CExpr_New_EOR_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, EOR, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator('|', left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(5399, left = conv.left);
+ CError_ASSERT(5400, right = conv.right);
+ }
+
+ left = integralpromote(left);
+ right = integralpromote(right);
+ CExpr_ArithmeticConversion(&left, &right);
+
+ if (iszero(right) || CExpr_AllBitsSet(left))
+ return left;
+ if (iszero(left) || CExpr_AllBitsSet(right))
+ return right;
+
+ if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) {
+ left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '|', right->data.intval);
+ return left;
+ }
+
+ left = makediadicnode(left, right, EOR);
+ optimizecomm(left);
+ return left;
+}
+
+ENode *CExpr_New_ELAND_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, ELAND, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_AND, left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(5438, left = conv.left);
+ CError_ASSERT(5439, right = conv.right);
+ }
+
+ switch (left->rtype->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEPOINTER:
+ case TYPEARRAY:
+ break;
+ case TYPEENUM:
+ case TYPEMEMBERPOINTER:
+ left = CExpr_ConvertToCondition(left);
+ break;
+ default:
+ CError_Error(CErrorStr144);
+ left = nullnode();
+ }
+ switch (right->rtype->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEPOINTER:
+ case TYPEARRAY:
+ break;
+ case TYPEENUM:
+ case TYPEMEMBERPOINTER:
+ right = CExpr_ConvertToCondition(right);
+ break;
+ default:
+ CError_Error(CErrorStr144);
+ right = nullnode();
+ }
+
+ if (iszero(left)) {
+ left->type = EINTCONST;
+ left->rtype = CParser_GetBoolType();
+ CInt64_SetLong(&left->data.intval, 0);
+ return left;
+ }
+
+ if (isnotzero(left)) {
+ if (iszero(right)) {
+ left->type = EINTCONST;
+ left->rtype = CParser_GetBoolType();
+ CInt64_SetLong(&left->data.intval, 0);
+ return left;
+ } else if (isnotzero(right)) {
+ left->type = EINTCONST;
+ left->rtype = CParser_GetBoolType();
+ CInt64_SetLong(&left->data.intval, 1);
+ return left;
+ } else {
+ left = makemonadicnode(right, ELOGNOT);
+ left->rtype = CParser_GetBoolType();
+ return makemonadicnode(left, ELOGNOT);
+ }
+ } else {
+ if (isnotzero(right)) {
+ left = makemonadicnode(left, ELOGNOT);
+ left->rtype = CParser_GetBoolType();
+ return makemonadicnode(left, ELOGNOT);
+ } else if (iszero(right)) {
+ right->type = EINTCONST;
+ right->rtype = CParser_GetBoolType();
+ CInt64_SetLong(&right->data.intval, 0);
+ return makecommaexpression(left, right);
+ } else {
+ left = makediadicnode(left, right, ELAND);
+ left->rtype = CParser_GetBoolType();
+ return left;
+ }
+ }
+}
+
+ENode *CExpr_New_ELOR_Node(ENode *left, ENode *right) {
+ Conversion conv;
+
+ if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype))
+ return CTempl_MakeTemplDepExpr(left, ELOR, right);
+
+ left = pointer_generation(left);
+ right = pointer_generation(right);
+ if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_OR, left, right, &conv)) {
+ if (conv.x0)
+ return conv.x0;
+ CError_ASSERT(5543, left = conv.left);
+ CError_ASSERT(5544, right = conv.right);
+ }
+
+ switch (left->rtype->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEPOINTER:
+ case TYPEARRAY:
+ break;
+ case TYPEENUM:
+ case TYPEMEMBERPOINTER:
+ left = CExpr_ConvertToCondition(left);
+ break;
+ default:
+ CError_Error(CErrorStr144);
+ left = nullnode();
+ }
+ switch (right->rtype->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEPOINTER:
+ case TYPEARRAY:
+ break;
+ case TYPEENUM:
+ case TYPEMEMBERPOINTER:
+ right = CExpr_ConvertToCondition(right);
+ break;
+ default:
+ CError_Error(CErrorStr144);
+ right = nullnode();
+ }
+
+ if (isnotzero(left)) {
+ left->type = EINTCONST;
+ left->rtype = CParser_GetBoolType();
+ CInt64_SetLong(&left->data.intval, 1);
+ return left;
+ }
+
+ if (iszero(left)) {
+ if (iszero(right)) {
+ left->type = EINTCONST;
+ left->rtype = CParser_GetBoolType();
+ CInt64_SetLong(&left->data.intval, 0);
+ return left;
+ } else if (isnotzero(right)) {
+ left->type = EINTCONST;
+ left->rtype = CParser_GetBoolType();
+ CInt64_SetLong(&left->data.intval, 1);
+ return left;
+ } else {
+ left = makemonadicnode(right, ELOGNOT);
+ left->rtype = CParser_GetBoolType();
+ return makemonadicnode(left, ELOGNOT);
+ }
+ } else {
+ if (isnotzero(right)) {
+ right->type = EINTCONST;
+ right->rtype = CParser_GetBoolType();
+ CInt64_SetLong(&right->data.intval, 1);
+ } else if (iszero(right)) {
+ left = makemonadicnode(left, ELOGNOT);
+ left->rtype = CParser_GetBoolType();
+ return makemonadicnode(left, ELOGNOT);
+ }
+ left = makediadicnode(left, right, ELOR);
+ left->rtype = CParser_GetBoolType();
+ return left;
+ }
+}
+
+ENode *CExpr_NewDyadicNode(ENode *left, ENodeType nt, ENode *right) {
+ switch (nt) {
+ default:
+ CError_FATAL(5642);
+ case EADD: return CExpr_New_EADD_Node(left, right);
+ case ESUB: return CExpr_New_ESUB_Node(left, right);
+ case EMUL: return CExpr_New_EMUL_Node(left, right);
+ case EDIV: return CExpr_New_EDIV_Node(left, right, 1);
+ case EMODULO: return CExpr_New_EMODULO_Node(left, right, 1);
+ case EAND: return CExpr_New_EAND_Node(left, right);
+ case EXOR: return CExpr_New_EXOR_Node(left, right);
+ case EOR: return CExpr_New_EOR_Node(left, right);
+ case ESHL: return CExpr_New_ESHL_Node(left, right);
+ case ESHR: return CExpr_New_ESHR_Node(left, right);
+ case ELESS: return CExpr_New_ELESS_Node(left, right);
+ case EGREATER: return CExpr_New_EGREATER_Node(left, right);
+ case ELESSEQU: return CExpr_New_ELESSEQU_Node(left, right);
+ case EGREATEREQU: return CExpr_New_EGREATEREQU_Node(left, right);
+ case EEQU: return CExpr_New_EEQU_Node(left, right);
+ case ENOTEQU: return CExpr_New_ENOTEQU_Node(left, right);
+ case ELAND: return CExpr_New_ELAND_Node(left, right);
+ case ELOR: return CExpr_New_ELOR_Node(left, right);
+ }
+}
+
+typedef struct DyadicInfo {
+ ENodeType t;
+ UInt8 prec;
+} DyadicInfo;
+
+static Boolean CExpr_GetDyadicInfo(short token, DyadicInfo *info) {
+ switch (token) {
+ case '*':
+ info->t = EMUL;
+ info->prec = 20;
+ return 1;
+ case '/':
+ info->t = EDIV;
+ info->prec = 20;
+ return 1;
+ case '%':
+ info->t = EMODULO;
+ info->prec = 20;
+ return 1;
+ case '+':
+ info->t = EADD;
+ info->prec = 19;
+ return 1;
+ case '-':
+ info->t = ESUB;
+ info->prec = 19;
+ return 1;
+ case TK_SHL:
+ info->t = ESHL;
+ info->prec = 18;
+ return 1;
+ case TK_SHR:
+ info->t = ESHR;
+ info->prec = 18;
+ return 1;
+ case '<':
+ info->t = ELESS;
+ info->prec = 17;
+ return 1;
+ case TK_LESS_EQUAL:
+ info->t = ELESSEQU;
+ info->prec = 17;
+ return 1;
+ case '>':
+ if (disallowgreaterthan)
+ return 0;
+ info->t = EGREATER;
+ info->prec = 17;
+ return 1;
+ case TK_GREATER_EQUAL:
+ info->t = EGREATEREQU;
+ info->prec = 17;
+ return 1;
+ case TK_LOGICAL_EQ:
+ info->t = EEQU;
+ info->prec = 16;
+ return 1;
+ case TK_LOGICAL_NE:
+ info->t = ENOTEQU;
+ info->prec = 16;
+ return 1;
+ case '&':
+ info->t = EAND;
+ info->prec = 15;
+ return 1;
+ case '^':
+ info->t = EXOR;
+ info->prec = 14;
+ return 1;
+ case '|':
+ info->t = EOR;
+ info->prec = 13;
+ return 1;
+ case TK_LOGICAL_AND:
+ info->t = ELAND;
+ info->prec = 12;
+ return 1;
+ case TK_LOGICAL_OR:
+ info->t = ELOR;
+ info->prec = 11;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static ENode *CExpr_ParseDyadicExpression(ENode *left, UInt8 prec, Boolean no_warning) {
+ ENode *right;
+ Boolean is_eland_or_elor;
+ Boolean save_dgt;
+ Boolean cont;
+ DyadicInfo left_info;
+ DyadicInfo right_info;
+
+ save_dgt = disallowgreaterthan;
+ if (!left) {
+ disallowgreaterthan = 0;
+ left = pm_expression();
+ disallowgreaterthan = save_dgt;
+ }
+
+ do {
+ if (!CExpr_GetDyadicInfo(tk, &left_info))
+ return left;
+
+ switch (left_info.t) {
+ case ELAND:
+ CExpr_CheckUnwantedAssignment(left);
+ if (iszero(left))
+ no_warning = 1;
+ is_eland_or_elor = 1;
+ break;
+ case ELOR:
+ CExpr_CheckUnwantedAssignment(left);
+ if (isnotzero(left))
+ no_warning = 1;
+ is_eland_or_elor = 1;
+ break;
+ default:
+ is_eland_or_elor = 0;
+ }
+
+ tk = lex();
+ disallowgreaterthan = 0;
+ right = pm_expression();
+ disallowgreaterthan = save_dgt;
+ inner_loop:
+ if (CExpr_GetDyadicInfo(tk, &right_info)) {
+ if (left_info.prec >= right_info.prec) {
+ cont = (prec >= right_info.prec);
+ } else {
+ right = CExpr_ParseDyadicExpression(right, left_info.prec, no_warning);
+ goto inner_loop;
+ }
+ } else {
+ cont = 1;
+ }
+
+ if (is_eland_or_elor)
+ CExpr_CheckUnwantedAssignment(right);
+
+ switch (left_info.t) {
+ case EDIV:
+ left = CExpr_New_EDIV_Node(left, right, no_warning);
+ break;
+ case EMODULO:
+ left = CExpr_New_EMODULO_Node(left, right, no_warning);
+ break;
+ default:
+ left = CExpr_NewDyadicNode(left, left_info.t, right);
+ }
+ } while (!cont);
+
+ return left;
+}
+
+static Boolean CExpr_IsBlockMoveType(Type *type) {
+ switch (type->type) {
+ case TYPESTRUCT:
+ case TYPECLASS:
+ return 1;
+ case TYPEMEMBERPOINTER:
+ return type->size != 4;
+ default:
+ return 0;
+ }
+}
+
+ENode *CExpr_New_ECOND_Node(ENode *cond, ENode *expr1, ENode *expr2) {
+ ENode *result;
+ ENodeList *args;
+ short cost;
+ Conversion conv;
+
+ cond = CExpr_ConvertToCondition(pointer_generation(cond));
+ expr1 = pointer_generation(expr1);
+ expr2 = pointer_generation(expr2);
+
+ if (!IS_TYPE_INT_OR_FLOAT(cond->rtype) && !IS_TYPE_POINTER_ONLY(cond->rtype)) {
+ CError_Error(CErrorStr144);
+ return nullnode();
+ }
+
+ cost = cond->cost + 1;
+ if (expr1->cost > expr2->cost)
+ cost += expr1->cost;
+ else
+ cost += expr2->cost;
+ if (expr2->cost > cost)
+ cost = expr2->cost;
+ if (cost > 200)
+ cost = 200;
+
+ result = CExpr_NewENode(ECOND);
+ result->cost = cost;
+ result->rtype = expr1->rtype;
+ result->flags = expr1->flags | expr2->flags;
+ result->data.cond.cond = cond;
+ if (ENODE_IS(expr1, EFUNCCALL) && expr1->rtype == &stvoid && (expr1->flags & ENODE_FLAG_VOLATILE) != 0) {
+ result->rtype = expr2->rtype;
+ result->flags = expr2->flags;
+ result->data.cond.expr1 = expr1;
+ result->data.cond.expr2 = expr2;
+ return result;
+ }
+ if (ENODE_IS(expr2, EFUNCCALL) && expr2->rtype == &stvoid && (expr2->flags & ENODE_FLAG_VOLATILE) != 0) {
+ result->rtype = expr1->rtype;
+ result->flags = expr1->flags;
+ result->data.cond.expr1 = expr1;
+ result->data.cond.expr2 = expr2;
+ return result;
+ }
+
+ if (
+ ENODE_IS(expr1, EINDIRECT) &&
+ ENODE_IS(expr2, EINDIRECT) &&
+ is_typesame(expr1->rtype, expr2->rtype) &&
+ ENODE_QUALS(expr1) == ENODE_QUALS(expr2) &&
+ CExpr_IsBlockMoveType(expr1->rtype) &&
+ !ENODE_IS(expr1->data.monadic, EBITFIELD) &&
+ !ENODE_IS(expr2->data.monadic, EBITFIELD)
+ ) {
+ if (isnotzero(cond))
+ return expr1;
+ if (iszero(cond))
+ return expr2;
+ result->data.cond.expr1 = getnodeaddress(expr1, 0);
+ result->data.cond.expr2 = getnodeaddress(expr2, 0);
+ result->rtype = result->data.cond.expr1->rtype;
+ result = makemonadicnode(result, EINDIRECT);
+ result->rtype = TPTR_TARGET(result->rtype);
+ return result;
+ }
+
+ if ((IS_TYPE_CLASS(expr1->rtype) || IS_TYPE_CLASS(expr2->rtype)) && !is_typesame(expr1->rtype, expr2->rtype)) {
+ if (!copts.old_argmatch) {
+ if (CExpr_CondOperatorMatch(expr1, expr2, &conv)) {
+ CError_ASSERT(6246, !conv.x0);
+ expr1 = conv.left;
+ expr2 = conv.right;
+ } else if (CExpr_CanImplicitlyConvert(expr1, expr2->rtype, ENODE_QUALS(expr2))) {
+ if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1)))
+ CError_Error(CErrorStr188);
+ expr1 = CExpr_Convert(expr1, expr2->rtype, ENODE_QUALS(expr2), 0, 1);
+ } else if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1))) {
+ expr2 = CExpr_Convert(expr2, expr1->rtype, ENODE_QUALS(expr1), 0, 1);
+ } else {
+ goto failed;
+ }
+
+ result->rtype = expr1->rtype;
+ } else {
+ args = lalloc(sizeof(ENodeList));
+ args->node = expr1;
+ args->next = lalloc(sizeof(ENodeList));
+ args->next->node = expr2;
+ args->next->next = NULL;
+
+ if (CExpr_CheckOperatorConversion(':', expr1, expr2, args, &conv)) {
+ CError_ASSERT(6274, !conv.x0);
+ expr1 = conv.left;
+ expr2 = conv.right;
+ }
+
+ result->rtype = expr1->rtype;
+ }
+ }
+
+ switch (expr1->rtype->type) {
+ case TYPEENUM:
+ if (expr1->rtype == expr2->rtype)
+ break;
+ expr1 = forceintegral(expr1);
+ case TYPEINT:
+ if (IS_TYPE_POINTER_ONLY(expr2->rtype) || IS_TYPE_MEMBERPOINTER(expr2->rtype)) {
+ expr1 = CExpr_Convert(expr1, expr2->rtype, ENODE_QUALS(expr2), 0, 1);
+ result->rtype = expr2->rtype;
+ break;
+ }
+ case TYPEFLOAT:
+ if (expr1->rtype != expr2->rtype) {
+ CExpr_ArithmeticConversion(&expr1, &expr2);
+ result->rtype = expr1->rtype;
+ }
+ break;
+ case TYPEPOINTER:
+ if (ENODE_IS(expr2, EINTCONST) && CInt64_IsZero(&expr2->data.intval)) {
+ expr2->rtype = TYPE(&stunsignedlong);
+ break;
+ }
+ if (IS_TYPE_POINTER_ONLY(expr2->rtype)) {
+ if (IS_TYPE_CLASS(TPTR_TARGET(expr1->rtype)) && IS_TYPE_CLASS(TPTR_TARGET(expr2->rtype))) {
+ if (TPTR_TARGET(expr1->rtype) != TPTR_TARGET(expr2->rtype)) {
+ if (CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(expr1->rtype)), TYPE_CLASS(TPTR_TARGET(expr2->rtype)), NULL, 0, 1)) {
+ expr1 = CExpr_SafeClassPointerCast(
+ expr1,
+ TYPE_CLASS(TPTR_TARGET(expr1->rtype)),
+ TYPE_CLASS(TPTR_TARGET(expr2->rtype)),
+ 0, 1);
+ expr1->rtype = expr2->rtype;
+ } else if (CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(expr2->rtype)), TYPE_CLASS(TPTR_TARGET(expr1->rtype)), NULL, 0, 1)) {
+ expr2 = CExpr_SafeClassPointerCast(
+ expr2,
+ TYPE_CLASS(TPTR_TARGET(expr2->rtype)),
+ TYPE_CLASS(TPTR_TARGET(expr1->rtype)),
+ 0, 1);
+ expr2->rtype = expr1->rtype;
+ } else {
+ goto failed;
+ }
+ }
+ result->rtype = expr1->rtype;
+ break;
+ }
+ if (TPTR_TARGET(expr2->rtype) == &stvoid)
+ result->rtype = expr2->rtype;
+ }
+ if (!is_typeequal(expr1->rtype, expr2->rtype)) {
+ if (!copts.objective_c)
+ goto failed;
+ if (!CObjC_IsCompatibleType(expr1->rtype, expr2->rtype))
+ goto failed;
+ expr1->rtype = expr2->rtype = CObjC_GetObjCType_id(1);
+ }
+ break;
+ case TYPEVOID:
+ if (!is_typeequal(expr1->rtype, expr2->rtype))
+ goto failed;
+ break;
+ case TYPESTRUCT:
+ case TYPECLASS:
+ if (!is_typeequal(expr1->rtype, expr2->rtype))
+ goto failed;
+ result->rtype = expr1->rtype;
+ break;
+ case TYPEMEMBERPOINTER:
+ if (IS_TYPE_MEMBERPOINTER(expr2->rtype) && TYPE_MEMBER_POINTER(expr1->rtype)->ty2 == TYPE_MEMBER_POINTER(expr2->rtype)->ty2) {
+ expr2 = CExpr_Convert(expr2, expr1->rtype, ENODE_QUALS(expr1), 0, 1);
+ } else if (CExpr_CanImplicitlyConvert(expr1, expr2->rtype, ENODE_QUALS(expr2))) {
+ if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1)))
+ CError_Error(CErrorStr188);
+ expr1 = CExpr_Convert(expr1, expr2->rtype, ENODE_QUALS(expr2), 0, 1);
+ } else if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1))) {
+ expr2 = CExpr_Convert(expr2, expr1->rtype, ENODE_QUALS(expr1), 0, 1);
+ } else {
+ goto failed;
+ }
+ result->rtype = expr1->rtype;
+ break;
+ default:
+ failed:
+ CError_Error(CErrorStr245, expr1->rtype, ENODE_QUALS(expr1), expr2->rtype, ENODE_QUALS(expr2));
+ return nullnode();
+ }
+
+ result->data.cond.expr1 = expr1;
+ result->data.cond.expr2 = expr2;
+ if (isnotzero(cond))
+ result = expr1;
+ else if (iszero(cond))
+ result = expr2;
+ return result;
+}
+
+static ENode *conditional_expression(void) {
+ ENode *cond;
+ ENode *expr1;
+ ENode *expr2;
+ ENode *result;
+ Boolean is_templdep_cond;
+
+ is_templdep_cond = 0;
+ cond = CExpr_ParseDyadicExpression(NULL, 0, 0);
+ if (tk != '?')
+ return cond;
+
+ cond = pointer_generation(cond);
+ if (!IS_TYPE_TEMPLDEPEXPR(cond->rtype)) {
+ cond = CExpr_ConvertToCondition(cond);
+ if (!IS_TYPE_INT_OR_FLOAT(cond->rtype) && !IS_TYPE_POINTER_ONLY(cond->rtype)) {
+ CError_Error(CErrorStr144);
+ return nullnode();
+ }
+ } else {
+ is_templdep_cond = 1;
+ }
+
+ tk = lex();
+ expr1 = expression();
+ if (tk != ':')
+ CError_ErrorSkip(CErrorStr141);
+ else
+ tk = lex();
+
+ expr2 = (copts.cplusplus && !copts.ARMconform) ? assignment_expression() : conditional_expression();
+
+ if (is_templdep_cond || IS_TYPE_TEMPLDEPEXPR(expr1->rtype) || IS_TYPE_TEMPLDEPEXPR(expr2->rtype)) {
+ result = CExpr_NewENode(ECOND);
+ result->rtype = &sttemplexpr;
+ result->data.cond.cond = cond;
+ result->data.cond.expr1 = expr1;
+ result->data.cond.expr2 = expr2;
+ return result;
+ }
+
+ return CExpr_New_ECOND_Node(cond, expr1, expr2);
+}
+
+static ENode *CExpr_MakeOpAssNode(ENode *left, ENode *right, ENodeType nt) {
+ if (left->rtype != right->rtype) {
+ switch (right->rtype->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ break;
+ case TYPEENUM:
+ right->rtype = TYPE_ENUM(right->rtype)->enumtype;
+ break;
+ default:
+ right = CExpr_AssignmentPromotion(right, left->rtype, 0, 1);
+ }
+ if (IS_TYPE_FLOAT(left->rtype)) {
+ if (IS_TYPE_INT(right->rtype) || (IS_TYPE_FLOAT(right->rtype) && left->rtype->size >= right->rtype->size))
+ right = CExpr_AssignmentPromotion(right, left->rtype, 0, 1);
+ } else if (IS_TYPE_INT(left->rtype)) {
+ if (IS_TYPE_INT(right->rtype) && (left->rtype->size > right->rtype->size || (left->rtype->size == right->rtype->size && is_unsigned(left->rtype) == is_unsigned(right->rtype))))
+ right = CExpr_AssignmentPromotion(right, left->rtype, 0, 1);
+ }
+ }
+
+ return makediadicnode(left, right, nt);
+}
+
+static ENode *makeassignmentnode(ENode *left, ENodeType nt, short token) {
+ ENode *right;
+ ENode *tmp;
+ ENode *funcexpr;
+ ENodeList *args;
+ Conversion conv;
+
+ tk = lex();
+ right = assignment_expression();
+ if (copts.cplusplus) {
+ if (copts.old_argmatch && !ENODE_IS(right, EMEMBER))
+ right = pointer_generation(right);
+ if (CExpr_CheckOperator(token, left, right, &conv)) {
+ if (!conv.x0) {
+ if (nt == EASS)
+ goto continue_anyway;
+ CError_FATAL(6531);
+ }
+ return conv.x0;
+ }
+ if (IS_TYPE_CLASS(left->rtype) && CClass_AssignmentOperator(TYPE_CLASS(left->rtype)))
+ CError_Error(CErrorStr144);
+ }
+continue_anyway:
+ if (IS_TYPE_ARRAY(left->rtype)) {
+ if (copts.gcc_extensions && nt == EASS && is_typesame(left->rtype, right->rtype)) {
+ tmp = makediadicnode(left, right, nt);
+ tmp->flags = left->flags;
+ return tmp;
+ }
+ CError_Error(CErrorStr144);
+ return nullnode();
+ }
+
+ left = CExpr_LValue(pointer_generation(left), 1, 1);
+ if (nt != EASS) {
+ if (!IS_TYPE_INT(right->rtype)) {
+ if (!IS_TYPE_ENUM(right->rtype)) {
+ CError_Error(CErrorStr144);
+ return left;
+ }
+ right = forceintegral(right);
+ }
+ if (!IS_TYPE_INT(left->rtype)) {
+ if (copts.cplusplus) {
+ CError_Error(CErrorStr144);
+ return left;
+ }
+ left = forceintegral(left);
+ if (!IS_TYPE_INT(left->rtype)) {
+ CError_Error(CErrorStr144);
+ return left;
+ }
+ }
+ return CExpr_MakeOpAssNode(left, right, nt);
+ }
+
+ if (IS_TYPE_CLASS(left->rtype) && TYPE_CLASS(left->rtype)->sominfo) {
+ CError_Error(CErrorStr285);
+ return left;
+ }
+
+ if (copts.warn_implicitconv && ENODE_IS(left, EINDIRECT) && ENODE_IS(left->data.monadic, EBITFIELD) && !ENODE_IS(right, EINTCONST)) {
+ copts.warn_implicitconv = 0;
+ right = CExpr_AssignmentPromotion(right, left->rtype, left->flags, 1);
+ copts.warn_implicitconv = 1;
+ } else {
+ right = CExpr_AssignmentPromotion(right, left->rtype, left->flags, 1);
+ }
+
+ tmp = right;
+ if (IS_TYPE_FLOAT(right->rtype) && ENODE_IS(right, ETYPCON) && right->rtype->size == right->data.monadic->rtype->size)
+ tmp = right->data.monadic;
+
+ if (
+ ENODE_IS(left, EINDIRECT) &&
+ ENODE_IS(left->data.monadic, EOBJREF) &&
+ ENODE_IS(tmp, EINDIRECT) &&
+ (ENODE_IS(funcexpr = right->data.monadic, EFUNCCALL) || ENODE_IS(funcexpr, EFUNCCALLP)) &&
+ left->rtype == funcexpr->data.funccall.functype->functype &&
+ CMach_GetFunctionResultClass(funcexpr->data.funccall.functype) == 1 &&
+ (args = funcexpr->data.funccall.args)
+ ) {
+ switch (CABI_GetStructResultArgumentIndex(funcexpr->data.funccall.functype)) {
+ case 0:
+ break;
+ case 1:
+ if ((args = args->next))
+ break;
+ CError_FATAL(6625);
+ default:
+ CError_FATAL(6626);
+ }
+ if (ENODE_IS(args->node, ETEMP)) {
+ if (!(IS_TYPE_CLASS(left->rtype) && CClass_Destructor(TYPE_CLASS(left->rtype)))) {
+ args->node = getnodeaddress(left, 0);
+ return right;
+ }
+ }
+ }
+
+ right = makediadicnode(left, right, nt);
+ right->flags = left->flags;
+ return right;
+}
+
+static ENode *makepassignmentnode(ENode *left, ENodeType nt, short token) {
+ ENode *right;
+ Boolean is_array;
+ Conversion conv;
+
+ is_array = IS_TYPE_ARRAY(left->rtype);
+ left = pointer_generation(left);
+ if (copts.cplusplus) {
+ tk = lex();
+ right = pointer_generation(assignment_expression());
+ if (CExpr_CheckOperator(token, left, right, &conv)) {
+ CError_ASSERT(6669, conv.x0);
+ return conv.x0;
+ }
+ left = CExpr_LValue(left, 1, 1);
+ } else {
+ left = CExpr_LValue(left, 1, 1);
+ tk = lex();
+ right = pointer_generation(assignment_expression());
+ }
+
+ if (is_array)
+ CError_Error(CErrorStr144);
+
+ switch (left->rtype->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEPOINTER:
+ break;
+ case TYPEENUM:
+ if (copts.cplusplus) {
+ CError_Error(CErrorStr144);
+ return left;
+ }
+ left = forceintegral(left);
+ break;
+ default:
+ CError_Error(CErrorStr144);
+ return left;
+ }
+
+ if (IS_TYPE_ENUM(right->rtype))
+ right = forceintegral(right);
+
+ if (iszero(right))
+ return left;
+
+ if (IS_TYPE_POINTER_ONLY(left->rtype)) {
+ if (IS_TYPE_INT(right->rtype)) {
+ if (nt == ESUBASS) {
+ left = psub(left, right);
+ if (ENODE_IS(left, ESUB))
+ left->type = ESUBASS;
+ return left;
+ } else {
+ left = padd(left, right);
+ if (ENODE_IS(left, EADD))
+ left->type = EADDASS;
+ return left;
+ }
+ }
+ CError_Error(CErrorStr144);
+ return left;
+ } else {
+ return CExpr_MakeOpAssNode(left, right, nt);
+ }
+}
+
+static ENode *makemulassignmentnode(ENode *left, ENodeType nt, short token) {
+ ENode *right;
+ Boolean is_array;
+ Conversion conv;
+
+ is_array = IS_TYPE_ARRAY(left->rtype);
+ left = pointer_generation(left);
+ if (copts.cplusplus) {
+ tk = lex();
+ right = pointer_generation(assignment_expression());
+ if (CExpr_CheckOperator(token, left, right, &conv)) {
+ CError_ASSERT(6753, conv.x0);
+ return conv.x0;
+ }
+ if (!IS_TYPE_INT(left->rtype) && !(IS_TYPE_FLOAT(left->rtype) && nt != EMODASS)) {
+ CError_Error(CErrorStr144);
+ return nullnode();
+ }
+ left = CExpr_LValue(left, 1, 1);
+ } else {
+ if (IS_TYPE_ENUM(left->rtype))
+ left = forceintegral(left);
+ if (!IS_TYPE_INT(left->rtype) && !(IS_TYPE_FLOAT(left->rtype) && nt != EMODASS)) {
+ CError_Error(CErrorStr144);
+ return nullnode();
+ }
+
+ left = CExpr_LValue(left, 1, 1);
+ tk = lex();
+ right = pointer_generation(assignment_expression());
+ }
+
+ if (is_array)
+ CError_Error(CErrorStr144);
+
+ if (IS_TYPE_ENUM(right->rtype))
+ right = forceintegral(right);
+
+ if (IS_TYPE_INT(left->rtype) && IS_TYPE_FLOAT(right->rtype) && nt == EMODASS) {
+ CError_Error(CErrorStr144);
+ return nullnode();
+ }
+
+ return CExpr_MakeOpAssNode(left, right, nt);
+}
+
+static ENode *CExpr_TransformOpAssign(ENode *expr) {
+ switch (expr->type) {
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ if (expr->rtype == TYPE(&stbool)) {
+ expr = CIRTrans_TransformOpAss(expr);
+ if (ENODE_IS(expr, EASS)) {
+ expr->data.diadic.right = makemonadicnode(expr->data.diadic.right, ELOGNOT);
+ expr->data.diadic.right->rtype = TYPE(&stbool);
+ expr->data.diadic.right = makemonadicnode(expr->data.diadic.right, ELOGNOT);
+ }
+ }
+ }
+
+ return expr;
+}
+
+ENode *assignment_expression(void) {
+ ENode *expr;
+
+ if (tk == TK_THROW)
+ return CExcept_ScanThrowExpression();
+
+ expr = conditional_expression();
+ switch (tk) {
+ case '=':
+ return makeassignmentnode(expr, EASS, tk);
+ case TK_ADD_ASSIGN:
+ return CExpr_TransformOpAssign(makepassignmentnode(expr, EADDASS, tk));
+ case TK_SUB_ASSIGN:
+ return CExpr_TransformOpAssign(makepassignmentnode(expr, ESUBASS, tk));
+ case TK_MULT_ASSIGN:
+ expr = makemulassignmentnode(expr, EMULASS, tk);
+ if (ENODE_IS(expr, EMULASS) && CExpr_IsOne(expr->data.diadic.right))
+ return expr->data.diadic.left;
+ return CExpr_TransformOpAssign(expr);
+ case TK_DIV_ASSIGN:
+ expr = makemulassignmentnode(expr, EDIVASS, tk);
+ if (ENODE_IS(expr, EDIVASS)) {
+ if (iszero(expr->data.diadic.right) && !IS_TYPE_FLOAT(expr->rtype)) {
+ CError_Warning(CErrorStr139);
+ return expr->data.diadic.left;
+ }
+ if (CExpr_IsOne(expr->data.diadic.right))
+ return expr->data.diadic.left;
+ }
+ return CExpr_TransformOpAssign(expr);
+ case TK_MOD_ASSIGN:
+ expr = makemulassignmentnode(expr, EMODASS, tk);
+ if (ENODE_IS(expr, EMODASS)) {
+ if (iszero(expr->data.diadic.right)) {
+ CError_Warning(CErrorStr139);
+ return expr->data.diadic.left;
+ }
+ }
+ return CExpr_TransformOpAssign(expr);
+ case TK_SHL_ASSIGN:
+ expr = makeassignmentnode(expr, ESHLASS, tk);
+ if (ENODE_IS(expr, ESHLASS) && iszero(expr->data.diadic.right))
+ return expr->data.diadic.left;
+ return CExpr_TransformOpAssign(expr);
+ case TK_SHR_ASSIGN:
+ expr = makeassignmentnode(expr, ESHRASS, tk);
+ if (ENODE_IS(expr, ESHRASS) && iszero(expr->data.diadic.right))
+ return expr->data.diadic.left;
+ return CExpr_TransformOpAssign(expr);
+ case TK_AND_ASSIGN:
+ expr = makeassignmentnode(expr, EANDASS, tk);
+ if (ENODE_IS(expr, EANDASS) && CExpr_AllBitsSet(expr->data.diadic.right))
+ return expr->data.diadic.left;
+ return expr;
+ case TK_XOR_ASSIGN:
+ expr = makeassignmentnode(expr, EXORASS, tk);
+ if (ENODE_IS(expr, EXORASS) && iszero(expr->data.diadic.right))
+ return expr->data.diadic.left;
+ return CExpr_TransformOpAssign(expr);
+ case TK_OR_ASSIGN:
+ expr = makeassignmentnode(expr, EORASS, tk);
+ if (ENODE_IS(expr, EORASS) && iszero(expr->data.diadic.right))
+ return expr->data.diadic.left;
+ return CExpr_TransformOpAssign(expr);
+ default:
+ return expr;
+ }
+}
+
+ENode *conv_assignment_expression(void) {
+ return pointer_generation(assignment_expression());
+}
+
+static Boolean CExpr_HasSideEffect(ENode *expr) {
+ switch (expr->type) {
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ 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 EROTL:
+ case EROTR:
+ case EBITFIELD:
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case ETEMP:
+ case EARGOBJ:
+ case ELOCOBJ:
+ case EOBJLIST:
+ case EMEMBER:
+ case EVECTOR128CONST:
+ return 0;
+ case ETYPCON:
+ return IS_TYPE_VOID(expr->rtype);
+ case EINDIRECT:
+ switch (expr->data.monadic->type) {
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ return 1;
+ default:
+ return 0;
+ }
+ case ECOMMA:
+ return CInline_ExpressionHasSideEffect(expr->data.diadic.right);
+ case ECOND:
+ return CInline_ExpressionHasSideEffect(expr->data.cond.expr1) || CInline_ExpressionHasSideEffect(expr->data.cond.expr2);
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EFORCELOAD:
+ case EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ case EMFPOINTER:
+ case ENULLCHECK:
+ case EPRECOMP:
+ case ELABEL:
+ case ENEWEXCEPTION:
+ case ENEWEXCEPTIONARRAY:
+ case EINITTRYCATCH:
+ case EINSTRUCTION:
+ return 1;
+ default:
+ CError_FATAL(7056);
+ return 0;
+ }
+}
+
+void CExpr_CheckUnusedExpression(ENode *expr) {
+ ENode *scan;
+ ENodeList *arg;
+
+ if (copts.warn_possunwant) {
+ scan = expr;
+ while (ENODE_IS(scan, ETYPCON))
+ scan = scan->data.monadic;
+ if (ENODE_IS(scan, EEQU)) {
+ CError_Warning(CErrorStr208);
+ return;
+ }
+ }
+
+ if (copts.warn_no_side_effect) {
+ if (!CExpr_HasSideEffect(expr)) {
+ CError_Warning(CErrorStr369);
+ return;
+ }
+ }
+
+ if (copts.warn_resultnotused) {
+ scan = expr;
+ if (IS_TYPE_VOID(expr->rtype))
+ return;
+ if (ENODE_IS(expr, EINDIRECT))
+ scan = expr->data.monadic;
+
+ switch (scan->type) {
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ if (ENODE_IS(scan->data.funccall.funcref, EOBJREF) && scan->data.funccall.funcref->data.objref->name == asop_name_node)
+ return;
+ if (CMach_GetFunctionResultClass(scan->data.funccall.functype) == 1 && (arg = scan->data.funccall.args)) {
+ switch (CABI_GetStructResultArgumentIndex(scan->data.funccall.functype)) {
+ case 0:
+ break;
+ case 1:
+ if ((arg = arg->next))
+ break;
+ CError_FATAL(7110);
+ default:
+ CError_FATAL(7111);
+ }
+
+ if (!ENODE_IS(arg->node, ETEMP))
+ return;
+ }
+ CError_Warning(CErrorStr370);
+ }
+ }
+}
+
+ENode *s_expression(void) {
+ ENode *left;
+ ENode *right;
+ Conversion conv;
+
+ left = assignment_expression();
+ while (tk == ',') {
+ left = pointer_generation(left);
+ tk = lex();
+ right = pointer_generation(assignment_expression());
+
+ if (copts.cplusplus && CExpr_CheckOperator(',', left, right, &conv)) {
+ CError_ASSERT(7143, left = conv.x0);
+ } else {
+ CExpr_CheckUnusedExpression(left);
+ left = makecommaexpression(left, right);
+ left->rtype = right->rtype;
+ }
+ }
+
+ return left;
+}
+
+ENode *expression(void) {
+ return pointer_generation(s_expression());
+}
+
+CInt64 CExpr_IntegralConstExprType(Type **tint) {
+ ENode *expr;
+
+ expr = pointer_generation(conditional_expression());
+ if (ENODE_IS(expr, EINTCONST)) {
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ *tint = expr->rtype;
+ return expr->data.intval;
+ case TYPEENUM:
+ *tint = TYPE_ENUM(expr->rtype)->enumtype;
+ return expr->data.intval;
+ }
+ }
+
+ CError_Error(CErrorStr124);
+ *tint = TYPE(&stchar);
+ return cint64_zero;
+}
+
+ENode *CExpr_IntegralConstOrDepExpr(void) {
+ ENode *expr;
+
+ expr = pointer_generation(conditional_expression());
+ if (ENODE_IS(expr, EINTCONST)) {
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ return expr;
+ case TYPEENUM:
+ expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
+ return expr;
+ default:
+ CError_FATAL(7209);
+ }
+ }
+
+ if (CTemplTool_IsTemplateArgumentDependentExpression(expr))
+ return expr;
+
+ CError_Error(CErrorStr124);
+ expr = nullnode();
+ expr->rtype = TYPE(&stchar);
+ return expr;
+}
+
+CInt64 CExpr_IntegralConstExpr(void) {
+ Type *throwaway;
+ return CExpr_IntegralConstExprType(&throwaway);
+}
+
+void CExpr_CheckUnwantedAssignment(ENode *expr) {
+ if (copts.warn_possunwant) {
+ if (ENODE_IS(expr, EASS) && !(expr->flags & ENODE_FLAG_80))
+ CError_Warning(CErrorStr207);
+ }
+}
+
+Boolean CExpr_ParseAsmExpr(Object **objptr, CInt64 *valptr) {
+ ENode *expr;
+
+ if (objptr)
+ *objptr = NULL;
+ *valptr = cint64_zero;
+
+ expr = pointer_generation(assignment_expression());
+ if (ENODE_IS(expr, EINTCONST)) {
+ *valptr = expr->data.intval;
+ return 1;
+ }
+
+ if (objptr) {
+ switch (expr->type) {
+ case EINDIRECT:
+ if (CInit_RelocInitCheck(expr->data.monadic, objptr, valptr, 1))
+ return 1;
+ break;
+ case EOBJREF:
+ *objptr = expr->data.objref;
+ while ((*objptr)->datatype == DALIAS)
+ *objptr = (*objptr)->u.alias.object;
+ return 1;
+ case EMEMBER:
+ if (expr->data.emember->list->object->otype == OT_OBJECT) {
+ if (expr->data.emember->list->next && expr->data.emember->list->next->object->otype == OT_OBJECT)
+ CError_Error(CErrorStr199);
+ *objptr = OBJECT(expr->data.emember->list->object);
+ while ((*objptr)->datatype == DALIAS)
+ *objptr = (*objptr)->u.alias.object;
+ return 1;
+ }
+ break;
+ case EOBJLIST:
+ CError_Error(CErrorStr199);
+ return 0;
+ }
+ }
+
+ CError_Error(CErrorStr155);
+ return 0;
+}
diff --git a/compiler_and_linker/FrontEnd/C/CExpr2.c b/compiler_and_linker/FrontEnd/C/CExpr2.c
new file mode 100644
index 0000000..fc26c7e
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CExpr2.c
@@ -0,0 +1,4206 @@
+#include "compiler/CExpr.h"
+#include "compiler/CABI.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CInit.h"
+#include "compiler/CInt64.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInline.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CObjC.h"
+#include "compiler/CObjCModern.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CScope.h"
+#include "compiler/CSOM.h"
+#include "compiler/CTemplateFunc.h"
+#include "compiler/CTemplateTools.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/enode.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/templates.h"
+
+#ifdef __MWERKS__
+#undef va_start
+#undef va_arg
+#define va_start(ap, parm) ap = __va_start(parm)
+#define __va_start(parm) (va_list) (&parm + 1)
+//#define va_arg(ap, type) ((((type *) (ap = (va_list) (( ((long) ap + sizeof(type) - 1) & ~(sizeof(type)) ) + sizeof(type) ) ))[-1]))
+#define va_arg(ap, type) (*(((type *) (ap = (char *)((((unsigned long)ap + __builtin_align(type) - 1) & ~(__builtin_align(type) - 1) ) + sizeof(type)))) - 1))
+#endif
+
+ENode *assign_node;
+Boolean temp_reference_init;
+static SInt32 assign_value; // type?
+static ENode *firstarrayexpr;
+static Match5 user_std_match;
+static Boolean cexpr_hascall;
+static Boolean cexpr_esearch_bool[MAXEXPR];
+static Boolean cexpr_rsearch_bool[MAXEXPR];
+static CExprSearchCB cexpr_esearch_callback;
+static CExprReplaceCB cexpr_rsearch_callback;
+static Type *cexpr_left_conversion_type;
+static Type *cexpr_right_conversion_type;
+
+static FuncArg mon_arg = {NULL, NULL, NULL, NULL, 0, 0, 0};
+static FuncArg diadic_arg2 = {NULL, NULL, NULL, NULL, 0, 0, 0};
+static FuncArg diadic_arg1 = {&diadic_arg1, NULL, NULL, NULL, 0, 0, 0};
+
+static void CExpr_RecSearchExprTree(ENode *expr) {
+ ENodeList *list;
+
+restart:
+ if (cexpr_esearch_bool[expr->type])
+ cexpr_esearch_callback(expr);
+
+ switch (expr->type) {
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EINDIRECT:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case EFORCELOAD:
+ case ETYPCON:
+ case EBITFIELD:
+ expr = expr->data.monadic;
+ goto restart;
+ 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:
+ CExpr_RecSearchExprTree(expr->data.diadic.left);
+ expr = expr->data.diadic.right;
+ goto restart;
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EPRECOMP:
+ case ETEMP:
+ case EARGOBJ:
+ case ELOCOBJ:
+ case ELABEL:
+ case EOBJLIST:
+ case EMEMBER:
+ case EINSTRUCTION:
+ case EVECTOR128CONST:
+ return;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ for (list = expr->data.funccall.args; list; list = list->next)
+ CExpr_RecSearchExprTree(list->node);
+ expr = expr->data.funccall.funcref;
+ goto restart;
+ case ENULLCHECK:
+ CExpr_RecSearchExprTree(expr->data.nullcheck.nullcheckexpr);
+ expr = expr->data.nullcheck.condexpr;
+ goto restart;
+ case EMFPOINTER:
+ CExpr_RecSearchExprTree(expr->data.mfpointer.accessnode);
+ expr = expr->data.mfpointer.mfpointer;
+ goto restart;
+ case ECOND:
+ CExpr_RecSearchExprTree(expr->data.cond.cond);
+ CExpr_RecSearchExprTree(expr->data.cond.expr1);
+ expr = expr->data.cond.expr2;
+ goto restart;
+ case ENEWEXCEPTION:
+ case ENEWEXCEPTIONARRAY:
+ CExpr_RecSearchExprTree(expr->data.newexception.initexpr);
+ expr = expr->data.newexception.tryexpr;
+ goto restart;
+ case EINITTRYCATCH:
+ if (expr->data.itc.initexpr)
+ CExpr_RecSearchExprTree(expr->data.itc.initexpr);
+ if (expr->data.itc.tryexpr)
+ CExpr_RecSearchExprTree(expr->data.itc.tryexpr);
+ if (expr->data.itc.catchexpr)
+ CExpr_RecSearchExprTree(expr->data.itc.catchexpr);
+ if (expr->data.itc.result)
+ CExpr_RecSearchExprTree(expr->data.itc.result);
+ return;
+ default:
+ CError_FATAL(128);
+ }
+}
+
+void CExpr_SearchExprTree(ENode *expr, CExprSearchCB callback, int count, ...) {
+ va_list ap;
+ short i;
+
+ cexpr_esearch_callback = callback;
+
+ va_start(ap, count);
+ for (i = 0; i < MAXEXPR; i++)
+ cexpr_esearch_bool[i] = 0;
+ i = 0;
+ while ((short) i < count) {
+ cexpr_esearch_bool[va_arg(ap, int)] = 1;
+ ++i;
+ }
+ va_end(ap);
+
+ CExpr_RecSearchExprTree(expr);
+}
+
+static ENode *CExpr_RecSearchExprTreeReplace(ENode *expr) {
+ ENodeList *list;
+ ENode *replaced;
+
+ if (cexpr_rsearch_bool[expr->type]) {
+ replaced = cexpr_rsearch_callback(expr);
+ if (!replaced)
+ return expr;
+ expr = replaced;
+ }
+
+ switch (expr->type) {
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EINDIRECT:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case EFORCELOAD:
+ case ETYPCON:
+ case EBITFIELD:
+ expr->data.monadic = CExpr_RecSearchExprTreeReplace(expr->data.monadic);
+ return expr;
+ 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:
+ expr->data.diadic.left = CExpr_RecSearchExprTreeReplace(expr->data.diadic.left);
+ expr->data.diadic.right = CExpr_RecSearchExprTreeReplace(expr->data.diadic.right);
+ return expr;
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EPRECOMP:
+ case ETEMP:
+ case EARGOBJ:
+ case ELOCOBJ:
+ case ELABEL:
+ case EMEMBER:
+ case EINSTRUCTION:
+ case EVECTOR128CONST:
+ return expr;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ for (list = expr->data.funccall.args; list; list = list->next)
+ list->node = CExpr_RecSearchExprTreeReplace(list->node);
+ expr->data.funccall.funcref = CExpr_RecSearchExprTreeReplace(expr->data.funccall.funcref);
+ return expr;
+ case ENULLCHECK:
+ expr->data.nullcheck.nullcheckexpr = CExpr_RecSearchExprTreeReplace(expr->data.nullcheck.nullcheckexpr);
+ expr->data.nullcheck.condexpr = CExpr_RecSearchExprTreeReplace(expr->data.nullcheck.condexpr);
+ return expr;
+ case EMFPOINTER:
+ expr->data.mfpointer.accessnode = CExpr_RecSearchExprTreeReplace(expr->data.mfpointer.accessnode);
+ expr->data.mfpointer.mfpointer = CExpr_RecSearchExprTreeReplace(expr->data.mfpointer.mfpointer);
+ return expr;
+ case ECOND:
+ expr->data.cond.cond = CExpr_RecSearchExprTreeReplace(expr->data.cond.cond);
+ expr->data.cond.expr1 = CExpr_RecSearchExprTreeReplace(expr->data.cond.expr1);
+ expr->data.cond.expr2 = CExpr_RecSearchExprTreeReplace(expr->data.cond.expr2);
+ return expr;
+ default:
+ CError_FATAL(220);
+ return NULL;
+ }
+}
+
+ENode *CExpr_SearchExprTreeReplace(ENode *expr, CExprReplaceCB callback, int count, ...) {
+ va_list ap;
+ short i;
+
+ cexpr_rsearch_callback = callback;
+
+ va_start(ap, count);
+ for (i = 0; i < MAXEXPR; i++)
+ cexpr_rsearch_bool[i] = 0;
+ i = 0;
+ while ((short) i < count) {
+ cexpr_rsearch_bool[va_arg(ap, int)] = 1;
+ ++i;
+ }
+ va_end(ap);
+
+ return CExpr_RecSearchExprTreeReplace(expr);
+}
+
+static void CExpr_HasFuncCallCallBack(ENode *expr) {
+ cexpr_hascall = 1;
+}
+
+Boolean CExpr_HasFuncCall(ENode *expr) {
+ cexpr_hascall = 0;
+ CExpr_SearchExprTree(expr, CExpr_HasFuncCallCallBack, 2, EFUNCCALL, EFUNCCALLP);
+ return cexpr_hascall;
+}
+
+void CExpr_AliasTransform(ENode *expr) {
+ ENode *n;
+
+ Object *obj = expr->data.objref;
+ if (obj->u.alias.offset) {
+ n = makediadicnode(
+ create_objectrefnode(obj->u.alias.object),
+ intconstnode(TYPE(&stunsignedlong), obj->u.alias.offset),
+ EADD);
+ *expr = *n;
+ } else {
+ expr->data.objref = obj->u.alias.object;
+ }
+}
+
+ENode *CExpr_UnaryFloatExpression(ENode *expr) {
+ return expr;
+}
+
+ENode *CExpr_BinaryFloatExpression(ENode *expr) {
+ return expr;
+}
+
+ENode *CExpr_NewENode(ENodeType ty) {
+ ENode *expr = lalloc(sizeof(ENode));
+ memclrw(expr, sizeof(ENode));
+ expr->type = ty;
+ return expr;
+}
+
+ENode *CExpr_NewTemplDepENode(TemplDepSubType t) {
+ ENode *expr = CExpr_NewENode(ETEMPLDEP);
+ expr->rtype = &sttemplexpr;
+ expr->data.templdep.subtype = t;
+ return expr;
+}
+
+ENode *nullnode(void) {
+ ENode *expr = CExpr_NewENode(EINTCONST);
+ expr->rtype = (Type *) &stsignedlong;
+ return expr;
+}
+
+ENode *intconstnode(Type *type, SInt32 value) {
+ ENode *expr = CExpr_NewENode(EINTCONST);
+ expr->rtype = type;
+ CInt64_SetLong(&expr->data.intval, value);
+ return expr;
+}
+
+ENode *stringconstnode(char *str) {
+ ENode *expr;
+ SInt32 size;
+
+ size = strlen(str) + 1;
+ expr = CExpr_NewENode(ESTRINGCONST);
+ expr->rtype = CDecl_NewArrayType((Type *) &stchar, size);
+ expr->data.string.size = size;
+ expr->data.string.data = str;
+ expr->data.string.ispascal = 0;
+ if (copts.const_strings)
+ expr->flags = Q_CONST;
+
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype);
+ return expr;
+}
+
+ENode *forceintegral(ENode *expr) {
+ if (!IS_TYPE_ENUM(expr->rtype)) {
+ CError_Error(CErrorStr144);
+ return nullnode();
+ } else {
+ expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
+ return expr;
+ }
+}
+
+ENode *makemonadicnode(ENode *inner, ENodeType ty) {
+ ENode *expr = lalloc(sizeof(ENode));
+ expr->type = ty;
+ if ((expr->cost = inner->cost) == 0)
+ expr->cost = 1;
+ expr->flags = inner->flags & ENODE_FLAG_QUALS;
+ expr->rtype = inner->rtype;
+ expr->data.monadic = inner;
+ return expr;
+}
+
+ENode *makediadicnode(ENode *left, ENode *right, ENodeType ty) {
+ ENode *expr = lalloc(sizeof(ENode));
+ expr->type = ty;
+ expr->rtype = left->rtype;
+ expr->data.diadic.left = left;
+ expr->data.diadic.right = right;
+
+ if (left->cost != right->cost) {
+ expr->cost = right->cost;
+ if (left->cost > expr->cost)
+ expr->cost = left->cost;
+ } else {
+ expr->cost = right->cost + 1;
+ if (expr->cost > 200)
+ expr->cost = 200;
+ }
+
+ expr->flags = (left->flags | right->flags) & ENODE_FLAG_QUALS;
+ return expr;
+}
+
+ENode *makecommaexpression(ENode *left, ENode *right) {
+ ENode *expr;
+
+ if (ENODE_IS(right, EINDIRECT) && !ENODE_IS(right->data.monadic, EBITFIELD)) {
+ Boolean savecpp = copts.cplusplus;
+ copts.cplusplus = 1;
+ expr = makediadicnode(left, getnodeaddress(right, 0), ECOMMA);
+ copts.cplusplus = savecpp;
+ expr->rtype = expr->data.diadic.right->rtype;
+ expr = makemonadicnode(expr, EINDIRECT);
+ } else {
+ expr = makediadicnode(left, right, ECOMMA);
+ }
+
+ expr->rtype = right->rtype;
+ expr->flags = right->flags;
+ return expr;
+}
+
+short iszero(ENode *expr) {
+ switch (expr->type) {
+ case EINTCONST:
+ return CInt64_IsZero(&expr->data.intval);
+ case EFLOATCONST:
+ return CMach_FloatIsZero(expr->data.floatval);
+ default:
+ return 0;
+ }
+}
+
+short isnotzero(ENode *expr) {
+ Object *obj;
+
+ switch (expr->type) {
+ case EINTCONST:
+ return !CInt64_IsZero(&expr->data.intval);
+ case EFLOATCONST:
+ return !CMach_FloatIsZero(expr->data.floatval);
+ case ESTRINGCONST:
+ case ETEMP:
+ return 1;
+ case EOBJREF:
+ obj = expr->data.objref;
+ break;
+ case EADD:
+ case ESUB:
+ if (ENODE_IS(expr->data.diadic.left, EOBJREF) && ENODE_IS(expr->data.diadic.right, EINTCONST)) {
+ obj = expr->data.diadic.left->data.objref;
+ break;
+ }
+ if (ENODE_IS(expr->data.diadic.left, EINTCONST) && ENODE_IS(expr->data.diadic.right, EOBJREF)) {
+ obj = expr->data.diadic.right->data.objref;
+ break;
+ }
+ return 0;
+ default:
+ return 0;
+ }
+
+ switch (obj->datatype) {
+ case DLOCAL:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+Boolean CExpr_IsOne(ENode *expr) {
+ if (ENODE_IS(expr, EINTCONST))
+ return CInt64_Equal(expr->data.intval, cint64_one);
+ else if (ENODE_IS(expr, EFLOATCONST))
+ return CMach_FloatIsOne(expr->data.floatval);
+ else
+ return 0;
+}
+
+Boolean CExpr_AllBitsSet(ENode *expr) {
+ SInt32 v;
+
+ if (ENODE_IS(expr, EINTCONST)) {
+ switch (expr->rtype->size) {
+ case 1:
+ v = CInt64_GetULong(&expr->data.intval) & 0xFF;
+ return v == 0xFF;
+ case 2:
+ v = CInt64_GetULong(&expr->data.intval) & 0xFFFF;
+ return v == 0xFFFF;
+ case 3:
+ v = CInt64_GetULong(&expr->data.intval) & 0xFFFFFF;
+ return v == 0xFFFFFF;
+ case 4:
+ v = CInt64_GetULong(&expr->data.intval) & 0xFFFFFFFF;
+ return v == 0xFFFFFFFF;
+ default:
+ return CInt64_Equal(expr->data.intval, cint64_negone);
+ }
+ }
+
+ return 0;
+}
+
+ENode *CExpr_NewETEMPNode(Type *type, Boolean assign_id) {
+ ENode *expr = lalloc(sizeof(ENode));
+ expr->type = ETEMP;
+ expr->cost = 0;
+ expr->flags = 0;
+ expr->rtype = CDecl_NewPointerType(type);
+ expr->data.temp.type = type;
+ expr->data.temp.uniqueid = assign_id ? CParser_GetUniqueID() : 0;
+ expr->data.temp.needs_dtor = 0;
+ return expr;
+}
+
+static ENode *CExpr_DerefETEMPCopy(ENode *expr) {
+ ENode *copy;
+
+ CError_ASSERT(636, IS_TYPE_POINTER_ONLY(expr->rtype));
+
+ copy = lalloc(sizeof(ENode));
+ *copy = *expr;
+ copy = makemonadicnode(copy, EINDIRECT);
+ copy->rtype = TYPE_POINTER(copy->rtype)->target;
+ return copy;
+}
+
+ENode *CExpr_GetETEMPCopy(ENode *expr) {
+ ENode *newnode;
+ ENode *assnode;
+ ENode *finalnode;
+
+ newnode = CExpr_NewETEMPNode(expr->rtype, 1);
+ newnode->flags = expr->flags;
+
+ assnode = makediadicnode(CExpr_DerefETEMPCopy(newnode), expr, EASS);
+ assnode->data.diadic.right = lalloc(sizeof(ENode));
+ *assnode->data.diadic.right = *expr;
+ *expr = *assnode;
+
+ finalnode = makemonadicnode(newnode, EINDIRECT);
+ finalnode->rtype = expr->rtype;
+ return finalnode;
+}
+
+ENode *integralpromote(ENode *expr) {
+ if (!IS_TYPE_INT(expr->rtype))
+ expr = forceintegral(expr);
+
+ if (TYPE_INTEGRAL(expr->rtype)->integral >= IT_INT)
+ return expr;
+
+ if (!ENODE_IS(expr, EINTCONST))
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = (Type *) &stsignedint;
+
+ return expr;
+}
+
+CInt64 CExpr_IntConstConvert(Type *a, Type *b, CInt64 val) {
+ if (a == (Type *) &stbool)
+ return CMach_CalcIntDiadic(b, val, TK_LOGICAL_NE, cint64_zero);
+ else
+ return CMach_CalcIntDiadic(a, val, '+', cint64_zero);
+}
+
+ENode *promote(ENode *expr, Type *type) {
+ if (ENODE_IS(expr, EINTCONST)) {
+ if (IS_TYPE_FLOAT(type)) {
+ expr->type = EFLOATCONST;
+ expr->data.floatval = CMach_CalcFloatConvertFromInt(expr->rtype, expr->data.intval);
+ } else {
+ expr->data.intval = CExpr_IntConstConvert(type, expr->rtype, expr->data.intval);
+ }
+ expr->rtype = type;
+ return expr;
+ }
+ if (ENODE_IS(expr, EFLOATCONST)) {
+ if (IS_TYPE_FLOAT(type)) {
+ expr->data.floatval = CMach_CalcFloatConvert(type, expr->data.floatval);
+ expr->rtype = type;
+ return expr;
+ } else if (IS_TYPE_INT(type)) {
+ expr->data.intval = CMach_CalcIntConvertFromFloat(type, expr->data.floatval);
+ expr->type = EINTCONST;
+ expr->rtype = type;
+ return expr;
+ }
+ }
+
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = type;
+ return expr;
+}
+
+void CExpr_ArithmeticConversion(ENode **left, ENode **right) {
+ switch ((*left)->rtype->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ break;
+ case TYPEENUM:
+ (*left)->rtype = TYPE_ENUM((*left)->rtype)->enumtype;
+ break;
+ default:
+ CError_Error(CErrorStr144);
+ (*left) = nullnode();
+ }
+
+ switch ((*right)->rtype->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ break;
+ case TYPEENUM:
+ (*right)->rtype = TYPE_ENUM((*right)->rtype)->enumtype;
+ break;
+ default:
+ CError_Error(CErrorStr144);
+ (*right) = nullnode();
+ }
+
+ if (IS_TYPE_FLOAT((*left)->rtype) || IS_TYPE_FLOAT((*right)->rtype)) {
+ if ((*left)->rtype != (*right)->rtype) {
+ if (TYPE_INTEGRAL((*left)->rtype)->integral > TYPE_INTEGRAL((*right)->rtype)->integral)
+ *right = promote(*right, (*left)->rtype);
+ else
+ *left = promote(*left, (*right)->rtype);
+ }
+ return;
+ }
+
+ *left = integralpromote(*left);
+ *right = integralpromote(*right);
+ if ((*left)->rtype != (*right)->rtype) {
+ if (TYPE_INTEGRAL((*left)->rtype)->integral < TYPE_INTEGRAL((*right)->rtype)->integral) {
+ ENode **tmp = left;
+ left = right;
+ right = tmp;
+ }
+
+ if ((*left)->rtype->size == (*right)->rtype->size && !is_unsigned((*left)->rtype) && is_unsigned((*right)->rtype)) {
+ if ((*left)->rtype == (Type *) &stsignedlong) {
+ *left = promote(*left, (Type *) &stunsignedlong);
+ } else {
+ CError_ASSERT(838, (*left)->rtype == (Type *) &stsignedlonglong);
+ *left = promote(*left, (Type *) &stunsignedlonglong);
+ }
+ }
+
+ *right = promote(*right, (*left)->rtype);
+ }
+}
+
+static ENode *CExpr_GetEA(ENode *expr) {
+ ENode *copy;
+
+ for (;;) {
+ switch (expr->type) {
+ case EINDIRECT:
+ expr = expr->data.monadic;
+ for (;;) {
+ switch (expr->type) {
+ case EOBJREF:
+ copy = lalloc(sizeof(ENode));
+ *copy = *expr;
+ return copy;
+ case ECOMMA:
+ expr = expr->data.diadic.right;
+ continue;
+ default:
+ return CExpr_GetETEMPCopy(expr);
+ }
+ }
+ break;
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ expr = expr->data.monadic;
+ continue;
+ case EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ expr = expr->data.monadic;
+ continue;
+ case ECOMMA:
+ expr = expr->data.diadic.right;
+ continue;
+ default:
+ return NULL;
+ }
+ }
+}
+
+ENode *CExpr_TempModifyExpr(ENode *expr) {
+ Type *type;
+ ENode *left;
+ ENode *right;
+ ENode *eanode;
+ ENode *tempnode;
+ ENode *indnode;
+ ENode *truenode;
+
+ type = expr->rtype;
+ tempnode = CExpr_NewETEMPNode(type, 1);
+ eanode = CExpr_GetEA(expr);
+ if (!eanode) {
+ CError_Error(CErrorStr142);
+ return expr;
+ }
+
+ // tempnode = expr
+ left = makemonadicnode(tempnode, EINDIRECT);
+ left->rtype = type;
+ left = makediadicnode(left, expr, EASS);
+
+ // eanode = true
+ indnode = makemonadicnode(eanode, EINDIRECT);
+ indnode->rtype = type;
+ truenode = nullnode();
+ truenode->rtype = (Type *) &stbool;
+ CInt64_SetLong(&truenode->data.intval, 1);
+ right = makediadicnode(indnode, truenode, EASS);
+
+ expr = makediadicnode(left, right, ECOMMA);
+
+ indnode = makemonadicnode(tempnode, EINDIRECT);
+ indnode->rtype = type;
+ return makediadicnode(expr, indnode, ECOMMA);
+}
+
+Boolean CExpr_IsLValue(ENode *expr) {
+ while (!ENODE_IS(expr, EINDIRECT)) {
+ switch (expr->type) {
+ case EPREINC:
+ case EPREDEC:
+ return copts.cplusplus;
+ case EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ if (!copts.cplusplus)
+ return 0;
+ expr = expr->data.diadic.left;
+ continue;
+ case ECOMMA:
+ if (!copts.cplusplus)
+ return 0;
+ expr = expr->data.diadic.right;
+ continue;
+ case ECOND:
+ if (
+ copts.cplusplus &&
+ is_typesame(expr->data.cond.expr1->rtype, expr->data.cond.expr2->rtype) &&
+ (expr->data.cond.expr1->rtype->type != TYPEPOINTER || (UInt32) (expr->data.cond.expr1->flags & ENODE_FLAG_QUALS) == (expr->data.cond.expr2->flags & ENODE_FLAG_QUALS))
+ ) {
+ return CExpr_IsLValue(expr->data.cond.expr1) && CExpr_IsLValue(expr->data.cond.expr2);
+ }
+ return 0;
+ default:
+ return 0;
+ }
+ }
+
+ expr = expr->data.monadic;
+ switch (expr->type) {
+ case ETEMP:
+ return 0;
+ case EFUNCCALL:
+ if (expr->data.funccall.functype->functype->type != TYPEPOINTER || (expr->data.funccall.functype->flags & FUNC_IS_CTOR))
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+ENode *CExpr_LValue(ENode *expr, Boolean flag1, Boolean flag2) {
+ ENode *eanode;
+ ENode *tmpnode;
+
+loop:
+ switch (expr->type) {
+ case ETYPCON:
+ if (copts.pointercast_lvalue || !copts.ANSIstrict) {
+ if (expr->rtype->type == TYPEPOINTER && expr->data.monadic->rtype->type == TYPEPOINTER) {
+ switch (expr->data.monadic->type) {
+ case EINDIRECT:
+ case ETYPCON:
+ expr->data.monadic->rtype = expr->rtype;
+ expr->data.monadic->flags = expr->flags;
+ expr = expr->data.monadic;
+ goto loop;
+ }
+ }
+ }
+ break;
+ case EINDIRECT:
+ if (flag2) {
+ if (!CExpr_IsLValue(expr))
+ CError_Warning(CErrorStr142);
+
+ if (
+ ENODE_IS(expr->data.monadic, EOBJREF) &&
+ expr->data.monadic->data.objref->name == this_name_node &&
+ cscope_currentfunc &&
+ cscope_currentclass &&
+ expr->data.monadic->data.objref == CClass_ThisSelfObject())
+ CError_Error(CErrorStr189);
+ }
+ if (flag1) {
+ if (CParser_IsConst(expr->rtype, expr->flags & ENODE_FLAG_QUALS))
+ CError_Error(CErrorStr179);
+ }
+ return expr;
+ case EPREINC:
+ case EPREDEC:
+ case EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case ECOMMA:
+ if (copts.cplusplus) {
+ if ((eanode = CExpr_GetEA(expr))) {
+ tmpnode = makediadicnode(expr, eanode, ECOMMA);
+ tmpnode->rtype = tmpnode->data.diadic.right->rtype;
+ tmpnode = makemonadicnode(tmpnode, EINDIRECT);
+ tmpnode->rtype = expr->rtype;
+ return tmpnode;
+ }
+ CError_Error(CErrorStr190);
+ return expr;
+ }
+ break;
+ case ECOND:
+ if (
+ copts.cplusplus &&
+ is_typesame(expr->data.cond.expr1->rtype, expr->data.cond.expr2->rtype) &&
+ (expr->data.cond.expr1->rtype->type != TYPEPOINTER || (UInt32) (expr->data.cond.expr1->flags & ENODE_FLAG_QUALS) == (expr->data.cond.expr2->flags & ENODE_FLAG_QUALS))
+ ) {
+ expr->data.cond.expr1 = CExpr_LValue(expr->data.cond.expr1, flag1, flag2);
+ expr->data.cond.expr2 = CExpr_LValue(expr->data.cond.expr2, flag1, flag2);
+ if (ENODE_IS(expr->data.cond.expr1, EINDIRECT) && ENODE_IS(expr->data.cond.expr2, EINDIRECT)) {
+ if (!ENODE_IS(expr->data.cond.expr1->data.monadic, EBITFIELD) && !ENODE_IS(expr->data.cond.expr2->data.monadic, EBITFIELD)) {
+ expr->data.cond.expr1 = getnodeaddress(expr->data.cond.expr1, 0);
+ expr->data.cond.expr2 = getnodeaddress(expr->data.cond.expr2, 0);
+ expr->rtype = expr->data.cond.expr1->rtype;
+ tmpnode = makemonadicnode(expr, EINDIRECT);
+ tmpnode->rtype = TYPE_POINTER(tmpnode->rtype)->target;
+ return tmpnode;
+ }
+ }
+ }
+ break;
+ }
+
+ if (flag2)
+ CError_Error(CErrorStr142);
+ return expr;
+}
+
+ENode *CExpr_MakeObjRefNode(Object *obj, Boolean flag) {
+ ENode *expr;
+
+ if (obj->sclass == TK_TYPEDEF) {
+ CError_Error(CErrorStr141);
+ return intconstnode((Type *) &void_ptr, 0);
+ }
+
+ expr = lalloc(sizeof(ENode));
+ memclrw(expr, sizeof(ENode));
+ expr->type = EOBJREF;
+ expr->data.objref = obj;
+ expr->rtype = CDecl_NewPointerType(obj->type);
+
+ if (!IS_TYPE_FUNC(obj->type))
+ expr->flags = obj->qual & ENODE_FLAG_QUALS;
+ if (flag)
+ obj->flags |= OBJECT_USED;
+
+ return expr;
+}
+
+ENode *create_objectrefnode(Object *obj) {
+ if (name_obj_check && !name_obj_check(NULL, obj))
+ return intconstnode((Type *) &void_ptr, 0);
+ return CExpr_MakeObjRefNode(obj, 1);
+}
+
+ENode *create_objectnode2(Object *obj) {
+ ENode *expr;
+
+ if (name_obj_check && !name_obj_check(NULL, obj))
+ return nullnode();
+
+ expr = makemonadicnode(CExpr_MakeObjRefNode(obj, 1), EINDIRECT);
+ expr->rtype = TYPE_POINTER(expr->rtype)->target;
+ return expr;
+}
+
+ENode *create_objectnode(Object *obj) {
+ return checkreference(create_objectnode2(obj));
+}
+
+static ENode *CExpr_ExpandArg(ENode *expr, Type *type) {
+ if (ENODE_IS(expr, ETYPCON) && IS_TYPE_FLOAT(type)) {
+ expr->rtype = type;
+ return expr;
+ } else {
+ return promote(expr, type);
+ }
+}
+
+ENode *CExpr_IsTempConstruction(ENode *expr, Type *type, ENode **resultexpr) {
+ ENodeList *args;
+ ENode *funccall;
+ ENode *funcref;
+
+ if (
+ !ENODE_IS(expr, EINDIRECT) ||
+ expr->rtype != type ||
+ !ENODE_IS((funccall = expr->data.monadic), EFUNCCALL) ||
+ !(args = funccall->data.funccall.args)
+ )
+ return NULL;
+
+ if (!ENODE_IS((funcref = funccall->data.funccall.funcref), EOBJREF) || !CClass_IsConstructor(funcref->data.objref)) {
+ if (expr->data.monadic->data.funccall.functype->functype != type)
+ return NULL;
+ if (CABI_GetStructResultArgumentIndex(expr->data.monadic->data.funccall.functype) == 1) {
+ args = args->next;
+ CError_ASSERT(1277, args);
+ }
+ }
+
+ if (resultexpr)
+ *resultexpr = args->node;
+ return expr->data.monadic;
+}
+
+ENode *CExpr_AdjustFunctionCall(ENode *expr) {
+ ENodeList *list;
+
+ switch (expr->data.funccall.functype->functype->type) {
+ case TYPECLASS:
+ CDecl_CompleteType(expr->data.funccall.functype->functype);
+ case TYPESTRUCT:
+ if (!expr->data.funccall.functype->functype->size)
+ CError_Error(CErrorStr136, expr->data.funccall.functype->functype, 0);
+ }
+
+ if (CMach_GetFunctionResultClass(expr->data.funccall.functype)) {
+ list = lalloc(sizeof(ENodeList));
+ if (IS_TYPE_CLASS(expr->data.funccall.functype->functype)) {
+ CDecl_CompleteType(expr->data.funccall.functype->functype);
+ if (CClass_Destructor(TYPE_CLASS(expr->data.funccall.functype->functype)))
+ list->node = create_temp_node2(expr->rtype);
+ else
+ list->node = create_temp_node(expr->rtype);
+ } else {
+ list->node = create_temp_node(expr->rtype);
+ }
+ list->next = expr->data.funccall.args;
+ expr->data.funccall.args = list;
+
+ if (expr->data.funccall.funcref->flags & ENODE_FLAG_10)
+ expr = CSOM_EnvCheck(expr, list);
+
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype);
+ return expr;
+ }
+
+ if (expr->data.funccall.funcref->flags & ENODE_FLAG_10)
+ expr = CSOM_EnvCheck(expr, NULL);
+ return expr;
+}
+
+ENode *funccallexpr(Object *func, ENode *arg1, ENode *arg2, ENode *arg3, ENode *arg4) {
+ ENode *expr;
+ TypeFunc *tfunc;
+ ENodeList *list;
+
+ tfunc = TYPE_FUNC(func->type);
+ CError_ASSERT(1411, IS_TYPE_FUNC(tfunc));
+
+ expr = lalloc(sizeof(ENode));
+ expr->type = EFUNCCALL;
+ expr->cost = 4;
+ expr->rtype = tfunc->functype;
+ expr->flags = tfunc->qual & ENODE_FLAG_QUALS;
+ expr->data.funccall.funcref = create_objectrefnode(func);
+ expr->data.funccall.functype = tfunc;
+
+ if (arg1) {
+ list = lalloc(sizeof(ENodeList));
+ expr->data.funccall.args = list;
+ list->node = arg1;
+ if (arg2) {
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->node = arg2;
+ if (arg3) {
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->node = arg3;
+ if (arg4) {
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->node = arg4;
+ }
+ }
+ }
+ list->next = NULL;
+ } else {
+ expr->data.funccall.args = NULL;
+ }
+
+ return CExpr_AdjustFunctionCall(expr);
+}
+
+ENode *CExpr_FuncCallSix(Object *func, ENode *arg1, ENode *arg2, ENode *arg3, ENode *arg4, ENode *arg5, ENode *arg6) {
+ ENode *expr;
+ TypeFunc *tfunc;
+ ENodeList *list;
+
+ tfunc = TYPE_FUNC(func->type);
+ CError_ASSERT(1460, IS_TYPE_FUNC(tfunc));
+
+ expr = lalloc(sizeof(ENode));
+ expr->type = EFUNCCALL;
+ expr->cost = 4;
+ expr->rtype = tfunc->functype;
+ expr->flags = tfunc->qual & ENODE_FLAG_QUALS;
+ expr->data.funccall.funcref = create_objectrefnode(func);
+ expr->data.funccall.functype = tfunc;
+
+ list = lalloc(sizeof(ENodeList));
+ expr->data.funccall.args = list;
+ list->node = arg1;
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->node = arg2;
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->node = arg3;
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->node = arg4;
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->node = arg5;
+ if (arg6) {
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->node = arg6;
+ }
+ list->next = NULL;
+
+ return CExpr_AdjustFunctionCall(expr);
+}
+
+static void CExpr_CalcStdAssign(short checkresult, Match5 *match, Type *t1, UInt32 q1, Type *t2, UInt32 q2, Boolean flag) {
+ memclrw(match, sizeof(Match5));
+ switch (checkresult) {
+ case CheckResult1:
+ match->x0++;
+ break;
+ case CheckResult2:
+ match->x2++;
+ break;
+ case CheckResult3:
+ match->x4++;
+ match->x6 += assign_value;
+ break;
+ default:
+ CError_FATAL(1504);
+ }
+
+ if (flag || (IS_TYPE_POINTER_ONLY(t2) && (IS_TYPE_POINTER_ONLY(t1) || IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(t2))) != 0)) {
+ if ((q2 & Q_CONST) == (q1 & Q_CONST))
+ match->x8++;
+ if ((q2 & Q_VOLATILE) == (q1 & Q_VOLATILE))
+ match->x8++;
+ }
+}
+
+void CExpr_MatchCV(Type *t1, UInt32 q1, Type *t2, UInt32 q2, Match13 *match) {
+ Boolean r8;
+
+ if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(t2))) {
+ t2 = TYPE_POINTER(t2)->target;
+ r8 = 1;
+ } else {
+ r8 = 0;
+ }
+
+ while (IS_TYPE_POINTER_ONLY(t2) && IS_TYPE_POINTER_ONLY(t1)) {
+ if (r8) {
+ if ((TYPE_POINTER(t1)->qual & Q_CONST) != (TYPE_POINTER(t2)->qual & Q_CONST))
+ match->anotherm5.x8--;
+ if ((TYPE_POINTER(t1)->qual & Q_VOLATILE) != (TYPE_POINTER(t2)->qual & Q_VOLATILE))
+ match->anotherm5.x8--;
+ }
+ t2 = TYPE_POINTER(t2)->target;
+ t1 = TYPE_POINTER(t1)->target;
+ r8 = 1;
+ }
+
+ if ((q1 & Q_CONST) != (q2 & Q_CONST))
+ match->anotherm5.x8--;
+ if ((q1 & Q_VOLATILE) != (q2 & Q_VOLATILE))
+ match->anotherm5.x8--;
+}
+
+Boolean CExpr_MatchAssign(Type *type, UInt32 qual, ENode *expr, Match13 *match) {
+ switch (assign_check(expr, type, qual, 0, 0, 1)) {
+ case CheckResult0:
+ return 0;
+ case CheckResult1:
+ match->anotherm5.x0++;
+ break;
+ case CheckResult2:
+ match->anotherm5.x2++;
+ break;
+ case CheckResult3:
+ match->anotherm5.x4++;
+ match->anotherm5.x6 += assign_value;
+ break;
+ case CheckResult4:
+ match->xE++;
+ match->match5.x0 += user_std_match.x0;
+ match->match5.x2 += user_std_match.x2;
+ match->match5.x4 += user_std_match.x4;
+ match->match5.x6 += user_std_match.x6;
+ match->match5.x8 += user_std_match.x8;
+ break;
+ default:
+ CError_FATAL(1585);
+ }
+
+ if (IS_TYPE_POINTER_ONLY(type))
+ CExpr_MatchCV(expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, qual, match);
+
+ return 1;
+}
+
+static short CExpr_StdMatchCompare(Match5 *a, Match5 *b, Boolean flag) {
+ if (a->x0 > b->x0) return 1;
+ if (a->x0 == b->x0) {
+ if (a->x2 > b->x2) return 1;
+ if (a->x2 == b->x2) {
+ if (a->x4 > b->x4) return 1;
+ if (a->x4 == b->x4) {
+ if (a->x6 > b->x6) return 1;
+ if (a->x6 == b->x6) {
+ if (!flag)
+ return 0;
+ if (a->x8 > b->x8) return 1;
+ if (a->x8 == b->x8) return 0;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+static short CExpr2_MemberPointerConversion(Type *type, ENode *expr, Boolean flag1) {
+ ENode *newnode;
+ short depth;
+
+ newnode = lalloc(sizeof(ENode));
+ *newnode = *expr;
+ if (!IS_TYPE_MEMBERPOINTER(newnode->rtype)) {
+ newnode = CExpr_MemberPointerConversion(newnode, TYPE_MEMBER_POINTER(type), flag1);
+ if (iscpp_typeequal(newnode->rtype, type)) {
+ if (flag1)
+ assign_node = newnode;
+ return CheckResult3;
+ }
+ }
+
+ if (IS_TYPE_MEMBERPOINTER(newnode->rtype)) {
+ CError_ASSERT(1656, IS_TYPE_CLASS(TYPE_MEMBER_POINTER(type)->ty2));
+ CError_ASSERT(1657, IS_TYPE_CLASS(TYPE_MEMBER_POINTER(newnode->rtype)->ty2));
+
+ if (CClass_IsBaseClass(TYPE_CLASS(TYPE_MEMBER_POINTER(type)->ty2), TYPE_CLASS(TYPE_MEMBER_POINTER(newnode->rtype)->ty2), &depth, 0, 0)) {
+ assign_value = 1000 - depth;
+ if (flag1)
+ assign_node = PointerToMemberCast(newnode, TYPE_MEMBER_POINTER(newnode->rtype), TYPE_MEMBER_POINTER(type), 1);
+ return CheckResult3;
+ }
+ }
+
+ return CheckResult0;
+}
+
+ENode *CExpr_ClassPointerCast(BClassList *cls, ENode *origexpr, Boolean nullcheckflag) {
+ ENode *expr;
+ ClassList *base;
+ Boolean do_nullcheck;
+ TypeClass *tclass;
+ SInt32 offset;
+ ENode *tmp;
+
+ expr = origexpr;
+ tclass = TYPE_CLASS(cls->type);
+ do_nullcheck = 0;
+ CError_ASSERT(1691, cls);
+
+ if (!IS_TYPE_POINTER_ONLY(origexpr->rtype)) {
+ CError_Error(CErrorStr141);
+ return origexpr;
+ }
+
+ cls = cls->next;
+ while (cls) {
+ for (base = tclass->bases; base; base = base->next) {
+ if (base->base == TYPE_CLASS(cls->type))
+ break;
+ }
+
+ if (!base) {
+ CError_Error(CErrorStr221);
+ while (cls->next)
+ cls = cls->next;
+
+ tmp = nullnode();
+ tmp->rtype = CDecl_NewPointerType(cls->type);
+ return tmp;
+ }
+
+ if (base->is_virtual) {
+ if (!base->base->sominfo) {
+ do_nullcheck = 1;
+ if ((offset = base->offset) && !canadd(expr, offset)) {
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD);
+ optimizecomm(expr);
+ }
+ expr->rtype = CDecl_NewPointerType(CDecl_NewPointerType(TYPE(base->base)));
+ expr = makemonadicnode(expr, EINDIRECT);
+ }
+ } else {
+ if ((offset = base->offset)) {
+ do_nullcheck = 1;
+ if (!canadd(expr, offset)) {
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD);
+ optimizecomm(expr);
+ }
+ }
+ }
+
+ switch (expr->type) {
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ expr = makemonadicnode(expr, ETYPCON);
+ }
+
+ expr->rtype = CDecl_NewPointerType(TYPE(base->base));
+ tclass = TYPE_CLASS(cls->type);
+ cls = cls->next;
+ }
+
+ if (nullcheckflag && do_nullcheck)
+ expr = do_castnullcheck(expr, origexpr);
+ return expr;
+}
+
+ENode *CExpr_GetClassAccessNode(BClassList *a, BClassList *b, ENode *expr, Object *obj, AccessType access, Boolean flag) {
+ TypeClass *tclass;
+ ENode *tmp;
+
+ if (!expr) {
+ if (!cscope_currentfunc || !cscope_currentclass || !cscope_is_member_func || !(expr = CClass_CreateThisSelfExpr())) {
+ CError_Error(CErrorStr221);
+ return NULL;
+ }
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TYPE(cscope_currentclass);
+ }
+
+ CError_ASSERT(1786, a);
+ CError_ASSERT(1787, IS_TYPE_CLASS(expr->rtype));
+
+ tclass = TYPE_CLASS(expr->rtype);
+ a = CScope_GetClassAccessPath(a, tclass);
+ if (!a || a->type != TYPE(tclass)) {
+ CError_Error(CErrorStr221);
+ return NULL;
+ }
+
+ if (flag)
+ CClass_CheckPathAccess(a, obj, access);
+
+ if (!TYPE_CLASS(a->type)->sominfo) {
+ if (b)
+ a = CClass_AppendPath(a, b);
+
+ if (!ENODE_IS(expr, EINDIRECT))
+ expr = CExpr_LValue(expr, 0, 0);
+
+ if (ENODE_IS(expr, EINDIRECT)) {
+ expr->data.monadic->flags = expr->flags;
+ tmp = expr->data.monadic;
+ switch (tmp->type) {
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ tmp = makemonadicnode(tmp, ETYPCON);
+ }
+ expr = makemonadicnode(CExpr_ClassPointerCast(a, tmp, 0), EINDIRECT);
+ expr->rtype = TYPE(tclass);
+ }
+ }
+
+ return expr;
+}
+
+static short std_assign_check_overload(NameSpaceObjectList *list, TemplArg *templargs, Type *type, Boolean flag1) {
+ Object *obj;
+ Object *used_obj;
+ Boolean found_non_template_func;
+ Boolean is_ambig;
+ TemplFuncInstance *instance;
+ ENode *expr;
+ Object *cmp1;
+ Object *cmp2;
+
+ if (!IS_TYPE_POINTER_ONLY(type) || !IS_TYPE_FUNC(TYPE_POINTER(type)->target))
+ return CheckResult0;
+
+ used_obj = NULL;
+ type = TYPE_POINTER(type)->target;
+ found_non_template_func = 0;
+ is_ambig = 0;
+ for (; list; list = list->next) {
+ obj = OBJECT(list->object);
+ if (obj->otype != OT_OBJECT)
+ continue;
+
+ if (IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_IS_TEMPL)) {
+ if (!found_non_template_func && CTempl_CanDeduceFunc(obj, TYPE_FUNC(type), templargs)) {
+ instance = CTempl_DeduceFunc(obj, TYPE_FUNC(type), templargs, NULL, 0);
+ CError_ASSERT(1861, instance);
+ if (is_typesame(instance->object->type, type)) {
+ if (used_obj && used_obj != instance->object)
+ is_ambig = 1;
+ else
+ used_obj = instance->object;
+ }
+ }
+ } else {
+ if (is_typesame(obj->type, type)) {
+ if (used_obj && found_non_template_func) {
+ cmp1 = obj;
+ if (obj->datatype == DALIAS)
+ cmp1 = obj->u.alias.object;
+ cmp2 = used_obj;
+ if (used_obj->datatype == DALIAS)
+ cmp2 = used_obj->u.alias.object;
+ if (cmp1 != cmp2)
+ is_ambig = 1;
+ } else {
+ is_ambig = 0;
+ used_obj = obj;
+ }
+ found_non_template_func = 1;
+ }
+ }
+ }
+
+ if (used_obj) {
+ if (flag1) {
+ if (is_ambig)
+ CError_Error(CErrorStr199);
+ expr = CExpr_MakeObjRefNode(used_obj, 1);
+ assign_node = expr;
+ expr->rtype = CDecl_NewPointerType(used_obj->type);
+ expr->flags = obj->qual & ENODE_FLAG_QUALS;
+ used_obj->flags |= OBJECT_USED;
+ if (used_obj->datatype == DINLINEFUNC)
+ CError_Error(CErrorStr175);
+ }
+ return CheckResult1;
+ } else {
+ return CheckResult0;
+ }
+}
+
+ENode *CExpr_ConvertToBool(ENode *expr, Boolean isExplicit) {
+ if (IS_TYPE_MEMBERPOINTER(expr->rtype))
+ expr = CExpr_ConvertToCondition(expr);
+
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPEPOINTER:
+ if (IS_TYPE_ENUM(expr->rtype))
+ expr = forceintegral(expr);
+ switch (expr->type) {
+ case EINTCONST:
+ CInt64_SetLong(&expr->data.intval, !CInt64_IsZero(&expr->data.intval));
+ break;
+ case EFLOATCONST:
+ CInt64_SetLong(&expr->data.intval, !CMach_FloatIsZero(expr->data.floatval));
+ expr->type = EINTCONST;
+ break;
+ default:
+ expr = makemonadicnode(expr, ELOGNOT);
+ expr->rtype = TYPE(&stbool);
+ expr = makemonadicnode(expr, ELOGNOT);
+ }
+ break;
+ default:
+ CError_Error(
+ isExplicit ? CErrorStr247 : CErrorStr209,
+ expr->rtype,
+ expr->flags & ENODE_FLAG_QUALS,
+ &stbool,
+ 0);
+ expr = nullnode();
+ }
+
+ expr->rtype = TYPE(&stbool);
+ return expr;
+}
+
+static short std_assign_check(ENode *expr, Type *type, Boolean flag1, Boolean flag2) {
+ short result;
+
+ if (copts.cplusplus) {
+ illegalimplicitconversion = 0;
+
+ if ((result = iscpp_typeequal(expr->rtype, type))) {
+ assign_node = expr;
+ if (result == -1) {
+ assign_value = 1;
+ return CheckResult3;
+ } else {
+ return CheckResult1;
+ }
+ }
+
+ if (flag1 && illegalimplicitconversion) {
+ CError_Error(CErrorStr209, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, 0);
+ return CheckResult0;
+ }
+ } else {
+ if (is_typeequal(expr->rtype, type)) {
+ assign_node = expr;
+ return CheckResult1;
+ }
+ }
+
+ if (type == TYPE(&stbool)) {
+ switch (expr->rtype->type) {
+ case TYPEPOINTER:
+ case TYPEMEMBERPOINTER:
+ assign_value = 0;
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ if (flag1)
+ assign_node = CExpr_ConvertToBool(expr, 0);
+ return CheckResult3;
+ default:
+ return CheckResult0;
+ }
+ }
+
+ if (IS_TYPE_ENUM(expr->rtype) && (IS_TYPE_INT(type) || IS_TYPE_FLOAT(type))) {
+ result = CheckResult3;
+ if (IS_TYPE_INT(type)) {
+ if (TYPE_ENUM(expr->rtype)->enumtype == type) {
+ result = CheckResult2;
+ } else if (TYPE_INTEGRAL(TYPE_ENUM(expr->rtype)->enumtype)->integral < IT_INT) {
+ switch (TYPE_INTEGRAL(type)->integral) {
+ case IT_INT:
+ if (expr->rtype->size < stsignedint.size || TYPE_ENUM(expr->rtype)->enumtype == TYPE(&stsignedshort))
+ result = CheckResult2;
+ break;
+ case IT_UINT:
+ if (expr->rtype->size >= stsignedint.size && TYPE_ENUM(expr->rtype)->enumtype != TYPE(&stsignedshort))
+ result = CheckResult2;
+ break;
+ }
+ }
+ }
+ if (flag1) {
+ expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
+ assign_node = promote(expr, type);
+ }
+ return result;
+ }
+
+ if (IS_TYPE_INT(expr->rtype) && (IS_TYPE_INT(type) || IS_TYPE_FLOAT(type))) {
+ result = CheckResult3;
+ if (TYPE_INTEGRAL(expr->rtype)->integral <= IT_INT) {
+ if (type == TYPE(&stsignedint) || type == TYPE(&stunsignedint)) {
+ switch (TYPE_INTEGRAL(type)->integral) {
+ case IT_INT:
+ if (expr->rtype->size < stsignedint.size || type != TYPE(&stunsignedshort))
+ result = CheckResult2;
+ break;
+ case IT_UINT:
+ if (expr->rtype->size == stsignedint.size && type == TYPE(&stunsignedshort))
+ result = CheckResult2;
+ break;
+ }
+ }
+ }
+
+ if (flag1 && type != expr->rtype)
+ assign_node = promote(expr, type);
+ else
+ assign_node = expr;
+ return result;
+ }
+
+ if (IS_TYPE_FLOAT(expr->rtype) && (IS_TYPE_INT(type) || IS_TYPE_FLOAT(type))) {
+ if (type == TYPE(&stdouble) && (expr->rtype == TYPE(&stfloat) || expr->rtype == TYPE(&stshortdouble)))
+ result = CheckResult2;
+ else
+ result = CheckResult3;
+
+ if (flag1 && (!IS_TYPE_FLOAT(type) || type->size != expr->rtype->size))
+ assign_node = promote(expr, type);
+ else
+ assign_node = expr;
+ return result;
+ }
+
+ if (IS_TYPE_POINTER_ONLY(type)) {
+ if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval) && (IS_TYPE_INT(expr->rtype) || (!copts.cplusplus && IS_TYPE_ENUM(expr->rtype)))) {
+ if (flag1)
+ expr->rtype = TYPE(&stunsignedlong);
+ assign_node = expr;
+ return CheckResult3;
+ }
+ if (ENODE_IS(expr, EOBJLIST)) {
+ return std_assign_check_overload(expr->data.objlist.list, expr->data.objlist.templargs, type, flag1);
+ }
+ if (IS_TYPE_POINTER_ONLY(expr->rtype)) {
+ if (ENODE_IS(expr, EOBJREF) && IS_TYPE_FUNC(expr->data.objref->type) && (TYPE_FUNC(expr->data.objref->type)->flags & FUNC_IS_TEMPL)) {
+ NameSpaceObjectList list;
+ list.next = NULL;
+ list.object = OBJ_BASE(expr->data.objref);
+ return std_assign_check_overload(&list, NULL, type, flag1);
+ }
+ if (copts.objective_c && CObjC_IsCompatibleType(expr->rtype, type)) {
+ assign_value = 1;
+ return CheckResult3;
+ }
+ if (IS_TYPE_CLASS(TYPE_POINTER(expr->rtype)->target) && IS_TYPE_CLASS(TYPE_POINTER(type)->target)) {
+ short depth;
+ Boolean isambig;
+ BClassList *path;
+ path = CClass_GetBasePath(
+ TYPE_CLASS(TYPE_POINTER(expr->rtype)->target),
+ TYPE_CLASS(TYPE_POINTER(type)->target),
+ &depth, &isambig
+ );
+ if (path) {
+ assign_value = 1000 - depth;
+ if (flag1) {
+ if (isambig)
+ CError_Error(CErrorStr188);
+ if (flag2)
+ CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC);
+ assign_node = CExpr_ClassPointerCast(path, expr, 1);
+ }
+ return CheckResult3;
+ } else {
+ if (flag1) {
+ if (isambig)
+ CError_Error(CErrorStr188);
+ else
+ CError_Error(
+ CErrorStr244,
+ expr->rtype,
+ expr->flags & ENODE_FLAG_QUALS,
+ type,
+ 0);
+ }
+ return CheckResult0;
+ }
+ }
+ }
+ }
+
+ if (IS_TYPE_MEMBERPOINTER(type) && !IS_TYPE_CLASS(expr->rtype)) {
+ return CExpr2_MemberPointerConversion(type, expr, flag1);
+ }
+
+ if (IS_TYPE_CLASS(expr->rtype) && IS_TYPE_CLASS(type)) {
+ short depth;
+ Boolean isambig;
+ BClassList *path;
+ path = CClass_GetBasePath(
+ TYPE_CLASS(expr->rtype),
+ TYPE_CLASS(type),
+ &depth, &isambig
+ );
+ if (path) {
+ assign_value = 1000 - depth;
+ if (flag1) {
+ if (isambig)
+ CError_Error(CErrorStr188);
+ CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC);
+ assign_node = getnodeaddress(expr, 0);
+ assign_node = CExpr_ClassPointerCast(path, assign_node, 0);
+ assign_node = makemonadicnode(assign_node, EINDIRECT);
+ assign_node->rtype = type;
+ }
+ return CheckResult3;
+ }
+ }
+
+ if (IS_TYPE_ENUM(type)) {
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ if (!copts.cplusplus) {
+ if (flag1) {
+ if (copts.pedantic)
+ CError_Warning(CErrorStr217, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, 0);
+ assign_node = do_typecast(expr, type, 0);
+ assign_node->flags = expr->flags;
+ }
+ return CheckResult2;
+ } else {
+ if (flag1)
+ CError_Error(CErrorStr217, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, 0);
+ }
+ }
+ }
+
+ return CodeGen_AssignCheck(expr, type, flag1, flag2);
+}
+
+static short is_compatible_conversion(Type *a, Type *b) {
+ if (IS_TYPE_REFERENCE(a))
+ a = TYPE_POINTER(a)->target;
+ if (IS_TYPE_REFERENCE(b))
+ b = TYPE_POINTER(b)->target;
+ return iscpp_typeequal(b, a);
+}
+
+static void CExpr_ConIteratorInit(ConIterator *iter) {
+ ClassList *base;
+ ConIterator *subiter;
+ ConIteratorList *list;
+
+ for (base = iter->tclass->bases; base; base = base->next) {
+ if (base->base->flags & CLASS_IS_CONVERTIBLE) {
+ subiter = galloc(sizeof(ConIterator));
+ memclrw(subiter, sizeof(ConIterator));
+ subiter->parent = iter;
+ subiter->tclass = base->base;
+ CExpr_ConIteratorInit(subiter);
+
+ list = galloc(sizeof(ConIteratorList));
+ memclrw(list, sizeof(ConIteratorList));
+ list->iter = subiter;
+ list->next = iter->children;
+ iter->children = list;
+ }
+ }
+}
+
+void CExpr_ConversionIteratorInit(ConversionIterator *iter, TypeClass *tclass) {
+ memclrw(iter, sizeof(ConversionIterator));
+ if (tclass->flags & CLASS_IS_CONVERTIBLE) {
+ iter->coniter = &iter->myconiter;
+ iter->myconiter.tclass = tclass;
+ CExpr_ConIteratorInit(&iter->myconiter);
+ CScope_InitObjectIterator(&iter->objiter, tclass->nspace);
+ }
+}
+
+static Boolean CExpr_ConversionIteratorIsHidden(ConIterator *iter, TypeFunc *tfunc) {
+ CScopeObjectIterator objiter;
+ ObjBase *obj;
+ TypeFunc *objtfunc;
+
+ while (iter) {
+ CScope_InitObjectIterator(&objiter, iter->tclass->nspace);
+ while (1) {
+ if (!(obj = CScope_NextObjectIteratorObject(&objiter)))
+ break;
+
+ objtfunc = TYPE_FUNC(OBJECT(obj)->type);
+ if (
+ IS_TYPE_FUNC(objtfunc) &&
+ (objtfunc->flags & FUNC_CONVERSION) &&
+ is_compatible_conversion(tfunc->functype, objtfunc->functype) &&
+ (tfunc->args->qual & Q_CONST) == (objtfunc->args->qual & Q_CONST) &&
+ (tfunc->qual & Q_CONST) == (objtfunc->qual & Q_CONST)
+ )
+ return 1;
+ }
+ iter = iter->parent;
+ }
+
+ return 0;
+}
+
+Object *CExpr_ConversionIteratorNext(ConversionIterator *iter) {
+ ConIterator *ci;
+ Object *obj;
+
+ ci = iter->coniter;
+ if (!ci)
+ return NULL;
+
+restart:
+ if ((obj = OBJECT(CScope_NextObjectIteratorObject(&iter->objiter)))) {
+ if (
+ IS_TYPE_FUNC(obj->type) &&
+ (TYPE_FUNC(obj->type)->flags & FUNC_CONVERSION) &&
+ !CExpr_ConversionIteratorIsHidden(ci->parent, TYPE_FUNC(obj->type))
+ ) {
+ return obj;
+ }
+ goto restart;
+ }
+
+ do {
+ if (ci->children) {
+ iter->coniter = ci->children->iter;
+ ci->children = ci->children->next;
+ ci = iter->coniter;
+ CScope_InitObjectIterator(&iter->objiter, ci->tclass->nspace);
+ goto restart;
+ }
+ } while ((ci = ci->parent));
+
+ return NULL;
+}
+
+short user_assign_check(ENode *expr, Type *type, UInt32 qual, Boolean flag1, Boolean flag2, Boolean flag3) {
+ Object *r26;
+ ENode *r25;
+ Boolean r24;
+ Boolean r23;
+ Boolean r22;
+ Type *r18b;
+ short r18;
+ TypeFunc *r17;
+ Object *r17b;
+ NameSpaceObjectList *r16b;
+ Object *r16;
+ Object *r15;
+ ENode *r15b;
+ ENode *r14;
+ short r14b;
+ TypeFunc *r14c;
+ ENodeList *r14d;
+ TypeMemberFunc *r13;
+ ENodeList *r13b;
+ short result;
+ FuncArg *arg;
+ ConversionIterator iter;
+ Match5 stdmatch;
+ Match5 match_8C;
+ Match5 match_98;
+ BClassList path;
+ UInt16 chk;
+ Boolean is_const, is_volatile;
+
+ CError_ASSERT(2378, copts.old_argmatch);
+
+ memclrw(&stdmatch, sizeof(Match5));
+ r24 = 0;
+ r22 = 0;
+ r23 = 0;
+
+ if (!type->size)
+ CDecl_CompleteType(type);
+ if (!expr->rtype->size)
+ CDecl_CompleteType(expr->rtype);
+
+ if (IS_TYPE_CLASS(expr->rtype)) {
+ r18 = 0;
+ CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(expr->rtype));
+ while ((r16 = CExpr_ConversionIteratorNext(&iter))) {
+ r17 = TYPE_FUNC(r16->type);
+ r14 = CExpr_NewENode(ETEMP);
+ r14->rtype = r17->functype;
+ if (IS_TYPE_REFERENCE(r14->rtype)) {
+ r14->rtype = TYPE_POINTER(r14->rtype)->target;
+ if (!CParser_IsConst(r14->rtype, r17->qual)) {
+ r14 = makemonadicnode(r14, EINDIRECT);
+ r14->data.monadic->rtype = TYPE(&void_ptr);
+ r14 = makemonadicnode(r14, EINDIRECT);
+ r14->data.monadic->rtype = TYPE(&void_ptr);
+ }
+ }
+ if ((result = std_assign_check(r14, type, 0, flag3))) {
+ CExpr_CalcStdAssign(result, &match_98, r17->functype, r17->qual, type, qual, 1);
+ CError_ASSERT(2419, r17->args && IS_TYPE_POINTER_ONLY(r17->args->type));
+ chk = expr->flags;
+ if (!(is_const = (r17->args->qual & Q_CONST)) && (chk & Q_CONST) != 0)
+ continue;
+ if (!(is_volatile = (r17->args->qual & Q_VOLATILE)) && (chk & Q_VOLATILE) != 0)
+ continue;
+ //if (((r17->args->qual & Q_CONST) == 0 && (chk & Q_CONST) != 0) || ((r17->args->qual & Q_VOLATILE) == 0 && (chk & Q_VOLATILE) != 0))
+ // continue;
+
+ r14b = 0;
+ if (is_const == (expr->flags & Q_CONST))
+ r14b++;
+ if (is_volatile == (expr->flags & Q_VOLATILE))
+ r14b++;
+ switch (CExpr_StdMatchCompare(&match_98, &stdmatch, 1)) {
+ case -1:
+ continue;
+ case 0:
+ if (r26 == r16)
+ continue;
+ if (r14b < r18)
+ continue;
+ if (r14b != r18)
+ break;
+ r22 = 1;
+ continue;
+ }
+ r26 = r16;
+ stdmatch = match_98;
+ r24 = 1;
+ r22 = 0;
+ r18 = r14b;
+ }
+ }
+ }
+
+ if (IS_TYPE_CLASS(type) && (r16b = CClass_Constructor(TYPE_CLASS(type)))) {
+ memclrw(&match_8C, sizeof(Match5));
+ for (; r16b; r16b = r16b->next) {
+ r17b = OBJECT(r16b->object);
+ if (r17b->otype != OT_OBJECT)
+ continue;
+ r14c = TYPE_FUNC(r17b->type);
+ if (!IS_TYPE_FUNC(r14c))
+ continue;
+ if (!flag2 && (r14c->qual & Q_EXPLICIT))
+ continue;
+ if (!r14c->args)
+ continue;
+ if (!(arg = r14c->args->next))
+ continue;
+ if ((TYPE_CLASS(type)->flags & CLASS_HAS_VBASES) && !(arg = arg->next))
+ continue;
+ if (arg == &elipsis)
+ continue;
+ if (arg->next && !arg->next->dexpr && arg->next != &elipsis)
+ continue;
+
+ r18b = arg->type;
+ if (IS_TYPE_REFERENCE(r18b)) {
+ r18b = TYPE_POINTER(r18b)->target;
+ if (!CParser_IsConst(r18b, arg->qual) && !CExpr_IsLValue(expr))
+ continue;
+ }
+
+ if ((result = std_assign_check(expr, r18b, 0, flag3))) {
+ CExpr_CalcStdAssign(result, &match_98, r14c->functype, r14c->qual, type, qual, 0);
+ switch (CExpr_StdMatchCompare(&match_98, &match_8C, 1)) {
+ case -1:
+ case 0:
+ continue;
+ }
+ r25 = expr;
+ match_8C = match_98;
+ r23 = 1;
+ r15 = r17b;
+ }
+ }
+
+ if (r23) {
+ if (r24) {
+ switch (CExpr_StdMatchCompare(&stdmatch, &match_8C, 1)) {
+ case -1:
+ stdmatch = match_8C;
+ r24 = 0;
+ break;
+ case 0:
+ r22 = 1;
+ break;
+ }
+ } else {
+ stdmatch = match_8C;
+ }
+ }
+ }
+
+ if (r22 && flag1)
+ CError_Error(CErrorStr199);
+
+ if (r24 || r23) {
+ if (flag1) {
+ if (r24) {
+ r13 = TYPE_METHOD(r26->type);
+ CError_ASSERT(2537, r13->flags & FUNC_METHOD);
+ r15b = create_objectrefnode(r26);
+ r26->flags |= OBJECT_USED;
+ r14d = lalloc(sizeof(ENodeList));
+ r14d->next = NULL;
+ expr = getnodeaddress(expr, 0);
+ r14d->node = CExpr_AssignmentPromotion(expr, CDecl_NewPointerType(TYPE(r13->theclass)), expr->flags, 0);
+
+ expr = lalloc(sizeof(ENode));
+ expr->type = EFUNCCALL;
+ expr->cost = 4;
+ expr->rtype = r13->functype;
+ expr->flags = r13->qual & ENODE_FLAG_QUALS;
+ expr->data.funccall.funcref = r15b;
+ expr->data.funccall.args = r14d;
+ expr->data.funccall.functype = TYPE_FUNC(r26->type);
+ assign_node = checkreference(CExpr_AdjustFunctionCall(expr));
+ if (assign_node->rtype != type)
+ assign_node = CExpr_AssignmentPromotion(assign_node, type, qual, 1);
+ if (!IS_TYPE_REFERENCE(r13->functype))
+ temp_reference_init = 1;
+ } else {
+ r13b = lalloc(sizeof(ENodeList));
+ r13b->next = NULL;
+ r13b->node = r25;
+ if (TYPE_CLASS(type)->flags & CLASS_HAS_VBASES) {
+ r13b->next = lalloc(sizeof(ENodeList));
+ r13b->next->node = r25;
+ r13b->next->next = NULL;
+ r13b->node = intconstnode(TYPE(&stsignedshort), 1);
+ }
+ path.next = NULL;
+ path.type = type;
+ assign_node = makemonadicnode(create_temp_node(type), EINDIRECT);
+ assign_node->rtype = type;
+ assign_node = CExpr_GenericFuncCall(&path, assign_node, 0, r15, NULL, NULL, r13b, 0, 0, 1);
+ if (ENODE_IS2(assign_node, EFUNCCALL, EFUNCCALLP)) {
+ assign_node->rtype = CDecl_NewPointerType(type);
+ assign_node = makemonadicnode(assign_node, EINDIRECT);
+ assign_node->rtype = type;
+ }
+ temp_reference_init = 1;
+ }
+ }
+
+ user_std_match = stdmatch;
+ return CheckResult4;
+ } else {
+ if (flag1)
+ CError_Error(CErrorStr244, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, qual);
+ return CheckResult0;
+ }
+}
+
+ENode *CExpr_ConvertToCondition(ENode *expr) {
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEPOINTER:
+ return expr;
+ case TYPEENUM:
+ expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
+ return expr;
+ case TYPEMEMBERPOINTER:
+ return memberpointercompare(ENOTEQU, expr, nullnode());
+ case TYPECLASS:
+ return CExpr_Convert(expr, TYPE(&stbool), 0, 0, 1);
+ default:
+ CError_Error(CErrorStr376, expr->rtype, expr->flags & ENODE_FLAG_QUALS);
+ return nullnode();
+ }
+}
+
+ENode *CExpr_ConvertToIntegral(ENode *expr) {
+ ConversionIterator iter;
+ Type *found;
+ Object *obj;
+
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ case TYPEENUM:
+ return integralpromote(expr);
+ case TYPECLASS:
+ CDecl_CompleteType(expr->rtype);
+ found = NULL;
+ CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(expr->rtype));
+ while ((obj = CExpr_ConversionIteratorNext(&iter))) {
+ if (IS_TYPE_INT_OR_ENUM(TYPE_FUNC(obj->type)->functype)) {
+ if (found) {
+ CError_Error(CErrorStr199);
+ break;
+ }
+ found = TYPE_FUNC(obj->type)->functype;
+ }
+ }
+ if (found)
+ return integralpromote(CExpr_Convert(expr, found, 0, 0, 1));
+ break;
+ }
+
+ CError_Error(CErrorStr376, expr->rtype, expr->flags & ENODE_FLAG_QUALS);
+ return nullnode();
+}
+
+void CExpr_CheckArithmConversion(ENode *expr, Type *type) {
+ CInt64 val;
+
+ if (expr->rtype == type)
+ return;
+ if (expr->rtype == TYPE(&stbool))
+ return;
+
+ if (IS_TYPE_INT(expr->rtype)) {
+ if (IS_TYPE_FLOAT(type))
+ return;
+ CError_ASSERT(2772, IS_TYPE_INT(type));
+
+ if (type->size > expr->rtype->size)
+ return;
+ if (type->size == expr->rtype->size && is_unsigned(type) == is_unsigned(expr->rtype))
+ return;
+
+ switch (expr->type) {
+ case EINTCONST:
+ if (!CInt64_IsNegative(&expr->data.intval) || is_unsigned(expr->rtype) || !is_unsigned(type)) {
+ val = CExpr_IntConstConvert(type, expr->rtype, expr->data.intval);
+ val = CExpr_IntConstConvert(expr->rtype, type, val);
+ if (CInt64_Equal(val, expr->data.intval))
+ return;
+ }
+ break;
+ case ELOGNOT:
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ case ENOTEQU:
+ case ELAND:
+ case ELOR:
+ return;
+ }
+ } else {
+ if (IS_TYPE_FLOAT(type) && type->size >= expr->rtype->size)
+ return;
+ }
+
+ CError_Warning(CErrorStr317, expr->rtype, 0, type, 0);
+}
+
+ENode *get_address_of_temp_copy(ENode *expr, Boolean flag) {
+ char buf[64];
+ ENode *result;
+ Object *obj;
+ Type *innertype;
+
+ if (flag) {
+ if (ENODE_IS2(expr, EINTCONST, EFLOATCONST)) {
+ obj = CParser_NewCompilerDefDataObject();
+ obj->type = expr->rtype;
+ obj->name = CParser_GetUniqueName();
+ obj->sclass = TK_STATIC;
+ if (ENODE_IS(expr, EINTCONST)) {
+ innertype = expr->rtype;
+ switch (innertype->type) {
+ case TYPEINT:
+ break;
+ case TYPEENUM:
+ innertype = TYPE_ENUM(innertype)->enumtype;
+ break;
+ case TYPEPOINTER:
+ innertype = TYPE(&stunsignedlong);
+ break;
+ default:
+ CError_FATAL(2857);
+ }
+ CMach_InitIntMem(innertype, expr->data.intval, buf);
+ } else {
+ CMach_InitFloatMem(expr->rtype, expr->data.floatval, buf);
+ }
+ CInit_DeclareData(obj, buf, NULL, obj->type->size);
+ return create_objectrefnode(obj);
+ }
+
+ if (cinit_tempnodefunc == NULL)
+ result = CExpr_NewETEMPNode(expr->rtype, 1);
+ else
+ result = cinit_tempnodefunc(expr->rtype, 0);
+ result = makemonadicnode(result, EINDIRECT);
+ result->rtype = TYPE_POINTER(result->rtype)->target;
+ return makecommaexpression(makediadicnode(result, expr, EASS), result->data.monadic);
+ } else {
+ result = nullnode();
+ CInt64_SetLong(&result->data.intval, -1);
+ result->rtype = CDecl_NewPointerType(expr->rtype);
+ return result;
+ }
+}
+
+short assign_check(ENode *expr, Type *type, UInt32 qual, Boolean flag1, Boolean flag2, Boolean flag3) {
+ Type *type2;
+ Boolean r30;
+ Boolean r29;
+ short result;
+
+ assign_value = 1000;
+ r30 = 0;
+ r29 = 0;
+ temp_reference_init = 0;
+
+ type2 = type;
+ if (IS_TYPE_REFERENCE(type) && !IS_TYPE_FUNC(TYPE_POINTER(type)->target)) {
+ type2 = TYPE_POINTER(type)->target;
+ r30 = 1;
+ }
+
+ assign_node = expr;
+ if (IS_TYPE_ARRAY(type2)) {
+ r29 = 1;
+ type2 = CDecl_NewPointerType(TYPE_POINTER(type2)->target);
+ }
+
+ if (!type2->size) {
+ CDecl_CompleteType(type2);
+ if (!type2->size && !r30) {
+ if (flag1) {
+ if (IS_TYPE_CLASS(type2))
+ CError_Error(CErrorStr136, type2, 0);
+ else
+ CError_Error(CErrorStr244, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type2, qual);
+ }
+ return CheckResult0;
+ }
+ }
+
+ if (copts.warn_implicitconv && flag1 && !flag2) {
+ if (IS_TYPE_INT_OR_FLOAT(type2) && IS_TYPE_INT_OR_FLOAT(expr->rtype))
+ CExpr_CheckArithmConversion(expr, type2);
+ }
+
+ result = std_assign_check(expr, type2, flag1, flag3);
+ if (!result) {
+ if (IS_TYPE_CLASS(expr->rtype) || IS_TYPE_CLASS(type2)) {
+ result = user_assign_check(expr, type2, qual, flag1, flag2, flag3);
+ } else if (flag1) {
+ CError_Error(CErrorStr244, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type2, qual);
+ }
+ }
+
+ if (r30 && result) {
+ if (flag1) {
+ if (!ENODE_IS(assign_node, EINDIRECT)) {
+ if (!r29) {
+ assign_node = CExpr_LValue(assign_node, 0, 0);
+ if (!ENODE_IS(assign_node, EINDIRECT)) {
+ assign_node = get_address_of_temp_copy(assign_node, 1);
+ temp_reference_init = 1;
+ } else {
+ assign_node = getnodeaddress(assign_node, 0);
+ }
+ }
+ } else {
+ if (!CExpr_IsLValue(assign_node))
+ temp_reference_init = 1;
+ if (!r29)
+ assign_node = getnodeaddress(assign_node, 0);
+ }
+ } else {
+ if (!r29 && !CExpr_IsLValue(assign_node) && !CParser_IsConst(TYPE_POINTER(type)->target, qual)) {
+ result = CheckResult0;
+ }
+ }
+ }
+
+ return result;
+}
+
+Boolean CExpr_MatchCompare(Object *obj, Match13 *a, Match13 *b) {
+ Object *tmp;
+ ObjectList *list;
+
+ switch (CExpr_StdMatchCompare(&b->anotherm5, &a->anotherm5, 0)) {
+ case -1:
+ return 0;
+ case 0:
+ if (a->xE > b->xE)
+ return 0;
+ if (a->xE != b->xE)
+ break;
+ switch (CExpr_StdMatchCompare(&b->match5, &a->match5, 1)) {
+ case -1:
+ return 0;
+ case 0:
+ if (a->anotherm5.x8 > b->anotherm5.x8)
+ return 0;
+ if (a->anotherm5.x8 == b->anotherm5.x8 && (tmp = a->obj)) {
+ if (tmp->datatype == obj->datatype) {
+ add_it:
+ list = lalloc(sizeof(ObjectList));
+ list->next = a->list;
+ a->list = list;
+ list->object = obj;
+ return 0;
+ }
+ if (obj->datatype == DALIAS)
+ return 0;
+ if (tmp->datatype != DALIAS)
+ goto add_it;
+ }
+ }
+ }
+
+ *a = *b;
+ a->obj = obj;
+ return 1;
+}
+
+static void MatchOverloadFunc(Object *obj, FuncArg *args, ENodeList *argexprs, Match13 *match) {
+ Match13 match2;
+
+ if (IS_TYPE_FUNC(obj->type) && !(TYPE_FUNC(obj->type)->flags & FUNC_IS_TEMPL)) {
+ memclrw(&match2, sizeof(Match13));
+ while (1) {
+ if (!args || args->type == &stvoid) {
+ if (!argexprs)
+ break;
+ return;
+ }
+
+ if (args == &elipsis)
+ break;
+ if (args == &oldstyle)
+ break;
+
+ if (!argexprs) {
+ if (args->dexpr)
+ break;
+ return;
+ }
+
+ if (!CExpr_MatchAssign(args->type, args->qual, argexprs->node, &match2))
+ return;
+
+ argexprs = argexprs->next;
+ args = args->next;
+ }
+
+ CExpr_MatchCompare(obj, match, &match2);
+ }
+}
+
+Boolean CExpr_GetFuncMatchArgs(Object *obj, ENodeList *argexprs, ENode *expr, FuncMatchArgs *result) {
+ ENode *intexpr;
+
+ if (!(TYPE_FUNC(obj->type)->flags & FUNC_METHOD)) {
+ result->exprs = argexprs;
+ result->args = TYPE_FUNC(obj->type)->args;
+ return 1;
+ }
+
+ if (TYPE_METHOD(obj->type)->is_static) {
+ result->exprs = argexprs;
+ result->args = TYPE_FUNC(obj->type)->args;
+ return 1;
+ }
+
+ if (TYPE_FUNC(obj->type)->flags & FUNC_IS_CTOR) {
+ result->exprs = argexprs;
+ result->args = TYPE_FUNC(obj->type)->args->next;
+ return 1;
+ }
+
+ if (expr) {
+ intexpr = lalloc(sizeof(ENode));
+ intexpr->type = EINTCONST;
+ intexpr->cost = 0;
+ intexpr->flags = expr->flags;
+ intexpr->rtype = CDecl_NewPointerType(expr->rtype);
+ intexpr->data.intval = cint64_zero;
+
+ result->exprs = lalloc(sizeof(ENodeList));
+ result->exprs->next = argexprs;
+ result->exprs->node = intexpr;
+
+ if (obj->datatype == DALIAS) {
+ result->args = lalloc(sizeof(FuncArg));
+ *result->args = *TYPE_FUNC(obj->type)->args;
+ result->args->type = CDecl_NewPointerType(expr->rtype);
+ } else {
+ result->args = TYPE_FUNC(obj->type)->args;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static NameSpaceObjectList *CExpr_CopyNameSpaceObjectList(NameSpaceObjectList *list) {
+ NameSpaceObjectList *first;
+ NameSpaceObjectList *work;
+
+ first = work = lalloc(sizeof(NameSpaceObjectList));
+ while (1) {
+ work->object = list->object;
+ list = list->next;
+ if (!list) {
+ work->next = NULL;
+ break;
+ } else {
+ work->next = lalloc(sizeof(NameSpaceObjectList));
+ work = work->next;
+ }
+ }
+ return first;
+}
+
+static void CExpr_MatchArgList(NameSpaceObjectList *list, TemplArg *templargs, ENodeList *argexprs, Match13 *match, ENode *expr, Boolean flag) {
+ NameSpaceObjectList *copied_list;
+ NameSpaceObjectList *scan_list;
+ Object *obj;
+ ENodeList *scan_expr;
+ Boolean is_template;
+ FuncMatchArgs fma;
+
+ if (!copts.old_argmatch) {
+ CExpr_FuncArgMatch(CExpr_CopyNameSpaceObjectList(list), templargs, argexprs, match, expr, flag);
+ return;
+ }
+
+ copied_list = CExpr_CopyNameSpaceObjectList(list);
+
+ for (scan_expr = argexprs; scan_expr; scan_expr = scan_expr->next)
+ CDecl_CompleteType(scan_expr->node->rtype);
+
+ scan_list = copied_list;
+ is_template = 0;
+ for (; scan_list; scan_list = scan_list->next) {
+ obj = OBJECT(scan_list->object);
+ if (obj->otype != OT_OBJECT)
+ continue;
+ if (IS_TYPE_FUNC(obj->type) && (!flag || !(obj->qual & Q_EXPLICIT))) {
+ if (!(TYPE_FUNC(obj->type)->flags & FUNC_IS_TEMPL)) {
+ if (CExpr_GetFuncMatchArgs(obj, argexprs, expr, &fma))
+ MatchOverloadFunc(obj, fma.args, fma.exprs, match);
+ } else {
+ is_template = 1;
+ }
+ }
+ }
+
+ if (is_template) {
+ if (!match->obj || match->anotherm5.x2 || match->anotherm5.x4 || match->xE)
+ CTempl_FuncMatch(copied_list, templargs, argexprs, match, expr);
+ }
+}
+
+ENode *CExpr_GetDefaultArgument(ENode *funcexpr, FuncArg *arg) {
+ ENode *tmp;
+
+ if (CTemplTool_IsTemplateArgumentDependentExpression(arg->dexpr)) {
+ CError_ASSERT(3264, ENODE_IS(funcexpr, EOBJREF));
+ tmp = CTemplTool_DeduceDefaultArg(
+ funcexpr->data.objref,
+ CInline_CopyExpression(arg->dexpr, CopyMode0)
+ );
+ return argumentpromotion(tmp, arg->type, arg->qual, 1);
+ }
+
+ return CInline_CopyExpression(arg->dexpr, CopyMode0);
+}
+
+static ENode *CExpr_GenericCall(ENode *funcexpr, ENodeList *argexprs, TypeFunc *tfunc, FuncArg *args) {
+ ENodeList *list;
+ ENode *callexpr;
+
+ while (args) {
+ if (args->dexpr) {
+ if (argexprs) {
+ list = argexprs;
+ while (list->next)
+ list = list->next;
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ } else {
+ list = argexprs = lalloc(sizeof(ENodeList));
+ }
+ list->next = NULL;
+ list->node = CExpr_GetDefaultArgument(funcexpr, args);
+ }
+ args = args->next;
+ }
+
+ callexpr = lalloc(sizeof(ENode));
+ callexpr->type = EFUNCCALL;
+ callexpr->cost = 4;
+ callexpr->rtype = tfunc->functype;
+ callexpr->flags = tfunc->qual & ENODE_FLAG_QUALS;
+ callexpr->data.funccall.funcref = funcexpr;
+ callexpr->data.funccall.funcref->rtype = CDecl_NewPointerType(TYPE(tfunc));
+ callexpr->data.funccall.args = argexprs;
+ callexpr->data.funccall.functype = tfunc;
+ funcexpr->data.objref->flags |= OBJECT_USED;
+ return CExpr_AdjustFunctionCall(callexpr);
+}
+
+static Boolean CExpr_IsObjrefPlusX(ENode *expr) {
+ Type *type;
+
+ if (ENODE_IS(expr, EOBJREF)) {
+ type = expr->data.objref->type;
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+ return IS_TYPE_CLASS(type);
+ }
+
+ if (ENODE_IS2(expr, EADD, ESUB)) {
+ if (CExpr_IsObjrefPlusX(expr->data.diadic.left))
+ return 1;
+ if (CExpr_IsObjrefPlusX(expr->data.diadic.right))
+ return 1;
+ }
+
+ return 0;
+}
+
+static Boolean CExpr_IsStaticType(ENode *expr) {
+ return ENODE_IS(expr, EINDIRECT) && CExpr_IsObjrefPlusX(expr->data.monadic);
+}
+
+ENode *CExpr_VarArgPromotion(ENode *expr, Boolean flag) {
+ if (!copts.old_argmatch)
+ expr = pointer_generation(expr);
+
+ switch (expr->rtype->type) {
+ case TYPEVOID:
+ case TYPEFUNC:
+ CError_Error(CErrorStr353);
+ expr = nullnode();
+ break;
+ case TYPEINT:
+ case TYPEENUM:
+ expr = integralpromote(expr);
+ break;
+ case TYPEFLOAT:
+ if (TYPE_INTEGRAL(expr->rtype)->integral < IT_DOUBLE)
+ expr = promote(expr, TYPE(&stdouble));
+ break;
+ case TYPECLASS:
+ expr = classargument(expr);
+ break;
+ }
+
+ if (!flag && copts.warn_largeargs) {
+ if ((IS_TYPE_INT(expr->rtype) && TYPE_INTEGRAL(expr->rtype)->integral >= IT_LONGLONG) || IS_TYPE_FLOAT(expr->rtype))
+ CError_Warning(CErrorStr316);
+ }
+
+ return expr;
+}
+
+ENode *CExpr_GenericFuncCall(BClassList *path, ENode *funcexpr, Boolean flag1, Object *obj, NameSpaceObjectList *nsol, TemplArg *templargs, ENodeList *nodes, Boolean flag2, Boolean flag3, Boolean flag4) {
+ TypeFunc *tfunc;
+ AccessType access;
+ FuncArg *scan_arg;
+ BClassList *buildpath;
+ ENode *objexpr;
+ ENodeList *scan_expr;
+ BClassList *pathcopy;
+ Boolean had_alias;
+ NameSpaceObjectList my_list;
+ Match13 match;
+
+ memclrw(&match, sizeof(Match13));
+
+ if (!obj || IS_TEMPL_FUNC(obj->type)) {
+ if (!funcexpr && cscope_currentfunc && cscope_currentclass && cscope_is_member_func) {
+ funcexpr = CClass_CreateThisSelfExpr();
+ if (funcexpr) {
+ funcexpr = makemonadicnode(funcexpr, EINDIRECT);
+ funcexpr->rtype = TYPE(cscope_currentclass);
+ }
+ }
+
+ if (obj) {
+ my_list.next = NULL;
+ my_list.object = OBJ_BASE(obj);
+ nsol = &my_list;
+ }
+
+ CExpr_MatchArgList(nsol, templargs, nodes, &match, funcexpr, flag2);
+ if (!match.obj) {
+ CError_ErrorFuncCall(CErrorStr248, nsol, nodes);
+ return nullnode();
+ }
+ if (match.list)
+ CError_OverloadedFunctionError(match.obj, match.list);
+ obj = match.obj;
+ }
+
+ objexpr = create_objectrefnode(obj);
+ tfunc = TYPE_FUNC(obj->type);
+ if (!IS_TYPE_FUNC(tfunc)) {
+ CError_Error(CErrorStr161);
+ return nullnode();
+ }
+
+ if (IS_TYPEFUNC_METHOD(tfunc) && !TYPE_METHOD(tfunc)->is_static) {
+ had_alias = 0;
+ buildpath = NULL;
+ access = obj->access;
+ while (obj->datatype == DALIAS) {
+ buildpath = buildpath ? CClass_AppendPath(buildpath, CClass_GetPathCopy(obj->u.alias.member, 0)) : CClass_GetPathCopy(obj->u.alias.member, 0);
+ obj = obj->u.alias.object;
+ objexpr = create_objectrefnode(obj);
+ had_alias = 1;
+ }
+ if (flag3)
+ CError_Error(CErrorStr188);
+
+ if (TYPE_METHOD(tfunc)->theclass->sominfo && (!(obj->qual & Q_INLINE) || (obj->datatype == DVFUNC && !flag1))) {
+ pathcopy = CClass_GetPathCopy(path, 0);
+ funcexpr = CExpr_GetClassAccessNode(path, buildpath, funcexpr, obj, access, flag4);
+ if (!funcexpr)
+ return nullnode();
+ objexpr = CSOM_MethodAccess(pathcopy, obj, flag1);
+ } else {
+ if (obj->datatype == DVFUNC) {
+ if (flag1 || (!copts.always_vdispatch && !had_alias && funcexpr && CExpr_IsStaticType(funcexpr)))
+ objexpr->flags |= ENODE_FLAG_80;
+ }
+ funcexpr = CExpr_GetClassAccessNode(path, buildpath, funcexpr, obj, access, flag4);
+ if (!funcexpr)
+ return nullnode();
+ }
+
+ if (
+ (tfunc->flags & FUNC_PURE) &&
+ cscope_currentfunc &&
+ (TYPE_FUNC(cscope_currentfunc->type)->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR)) &&
+ cscope_currentclass == TYPE_METHOD(tfunc)->theclass &&
+ ENODE_IS(funcexpr, EINDIRECT) &&
+ ENODE_IS(funcexpr->data.monadic, EINDIRECT) &&
+ ENODE_IS(funcexpr->data.monadic->data.monadic, EOBJREF) &&
+ funcexpr->data.monadic->data.monadic->data.objref->name == this_name_node &&
+ !(objexpr->flags & ENODE_FLAG_80)
+ )
+ CError_Warning(CErrorStr195);
+
+ scan_expr = lalloc(sizeof(ENodeList));
+ scan_expr->next = nodes;
+ scan_expr->node = funcexpr->data.monadic;
+ if (ENODE_IS(scan_expr->node, EOBJREF))
+ scan_expr->node->data.objref->flags |= OBJECT_FLAGS_2;
+
+ if (((funcexpr->flags & Q_CONST) && !(tfunc->args->qual & Q_CONST)) || ((funcexpr->flags & Q_VOLATILE) && !(tfunc->args->qual & Q_VOLATILE))) {
+ if (!(tfunc->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR)))
+ CError_Error(CErrorStr236);
+ }
+
+ nodes = scan_expr;
+ scan_expr = scan_expr->next;
+ scan_arg = tfunc->args->next;
+ } else {
+ if (flag4 && obj->access != ACCESSPROTECTED)
+ CClass_CheckObjectAccess(path, obj);
+
+ scan_arg = tfunc->args;
+ scan_expr = nodes;
+ if (tfunc->flags & FUNC_METHOD) {
+ CError_ASSERT(3599, TYPE_METHOD(tfunc)->theclass->sominfo == NULL);
+ }
+ }
+
+ while (scan_expr) {
+ if (scan_arg && scan_arg != &elipsis && scan_arg != &oldstyle) {
+ scan_expr->node = argumentpromotion(scan_expr->node, scan_arg->type, scan_arg->qual, 1);
+ scan_arg = scan_arg->next;
+ } else {
+ if (!scan_arg) {
+ my_list.next = NULL;
+ my_list.object = OBJ_BASE(obj);
+ CError_ErrorFuncCall(CErrorStr248, &my_list, nodes);
+ }
+ scan_expr->node = CExpr_VarArgPromotion(scan_expr->node, scan_arg == &elipsis);
+ }
+ scan_expr = scan_expr->next;
+ }
+
+ if (scan_arg) {
+ if (scan_arg != &elipsis && scan_arg != &oldstyle) {
+ if (!scan_arg->dexpr) {
+ my_list.next = NULL;
+ my_list.object = OBJ_BASE(obj);
+ CError_ErrorFuncCall(CErrorStr248, &my_list, nodes);
+ scan_arg = NULL;
+ }
+ } else {
+ scan_arg = NULL;
+ }
+ }
+
+ return CExpr_GenericCall(objexpr, nodes, tfunc, scan_arg);
+}
+
+ENode *CExpr_GenericPtmfCall(Object *obj, TypeFunc *tfunc, ENodeList *arg_exprs) {
+ ENodeList *scan_expr;
+ FuncArg *arg;
+
+ scan_expr = arg_exprs;
+ arg = tfunc->args;
+ while (scan_expr) {
+ if (!arg) {
+ CError_Error(CErrorStr162);
+ return nullnode();
+ }
+
+ if (arg != &elipsis && arg != &oldstyle) {
+ scan_expr->node = argumentpromotion(scan_expr->node, arg->type, arg->qual, 1);
+ arg = arg->next;
+ } else {
+ scan_expr->node = CExpr_VarArgPromotion(scan_expr->node, arg == &elipsis);
+ }
+ scan_expr = scan_expr->next;
+ }
+
+ if (arg) {
+ if (arg != &elipsis && arg != &oldstyle) {
+ if (!arg->dexpr) {
+ CError_Error(CErrorStr162);
+ arg = NULL;
+ }
+ } else {
+ arg = NULL;
+ }
+ }
+
+ return CExpr_GenericCall(create_objectrefnode(obj), arg_exprs, tfunc, arg);
+}
+
+static ENode *CExpr_ConvertEMember(ENode *expr) {
+ ENode *result;
+
+ if (expr->data.emember->list->next || expr->data.emember->templargs) {
+ result = CExpr_NewENode(EOBJLIST);
+ result->rtype = OBJECT(expr->data.emember->list->object)->type;
+ result->data.objlist.list = expr->data.emember->list;
+ result->data.objlist.templargs = expr->data.emember->templargs;
+ return result;
+ }
+
+ if (expr->data.emember->list->object->otype != OT_OBJECT)
+ return NULL;
+ return CExpr_MakeObjRefNode(OBJECT(expr->data.emember->list->object), 1);
+}
+
+ENode *CExpr_MakeFunctionCall(ENode *funcexpr, ENodeList *arg_exprs) {
+ ENode *expr;
+ TypeFunc *tfunc;
+ BClassList *save_path;
+ ENode *save_expr;
+ Boolean save_1D;
+ Boolean save_isambig;
+
+ FuncArg *scan_arg;
+ ENodeList *scan_expr;
+ Boolean has_varargs;
+
+ if (ENODE_IS(funcexpr, EOBJLIST) && funcexpr->data.objlist.name) {
+ funcexpr->data.objlist.list = CScope_ArgumentDependentNameLookup(
+ funcexpr->data.objlist.list,
+ funcexpr->data.objlist.name,
+ arg_exprs, 0);
+ if (!funcexpr->data.objlist.list) {
+ CError_Error(CErrorStr140, CError_GetNameString(NULL, funcexpr->data.objlist.name));
+ return nullnode();
+ }
+
+ if (
+ funcexpr->data.objlist.list->object->otype == OT_OBJECT &&
+ (TYPE_FUNC(OBJECT(funcexpr->data.objlist.list->object)->type)->flags & FUNC_INTRINSIC) &&
+ (expr = CodeGen_HandleIntrinsicCall(OBJECT(funcexpr->data.objlist.list->object), arg_exprs)))
+ return expr;
+
+ return CExpr_GenericFuncCall(
+ NULL, NULL, 0, NULL,
+ funcexpr->data.objlist.list,
+ funcexpr->data.objlist.templargs,
+ arg_exprs, 0, 0, 1);
+ }
+
+ if (ENODE_IS(funcexpr, EMEMBER)) {
+ save_path = funcexpr->data.emember->path;
+ save_expr = funcexpr->data.emember->expr;
+ save_1D = funcexpr->data.emember->pr_1D;
+ save_isambig = funcexpr->data.emember->isambig;
+ funcexpr = CExpr_ConvertEMember(funcexpr);
+ if (!funcexpr) {
+ CError_Error(CErrorStr161);
+ return nullnode();
+ }
+ } else {
+ save_path = NULL;
+ save_expr = NULL;
+ save_1D = 0;
+ save_isambig = 0;
+ }
+
+ if (ENODE_IS(funcexpr, EOBJREF) && IS_TYPE_FUNC(funcexpr->data.objref->type) && (TYPE_FUNC(funcexpr->data.objref->type)->flags & FUNC_INTRINSIC)) {
+ if (!(expr = CodeGen_HandleIntrinsicCall(funcexpr->data.objref, arg_exprs))) {
+ expr = CExpr_GenericFuncCall(
+ save_path, save_expr, save_1D, funcexpr->data.objref,
+ NULL, NULL,
+ arg_exprs, 0, save_isambig, 1);
+ }
+ return expr;
+ }
+
+ if (ENODE_IS(funcexpr, EOBJLIST)) {
+ return CExpr_GenericFuncCall(
+ save_path, save_expr, save_1D, NULL,
+ funcexpr->data.objlist.list, funcexpr->data.objlist.templargs,
+ arg_exprs, 0, save_isambig, 1);
+ }
+
+ if (!IS_TYPE_POINTER_ONLY(funcexpr->rtype) || !IS_TYPE_FUNC((tfunc = TYPE_FUNC(TYPE_POINTER(funcexpr->rtype)->target)))) {
+ CError_Error(CErrorStr161);
+ return nullnode();
+ }
+
+ if (ENODE_IS(funcexpr, EOBJREF)) {
+ return CExpr_GenericFuncCall(
+ save_path, save_expr, save_1D, funcexpr->data.objref,
+ NULL, NULL, arg_exprs, 0, save_isambig, 1);
+ }
+
+ scan_expr = arg_exprs; // r25
+ scan_arg = tfunc->args; // r26
+ has_varargs = 0;
+ while (scan_expr) {
+ if (!has_varargs) {
+ if (!scan_arg) {
+ CError_Error(CErrorStr162);
+ return nullnode();
+ }
+ if (scan_arg == &elipsis || scan_arg == &oldstyle) {
+ scan_expr->node = CExpr_VarArgPromotion(scan_expr->node, scan_arg == &elipsis);
+ has_varargs = 1;
+ } else {
+ scan_expr->node = argumentpromotion(scan_expr->node, scan_arg->type, scan_arg->qual, 1);
+ scan_arg = scan_arg->next;
+ }
+ } else {
+ scan_expr->node = CExpr_VarArgPromotion(scan_expr->node, 0);
+ }
+ scan_expr = scan_expr->next;
+ }
+
+ if (!has_varargs && scan_arg && scan_arg != &elipsis && scan_arg != &oldstyle) {
+ do {
+ if (!scan_arg->dexpr) {
+ CError_Error(CErrorStr162);
+ return nullnode();
+ }
+
+ if (arg_exprs) {
+ scan_expr = arg_exprs;
+ while (scan_expr->next)
+ scan_expr = scan_expr->next;
+ scan_expr->next = lalloc(sizeof(ENodeList));
+ scan_expr = scan_expr->next;
+ } else {
+ scan_expr = lalloc(sizeof(ENodeList));
+ arg_exprs = scan_expr;
+ }
+
+ scan_expr->next = NULL;
+ scan_expr->node = CExpr_GetDefaultArgument(funcexpr, scan_arg);
+ } while ((scan_arg = scan_arg->next) && scan_arg != &elipsis && scan_arg != &oldstyle);
+ }
+
+ expr = CExpr_NewENode(EFUNCCALL);
+ expr->cost = 4;
+ expr->rtype = tfunc->functype;
+ expr->flags = tfunc->qual & ENODE_FLAG_QUALS;
+ expr->data.funccall.funcref = funcexpr;
+ expr->data.funccall.args = arg_exprs;
+ expr->data.funccall.functype = tfunc;
+ return CExpr_AdjustFunctionCall(expr);
+}
+
+static Boolean accept_conversion_type(Type *type, short mode) {
+ switch (mode) {
+ case 0:
+ return IS_TYPE_INT(type);
+ case 1:
+ return IS_TYPE_INT_OR_FLOAT(type);
+ case 2:
+ return IS_TYPE_INT_OR_FLOAT(type) || IS_TYPE_POINTER_ONLY(type);
+ case 3:
+ return IS_TYPE_POINTER_ONLY(type);
+ default:
+ CError_FATAL(3912);
+ return 0;
+ }
+}
+
+static ENode *CExpr_OperatorConversion(ENode *expr, Type *type, UInt32 qual) {
+ if (IS_TYPE_CLASS(expr->rtype) && type) {
+ if (user_assign_check(expr, type, qual, 1, 0, 1))
+ return assign_node;
+ CError_Error(CErrorStr144);
+ }
+ return expr;
+}
+
+static Boolean wild_conversion_check(ENode *left, ENode *right, Conversion *conv) {
+ ConversionIterator iter;
+ Object *obj;
+
+ Type *check;
+ Type *left_type;
+ Type *right_type;
+
+ left_type = right_type = NULL;
+ if (IS_TYPE_CLASS(left->rtype)) {
+ CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(left->rtype));
+ while ((obj = CExpr_ConversionIteratorNext(&iter))) {
+ check = TYPE_FUNC(obj->type)->functype;
+ if (accept_conversion_type(check, 2)) {
+ while ((obj = CExpr_ConversionIteratorNext(&iter))) {
+ if (accept_conversion_type(TYPE_FUNC(obj->type)->functype, 2))
+ CError_Error(CErrorStr199);
+ }
+ left_type = check;
+ goto found_left;
+ }
+ }
+ return 0;
+ }
+found_left:
+ if (IS_TYPE_CLASS(right->rtype)) {
+ CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(right->rtype));
+ while ((obj = CExpr_ConversionIteratorNext(&iter))) {
+ check = TYPE_FUNC(obj->type)->functype;
+ if (accept_conversion_type(check, 2)) {
+ while ((obj = CExpr_ConversionIteratorNext(&iter))) {
+ if (accept_conversion_type(TYPE_FUNC(obj->type)->functype, 2))
+ CError_Error(CErrorStr199);
+ }
+ right_type = check;
+ goto found_right;
+ }
+ }
+ return 0;
+ }
+found_right:
+ conv->x0 = NULL;
+ conv->left = CExpr_OperatorConversion(left, left_type, 0);
+ conv->right = CExpr_OperatorConversion(right, right_type, 0);
+ return 1;
+}
+
+static Boolean monadic_conversion_check(ENode *expr, short which, Conversion *conv) {
+ ConversionIterator iter;
+ Object *obj;
+ Type *check;
+
+ if (!IS_TYPE_CLASS(expr->rtype))
+ return 0;
+
+ if (which == 4)
+ which = 2;
+ else if (which == 5)
+ which = 1;
+
+ CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(expr->rtype));
+ while ((obj = CExpr_ConversionIteratorNext(&iter))) {
+ check = TYPE_FUNC(obj->type)->functype;
+ if (accept_conversion_type(check, which)) {
+ while ((obj = CExpr_ConversionIteratorNext(&iter))) {
+ if (accept_conversion_type(TYPE_FUNC(obj->type)->functype, which))
+ CError_Error(CErrorStr199);
+ }
+
+ conv->x0 = NULL;
+ conv->left = CExpr_OperatorConversion(expr, check, 0);
+ conv->right = NULL;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static Boolean is_legal_type_combination(Type *left, Type *right, short mode) {
+ int left_type;
+ int right_type;
+
+ if (IS_TYPE_ENUM(left))
+ left = TYPE_ENUM(left)->enumtype;
+ if (IS_TYPE_ENUM(right))
+ right = TYPE_ENUM(right)->enumtype;
+
+ if (IS_TYPE_REFERENCE(left))
+ left = TYPE_POINTER(left)->target;
+ if (IS_TYPE_REFERENCE(right))
+ right = TYPE_POINTER(right)->target;
+
+ left_type = left->type; // r7
+ right_type = right->type; // r8
+ switch (mode) {
+ case 3:
+ if (left_type != TYPEPOINTER || right_type != TYPEPOINTER)
+ return 0;
+ use_cpp_typeequal:
+ diadic_arg1.type = left;
+ diadic_arg2.type = right;
+ return iscpp_typeequal(left, right);
+ case 7:
+ if ((left_type == TYPEPOINTER && right_type == TYPEINT) || (left_type == TYPEINT && right_type == TYPEPOINTER)) {
+ diadic_arg1.type = left;
+ diadic_arg2.type = right;
+ return 1;
+ }
+ return 0;
+ case 6:
+ if ((left_type == TYPEPOINTER && right_type == TYPEINT) || (left_type == TYPEINT && right_type == TYPEPOINTER)) {
+ diadic_arg1.type = left;
+ diadic_arg2.type = right;
+ return 1;
+ }
+ case 2:
+ if (left_type == TYPEPOINTER || right_type == TYPEPOINTER)
+ goto use_cpp_typeequal;
+ case 1:
+ mode1:
+ if (left_type == TYPEFLOAT || right_type == TYPEFLOAT) {
+ if (left_type == TYPEFLOAT) {
+ if (right_type == TYPEFLOAT) {
+ if (TYPE_INTEGRAL(right)->integral > TYPE_INTEGRAL(left)->integral)
+ left = right;
+ diadic_arg2.type = left;
+ diadic_arg1.type = left;
+ return 1;
+ }
+ if (right_type != TYPEINT)
+ return 0;
+ diadic_arg2.type = left;
+ diadic_arg1.type = left;
+ return 1;
+ }
+ if (left_type != TYPEINT)
+ return 0;
+ diadic_arg2.type = right;
+ diadic_arg1.type = right;
+ return 1;
+ }
+ case 0:
+ if (left_type != TYPEINT || right_type != TYPEINT)
+ return 0;
+ if (TYPE_INTEGRAL(right)->integral > TYPE_INTEGRAL(left)->integral)
+ left = right;
+ if (TYPE_INTEGRAL(left)->integral < IT_INT)
+ left = TYPE(&stsignedint);
+ diadic_arg2.type = left;
+ diadic_arg1.type = left;
+ return 1;
+ case 4:
+ if (left_type == TYPEPOINTER) {
+ if (right_type != TYPEINT)
+ return 0;
+ diadic_arg1.type = left;
+ diadic_arg2.type = right;
+ return 1;
+ }
+ if (right_type == TYPEPOINTER) {
+ if (left_type != TYPEINT)
+ return 0;
+ diadic_arg1.type = left;
+ diadic_arg2.type = right;
+ return 1;
+ }
+ goto mode1;
+ case 5:
+ if (left_type != TYPEPOINTER)
+ goto mode1;
+ if (right_type == TYPEPOINTER)
+ goto use_cpp_typeequal;
+ if (right_type != TYPEINT)
+ return 0;
+ diadic_arg1.type = left;
+ diadic_arg2.type = right;
+ return 1;
+ default:
+ CError_FATAL(4132);
+ return 0;
+ }
+}
+
+static void match_class_type_conversion(Match13 *match, ENode *left, ENode *right, ENodeList *list, short which) {
+ ConversionIterator iter;
+ Object *obj;
+
+ if (which == 6) {
+ if (!ENODE_IS(right, EINTCONST) || !CInt64_IsZero(&right->data.intval) || !IS_TYPE_INT(right->rtype))
+ which = 2;
+ }
+
+ CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(left->rtype));
+ while ((obj = CExpr_ConversionIteratorNext(&iter))) {
+ if (is_legal_type_combination(TYPE_FUNC(obj->type)->functype, right->rtype, which)) {
+ MatchOverloadFunc(obj, &diadic_arg1, list, match);
+ if (match->obj == obj) {
+ cexpr_left_conversion_type = diadic_arg1.type;
+ cexpr_right_conversion_type = diadic_arg2.type;
+ }
+ }
+ }
+}
+
+static void match_type_class_conversion(Match13 *match, ENode *left, ENode *right, ENodeList *list, short which) {
+ ConversionIterator iter;
+ Object *obj;
+
+ if (which == 6) {
+ if (!ENODE_IS(left, EINTCONST) || !CInt64_IsZero(&left->data.intval) || !IS_TYPE_INT(left->rtype))
+ which = 2;
+ }
+
+ CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(right->rtype));
+ while ((obj = CExpr_ConversionIteratorNext(&iter))) {
+ if (is_legal_type_combination(left->rtype, TYPE_FUNC(obj->type)->functype, which)) {
+ MatchOverloadFunc(obj, &diadic_arg1, list, match);
+ if (match->obj == obj) {
+ cexpr_left_conversion_type = diadic_arg1.type;
+ cexpr_right_conversion_type = diadic_arg2.type;
+ }
+ }
+ }
+}
+
+static void match_class_class_conversion(Match13 *match, ENode *left, ENode *right, ENodeList *list, short which) {
+ ConversionIterator iter_left;
+ ConversionIterator iter_right;
+ Object *obj_left;
+ Object *obj_right;
+
+ if (which == 6)
+ which = 2;
+
+ CExpr_ConversionIteratorInit(&iter_left, TYPE_CLASS(left->rtype));
+ while ((obj_left = CExpr_ConversionIteratorNext(&iter_left))) {
+ CExpr_ConversionIteratorInit(&iter_right, TYPE_CLASS(right->rtype));
+ while ((obj_right = CExpr_ConversionIteratorNext(&iter_right))) {
+ if (is_legal_type_combination(TYPE_FUNC(obj_left->type)->functype, TYPE_FUNC(obj_right->type)->functype, which)) {
+ MatchOverloadFunc(obj_left, &diadic_arg1, list, match);
+ if (match->obj == obj_left) {
+ cexpr_left_conversion_type = diadic_arg1.type;
+ cexpr_right_conversion_type = diadic_arg2.type;
+ }
+ }
+ }
+ }
+}
+
+Boolean CExpr_CheckOperatorConversion(short token, ENode *left, ENode *right, ENodeList *list, Conversion *conv) {
+ Match13 match;
+ short which;
+
+ switch (token) {
+ case '*':
+ if (!right) {
+ which = 3;
+ break;
+ }
+ case '/':
+ which = 1;
+ break;
+ case '&':
+ if (!right)
+ return 0;
+ case '%':
+ case '^':
+ case '|':
+ case '~':
+ case TK_SHL:
+ case TK_SHR:
+ which = 0;
+ break;
+ case '[':
+ which = 7;
+ break;
+ case '+':
+ which = 4;
+ break;
+ case '-':
+ which = 5;
+ break;
+ case '!':
+ case ':':
+ case '<':
+ case '>':
+ case TK_LESS_EQUAL:
+ case TK_GREATER_EQUAL:
+ which = 2;
+ break;
+ case TK_LOGICAL_EQ:
+ case TK_LOGICAL_NE:
+ which = 6;
+ break;
+ case TK_LOGICAL_OR:
+ case TK_LOGICAL_AND:
+ return wild_conversion_check(left, right, conv);
+ default:
+ return 0;
+ }
+
+ if (!right)
+ return monadic_conversion_check(left, which, conv);
+
+ cexpr_left_conversion_type = cexpr_right_conversion_type = NULL;
+ memclrw(&match, sizeof(Match13));
+
+ if (IS_TYPE_CLASS(left->rtype)) {
+ if (IS_TYPE_CLASS(right->rtype))
+ match_class_class_conversion(&match, left, right, list, which);
+ else
+ match_class_type_conversion(&match, left, right, list, which);
+ } else {
+ if (IS_TYPE_CLASS(right->rtype))
+ match_type_class_conversion(&match, left, right, list, which);
+ else
+ return 0;
+ }
+
+ if (!match.obj)
+ return 0;
+ if (match.list)
+ CError_OverloadedFunctionError(match.obj, match.list);
+
+ conv->x0 = NULL;
+ conv->left = CExpr_OperatorConversion(left, cexpr_left_conversion_type, 0);
+ conv->right = CExpr_OperatorConversion(right, cexpr_right_conversion_type, 0);
+ return 1;
+}
+
+Boolean CExpr_CheckOperator(short token, ENode *left, ENode *right, Conversion *conv) {
+ Match13 match;
+ NameResult pr;
+ NameResult pr2;
+ ENode *expr;
+ Object *obj;
+ ENodeList *nodes;
+ HashNameNode *name;
+ BClassList *path;
+ EMemberInfo *member;
+ Object *prev_obj;
+ NameSpaceObjectList mylist_A8;
+ NameSpaceObjectList mylist_B0;
+
+ if (!copts.old_argmatch) {
+ if (token == '(') {
+ CDecl_CompleteType(left->rtype);
+ if (IS_TYPE_CLASS(left->rtype) && CScope_FindClassMemberObject(TYPE_CLASS(left->rtype), &pr,
+ CMangler_OperatorName(token))) {
+ if (pr.nsol_14 || (pr.obj_10 && pr.obj_10->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(pr.obj_10)->type))) {
+ member = lalloc(sizeof(EMemberInfo));
+ memclrw(member, sizeof(EMemberInfo));
+ member->path = pr.bcl_18;
+ member->expr = left;
+ member->pr_1D = pr.x1D;
+ if (!pr.nsol_14) {
+ member->list = galloc(sizeof(NameSpaceObjectList));
+ member->list->next = NULL;
+ member->list->object = pr.obj_10;
+ } else {
+ member->list = pr.nsol_14;
+ }
+ expr = CExpr_NewENode(EMEMBER);
+ expr->rtype = &stvoid;
+ expr->data.emember = member;
+ tk = lex();
+ conv->x0 = checkreference(CExpr_MakeFunctionCall(expr, CExpr_ScanExpressionList(1)));
+ conv->left = NULL;
+ conv->right = NULL;
+ tk = lex();
+ return 1;
+ } else {
+ CError_FATAL(4371);
+ }
+ }
+ return 0;
+ } else {
+ return CExpr_OperatorMatch(token, left, right, conv);
+ }
+ }
+
+ if (!IS_TYPE_CLASS(left->rtype)) {
+ if (!IS_TYPE_ENUM(left->rtype)) {
+ if (!right)
+ return 0;
+ if (!IS_TYPE_CLASS(right->rtype) && !IS_TYPE_ENUM(right->rtype))
+ return 0;
+ }
+ } else {
+ CDecl_CompleteType(left->rtype);
+ }
+
+ memclrw(&match, sizeof(Match13));
+ name = CMangler_OperatorName(token);
+ if (token == '(') {
+ if (IS_TYPE_CLASS(left->rtype) && CScope_FindClassMemberObject(TYPE_CLASS(left->rtype), &pr2, name)) {
+ if (pr2.nsol_14 || (pr2.obj_10 && pr2.obj_10->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(pr2.obj_10)->type))) {
+ member = lalloc(sizeof(EMemberInfo));
+ memclrw(member, sizeof(EMemberInfo));
+ member->path = pr2.bcl_18;
+ member->expr = left;
+ member->pr_1D = pr2.x1D;
+ if (!pr2.nsol_14) {
+ member->list = galloc(sizeof(NameSpaceObjectList));
+ member->list->next = NULL;
+ member->list->object = pr2.obj_10;
+ } else {
+ member->list = pr2.nsol_14;
+ }
+ expr = CExpr_NewENode(EMEMBER);
+ expr->rtype = &stvoid;
+ expr->data.emember = member;
+ tk = lex();
+ conv->x0 = checkreference(CExpr_MakeFunctionCall(expr, CExpr_ScanExpressionList(1)));
+ conv->left = NULL;
+ conv->right = NULL;
+ tk = lex();
+ return 1;
+ } else {
+ CError_FATAL(4439);
+ }
+ }
+ return 0;
+ }
+
+ nodes = lalloc(sizeof(ENodeList));
+ nodes->node = left;
+ if (right) {
+ nodes->next = lalloc(sizeof(ENodeList));
+ nodes->next->node = right;
+ nodes->next->next = NULL;
+ } else {
+ nodes->next = NULL;
+ }
+
+ obj = NULL;
+ if (IS_TYPE_CLASS(left->rtype) && CScope_FindClassMemberObject(TYPE_CLASS(left->rtype), &pr2, name)) {
+ if (pr2.obj_10) {
+ mylist_B0.next = NULL;
+ mylist_B0.object = pr2.obj_10;
+ pr2.nsol_14 = &mylist_B0;
+ } else {
+ CError_ASSERT(4470, pr2.nsol_14);
+ }
+
+ if (token != '=' || (pr2.bcl_18->type == left->rtype && pr2.bcl_18->next == NULL)) {
+ prev_obj = match.obj;
+ CExpr_MatchArgList(pr2.nsol_14, NULL, nodes->next, &match, left, 0);
+ if (prev_obj != match.obj) {
+ obj = match.obj;
+ path = pr2.bcl_18;
+ }
+ }
+ }
+
+ if (CScope_FindNonClassObject(cscope_current, &pr2, name)) {
+ if (pr2.obj_10) {
+ mylist_A8.next = NULL;
+ mylist_A8.object = pr2.obj_10;
+ pr2.nsol_14 = &mylist_A8;
+ }
+ } else {
+ pr2.nsol_14 = NULL;
+ }
+
+ if (copts.arg_dep_lookup)
+ pr2.nsol_14 = CScope_ArgumentDependentNameLookup(pr2.nsol_14, name, nodes, 1);
+ if (pr2.nsol_14)
+ CExpr_MatchArgList(pr2.nsol_14, NULL, nodes, &match, NULL, 0);
+
+ if (!match.obj) {
+ if (!IS_TYPE_CLASS(left->rtype) && (!right || !IS_TYPE_CLASS(right->rtype)))
+ return 0;
+ return CExpr_CheckOperatorConversion(token, left, right, nodes, conv);
+ }
+
+ if (!(token == '&' && !right) && (token != ',')) {
+ if (!IS_TYPE_CLASS(left->rtype) && (!right || !IS_TYPE_CLASS(right->rtype)) && match.xE)
+ return 0;
+ if (right && match.xE == 2 && CExpr_CheckOperatorConversion(token, left, right, nodes, conv))
+ return 1;
+ }
+
+ if (match.list)
+ CError_OverloadedFunctionError(match.obj, match.list);
+
+ if (match.obj == obj) {
+ conv->x0 = CExpr_GenericFuncCall(path, nodes->node, 0, match.obj, NULL, NULL, nodes->next, 0, 0, 1);
+ } else {
+ conv->x0 = CExpr_GenericFuncCall(NULL, NULL, 0, match.obj, NULL, NULL, nodes, 0, 0, 1);
+ }
+
+ conv->x0 = checkreference(conv->x0);
+ conv->left = NULL;
+ conv->right = NULL;
+ return 1;
+}
+
+ENode *CExpr_ConstructObject(TypeClass *tclass, ENode *addr_expr, ENodeList *args, Boolean flag1, Boolean flag2, Boolean flag3, Boolean flag4, Boolean flag5) {
+ ENode *expr;
+ NameSpaceObjectList *ctorlist;
+ BClassList path;
+
+ CError_ASSERT(4595, IS_TYPE_POINTER_ONLY(addr_expr->rtype));
+
+ addr_expr = makemonadicnode(addr_expr, EINDIRECT);
+ addr_expr->rtype = TYPE(tclass);
+
+ if (!flag3 && args && !args->next && args->node->rtype == TYPE(tclass) && !CClass_CopyConstructor(tclass)) {
+ CError_ASSERT(4605, IS_TYPE_CLASS(addr_expr->rtype));
+ expr = makediadicnode(addr_expr, args->node, EASS);
+ if (!flag1)
+ expr = getnodeaddress(expr, 0);
+ return expr;
+ }
+
+ if ((ctorlist = CClass_Constructor(tclass))) {
+ if (tclass->flags & CLASS_HAS_VBASES) {
+ ENodeList *list = lalloc(sizeof(ENodeList));
+ list->next = args;
+ args = list;
+ list->node = intconstnode(TYPE(&stsignedshort), flag2 != 0);
+ }
+ path.next = NULL;
+ path.type = TYPE(tclass);
+ expr = CExpr_GenericFuncCall(&path, addr_expr, 0, NULL, ctorlist, NULL, args, !flag5, 0, flag4);
+ if (ENODE_IS2(expr, EFUNCCALL, EFUNCCALLP))
+ expr->rtype = CDecl_NewPointerType(TYPE(tclass));
+ if (flag1) {
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TYPE(tclass);
+ }
+ return expr;
+ } else {
+ if (args) {
+ if (!args->next && ENODE_IS(addr_expr, EINDIRECT)) {
+ return makediadicnode(
+ addr_expr,
+ CExpr_AssignmentPromotion(args->node, TYPE(tclass), 0, 1),
+ EASS);
+ }
+ CError_Error(CErrorStr174);
+ }
+ return addr_expr;
+ }
+}
+
+static ENode *CExpr_DeleteFuncCall(Object *obj, ENode *arg, Type *type, Boolean include_size) {
+ ENode *expr;
+ ENodeList *list;
+
+ expr = lalloc(sizeof(ENode));
+ expr->type = EFUNCCALL;
+ expr->cost = 4;
+ expr->flags = 0;
+ expr->rtype = &stvoid;
+ expr->data.funccall.funcref = create_objectrefnode(obj);
+ expr->data.funccall.functype = TYPE_FUNC(obj->type);
+ obj->flags |= OBJECT_USED;
+
+ list = lalloc(sizeof(ENodeList));
+ list->node = arg;
+ expr->data.funccall.args = list;
+
+ if (include_size) {
+ list->next = lalloc(sizeof(ENodeList));
+ list->next->node = nullnode();
+ CInt64_SetLong(&list->next->node->data.intval, type->size);
+ list->next->node->rtype = CABI_GetSizeTType();
+ list->next->next = NULL;
+ } else {
+ list->next = NULL;
+ }
+
+ return expr;
+}
+
+static ENode *CExpr_CopyPlacementNewArg(ENodeList *list) {
+ switch (list->node->type) {
+ case EINDIRECT:
+ if (!ENODE_IS(list->node->data.monadic, EOBJREF))
+ break;
+ if (list->node->data.monadic->data.objref->datatype != DLOCAL && !is_const_object(list->node->data.monadic->data.objref))
+ break;
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EARGOBJ:
+ case ELOCOBJ:
+ case EOBJLIST:
+ case EVECTOR128CONST:
+ return CInline_CopyExpression(list->node, CopyMode0);
+ }
+
+ switch (list->node->rtype->type) {
+ default:
+ CError_FATAL(4726);
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPESTRUCT:
+ case TYPECLASS:
+ case TYPEMEMBERPOINTER:
+ case TYPEPOINTER:
+ case TYPEOBJCID:
+ return CExpr_GetETEMPCopy(list->node);
+ }
+}
+
+static ENode *CExpr_PlacementDeleteCall(Type *type, ENode *expr, Object *obj, Boolean flag1, Boolean flag2) {
+ ENodeList *list;
+ Object *funcobj;
+ ENode *result;
+ ENodeList *inputarg;
+ Boolean outflag;
+
+ CError_ASSERT(4752, ENODE_IS(expr, EFUNCCALL) && ENODE_IS(expr->data.funccall.funcref, EOBJREF));
+
+ funcobj = expr->data.funccall.funcref->data.objref;
+ CError_ASSERT(4756, IS_TYPE_FUNC(funcobj->type) && TYPE_FUNC(funcobj->type)->args && TYPE_FUNC(funcobj->type)->args->next);
+
+ funcobj = CParser_FindDeallocationObject(type, TYPE_FUNC(funcobj->type)->args->next, flag1, flag2, &outflag);
+ if (!funcobj)
+ return NULL;
+
+ result = CExpr_NewENode(EFUNCCALL);
+ result->type = EFUNCCALL;
+ result->cost = 4;
+ result->rtype = &stvoid;
+ result->data.funccall.funcref = create_objectrefnode(funcobj);
+ result->data.funccall.functype = TYPE_FUNC(funcobj->type);
+ funcobj->flags |= OBJECT_USED;
+
+ list = lalloc(sizeof(ENodeList));
+ list->node = create_objectnode(obj);
+ result->data.funccall.args = list;
+
+ CError_ASSERT(4780, (inputarg = expr->data.funccall.args) && (inputarg = inputarg->next));
+
+ do {
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->node = CExpr_CopyPlacementNewArg(inputarg);
+ inputarg = inputarg->next;
+ } while (inputarg);
+ list->next = NULL;
+
+ return result;
+}
+
+static Type *scan_type_name(UInt32 *qual) {
+ DeclInfo di;
+ memclrw(&di, sizeof(DeclInfo));
+
+ CParser_GetDeclSpecs(&di, 0);
+ di.x46 = 1;
+ scandeclarator(&di);
+
+ if (di.name)
+ CError_Error(CErrorStr146);
+
+ firstarrayexpr = di.x24;
+ *qual = di.qual;
+ return di.thetype;
+}
+
+static UInt32 cv_qualifier_list(void) {
+ UInt32 qual;
+
+ qual = 0;
+ tk = lex();
+ while (tk >= TK_CONST && tk <= TK_ASM) {
+ switch (tk) {
+ case TK_CONST:
+ if (qual & Q_CONST)
+ CError_Error(CErrorStr121);
+ qual |= Q_CONST;
+ break;
+ case TK_VOLATILE:
+ if (qual & Q_VOLATILE)
+ CError_Error(CErrorStr121);
+ qual |= Q_VOLATILE;
+ break;
+ default:
+ CError_Error(CErrorStr121);
+ }
+
+ tk = lex();
+ }
+
+ return qual;
+}
+
+static void scan_new_declarator(DeclInfo *di, Boolean flag) {
+ NameResult pr;
+ SInt32 size;
+ ENode *expr;
+
+ switch (tk) {
+ case '*':
+ makethetypepointer(di, cv_qualifier_list());
+ if (tk != '[')
+ scan_new_declarator(di, flag);
+ break;
+ case TK_IDENTIFIER:
+ case TK_COLON_COLON:
+ if (CScope_ParseQualifiedNameSpace(&pr, 1, 0) && pr.nspace_0 && pr.nspace_0->theclass && tk == '*') {
+ makememberpointertype(di, pr.nspace_0->theclass, cv_qualifier_list());
+ if (tk != '[')
+ scan_new_declarator(di, flag);
+ } else {
+ CError_Error(CErrorStr121);
+ }
+ break;
+ }
+
+ if (tk == '[') {
+ tk = lex();
+ expr = expression();
+
+ if (IS_TYPE_ENUM(expr->rtype))
+ expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
+ if (!IS_TYPE_INT(expr->rtype))
+ CError_Error(CErrorStr146);
+
+ if (tk != ']')
+ CError_Error(CErrorStr125);
+ else
+ tk = lex();
+
+ if (tk == '[')
+ scan_new_declarator(di, 0);
+
+ if (CanCreateObject(di->thetype) && IsCompleteType(di->thetype)) {
+ di->thetype = CDecl_NewArrayType(di->thetype, 0);
+ if (!ENODE_IS(expr, EINTCONST)) {
+ size = 1;
+ if (!flag)
+ CError_Error(CErrorStr124);
+ else
+ firstarrayexpr = expr;
+ } else {
+ size = CInt64_GetULong(&expr->data.intval);
+ }
+ TYPE_POINTER(di->thetype)->size = size * TYPE_POINTER(di->thetype)->target->size;
+ } else {
+ CError_Error(CErrorStr129);
+ }
+ }
+}
+
+static Type *scan_new_type_name(UInt32 *qual) {
+ DeclInfo di;
+ memclrw(&di, sizeof(DeclInfo));
+
+ di.x4F = 1;
+ CParser_GetDeclSpecs(&di, 0);
+ scan_new_declarator(&di, 1);
+
+ *qual = di.qual;
+ return di.thetype;
+}
+
+static ENode *CExpr_NewAlloc(Type *type, ENodeList *args, Boolean flag1, Boolean flag2) {
+ NameSpaceObjectList *list;
+ Object *obj;
+ Boolean found;
+ HashNameNode *name;
+ NameResult pr;
+
+ found = 0;
+ if (!flag1 && IS_TYPE_CLASS(type)) {
+ list = NULL;
+ obj = NULL;
+ name = (flag2 && copts.array_new_delete) ? newa_fobj->name : newp_fobj->name;
+ if (CScope_FindClassMemberObject(TYPE_CLASS(type), &pr, name)) {
+ list = pr.nsol_14;
+ obj = OBJECT(pr.obj_10);
+ CError_ASSERT(4935, list || obj);
+ found = 1;
+ } else if (TYPE_CLASS(type)->flags & CLASS_HANDLEOBJECT) {
+ CError_ASSERT(4942, !flag2);
+ obj = newh_func;
+ found = 1;
+ }
+ }
+
+ if (!found) {
+ if (flag2 && copts.array_new_delete)
+ list = &newa_fobj->first;
+ else
+ list = &newp_fobj->first;
+ obj = NULL;
+ }
+
+ return CExpr_GenericFuncCall(NULL, NULL, 0, obj, list, NULL, args, 0, 0, 1);
+}
+
+static ENode *CExpr_NewExceptionSafeAlloc(Type *type, ENode *node, ENodeList *args, Boolean flag1, Boolean flag2, Object **objptr) {
+ Object *obj;
+ ENode *result;
+ ENode *catchexpr;
+ Object *deletefunc;
+ Boolean include_size;
+
+ if (!cscope_currentfunc || !copts.delete_exception || !copts.exceptions)
+ return NULL;
+
+ obj = create_temp_object(TYPE(&void_ptr));
+ *objptr = obj;
+ deletefunc = NULL;
+ catchexpr = NULL;
+ include_size = 0;
+ if (args)
+ catchexpr = CExpr_PlacementDeleteCall(type, node, obj, flag1, flag2);
+ if (!args)
+ deletefunc = CParser_FindDeallocationObject(type, NULL, flag1, flag2, &include_size);
+
+ if (!deletefunc && !catchexpr)
+ return NULL;
+
+ result = lalloc(sizeof(ENode));
+ *result = *node;
+ node = makediadicnode(create_objectnode(obj), node, EASS);
+ if (!catchexpr && !include_size) {
+ result->type = ENEWEXCEPTION;
+ result->data.newexception.initexpr = node;
+ result->data.newexception.tryexpr = NULL;
+ result->data.newexception.pointertemp = obj;
+ result->data.newexception.deletefunc = deletefunc;
+ } else {
+ if (!catchexpr)
+ catchexpr = CExpr_DeleteFuncCall(deletefunc, create_objectnode(obj), type, include_size);
+ result->type = EINITTRYCATCH;
+ result->data.itc.initexpr = node;
+ result->data.itc.tryexpr = NULL;
+ result->data.itc.result = create_objectnode(obj);
+ result->data.itc.catchexpr = catchexpr;
+ }
+
+ return result;
+}
+
+static ENode *CExpr_NewExceptionSafeInit(ENode *expr, ENode *tryexpr) {
+ switch (expr->type) {
+ case ENEWEXCEPTION:
+ expr->data.newexception.tryexpr = tryexpr;
+ break;
+ case EINITTRYCATCH:
+ expr->data.itc.tryexpr = tryexpr;
+ break;
+ default:
+ CError_FATAL(5056);
+ }
+ return expr;
+}
+
+static ENode *CExpr_NewArray(Type *type, UInt32 qual, ENodeList *nodelist, Boolean flag) {
+ Type *tptr;
+ Type *sizetype;
+ Type *innertype;
+ ENodeList *newlist;
+ ENode *result;
+ Object *ctor;
+ Object *dtor;
+ ENode *ass;
+ ENode *etemp;
+ ENode *mul;
+ SInt32 count;
+ ENode *newalloc;
+ ENode *newESalloc;
+ Object *tempobj;
+ ENode *callexpr;
+
+ tptr = CDecl_NewPointerType(TYPE_POINTER(type)->target);
+ sizetype = CABI_GetSizeTType();
+ innertype = TYPE_POINTER(type)->target;
+ while (IS_TYPE_ARRAY(innertype))
+ innertype = TYPE_POINTER(innertype)->target;
+
+ if (!CanAllocObject(innertype) || !IsCompleteType(innertype))
+ return nullnode();
+
+ newlist = lalloc(sizeof(ENodeList));
+ newlist->next = nodelist;
+ if (tk == '(') {
+ tk = lex();
+ if (CExpr_ScanExpressionList(1))
+ CError_Error(CErrorStr174);
+ if (tk == ')')
+ tk = lex();
+ else
+ CError_Error(CErrorStr115);
+ }
+
+ if (!IS_TYPE_CLASS(innertype) || CClass_IsPODClass(TYPE_CLASS(innertype))) {
+ newlist->node = intconstnode(sizetype, type->size);
+ if (firstarrayexpr) {
+ newlist->node = makediadicnode(newlist->node, promote(firstarrayexpr, sizetype), EMUL);
+ optimizecomm(newlist->node);
+ }
+ result = CExpr_NewAlloc(innertype, newlist, flag, 1);
+ result->rtype = tptr;
+ result->flags |= (qual & ENODE_FLAG_QUALS);
+ return result;
+ }
+
+ ctor = NULL;
+ if (CClass_Constructor(TYPE_CLASS(innertype))) {
+ ctor = CClass_DefaultConstructor(TYPE_CLASS(innertype));
+ if (ctor) {
+ ctor->flags |= OBJECT_USED;
+ } else {
+ ctor = CClass_DummyDefaultConstructor(TYPE_CLASS(innertype));
+ if (!ctor)
+ CError_Error(CErrorStr203);
+ }
+ }
+
+ dtor = CClass_Destructor(TYPE_CLASS(innertype));
+ if (dtor)
+ dtor = CABI_GetDestructorObject(dtor, CABIDestroy1);
+
+ ass = NULL;
+ if (firstarrayexpr) {
+ etemp = CExpr_NewETEMPNode(sizetype, 1);
+ mul = promote(firstarrayexpr, sizetype);
+ if (innertype->size)
+ count = type->size / innertype->size;
+ else
+ count = 0;
+ if (count > 1) {
+ mul = makediadicnode(mul, intconstnode(sizetype, count), EMUL);
+ optimizecomm(mul);
+ }
+ ass = makediadicnode(CExpr_DerefETEMPCopy(etemp), mul, EASS);
+ mul = makediadicnode(CExpr_DerefETEMPCopy(etemp), intconstnode(sizetype, innertype->size), EMUL);
+ optimizecomm(mul);
+ mul = makediadicnode(mul, intconstnode(sizetype, 16), EADD);
+ optimizecomm(mul);
+ newlist->node = mul;
+ etemp = CExpr_DerefETEMPCopy(etemp);
+ } else {
+ newlist->node = intconstnode(sizetype, type->size + 16);
+ if (innertype->size)
+ count = type->size / innertype->size;
+ else
+ count = 0;
+ etemp = intconstnode(sizetype, count);
+ }
+
+ newalloc = CExpr_NewAlloc(innertype, newlist, flag, 1);
+ newalloc->rtype = tptr;
+ newESalloc = CExpr_NewExceptionSafeAlloc(innertype, newalloc, nodelist, 1, flag, &tempobj);
+ if (newESalloc) {
+ callexpr = CExpr_FuncCallSix(
+ cnar_func,
+ create_objectnode(tempobj),
+ ctor ? create_objectrefnode(ctor) : nullnode(),
+ dtor ? create_objectrefnode(dtor) : nullnode(),
+ intconstnode(sizetype, innertype->size),
+ etemp,
+ NULL
+ );
+ result = CExpr_NewExceptionSafeInit(newESalloc, makediadicnode(create_objectnode(tempobj), callexpr, EASS));
+ } else {
+ result = CExpr_FuncCallSix(
+ cnar_func,
+ newalloc,
+ ctor ? create_objectrefnode(ctor) : nullnode(),
+ dtor ? create_objectrefnode(dtor) : nullnode(),
+ intconstnode(sizetype, innertype->size),
+ etemp,
+ NULL
+ );
+ }
+
+ if (ass)
+ result = makecommaexpression(ass, result);
+ result->rtype = tptr;
+ result->flags |= (qual & ENODE_FLAG_QUALS);
+ return result;
+}
+
+static ENode *CExpr_NewSimpleClass(TypeClass *tclass, ENode *expr, ENodeList *args) {
+ ENode *precomp;
+ ENode *nullcheck;
+
+ precomp = lalloc(sizeof(ENode));
+ *precomp = *expr;
+ precomp->type = EPRECOMP;
+ precomp->data.precompid = CParser_GetUniqueID();
+
+ nullcheck = lalloc(sizeof(ENode));
+ *nullcheck = *expr;
+ nullcheck->type = ENULLCHECK;
+ nullcheck->cost = 4;
+ nullcheck->data.nullcheck.nullcheckexpr = expr;
+ nullcheck->data.nullcheck.condexpr = CExpr_ConstructObject(tclass, precomp, args, 0, 1, 1, 1, 1);
+ nullcheck->data.nullcheck.precompid = precomp->data.precompid;
+ return nullcheck;
+}
+
+static ENode *CExpr_NewClass(TypeClass *tclass, ENode *expr, ENodeList *args1, ENodeList *args2, Boolean flag) {
+ Object *objptr;
+ ENode *newESalloc;
+
+ if (!args2 && !flag && CABI_ConstructorCallsNew(tclass)) {
+ expr = nullnode();
+ expr->rtype = CDecl_NewPointerType(TYPE(tclass));
+ return CExpr_ConstructObject(tclass, expr, args1, 0, 1, 1, 1, 1);
+ } else {
+ newESalloc = CExpr_NewExceptionSafeAlloc(TYPE(tclass), expr, args2, 0, flag, &objptr);
+ if (newESalloc) {
+ return CExpr_NewExceptionSafeInit(
+ newESalloc,
+ CExpr_ConstructObject(tclass, create_objectnode(objptr), args1, 0, 1, 1, 1, 1));
+ } else {
+ return CExpr_NewSimpleClass(tclass, expr, args1);
+ }
+ }
+}
+
+ENode *scannew(Boolean flag) {
+ Type *type; // r27
+ UInt32 qual;
+ ENodeList *args; // r28
+ Boolean placement_flag; // r26
+ ENodeList *newargs; // r26
+ ENode *expr; // r26
+ ENodeList *args2; // r29
+ Object *tempobj;
+ ENode *newESalloc; // r28
+ ENode *tempobj_expr; // r25
+ ENode *etemp_expr; // r28
+ ENode *indirect_expr; // r25
+ ENode *ass; // r25
+ ENode *cond; // r27
+
+ type = NULL;
+ args = NULL;
+ firstarrayexpr = NULL;
+ if ((tk = lex()) == '(') {
+ tk = lex();
+ placement_flag = isdeclaration(1, 1, 1, ')');
+ if (!placement_flag)
+ args = CExpr_ScanExpressionList(1);
+ if (placement_flag)
+ type = scan_type_name(&qual);
+ if (tk != ')')
+ CError_Error(CErrorStr115);
+ else
+ tk = lex();
+ }
+
+ if (!type) {
+ if (tk == '(') {
+ tk = lex();
+ type = scan_type_name(&qual);
+ if (tk != ')')
+ CError_Error(CErrorStr115);
+ else
+ tk = lex();
+ } else {
+ type = scan_new_type_name(&qual);
+ }
+ }
+
+ if (IS_TYPE_ARRAY(type))
+ return CExpr_NewArray(type, qual, args, flag);
+
+ if (IS_TYPE_CLASS(type)) {
+ if (TYPE_CLASS(type)->sominfo)
+ return CSOM_New(TYPE_CLASS(type));
+ if (TYPE_CLASS(type)->objcinfo)
+ return CObjC_New(TYPE_CLASS(type));
+ }
+
+ if (!IsCompleteType(type) || !CanAllocObject(type))
+ return nullnode();
+
+ newargs = lalloc(sizeof(ENodeList));
+ newargs->next = args;
+ newargs->node = intconstnode(CABI_GetSizeTType(), type->size);
+
+ expr = CExpr_NewAlloc(type, newargs, flag, 0);
+ expr->rtype = CDecl_NewPointerType(type);
+ expr->flags |= (qual & ENODE_FLAG_QUALS);
+
+ if (tk == '(') {
+ tk = lex();
+ args2 = CExpr_ScanExpressionList(1);
+ if (!args2 && !IS_TYPE_CLASS(type)) {
+ args2 = lalloc(sizeof(ENodeList));
+ memclrw(args2, sizeof(ENodeList));
+ args2->node = do_typecast(nullnode(), type, 0);
+ }
+ if (tk == ')')
+ tk = lex();
+ else
+ CError_Error(CErrorStr115);
+ } else {
+ args2 = NULL;
+ }
+
+ if (ENODE_IS(expr, EINTCONST))
+ return expr;
+
+ if (IS_TYPE_CLASS(type) && CClass_Constructor(TYPE_CLASS(type)))
+ return CExpr_NewClass(TYPE_CLASS(type), expr, args2, args, flag);
+
+ if (args2) {
+ if (args2->next) {
+ CError_Error(CErrorStr174);
+ return nullnode();
+ }
+
+ newESalloc = CExpr_NewExceptionSafeAlloc(type, expr, args, 0, flag, &tempobj);
+ if (newESalloc) {
+ tempobj_expr = makemonadicnode(create_objectnode(tempobj), EINDIRECT);
+ tempobj_expr->rtype = type;
+ tempobj_expr->flags = args2->node->flags & ENODE_FLAG_QUALS;
+ return CExpr_NewExceptionSafeInit(
+ newESalloc,
+ makediadicnode(tempobj_expr, CExpr_AssignmentPromotion(args2->node, type, newESalloc->flags, 1), EASS)
+ );
+ } else {
+ etemp_expr = CExpr_GetETEMPCopy(expr);
+ indirect_expr = makemonadicnode(etemp_expr, EINDIRECT);
+ indirect_expr->rtype = type;
+ indirect_expr->flags = args2->node->flags & ENODE_FLAG_QUALS;
+ ass = makediadicnode(indirect_expr, CExpr_AssignmentPromotion(args2->node, type, indirect_expr->flags, 1), EASS);
+ cond = CExpr_NewENode(ECOND);
+ cond->cost = 4;
+ cond->rtype = &stvoid;
+ cond->data.cond.cond = expr;
+ cond->data.cond.expr1 = ass;
+ cond->data.cond.expr2 = nullnode();
+ cond = makecommaexpression(cond, etemp_expr);
+ cond->rtype = etemp_expr->rtype;
+ cond->flags = etemp_expr->flags;
+ return cond;
+ }
+ } else {
+ return expr;
+ }
+}
+
+static ENode *CExpr_DeleteArray(ENode *expr, Type *type, Boolean flag) {
+ Object *obj;
+ Object *dtor;
+ Boolean outflag;
+ ENode *precomp;
+ SInt32 precompid;
+ ENode *tmp;
+ ENode *result;
+
+ obj = CParser_FindDeallocationObject(type, NULL, 1, flag, &outflag);
+
+ if (!IS_TYPE_CLASS(type) || CClass_IsPODClass(TYPE_CLASS(type)))
+ return CExpr_DeleteFuncCall(obj, expr, type, outflag);
+
+ dtor = CClass_Destructor(TYPE_CLASS(type));
+ if (dtor || outflag) {
+ if (obj->nspace == cscope_root && !outflag) {
+ return funccallexpr(dnar_func, expr, dtor ? create_objectrefnode(dtor) : nullnode(), NULL, NULL);
+ }
+ return funccallexpr(
+ dnar3_func,
+ expr,
+ dtor ? create_objectrefnode(dtor) : nullnode(),
+ create_objectrefnode(obj),
+ intconstnode(TYPE(&stsignedshort), outflag));
+ }
+
+ precomp = lalloc(sizeof(ENode));
+ *precomp = *expr;
+ precomp->type = EPRECOMP;
+ precomp->data.precompid = precompid = CParser_GetUniqueID();
+ tmp = CExpr_DeleteFuncCall(obj, makediadicnode(precomp, intconstnode(CABI_GetSizeTType(), 16), ESUB), type, 0);
+
+ result = CExpr_NewENode(ENULLCHECK);
+ result->rtype = &stvoid;
+ result->cost = 4;
+ result->data.nullcheck.nullcheckexpr = expr;
+ result->data.nullcheck.condexpr = tmp;
+ result->data.nullcheck.precompid = precompid;
+
+ return result;
+}
+
+ENode *scandelete(Boolean flag) {
+ Boolean is_array; // r24
+ ENode *expr; // r25
+ Type *conv_type; // r22
+ UInt32 conv_qual; // r23
+ Type *innertype; // r23
+ Type *t;
+ Object *obj;
+ Object *dtor; // r24
+ ENode *result_expr; // r24???
+ ENode *precomp_orig; // r31
+ SInt32 precompid; // r30
+ Boolean is_virtual; // r23
+ ENode *nc;
+ ConversionIterator iter;
+ Boolean outflag;
+ BClassList path;
+
+ if ((tk = lex()) == '[') {
+ if ((tk = lex()) != ']')
+ CError_Error(CErrorStr125);
+ else
+ tk = lex();
+ is_array = 1;
+ } else {
+ is_array = 0;
+ }
+
+ expr = cast_expression();
+ if (!IS_TYPE_POINTER_ONLY(expr->rtype)) {
+ if (IS_TYPE_CLASS(expr->rtype)) {
+ conv_type = NULL;
+ CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(expr->rtype));
+ while ((obj = CExpr_ConversionIteratorNext(&iter))) {
+ if (IS_TYPE_POINTER_ONLY(TYPE_FUNC(obj->type)->functype)) {
+ if (conv_type) {
+ CError_Error(CErrorStr199);
+ break;
+ }
+ conv_type = TYPE_FUNC(obj->type)->functype;
+ conv_qual = TYPE_FUNC(obj->type)->qual;
+ }
+ }
+ if (conv_type) {
+ if (!copts.old_argmatch) {
+ expr = CExpr_Convert(expr, conv_type, conv_qual, 1, 1);
+ } else {
+ if (user_assign_check(expr, conv_type, conv_qual, 1, 0, 1))
+ expr = assign_node;
+ }
+ }
+ }
+ if (!IS_TYPE_POINTER_ONLY(expr->rtype)) {
+ CError_Error(CErrorStr146);
+ return nullnode();
+ }
+ }
+
+ innertype = TYPE_POINTER(expr->rtype)->target;
+ if (innertype->size == 0)
+ CDecl_CompleteType(innertype);
+
+ if (IS_TYPE_ARRAY(innertype) && !is_array)
+ CError_Error(CErrorStr146);
+
+ if (is_array) {
+ t = innertype;
+ while (IS_TYPE_ARRAY(t))
+ t = TYPE_POINTER(t)->target;
+ return CExpr_DeleteArray(expr, t, flag);
+ }
+
+ if (copts.objective_c && CObjC_IsType_id(expr->rtype))
+ return CObjC_Delete(NULL, expr);
+
+ if (!IS_TYPE_CLASS(innertype)) {
+ obj = CParser_FindDeallocationObject(innertype, NULL, 0, flag, &outflag);
+ CClass_CheckObjectAccess(NULL, obj);
+ return CExpr_DeleteFuncCall(obj, expr, innertype, outflag);
+ }
+
+ if (TYPE_CLASS(innertype)->sominfo)
+ return CSOM_Delete(TYPE_CLASS(innertype), expr);
+
+ if (TYPE_CLASS(innertype)->objcinfo)
+ return CObjC_Delete(TYPE_CLASS(innertype), expr);
+
+ if (!(TYPE_CLASS(innertype)->flags & CLASS_COMPLETED) && copts.pedantic)
+ CError_Warning(CErrorStr136, innertype, 0);
+
+ obj = CParser_FindDeallocationObject(innertype, NULL, 0, flag, &outflag);
+ CClass_CheckObjectAccess(NULL, obj);
+ dtor = CClass_Destructor(TYPE_CLASS(innertype));
+ if (!dtor)
+ return CExpr_DeleteFuncCall(obj, expr, innertype, outflag);
+
+ path.next = NULL;
+ path.type = innertype;
+ CClass_CheckObjectAccess(&path, dtor);
+
+ result_expr = lalloc(sizeof(ENode));
+ result_expr->type = EFUNCCALL;
+ result_expr->cost = 4;
+ result_expr->flags = 0;
+ result_expr->rtype = &stvoid;
+ if (dtor->datatype == DVFUNC) {
+ precomp_orig = expr;
+ expr = lalloc(sizeof(ENode));
+ *expr = *precomp_orig;
+ expr->type = EPRECOMP;
+ expr->data.precompid = precompid = CParser_GetUniqueID();
+ is_virtual = 1;
+ } else {
+ is_virtual = 0;
+ }
+
+ if (!flag) {
+ result_expr = CABI_DestroyObject(dtor, expr, 2, 0, 1);
+ } else {
+ CError_ASSERT(5650, !outflag);
+ result_expr = CABI_DestroyObject(dtor, expr, 2, 0, 0);
+ result_expr->rtype = TYPE(&void_ptr);
+ result_expr = funccallexpr(obj, result_expr, NULL, NULL, NULL);
+ obj->flags |= OBJECT_USED;
+ }
+
+ if (is_virtual) {
+ nc = lalloc(sizeof(ENode));
+ nc->type = ENULLCHECK;
+ nc->rtype = &stvoid;
+ nc->cost = 4;
+ nc->flags = 0;
+ nc->data.nullcheck.nullcheckexpr = precomp_orig;
+ nc->data.nullcheck.condexpr = result_expr;
+ nc->data.nullcheck.precompid = precompid;
+ return nc;
+ } else {
+ return result_expr;
+ }
+}
diff --git a/compiler_and_linker/FrontEnd/C/CExprConvMatch.c b/compiler_and_linker/FrontEnd/C/CExprConvMatch.c
new file mode 100644
index 0000000..5cc145f
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CExprConvMatch.c
@@ -0,0 +1,2518 @@
+#include "compiler/CExpr.h"
+#include "compiler/CABI.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CInt64.h"
+#include "compiler/CFunc.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CObjC.h"
+#include "compiler/CParser.h"
+#include "compiler/CScope.h"
+#include "compiler/CTemplateFunc.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/templates.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct StandardConv {
+ Type *type1;
+ Type *type2;
+ UInt32 qual1;
+ UInt32 qual2;
+ Boolean x10; // unknown
+ Boolean x11;
+ Boolean x12;
+ Boolean x13;
+ Boolean x14;
+ Boolean x15;
+} StandardConv;
+
+typedef enum EImplicitConvType {
+ ICT_0,
+ ICT_1,
+ ICT_2,
+ ICT_3
+} EImplicitConvType;
+
+typedef struct ImplicitConv {
+ EImplicitConvType type;
+ union {
+ struct {
+ Object *x2;
+ StandardConv standardConv;
+ } ic2;
+ struct {
+ StandardConv standardConv;
+ } ic3;
+ } u;
+} ImplicitConv;
+
+typedef struct ConversionTypeList {
+ struct ConversionTypeList *next;
+ Object *func;
+ Type *type;
+ UInt32 qual;
+} ConversionTypeList;
+
+typedef struct Match {
+ struct Match *next;
+ Object *object;
+ Object *specialfunc;
+ Type *type;
+ UInt32 qual;
+ Type *type2;
+ UInt32 qual2;
+ ImplicitConv conv[3];
+} Match;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+// forward decls
+static ENode *CExpr_DerivedToBase(ENode *expr, Type *type2, UInt32 qual2, Boolean flag1, Boolean flag2, Boolean flag3);
+
+static Type *CExpr_GetImplictObjectParamType(Object *object, UInt32 *qual) {
+ Type *type;
+
+ CError_ASSERT(98, IS_TYPE_FUNC(object->type));
+ CError_ASSERT(99, TYPE_FUNC(object->type)->flags & FUNC_METHOD);
+ CError_ASSERT(100, !TYPE_METHOD(object->type)->is_static);
+ CError_ASSERT(101, TYPE_METHOD(object->type)->args);
+
+ type = CDecl_NewRefPointerType(TYPE(TYPE_METHOD(object->type)->theclass));
+ *qual = TYPE_METHOD(object->type)->args->qual & Q_CV;
+ return type;
+}
+
+static Type *CExpr_GetParamType(Object *object, int index, UInt32 *qual) {
+ FuncArg *arg;
+
+ CError_ASSERT(120, IS_TYPE_FUNC(object->type));
+ CError_ASSERT(121, arg = TYPE_FUNC(object->type)->args);
+ if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(object->type)))
+ CError_ASSERT(125, arg = arg->next);
+
+ while (index > 0) {
+ CError_ASSERT(129, arg = arg->next);
+ index--;
+ }
+
+ *qual = arg->qual & Q_CV;
+ return arg->type;
+}
+
+static Boolean CExpr_HasNParams(Object *object, int count) {
+ FuncArg *arg;
+ int i;
+
+ CError_ASSERT(146, IS_TYPE_FUNC(object->type));
+ CError_ASSERT(147, arg = TYPE_FUNC(object->type)->args);
+ if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(object->type)))
+ arg = arg->next;
+
+ i = 0;
+ while (arg) {
+ arg = arg->next;
+ i++;
+ }
+
+ return i == count;
+}
+
+typedef enum TypeCompareMode {
+ TCM_0,
+ TCM_1,
+ TCM_2
+} TypeCompareMode;
+
+static Boolean CExpr_TypeCompare(Type *typeA, UInt32 qualA, Type *typeB, UInt32 qualB, TypeCompareMode mode) {
+ if (typeA->type != typeB->type)
+ return 0;
+
+ switch (mode) {
+ case TCM_0:
+ while (1) {
+ switch (typeA->type) {
+ case TYPEPOINTER:
+ typeA = TPTR_TARGET(typeA);
+ typeB = TPTR_TARGET(typeB);
+ if (typeA->type != typeB->type)
+ return 0;
+ continue;
+
+ case TYPEMEMBERPOINTER:
+ if (!is_typesame(TYPE_MEMBER_POINTER(typeA)->ty2, TYPE_MEMBER_POINTER(typeB)->ty2))
+ return 0;
+ typeA = TYPE_MEMBER_POINTER(typeA)->ty1;
+ typeB = TYPE_MEMBER_POINTER(typeB)->ty1;
+ if (typeA->type != typeB->type)
+ return 0;
+ continue;
+ }
+ break;
+ }
+ break;
+
+ case TCM_1:
+ switch (typeA->type) {
+ case TYPEPOINTER:
+ if ((qualA & Q_CV) != (qualB & Q_CV))
+ return 0;
+
+ typeA = TPTR_TARGET(typeA);
+ typeB = TPTR_TARGET(typeB);
+ break;
+
+ case TYPEMEMBERPOINTER:
+ if ((qualA & Q_CV) != (qualB & Q_CV))
+ return 0;
+
+ if (!is_typesame(TYPE_MEMBER_POINTER(typeA)->ty2, TYPE_MEMBER_POINTER(typeB)->ty2))
+ return 0;
+ typeA = TYPE_MEMBER_POINTER(typeA)->ty1;
+ typeB = TYPE_MEMBER_POINTER(typeB)->ty1;
+ break;
+ }
+ break;
+
+ case TCM_2:
+ if ((qualA & Q_CV) != (qualB & Q_CV))
+ return 0;
+ break;
+ }
+
+ return is_typesame(typeA, typeB);
+}
+
+static int CExpr_IsReferenceCompatible(Type *typeA, UInt32 qualA, Type *typeB, UInt32 qualB) {
+ if (CParser_IsSameOrMoreCVQualified(CParser_GetCVTypeQualifiers(typeA, qualA), CParser_GetCVTypeQualifiers(typeB, qualB))) {
+ if (CExpr_TypeCompare(typeA, qualA, typeB, qualB, TCM_1))
+ return 1;
+
+ if (IS_TYPE_CLASS(typeB) && IS_TYPE_CLASS(typeA)) {
+ short depth;
+ Boolean isambigbase;
+ if (CClass_GetBasePath(TYPE_CLASS(typeB), TYPE_CLASS(typeA), &depth, &isambigbase))
+ return 2;
+ }
+ }
+
+ return 0;
+}
+
+static Boolean CExpr_IsBaseOf(TypeClass *baseclass, TypeClass *superclass) {
+ ClassList *base;
+
+ for (base = superclass->bases; base; base = base->next) {
+ if (base->base == baseclass || CExpr_IsBaseOf(baseclass, base->base))
+ return 1;
+ }
+
+ return 0;
+}
+
+static Boolean CExpr_IsBetterClassConversion(TypeClass *a, TypeClass *b, TypeClass *c, TypeClass *d) {
+ if (a == c)
+ return CExpr_IsBaseOf(d, b);
+ if (b == d)
+ return CExpr_IsBaseOf(a, c);
+ return 0;
+}
+
+CW_INLINE Boolean Inline_501D40(Type *a, Type *b) {
+ return (a == TYPE(&stbool)) && (IS_TYPE_POINTER_ONLY(b) || IS_TYPE_MEMBERPOINTER(b));
+}
+
+static Boolean CExpr_IsBetterStandardConv(StandardConv *a, StandardConv *b) {
+ Boolean flag10;
+ Boolean flag3;
+
+ flag10 = 1;
+ flag3 = 0;
+
+ if (b->x11) {
+ if (!a->x11)
+ flag3 = 1;
+ } else {
+ if (a->x11)
+ flag10 = 0;
+ }
+
+ if (b->x12) {
+ if (!a->x12)
+ flag3 = 1;
+ } else {
+ if (a->x12)
+ flag10 = 0;
+ }
+
+ if (b->x13) {
+ if (a->x13) {
+ if (Inline_501D40(b->type2, b->type1)) {
+ if (!Inline_501D40(a->type2, a->type1))
+ return 1;
+ } else {
+ if (Inline_501D40(a->type2, a->type1))
+ return 0;
+ }
+ } else {
+ flag3 = 1;
+ }
+ } else {
+ if (a->x13)
+ flag10 = 0;
+ }
+
+ if (flag10 && flag3)
+ return 1;
+
+ if (!a->x13) {
+ if (b->x13)
+ return 1;
+
+ if (a->x12) {
+ if (!b->x12)
+ return 0;
+ } else {
+ if (b->x12)
+ return 1;
+ }
+ } else {
+ if (!b->x13)
+ return 0;
+ }
+
+ if (
+ IS_TYPE_POINTER_ONLY(a->type1) &&
+ IS_TYPE_CLASS(TPTR_TARGET(a->type1)) &&
+ IS_TYPE_POINTER_ONLY(a->type2) &&
+ IS_TYPE_POINTER_ONLY(b->type1) &&
+ IS_TYPE_CLASS(TPTR_TARGET(b->type1)) &&
+ IS_TYPE_POINTER_ONLY(b->type2)
+ )
+ {
+ if (TPTR_TARGET(b->type2) == &stvoid) {
+ if (TPTR_TARGET(a->type2) == &stvoid) {
+ if (CExpr_IsBaseOf(TYPE_CLASS(TPTR_TARGET(a->type1)), TYPE_CLASS(TPTR_TARGET(b->type1))))
+ return 1;
+ } else {
+ if (TPTR_TARGET(a->type1) == TPTR_TARGET(b->type1) && IS_TYPE_CLASS(TPTR_TARGET(a->type2)))
+ return 1;
+ }
+ } else if (IS_TYPE_CLASS(TPTR_TARGET(a->type2)) && IS_TYPE_CLASS(TPTR_TARGET(b->type2))) {
+ if (CExpr_IsBetterClassConversion(
+ TYPE_CLASS(TPTR_TARGET(a->type1)),
+ TYPE_CLASS(TPTR_TARGET(a->type2)),
+ TYPE_CLASS(TPTR_TARGET(b->type1)),
+ TYPE_CLASS(TPTR_TARGET(b->type2))
+ ))
+ return 1;
+ }
+ }
+
+ if (
+ IS_TYPE_CLASS(a->type1) &&
+ IS_TYPE_CLASS(a->type2) &&
+ IS_TYPE_CLASS(b->type1) &&
+ IS_TYPE_CLASS(b->type2) &&
+ CExpr_IsBetterClassConversion(
+ TYPE_CLASS(a->type1),
+ TYPE_CLASS(a->type2),
+ TYPE_CLASS(b->type1),
+ TYPE_CLASS(b->type2)
+ )
+ )
+ return 1;
+
+ if (
+ IS_TYPE_MEMBERPOINTER(a->type1) &&
+ IS_TYPE_MEMBERPOINTER(a->type2) &&
+ IS_TYPE_MEMBERPOINTER(b->type1) &&
+ IS_TYPE_MEMBERPOINTER(b->type2) &&
+ IS_TYPE_CLASS(TYPE_MEMBER_POINTER(a->type1)->ty2) &&
+ IS_TYPE_CLASS(TYPE_MEMBER_POINTER(a->type2)->ty2) &&
+ IS_TYPE_CLASS(TYPE_MEMBER_POINTER(b->type1)->ty2) &&
+ IS_TYPE_CLASS(TYPE_MEMBER_POINTER(b->type2)->ty2) &&
+ CExpr_IsBetterClassConversion(
+ TYPE_CLASS(TYPE_MEMBER_POINTER(b->type1)->ty2),
+ TYPE_CLASS(TYPE_MEMBER_POINTER(b->type2)->ty2),
+ TYPE_CLASS(TYPE_MEMBER_POINTER(a->type1)->ty2),
+ TYPE_CLASS(TYPE_MEMBER_POINTER(a->type2)->ty2)
+ )
+ )
+ return 1;
+
+ if (
+ a->x14 &&
+ b->x14 &&
+ CExpr_TypeCompare(a->type2, a->qual2, b->type2, b->qual2, TCM_1) &&
+ CParser_IsMoreCVQualified(
+ CParser_GetTypeQualifiers(b->type2, b->qual2),
+ CParser_GetTypeQualifiers(a->type2, a->qual2)
+ )
+ )
+ return 1;
+
+ return 0;
+}
+
+static Boolean CExpr_IsBetterImplicitConv(ImplicitConv *a, ImplicitConv *b) {
+ if (a->type > b->type)
+ return 1;
+ if (a->type != b->type)
+ return 0;
+
+ if (a->type == ICT_3)
+ return CExpr_IsBetterStandardConv(&a->u.ic3.standardConv, &b->u.ic3.standardConv);
+
+ if (a->type == ICT_2 && a->u.ic2.x2 == b->u.ic2.x2 && CExpr_IsBetterStandardConv(&a->u.ic2.standardConv, &b->u.ic2.standardConv))
+ return 1;
+
+ return 0;
+}
+
+typedef enum SSCRMode {
+ SSCR_0,
+ SSCR_1,
+ SSCR_2
+} SSCRMode;
+
+static Boolean CExpr_SetupStandardConversionResult(ENode *expr, Type *type2, UInt32 qual2, SSCRMode mode, Boolean x14, Boolean refFlag, StandardConv *result) {
+ UInt32 cv1;
+ UInt32 cv2;
+
+ if (x14) {
+ if (!CParser_IsConst(type2, qual2)) {
+ if (!refFlag && !CExpr_IsLValue(expr))
+ return 0;
+ if (mode != SSCR_0 && !IS_TYPE_CLASS(type2))
+ return 0;
+ }
+
+ cv2 = CParser_GetTypeQualifiers(type2, qual2) & Q_CV;
+ cv1 = CParser_GetTypeQualifiers(expr->rtype, ENODE_QUALS(expr)) & Q_CV;
+ if (cv2 != cv1 && !CParser_IsMoreCVQualified(cv2, cv1))
+ return 0;
+ }
+
+ memclrw(result, sizeof(StandardConv));
+ result->type2 = type2;
+ result->qual2 = qual2;
+ result->type1 = expr->rtype;
+ result->qual1 = ENODE_QUALS(expr);
+ result->x14 = x14;
+
+ switch (mode) {
+ case SSCR_0:
+ break;
+ case SSCR_1:
+ result->x12 = 1;
+ break;
+ case SSCR_2:
+ result->x13 = 1;
+ break;
+ default:
+ CError_FATAL(581);
+ }
+
+ return 1;
+}
+
+typedef enum MysteryEnum {
+ ME_0,
+ ME_1,
+ ME_255 = 255
+} MysteryEnum;
+
+CW_INLINE MysteryEnum Inline_501FF0(UInt32 qual1, UInt32 qual2) {
+ if ((qual1 & Q_CV) == (qual2 & Q_CV))
+ return ME_0;
+
+ if (((qual2 & Q_CONST) && !(qual1 & Q_CONST)) || ((qual2 & Q_VOLATILE) && !(qual1 & Q_VOLATILE)))
+ return ME_255;
+
+ return ME_1;
+}
+
+static Boolean CExpr_SetQualConversionResult(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, StandardConv *result) {
+ Boolean flag = 1;
+ UInt32 cv1;
+ UInt32 cv2;
+
+ while (1) {
+ cv1 = CParser_GetCVTypeQualifiers(type1, qual1);
+ cv2 = CParser_GetCVTypeQualifiers(type2, qual2);
+
+ switch (Inline_501FF0(cv1, cv2)) {
+ case ME_0:
+ break;
+
+ case ME_1:
+ result->x11 = 1;
+ if (!flag)
+ return 0;
+ break;
+
+ default:
+ return 0;
+ }
+
+ if (!(cv1 & Q_CONST))
+ flag = 0;
+
+ if (IS_TYPE_POINTER_ONLY(type1)) {
+ CError_ASSERT(635, IS_TYPE_POINTER_ONLY(type2));
+ type1 = TPTR_TARGET(type1);
+ type2 = TPTR_TARGET(type2);
+ } else {
+ if (!IS_TYPE_MEMBERPOINTER(type1))
+ return 1;
+
+ CError_ASSERT(642, IS_TYPE_MEMBERPOINTER(type2));
+ type1 = TYPE_MEMBER_POINTER(type1)->ty1;
+ type2 = TYPE_MEMBER_POINTER(type2)->ty1;
+ }
+ }
+}
+
+static Boolean CExpr_OverloadFuncMatch(NameSpaceObjectList *list, TemplArg *templargs, Type *type, ENode **outExpr) {
+ Object *object;
+ TemplFuncInstance *inst;
+ ENode *expr;
+ FuncArg *arg;
+ int i;
+ ObjectList *objlist;
+ Object *object26;
+ ObjectList *objlist25;
+ ObjectList *objlist24;
+ Boolean flag23;
+
+ if (!IS_TYPE_POINTER_ONLY(type) || !IS_TYPE_FUNC(type = TPTR_TARGET(type)))
+ return 0;
+
+ object26 = NULL;
+ objlist25 = NULL;
+ objlist24 = NULL;
+ flag23 = 0;
+
+ while (list) {
+ object = OBJECT(list->object);
+ if (object->otype == OT_OBJECT) {
+ if (IS_TEMPL_FUNC(object->type)) {
+ if (!flag23 && CTempl_CanDeduceFunc(object, TYPE_FUNC(type), templargs)) {
+ CError_ASSERT(685, inst = CTempl_DeduceFunc(object, TYPE_FUNC(type), templargs, NULL, 0));
+ if (is_typesame(inst->object->type, type)) {
+ objlist = lalloc(sizeof(ObjectList));
+ objlist->next = objlist24;
+ objlist->object = object;
+ objlist24 = objlist;
+
+ if (object26 && object26 != inst->object) {
+ objlist = lalloc(sizeof(ObjectList));
+ objlist->next = objlist25;
+ objlist->object = inst->object;
+ objlist25 = objlist;
+ } else {
+ object26 = inst->object;
+ }
+ }
+ }
+ } else if (is_typesame(object->type, type)) {
+ if (object26 && flag23) {
+ Object *checkA, *checkB;
+ checkA = object;
+ if (checkA->datatype == DALIAS)
+ checkA = checkA->u.alias.object;
+ checkB = object26;
+ if (checkB->datatype == DALIAS)
+ checkB = checkB->u.alias.object;
+ if (checkA != checkB) {
+ objlist = lalloc(sizeof(ObjectList));
+ objlist->next = objlist25;
+ objlist->object = object;
+ objlist25 = objlist;
+ }
+ } else {
+ objlist25 = NULL;
+ object26 = object;
+ }
+ flag23 = 1;
+ }
+ }
+ list = list->next;
+ }
+
+ if (object26) {
+ if (outExpr) {
+ if (objlist25) {
+ i = 0;
+ for (arg = TYPE_FUNC(object->type)->args; arg; arg = arg->next)
+ i++;
+
+ if (!flag23 && (object = CTempl_PartialOrdering(objlist24->object, objlist24->next, i))) {
+ CError_ASSERT(741, inst = CTempl_DeduceFunc(object, TYPE_FUNC(type), templargs, NULL, 0));
+ object26 = inst->object;
+ } else {
+ CError_OverloadedFunctionError(object26, objlist25);
+ }
+ }
+
+ expr = CExpr_MakeObjRefNode(object26, 1);
+ *outExpr = expr;
+ expr->rtype = CDecl_NewPointerType(object26->type);
+ expr->flags = object->qual & ENODE_FLAG_QUALS;
+ object26->flags |= OBJECT_USED;
+ if (object26->datatype == DINLINEFUNC)
+ CError_Error(CErrorStr175);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static Boolean CExpr_StandardConversionMatch(ENode *expr, Type *type2, UInt32 qual2, Boolean x14, StandardConv *result) {
+ Type *type1;
+ UInt32 qual1;
+ Boolean refFlag;
+ Type *inner2;
+ Type *inner1;
+ SSCRMode mode;
+ NameSpaceObjectList list;
+
+ if (IS_TYPE_REFERENCE(type2)) {
+ type2 = TPTR_TARGET(type2);
+ if (IS_TYPE_POINTER_ONLY(type2))
+ expr = pointer_generation(expr);
+ refFlag = 1;
+ } else {
+ if (
+ (IS_TYPE_ARRAY(expr->rtype) && !IS_TYPE_ARRAY(type2)) ||
+ (IS_TYPE_FUNC(expr->rtype) && !IS_TYPE_FUNC(type2))
+ )
+ expr = pointer_generation(expr);
+ refFlag = 0;
+ }
+
+ type1 = expr->rtype;
+ qual1 = ENODE_QUALS(expr);
+
+ if (IS_TYPE_POINTER_ONLY(type2)) {
+ if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval)) {
+ if (IS_TYPE_INT(type1) || (!copts.cplusplus && IS_TYPE_ENUM(type1)))
+ return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, x14, refFlag, result);
+ }
+
+ if (
+ IS_TYPE_INT(expr->rtype) &&
+ ENODE_IS_INDIRECT_TO(expr, EOBJREF) &&
+ (expr->data.monadic->data.objref->qual & Q_INLINE_DATA) &&
+ CInt64_IsZero(&expr->data.monadic->data.objref->u.data.u.intconst)
+ )
+ return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, x14, refFlag, result);
+
+ if (ENODE_IS(expr, EOBJLIST))
+ return CExpr_OverloadFuncMatch(expr->data.objlist.list, expr->data.objlist.templargs, type2, NULL) &&
+ CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result);
+
+ if (ENODE_IS(expr, EOBJREF) && IS_TEMPL_FUNC(expr->data.objref->type)) {
+ list.next = NULL;
+ list.object = OBJ_BASE(expr->data.objref);
+ return CExpr_OverloadFuncMatch(&list, NULL, type2, NULL) &&
+ CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result);
+ }
+
+ if (IS_TYPE_POINTER_ONLY(type1)) {
+ if (
+ ENODE_IS(expr, ESTRINGCONST) &&
+ TPTR_TARGET(type2) == TPTR_TARGET(type1) &&
+ !(qual2 & Q_CONST) &&
+ (
+ TPTR_TARGET(type2) == TYPE(&stchar) ||
+ TPTR_TARGET(type2) == TYPE(&stunsignedchar) ||
+ TPTR_TARGET(type2) == CParser_GetWCharType()
+ )
+ )
+ {
+ if (
+ CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result) &&
+ CExpr_SetQualConversionResult(TPTR_TARGET(type2), qual2, TPTR_TARGET(type1), qual1 & ~Q_CONST, result)
+ )
+ {
+ result->x11 = 1;
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ if (copts.objective_c && CObjC_IsCompatibleType(expr->rtype, type2))
+ return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, x14, refFlag, result);
+
+ if (IS_TYPE_VOID(TPTR_TARGET(type2)) || (!copts.cplusplus && IS_TYPE_VOID(TPTR_TARGET(type1)))) {
+ if (CExpr_SetupStandardConversionResult(expr, type2, qual2, IS_TYPE_VOID(TPTR_TARGET(type1)) ? SSCR_0 : SSCR_2, refFlag, x14, result)) {
+ switch (Inline_501FF0(qual2, CParser_GetCVTypeQualifiers(TPTR_TARGET(type1), qual1))) {
+ case ME_1:
+ result->x11 = 1;
+ case ME_0:
+ return 1;
+ default:
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ inner2 = TPTR_TARGET(type2);
+ inner1 = TPTR_TARGET(type1);
+ while (1) {
+ if (inner2->type != inner1->type)
+ break;
+
+ switch (inner2->type) {
+ case TYPEPOINTER:
+ inner2 = TPTR_TARGET(inner2);
+ inner1 = TPTR_TARGET(inner1);
+ continue;
+ case TYPEMEMBERPOINTER:
+ if (!is_typesame(TYPE_MEMBER_POINTER(inner2)->ty2, TYPE_MEMBER_POINTER(inner1)->ty2))
+ break;
+
+ inner2 = TYPE_MEMBER_POINTER(inner2)->ty1;
+ inner1 = TYPE_MEMBER_POINTER(inner1)->ty1;
+ if (!IS_TYPE_POINTER_ONLY(inner2) && !IS_TYPE_MEMBERPOINTER(inner2)) {
+ if (!is_memberpointerequal(inner2, inner1))
+ break;
+
+ if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result))
+ return CExpr_SetQualConversionResult(TPTR_TARGET(type2), qual2, TPTR_TARGET(type1), qual1, result);
+ else
+ return 0;
+ }
+ continue;
+ default:
+ if (!is_typesame(inner2, inner1))
+ break;
+
+ if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result))
+ return CExpr_SetQualConversionResult(TPTR_TARGET(type2), qual2, TPTR_TARGET(type1), qual1, result);
+ else
+ return 0;
+ }
+
+ break;
+ }
+
+ if (IS_TYPE_CLASS(TPTR_TARGET(type2)) && IS_TYPE_CLASS(TPTR_TARGET(type1))) {
+ short depth;
+ Boolean isambigbase;
+ if (CClass_GetBasePath(TYPE_CLASS(TPTR_TARGET(type1)), TYPE_CLASS(TPTR_TARGET(type2)), &depth, &isambigbase)) {
+ if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result))
+ return CExpr_SetQualConversionResult(TPTR_TARGET(type2), qual2, TPTR_TARGET(type1), qual1, result);
+ else
+ return 0;
+ }
+ }
+ }
+
+ if (copts.mpwc_relax && !copts.cplusplus && IS_TYPE_POINTER_ONLY(type1)) {
+ if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result))
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if (is_typesame(type2, type1))
+ return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result);
+
+ if (type2 == TYPE(&stbool)) {
+ switch (type1->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPEMEMBERPOINTER:
+ case TYPEPOINTER:
+ return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result);
+ default:
+ return 0;
+ }
+ }
+
+ if (IS_TYPE_MEMBERPOINTER(type2)) {
+ if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval)) {
+ if (IS_TYPE_INT(type1) || (!copts.cplusplus && IS_TYPE_ENUM(type1)))
+ return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result);
+ }
+
+ if (ENODE_IS(expr, EMEMBER)) {
+ expr = getpointertomemberfunc(expr, type2, 0);
+ type1 = expr->rtype;
+ }
+
+ if (IS_TYPE_MEMBERPOINTER(type1)) {
+ short depth;
+ Boolean isambigbase;
+
+ CError_ASSERT(996, IS_TYPE_CLASS(TYPE_MEMBER_POINTER(type2)->ty2) && IS_TYPE_CLASS(TYPE_MEMBER_POINTER(type1)->ty2));
+ if (!is_memberpointerequal(TYPE_MEMBER_POINTER(type2)->ty1, TYPE_MEMBER_POINTER(type1)->ty1))
+ return 0;
+
+ if (
+ TYPE_MEMBER_POINTER(type2)->ty2 == TYPE_MEMBER_POINTER(type1)->ty2 ||
+ CClass_GetBasePath(TYPE_CLASS(TYPE_MEMBER_POINTER(type2)->ty2), TYPE_CLASS(TYPE_MEMBER_POINTER(type1)->ty2), &depth, &isambigbase)
+ )
+ {
+ if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result))
+ return CExpr_SetQualConversionResult(TYPE_MEMBER_POINTER(type2)->ty1, qual2, TYPE_MEMBER_POINTER(type1)->ty1, qual1, result);
+ else
+ return 0;
+ }
+ }
+
+ return 0;
+ }
+
+ mode = SSCR_2;
+ switch (type1->type) {
+ case TYPEINT:
+ switch (type2->type) {
+ case TYPEINT:
+ if (TYPE_INTEGRAL(type1)->integral < IT_INT) {
+ if (type2 == TYPE(&stsignedint)) {
+ if (type1->size < type2->size || !is_unsigned(type1))
+ mode = SSCR_1;
+ } else if (type2 == TYPE(&stunsignedint)) {
+ if (type2->size == type1->size && is_unsigned(type1))
+ mode = SSCR_1;
+ }
+ }
+ break;
+ case TYPEFLOAT:
+ break;
+ case TYPEENUM:
+ if (copts.cplusplus)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ break;
+
+ case TYPEFLOAT:
+ switch (type2->type) {
+ case TYPEINT:
+ break;
+ case TYPEFLOAT:
+ if (type2 == TYPE(&stdouble)) {
+ if (type1 == TYPE(&stfloat) || type1 == TYPE(&stshortdouble))
+ mode = SSCR_1;
+ }
+ break;
+ case TYPEENUM:
+ if (copts.cplusplus)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ break;
+
+ case TYPEENUM:
+ switch (type2->type) {
+ case TYPEINT:
+ if (TYPE_INTEGRAL(TYPE_ENUM(expr->rtype)->enumtype)->integral < IT_INT) {
+ if (type1->size == type2->size && is_unsigned(TYPE_ENUM(type1)->enumtype)) {
+ if (type2 == TYPE(&stunsignedint))
+ mode = SSCR_1;
+ } else {
+ if (type2 == TYPE(&stsignedint))
+ mode = SSCR_1;
+ }
+ } else {
+ if (TYPE_ENUM(type1)->enumtype == type2)
+ mode = SSCR_1;
+ }
+ break;
+ case TYPEFLOAT:
+ break;
+ case TYPEENUM:
+ if (copts.cplusplus)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ break;
+
+ case TYPECLASS: {
+ short depth;
+ Boolean isambigbase;
+
+ if (!IS_TYPE_CLASS(type1) || !CClass_GetBasePath(TYPE_CLASS(type1), TYPE_CLASS(type2), &depth, &isambigbase))
+ return 0;
+ break;
+ }
+
+ default:
+ return 0;
+ }
+
+ return CExpr_SetupStandardConversionResult(expr, type2, qual2, mode, refFlag, x14, result);
+}
+
+static ENode *CExpr_UserConversion(ENode *expr, Type *type2, UInt32 qual2, ImplicitConv *result, Boolean flag1, Boolean isExplicit, Boolean flag3) {
+ Object *object28;
+ Object *object27;
+ Object *object26;
+ ObjectList *objlist25;
+ ObjectList *objlist24;
+ ObjectList *objlist;
+ TypeFunc *tfunc23;
+ Type *tmptype23;
+ NameSpaceObjectList *list22;
+ Boolean flag22;
+ Boolean flag21;
+ FuncArg *arg21;
+ Boolean flag20;
+ ENode *newExpr;
+ ENode *funcref;
+ ENode *tmpExpr;
+ ENodeList *arglist;
+ UInt32 q1;
+ UInt32 q2;
+ StandardConv sc3;
+ StandardConv sc2;
+ StandardConv sc1;
+ ConversionIterator convIter;
+ ENodeList myarglist;
+ ObjectList myobjlist;
+ BClassList path;
+
+ object28 = NULL;
+ object27 = NULL;
+ objlist25 = NULL;
+ objlist24 = NULL;
+
+ if (type2->size == 0)
+ CDecl_CompleteType(type2);
+ if (expr->rtype->size == 0)
+ CDecl_CompleteType(expr->rtype);
+
+ if (IS_TYPE_CLASS(expr->rtype)) {
+ CExpr_ConversionIteratorInit(&convIter, TYPE_CLASS(expr->rtype));
+ flag22 = 1;
+ while ((object26 = CExpr_ConversionIteratorNext(&convIter))) {
+ tfunc23 = TYPE_FUNC(object26->type);
+ if (tfunc23->flags & FUNC_IS_TEMPL) {
+ object26 = CTempl_DeduceFromConversion(object26, type2, qual2);
+ if (!object26)
+ continue;
+ tfunc23 = TYPE_FUNC(object26->type);
+ }
+
+ if (flag3) {
+ if (
+ !IS_TYPE_REFERENCE(tfunc23->functype) ||
+ !CExpr_IsReferenceCompatible(type2, qual2, TPTR_TARGET(tfunc23->functype), tfunc23->qual)
+ )
+ continue;
+ }
+
+ CError_ASSERT(1230, tfunc23->args && IS_TYPE_POINTER_ONLY(tfunc23->args->type));
+
+ q1 = ENODE_QUALS(expr);
+ q2 = tfunc23->args->qual;
+ if ((q1 & Q_CV) != (q2 & Q_CV)) {
+ if (!flag22)
+ continue;
+ if ((q1 & Q_CONST) && !(q2 & Q_CONST))
+ continue;
+ if ((q1 & Q_VOLATILE) && !(q2 & Q_VOLATILE))
+ continue;
+ flag21 = 1;
+ } else {
+ flag21 = 0;
+ }
+
+ newExpr = CExpr_NewENode(ETEMP);
+ newExpr->rtype = tfunc23->functype;
+ newExpr->flags = tfunc23->qual & ENODE_FLAG_QUALS;
+ flag20 = 0;
+
+ if (IS_TYPE_REFERENCE(newExpr->rtype)) {
+ newExpr->rtype = TPTR_TARGET(newExpr->rtype);
+ if (!CParser_IsConst(newExpr->rtype, tfunc23->qual)) {
+ newExpr = makemonadicnode(newExpr, EINDIRECT);
+ newExpr->data.monadic->rtype = TYPE(&void_ptr);
+ newExpr = makemonadicnode(newExpr, EINDIRECT);
+ newExpr->data.monadic->rtype = TYPE(&void_ptr);
+ flag20 = 1;
+ }
+ }
+
+ if (CExpr_StandardConversionMatch(newExpr, type2, qual2, 0, &sc1)) {
+ if (flag22 && !flag21) {
+ object28 = NULL;
+ objlist25 = NULL;
+ flag22 = 0;
+ }
+
+ if (object28 && object28 != object26) {
+ if (CExpr_IsBetterStandardConv(&sc3, &sc1))
+ continue;
+
+ if (!CExpr_IsBetterStandardConv(&sc1, &sc3)) {
+ objlist = lalloc(sizeof(ObjectList));
+ objlist->next = objlist25;
+ objlist->object = object28;
+ objlist25 = objlist;
+ } else {
+ objlist25 = NULL;
+ }
+ }
+
+ object28 = object26;
+ sc3 = sc1;
+ sc3.x15 = flag20;
+ }
+ }
+ }
+
+ if (!flag3 && IS_TYPE_CLASS(type2) && (list22 = CClass_Constructor(TYPE_CLASS(type2)))) {
+ for (; list22; list22 = list22->next) {
+ object26 = OBJECT(list22->object);
+ if (
+ object26->otype == OT_OBJECT &&
+ IS_TYPE_FUNC(tfunc23 = TYPE_FUNC(object26->type)) &&
+ (isExplicit || !(object26->qual & Q_EXPLICIT))
+ )
+ {
+ if (tfunc23->flags & FUNC_IS_TEMPL) {
+ myarglist.next = NULL;
+ myarglist.node = expr;
+ object26 = CTempl_DeduceFromFunctionCall(object26, NULL, &myarglist);
+ if (!object26)
+ continue;
+ tfunc23 = TYPE_FUNC(object26->type);
+ }
+
+ if (!(arg21 = tfunc23->args))
+ continue;
+ if (!(arg21 = arg21->next))
+ continue;
+ if ((TYPE_CLASS(type2)->flags & CLASS_HAS_VBASES) && !(arg21 = arg21->next))
+ continue;
+ if (arg21 == &elipsis)
+ continue;
+ if (arg21->next && !arg21->next->dexpr && arg21->next != &elipsis)
+ continue;
+
+ tmptype23 = arg21->type;
+ if (IS_TYPE_REFERENCE(tmptype23)) {
+ tmptype23 = TPTR_TARGET(tmptype23);
+ if (!CParser_IsConst(tmptype23, arg21->qual) && !CExpr_IsLValue(expr))
+ continue;
+ }
+
+ if (CExpr_StandardConversionMatch(expr, tmptype23, arg21->qual, 0, &sc1)) {
+ if (object27) {
+ if (object26->u.func.inst && !object27->u.func.inst)
+ continue;
+ if (CExpr_IsBetterStandardConv(&sc2, &sc1))
+ continue;
+
+ if (!CExpr_IsBetterStandardConv(&sc1, &sc2)) {
+ if (!object26->u.func.inst && object27->u.func.inst) {
+ objlist24 = NULL;
+ } else {
+ objlist = lalloc(sizeof(ObjectList));
+ objlist->next = objlist25;
+ objlist->object = object28;
+ objlist25 = objlist;
+ }
+ } else {
+ objlist25 = NULL;
+ }
+ }
+
+ object27 = object26;
+ sc2 = sc1;
+ }
+ }
+ }
+ }
+
+ if (object28 && object27) {
+ if (!CExpr_IsBetterStandardConv(&sc2, &sc3)) {
+ if (!CExpr_IsBetterStandardConv(&sc3, &sc2)) {
+ if (result) {
+ result->type = ICT_2;
+ result->u.ic2.x2 = object28;
+ result->u.ic2.standardConv = sc3;
+ }
+ if (flag1) {
+ myobjlist.next = NULL;
+ myobjlist.object = object27;
+ CError_OverloadedFunctionError(object28, &myobjlist);
+ }
+ } else {
+ object27 = NULL;
+ }
+ } else {
+ object28 = NULL;
+ }
+ }
+
+ if (object28) {
+ if (result) {
+ result->type = ICT_2;
+ result->u.ic2.x2 = object28;
+ result->u.ic2.standardConv = sc3;
+ }
+ if (!flag1)
+ return expr;
+ if (objlist25)
+ CError_OverloadedFunctionError(object28, objlist25);
+ tfunc23 = TYPE_FUNC(object28->type);
+ CError_ASSERT(1416, IS_TYPEFUNC_METHOD(tfunc23));
+
+ funcref = create_objectrefnode(object28);
+ object28->flags |= OBJECT_USED;
+
+ arglist = lalloc(sizeof(ENodeList));
+ arglist->next = NULL;
+
+ expr = getnodeaddress(expr, 0);
+ arglist->node = CExpr_AssignmentPromotion(
+ expr,
+ CDecl_NewPointerType(TYPE(TYPE_METHOD(tfunc23)->theclass)),
+ expr->flags,
+ 0);
+
+ newExpr = lalloc(sizeof(ENode));
+ newExpr->type = EFUNCCALL;
+ newExpr->cost = 4;
+ newExpr->rtype = tfunc23->functype;
+ newExpr->flags = tfunc23->qual & ENODE_FLAG_QUALS;
+ newExpr->data.funccall.funcref = funcref;
+ newExpr->data.funccall.args = arglist;
+ newExpr->data.funccall.functype = TYPE_FUNC(object28->type);
+ newExpr = CExpr_AdjustFunctionCall(newExpr);
+ newExpr = checkreference(newExpr);
+
+ if (newExpr->rtype != type2) {
+ if (flag3) {
+ tmpExpr = CExpr_DerivedToBase(newExpr, type2, qual2, 1, 0, 1);
+ if (tmpExpr)
+ return tmpExpr;
+ }
+ newExpr = CExpr_Convert(newExpr, type2, qual2, 0, 1);
+ }
+ return newExpr;
+ }
+
+ if (object27) {
+ if (result) {
+ result->type = ICT_2;
+ result->u.ic2.x2 = object27;
+ result->u.ic2.standardConv = sc2;
+ }
+ if (!flag1)
+ return expr;
+ if (objlist24)
+ CError_OverloadedFunctionError(object27, objlist24);
+
+ arglist = lalloc(sizeof(ENodeList));
+ arglist->next = NULL;
+ arglist->node = expr;
+
+ if (TYPE_CLASS(type2)->flags & CLASS_HAS_VBASES) {
+ arglist->next = lalloc(sizeof(ENodeList));
+ arglist->next->node = expr;
+ arglist->next->next = NULL;
+ arglist->node = intconstnode(TYPE(&stsignedshort), 1);
+ }
+
+ path.next = NULL;
+ path.type = type2;
+
+ tmpExpr = makemonadicnode(create_temp_node(type2), EINDIRECT);
+ tmpExpr->rtype = type2;
+
+ newExpr = CExpr_GenericFuncCall(
+ &path, tmpExpr, 0, object27, NULL, NULL, arglist, 0, 0, 1
+ );
+
+ if (ENODE_IS2(newExpr, EFUNCCALL, EFUNCCALLP)) {
+ newExpr->rtype = CDecl_NewPointerType(type2);
+ newExpr = makemonadicnode(newExpr, EINDIRECT);
+ newExpr->rtype = type2;
+ }
+
+ return newExpr;
+ }
+
+ return NULL;
+}
+
+static Boolean CExpr_UserConversionMatch(ENode *expr, Type *type2, UInt32 qual2, ImplicitConv *result) {
+ Boolean flag;
+
+ if (IS_TYPE_REFERENCE(type2)) {
+ type2 = TPTR_TARGET(type2);
+ flag = !CParser_IsConst(type2, qual2);
+ } else {
+ expr = pointer_generation(expr);
+ flag = 0;
+ }
+
+ if (CExpr_UserConversion(expr, type2, qual2, result, 0, 0, flag))
+ return 1;
+
+ return 0;
+}
+
+static Boolean CExpr_ImplicitConversionMatch(ENode *expr, Type *type2, UInt32 qual2, ImplicitConv *result) {
+ if (CExpr_StandardConversionMatch(expr, type2, qual2, 0, &result->u.ic3.standardConv)) {
+ result->type = ICT_3;
+ return 1;
+ }
+
+ if (IS_TYPE_CLASS(expr->rtype) || IS_TYPE_CLASS(type2) || (IS_TYPE_REFERENCE(type2) && IS_TYPE_CLASS(TPTR_TARGET(type2)))) {
+ if (CExpr_UserConversionMatch(expr, type2, qual2, result)) {
+ result->type = ICT_2;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+Boolean CExpr_CanImplicitlyConvert(ENode *expr, Type *type2, UInt32 qual2) {
+ ImplicitConv result;
+ return CExpr_ImplicitConversionMatch(expr, type2, qual2, &result);
+}
+
+static ENode *CExpr_DerivedToBase(ENode *expr, Type *type2, UInt32 qual2, Boolean flag1, Boolean nullcheckflag, Boolean pathcheckflag) {
+ BClassList *path;
+ short depth;
+ Boolean isambigbase;
+
+ if (
+ IS_TYPE_CLASS(type2) &&
+ IS_TYPE_CLASS(expr->rtype) &&
+ (path = CClass_GetBasePath(TYPE_CLASS(expr->rtype), TYPE_CLASS(type2), &depth, &isambigbase))
+ )
+ {
+ if (isambigbase)
+ CError_Error(CErrorStr188);
+ if (flag1)
+ CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC);
+
+ if (pathcheckflag) {
+ expr = getnodeaddress(expr, 0);
+ expr = makemonadicnode(CExpr_ClassPointerCast(path, expr, nullcheckflag), EINDIRECT);
+ expr->rtype = type2;
+ expr->flags = qual2 & ENODE_FLAG_QUALS;
+ }
+
+ return expr;
+ }
+ else {
+ return NULL;
+ }
+}
+
+static ENode *CExpr_ClassReferenceConversion(ENode *expr, Type *type2, UInt32 qual2, Boolean pathcheckflag) {
+ int refcompat;
+
+ if (CExpr_IsLValue(expr) && IS_TYPE_CLASS(type2) && IS_TYPE_CLASS(expr->rtype)) {
+ refcompat = CExpr_IsReferenceCompatible(type2, 0, expr->rtype, 0);
+ if (refcompat > 0) {
+ if (refcompat == 2) {
+ CError_ASSERT(1668, IS_TYPE_CLASS(type2) && IS_TYPE_CLASS(expr->rtype));
+ expr = CExpr_DerivedToBase(expr, type2, qual2, pathcheckflag, 0, 1);
+ }
+ expr->flags = qual2 & ENODE_FLAG_QUALS;
+ return expr;
+ }
+
+ refcompat = CExpr_IsReferenceCompatible(expr->rtype, 0, type2, 0);
+ if (refcompat > 0) {
+ expr = CClass_ClassPointerCast(
+ getnodeaddress(expr, 0),
+ TYPE_CLASS(expr->rtype), TYPE_CLASS(type2),
+ 1, 1, pathcheckflag
+ );
+ CError_ASSERT(1680, IS_TYPE_POINTER_ONLY(expr->rtype));
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = type2;
+ expr->flags = qual2 & ENODE_FLAG_QUALS;
+ return expr;
+ }
+ }
+
+ if (IS_TYPE_CLASS(expr->rtype)) {
+ if ((expr = CExpr_UserConversion(expr, type2, qual2, NULL, 1, 0, 1)))
+ return expr;
+ }
+
+ return NULL;
+}
+
+static ENode *CExpr_BindToReference(ENode *expr, Type *type2, UInt32 qual2) {
+ UInt32 cv;
+ int refcompat;
+ ENode *tmp;
+
+ cv = CParser_GetCVTypeQualifiers(type2, qual2);
+
+ if (CExpr_IsLValue(expr)) {
+ refcompat = CExpr_IsReferenceCompatible(type2, qual2, expr->rtype, ENODE_QUALS(expr));
+ if (refcompat > 0) {
+ if (refcompat == 2) {
+ CError_ASSERT(1718, IS_TYPE_CLASS(type2) && IS_TYPE_CLASS(expr->rtype));
+ expr = CExpr_DerivedToBase(expr, type2, qual2, 1, 0, 1);
+ }
+ return getnodeaddress(expr, 0);
+ }
+ } else if (IS_TYPE_CLASS(type2) && IS_TYPE_CLASS(expr->rtype)) {
+ refcompat = CExpr_IsReferenceCompatible(type2, qual2, expr->rtype, ENODE_QUALS(expr));
+ if (refcompat > 0) {
+ if (refcompat == 2)
+ expr = CExpr_DerivedToBase(expr, type2, qual2, 1, 0, 1);
+ return getnodeaddress(expr, 0);
+ }
+ }
+
+ if (IS_TYPE_CLASS(expr->rtype)) {
+ if ((tmp = CExpr_UserConversion(expr, type2, qual2, NULL, 1, 0, 1)))
+ return getnodeaddress(tmp, 0);
+ }
+
+ if (!(cv & Q_CONST))
+ CError_Error(CErrorStr228);
+ if (cv & Q_VOLATILE)
+ CError_Error(CErrorStr259);
+
+ if (expr->rtype != type2)
+ expr = CExpr_Convert(expr, type2, qual2, 0, 1);
+
+ if (!CExpr_IsLValue(expr)) {
+ expr = CExpr_LValue(expr, 0, 0);
+ if (!ENODE_IS(expr, EINDIRECT))
+ expr = get_address_of_temp_copy(expr, 1);
+ else
+ expr = getnodeaddress(expr, 0);
+ } else {
+ expr = getnodeaddress(expr, 0);
+ }
+
+ return expr;
+}
+
+ENode *CExpr_Convert(ENode *expr, Type *type, UInt32 qual, Boolean isExplicit, Boolean flag2) {
+ UInt32 cv;
+ ENode *refExpr;
+ ENode *newExpr;
+ Type *typeCopy;
+ NameSpaceObjectList myList;
+
+ cv = qual & Q_CV;
+
+ if (copts.cpp_extensions && is_typesame(expr->rtype, type) && !ENODE_IS(expr, EOBJLIST)) {
+ expr = CExpr_RewriteConst(expr);
+ expr->rtype = type;
+ expr->flags &= ~ENODE_FLAG_QUALS;
+ expr->flags |= cv;
+ return expr;
+ }
+
+ if (type == TYPE(&stvoid)) {
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = type;
+ expr->flags = cv;
+ return expr;
+ }
+
+ if (IS_TYPE_REFERENCE(type)) {
+ if (isExplicit) {
+ refExpr = CExpr_ClassReferenceConversion(expr, TPTR_TARGET(type), qual, flag2);
+ if (refExpr)
+ return refExpr;
+
+ expr = getnodeaddress(expr, 0);
+ typeCopy = galloc(sizeof(TypePointer));
+ *TYPE_POINTER(typeCopy) = *TYPE_POINTER(type);
+ TPTR_QUAL(typeCopy) &= ~Q_REFERENCE;
+ expr = CExpr_Convert(expr, typeCopy, qual, 0, flag2);
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TPTR_TARGET(type);
+ expr->flags = cv;
+ return expr;
+ } else {
+ return CExpr_BindToReference(expr, TPTR_TARGET(type), qual);
+ }
+ }
+
+ if (
+ (IS_TYPE_ARRAY(expr->rtype) && !IS_TYPE_ARRAY(type)) ||
+ (IS_TYPE_FUNC(expr->rtype) && !IS_TYPE_FUNC(type))
+ )
+ {
+ expr = pointer_generation(expr);
+ } else {
+ expr = CExpr_RewriteConst(expr);
+ }
+
+ if (ENODE_IS(expr, EOBJLIST)) {
+ if (CExpr_OverloadFuncMatch(expr->data.objlist.list, expr->data.objlist.templargs, type, &refExpr))
+ return refExpr;
+ } else if (ENODE_IS(expr, EOBJREF) && IS_TEMPL_FUNC(expr->data.objref->type)) {
+ myList.next = NULL;
+ myList.object = OBJ_BASE(expr->data.objref);
+ if (CExpr_OverloadFuncMatch(&myList, NULL, type, &refExpr))
+ return refExpr;
+ } else if (IS_TYPE_CLASS(expr->rtype) || IS_TYPE_CLASS(type)) {
+ if (expr->rtype->size == 0)
+ CDecl_CompleteType(expr->rtype);
+
+ if (IS_TYPE_CLASS(type)) {
+ CanAllocObject(type);
+ if (!CClass_CopyConstructor(TYPE_CLASS(type)) || CClass_IsTrivialCopyClass(TYPE_CLASS(type))) {
+ if (expr->rtype == type)
+ return expr;
+
+ refExpr = CExpr_DerivedToBase(expr, type, qual, flag2, 0, 1);
+ if (refExpr)
+ return refExpr;
+ }
+ }
+
+ refExpr = CExpr_UserConversion(expr, type, qual, NULL, 1, isExplicit, 0);
+ if (refExpr) {
+ refExpr->flags = cv;
+ return refExpr;
+ }
+ } else if (!isExplicit && is_typesame(expr->rtype, type)) {
+ if (ENODE_IS(expr, EINDIRECT) && ENODE_QUALS(expr) != cv)
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = type;
+ expr->flags = cv;
+ return expr;
+ } else {
+ if (
+ copts.warn_implicitconv &&
+ !isExplicit &&
+ IS_TYPE_INT_OR_FLOAT(type) &&
+ IS_TYPE_INT_OR_FLOAT(expr->rtype)
+ )
+ CExpr_CheckArithmConversion(expr, type);
+
+ switch (type->type) {
+ case TYPEINT:
+ if (type == TYPE(&stbool)) {
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPEMEMBERPOINTER:
+ case TYPEPOINTER:
+ return CExpr_ConvertToBool(expr, isExplicit);
+ }
+ } else {
+ switch (expr->rtype->type) {
+ case TYPEENUM:
+ expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
+ case TYPEINT:
+ case TYPEFLOAT:
+ do_int_float_conversion:
+ if (
+ ENODE_IS(expr, ETYPCON) &&
+ expr->rtype->type == type->type &&
+ expr->rtype->size == type->size &&
+ is_unsigned(expr->rtype) == is_unsigned(type) &&
+ ENODE_QUALS(expr) == qual
+ )
+ {
+ expr->rtype = type;
+ expr->flags |= ENODE_FLAG_80;
+ return expr;
+ } else {
+ refExpr = promote(expr, type);
+ refExpr->flags = cv;
+ return refExpr;
+ }
+ break;
+ case TYPEPOINTER:
+ if (expr->rtype->size > type->size && copts.warn_ptr_int_conv)
+ CError_Warning(CErrorStr382);
+ if (ENODE_IS(expr, ETYPCON)) {
+ ENode *inner = expr->data.monadic;
+ if (ENODE_IS(inner, EINTCONST)) {
+ inner->rtype = type;
+ inner->flags = cv;
+ inner->data.intval = CExpr_IntConstConvert(type, TYPE(&stunsignedlong), inner->data.intval);
+ return inner;
+ }
+ }
+ if (type->size != 4) {
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = TYPE(&stunsignedlong);
+ }
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = type;
+ expr->flags = cv;
+ return expr;
+ }
+ }
+ break;
+
+ case TYPEFLOAT:
+ switch (expr->rtype->type) {
+ case TYPEENUM:
+ expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
+ case TYPEINT:
+ case TYPEFLOAT:
+ goto do_int_float_conversion;
+ }
+ break;
+
+ case TYPEENUM:
+ expr = CExpr_Convert(expr, TYPE_ENUM(type)->enumtype, qual, isExplicit, flag2);
+ if (!ENODE_IS(expr, EINTCONST))
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = type;
+ expr->flags = cv;
+ return expr;
+
+ case TYPEPOINTER:
+ switch (expr->rtype->type) {
+ case TYPEENUM:
+ expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
+ case TYPEINT:
+ if (expr->rtype->size != 4) {
+ if (!ENODE_IS(expr, EINTCONST))
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = TYPE(&stunsignedlong);
+ }
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = type;
+ expr->flags = cv;
+ return expr;
+
+ case TYPEPOINTER:
+ if (IS_TYPE_CLASS(TPTR_TARGET(expr->rtype)) && IS_TYPE_CLASS(TPTR_TARGET(type)))
+ expr = CExpr_SafeClassPointerCast(expr, TYPE_CLASS(TPTR_TARGET(expr->rtype)), TYPE_CLASS(TPTR_TARGET(type)), 1, flag2);
+ if (!ENODE_IS(expr, ETYPCON))
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = type;
+ expr->flags = cv;
+ return expr;
+ }
+ break;
+
+ case TYPEMEMBERPOINTER:
+ if (!IS_TYPE_MEMBERPOINTER(expr->rtype))
+ expr = CExpr_MemberPointerConversion(expr, TYPE_MEMBER_POINTER(type), 1);
+
+ if (IS_TYPE_MEMBERPOINTER(expr->rtype)) {
+ expr = PointerToMemberCast(expr, TYPE_MEMBER_POINTER(expr->rtype), TYPE_MEMBER_POINTER(type), flag2);
+ expr->flags = cv;
+ return expr;
+ }
+ break;
+ }
+ }
+
+ if (isExplicit) {
+ if ((newExpr = CodeGen_HandleTypeCast(expr, type, qual)))
+ return newExpr;
+ }
+
+ CError_Error(
+ isExplicit ? CErrorStr247 : CErrorStr209,
+ expr->rtype, ENODE_QUALS(expr),
+ type, qual);
+ return nullnode();
+}
+
+ENode *CExpr_AssignmentPromotion(ENode *expr, Type *type2, UInt32 qual2, Boolean flag) {
+ ImplicitConv result;
+
+ if (copts.old_argmatch)
+ return oldassignmentpromotion(expr, type2, qual2, flag);
+
+ if (ENODE_IS(expr, EMEMBER))
+ expr = getpointertomemberfunc(expr, type2, 1);
+
+ if (!CExpr_ImplicitConversionMatch(expr, type2, qual2, &result)) {
+ CError_Error(CErrorStr209, expr->rtype, ENODE_QUALS(expr), type2, qual2);
+ return nullnode();
+ }
+
+ return CExpr_Convert(expr, type2, qual2, 0, flag);
+}
+
+static Boolean CExpr_IsBetterMatch(Match *a, Match *b, int count) {
+ ImplicitConv *convA;
+ ImplicitConv *convB;
+ int i;
+ Boolean flag;
+
+ convA = a->conv;
+ convB = b->conv;
+ flag = 0;
+
+ if (convA->type != ICT_0 && convB->type != ICT_0) {
+ if (CExpr_IsBetterImplicitConv(convB, convA))
+ return 0;
+ if (CExpr_IsBetterImplicitConv(convA, convB))
+ flag = 1;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (CExpr_IsBetterImplicitConv(++convB, ++convA))
+ return 0;
+ if (CExpr_IsBetterImplicitConv(convA, convB))
+ flag = 1;
+ }
+
+ if (flag)
+ return 1;
+
+ if (b->object) {
+ CError_ASSERT(2165, IS_TYPE_FUNC(b->object->type));
+ if (b->object->u.func.inst) {
+ if (!a->object)
+ return 1;
+
+ CError_ASSERT(2169, IS_TYPE_FUNC(a->object->type));
+ if (!a->object->u.func.inst)
+ return 1;
+
+ CError_ASSERT(2174, a->specialfunc && b->specialfunc);
+ if (CTempl_FuncIsMoreSpecialized(a->specialfunc, b->specialfunc))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static Boolean CExpr_MatchArgs(Object *func, ENodeList *argexprs, ENode *expr, ImplicitConv *convs) {
+ FuncArg *args;
+ ENode *newExpr;
+ Type *type;
+
+ args = TYPE_FUNC(func->type)->args;
+
+ if (!(TYPE_FUNC(func->type)->flags & FUNC_METHOD)) {
+ convs->type = ICT_0;
+ } else if (TYPE_METHOD(func->type)->is_static) {
+ convs->type = ICT_0;
+ } else if (TYPE_FUNC(func->type)->flags & FUNC_IS_CTOR) {
+ convs->type = ICT_0;
+ args = args->next;
+ } else {
+ if (!expr)
+ return 0;
+
+ newExpr = lalloc(sizeof(ENode));
+ newExpr->type = EINTCONST;
+ newExpr->cost = 0;
+ newExpr->flags = expr->flags;
+ newExpr->rtype = CDecl_NewPointerType(expr->rtype);
+ newExpr->data.intval = cint64_zero;
+
+ if (func->datatype == DALIAS) {
+ CError_ASSERT(2231, func->u.alias.member);
+ type = CDecl_NewPointerType(func->u.alias.member->type);
+ } else {
+ type = args->type;
+ }
+
+ if (!CExpr_ImplicitConversionMatch(newExpr, type, args->qual, convs))
+ return 0;
+ args = args->next;
+ }
+
+ convs++;
+ while (1) {
+ if (!args || args->type == &stvoid) {
+ if (argexprs)
+ return 0;
+ else
+ return 1;
+ }
+
+ if (args == &elipsis || args == &oldstyle) {
+ while (argexprs) {
+ convs->type = ICT_1;
+ argexprs = argexprs->next;
+ convs++;
+ }
+ return 1;
+ }
+
+ if (!argexprs)
+ return args->dexpr != NULL;
+
+ if (!CExpr_ImplicitConversionMatch(argexprs->node, args->type, args->qual, convs))
+ return 0;
+
+ argexprs = argexprs->next;
+ args = args->next;
+ convs++;
+ }
+}
+
+static Object *CExpr_GetMatchObject(Match *match, HashNameNode *name) {
+ Object *object;
+ FuncArg *arg;
+ TypeFunc *tfunc;
+
+ if (match->object)
+ return match->object;
+
+ tfunc = lalloc(sizeof(TypeFunc));
+ memclrw(tfunc, sizeof(TypeFunc));
+ tfunc->type = TYPEFUNC;
+ tfunc->functype = &stvoid;
+
+ arg = lalloc(sizeof(FuncArg));
+ memclrw(arg, sizeof(FuncArg));
+ arg->type = match->type;
+ arg->qual = match->qual;
+ tfunc->args = arg;
+
+ if (match->type2) {
+ arg = lalloc(sizeof(FuncArg));
+ memclrw(arg, sizeof(FuncArg));
+ arg->type = match->type2;
+ arg->qual = match->qual2;
+ tfunc->args->next = arg;
+ }
+
+ object = lalloc(sizeof(Object));
+ memclrw(object, sizeof(Object));
+ object->name = name;
+ object->datatype = DFUNC;
+ object->nspace = cscope_root;
+ object->type = TYPE(tfunc);
+ return object;
+}
+
+static Match *CExpr_FindBestMatch(Match *matches, int count, HashNameNode *name, ObjectList **outList, ENodeList *argExprs) {
+ Match *scan;
+ Match *best;
+ ObjectList *listHead;
+ ObjectList *list;
+
+ best = matches;
+ for (scan = matches->next; scan; scan = scan->next) {
+ if (CExpr_IsBetterMatch(scan, best, count))
+ best = scan;
+ }
+
+ for (scan = matches, listHead = NULL; scan; scan = scan->next) {
+ if (scan != best && !CExpr_IsBetterMatch(best, scan, count)) {
+ list = lalloc(sizeof(ObjectList));
+ list->next = listHead;
+ list->object = CExpr_GetMatchObject(scan, name);
+ listHead = list;
+ }
+ }
+
+ if (!outList) {
+ if (listHead)
+ CError_OverloadedFunctionError(CExpr_GetMatchObject(best, name), listHead);
+ } else {
+ *outList = listHead;
+ }
+
+ return best;
+}
+
+void CExpr_FuncArgMatch(NameSpaceObjectList *list, TemplArg *templargs, ENodeList *argexprs, Match13 *match13, ENode *expr, Boolean flag) {
+ NameSpaceObjectList *i;
+ NameSpaceObjectList *j;
+ Match *match;
+ Match *matches;
+ Object *object;
+ Object *object2;
+ Object *specialfunc;
+ ENodeList *argscan;
+ int argcount;
+
+ for (argscan = argexprs, argcount = 0; argscan; argscan = argscan->next) {
+ CDecl_CompleteType(argscan->node->rtype);
+ argcount++;
+ }
+
+ matches = NULL;
+ match = lalloc(sizeof(Match) + ((argcount - 2) * sizeof(ImplicitConv)));
+
+ for (i = list; i; i = i->next) {
+ object = OBJECT(i->object);
+ if (
+ object->otype == OT_OBJECT &&
+ IS_TYPE_FUNC(object->type) &&
+ (!flag || !(object->qual & Q_EXPLICIT))
+ )
+ {
+ if (object->datatype == DALIAS && (TYPE_FUNC(object->type)->flags & FUNC_METHOD)) {
+ for (j = list; j; j = j->next) {
+ if (j == i)
+ continue;
+
+ object2 = OBJECT(j->object);
+ if (
+ object2->otype == OT_OBJECT &&
+ IS_TYPE_METHOD(object2->type) &&
+ (TYPE_FUNC(object2->type)->flags & FUNC_FLAGS_CV) == (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_CV)
+ )
+ {
+ FuncArg *argsA;
+ FuncArg *argsB;
+ argsA = TYPE_FUNC(object->type)->args;
+ if (argsA && !TYPE_METHOD(object->type)->is_static)
+ argsA = argsA->next;
+ argsB = TYPE_FUNC(object2->type)->args;
+ if (argsB && !TYPE_METHOD(object2->type)->is_static)
+ argsB = argsB->next;
+ if (is_arglistsame(argsA, argsB))
+ break;
+ }
+ }
+
+ if (j)
+ continue;
+ }
+
+ if (TYPE_FUNC(object->type)->flags & FUNC_IS_TEMPL) {
+ specialfunc = object;
+ object = CTempl_DeduceFromFunctionCall(object, templargs, argexprs);
+ if (!object)
+ continue;
+ } else {
+ if (templargs)
+ continue;
+ specialfunc = NULL;
+ }
+
+ if (CExpr_MatchArgs(object, argexprs, expr, match->conv)) {
+ match->object = object;
+ match->specialfunc = specialfunc;
+ match->next = matches;
+ matches = match;
+ match = lalloc(sizeof(Match) + ((argcount - 2) * sizeof(ImplicitConv)));
+ }
+ }
+ }
+
+ if (matches) {
+ matches = CExpr_FindBestMatch(matches, argcount, NULL, &match13->list, argexprs);
+ match13->obj = matches->object;
+ }
+}
+
+static ConversionTypeList *CExpr_BuildConversionTypeList(ENode *expr) {
+ ConversionTypeList *first;
+ ConversionTypeList *list;
+ Object *object;
+ Type *type;
+ ConversionIterator convIter;
+
+ if (!IS_TYPE_CLASS(expr->rtype)) {
+ first = lalloc(sizeof(ConversionTypeList));
+ first->next = NULL;
+ first->func = NULL;
+ first->type = expr->rtype;
+ first->qual = ENODE_QUALS(expr);
+ if (IS_TYPE_ENUM(first->type))
+ first->qual = 0;
+ } else {
+ first = NULL;
+ CExpr_ConversionIteratorInit(&convIter, TYPE_CLASS(expr->rtype));
+ while ((object = CExpr_ConversionIteratorNext(&convIter))) {
+ type = TYPE_FUNC(object->type)->functype;
+ if (IS_TYPE_REFERENCE(type))
+ type = TPTR_TARGET(type);
+
+ if (!IS_TYPE_CLASS(type)) {
+ list = lalloc(sizeof(ConversionTypeList));
+ list->next = first;
+ list->func = object;
+ list->type = type;
+ list->qual = TYPE_FUNC(object->type)->qual & Q_CV;
+ first = list;
+ }
+ }
+ }
+
+ return first;
+}
+
+static Type *CExpr_NextPromotedIntegralType(int *p) {
+ switch (++(*p)) {
+ case 1: return TYPE(&stsignedint);
+ case 2: return TYPE(&stunsignedint);
+ case 3: return TYPE(&stsignedlong);
+ case 4: return TYPE(&stunsignedlong);
+ case 5:
+ if (copts.longlong)
+ return TYPE(&stsignedlonglong);
+ else
+ return NULL;
+ case 6:
+ if (copts.longlong)
+ return TYPE(&stunsignedlonglong);
+ else
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static Type *CExpr_NextArithmeticType(int *p) {
+ switch (++(*p)) {
+ case 1: return TYPE(&stbool);
+ case 2: return TYPE(&stchar);
+ case 3: return TYPE(&stsignedchar);
+ case 4: return TYPE(&stunsignedchar);
+ case 5: return TYPE(&stwchar);
+ case 6: return TYPE(&stsignedshort);
+ case 7: return TYPE(&stunsignedshort);
+ case 8: return TYPE(&stsignedint);
+ case 9: return TYPE(&stunsignedint);
+ case 10: return TYPE(&stsignedlong);
+ case 11: return TYPE(&stunsignedlong);
+ case 12: return TYPE(&stfloat);
+ case 13: return TYPE(&stdouble);
+ case 14: return TYPE(&stlongdouble);
+ case 15:
+ if (copts.longlong)
+ return TYPE(&stsignedlonglong);
+ else
+ return NULL;
+ case 16:
+ if (copts.longlong)
+ return TYPE(&stunsignedlonglong);
+ else
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static Type *CExpr_NextPromotedArithmeticType(int *p) {
+ switch (++(*p)) {
+ case 1: return TYPE(&stsignedint);
+ case 2: return TYPE(&stunsignedint);
+ case 3: return TYPE(&stsignedlong);
+ case 4: return TYPE(&stunsignedlong);
+ case 5: return TYPE(&stdouble);
+ case 6: return TYPE(&stlongdouble);
+ case 7:
+ if (copts.longlong)
+ return TYPE(&stsignedlonglong);
+ else
+ return NULL;
+ case 8:
+ if (copts.longlong)
+ return TYPE(&stunsignedlonglong);
+ else
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static Match *CExpr_MatchBuiltin(Match *matches, ENode *left, Type *leftType, UInt32 leftQual, ENode *right, Type *rightType, UInt32 rightQual) {
+ Match *scan;
+ Match mymatch;
+
+ if (CExpr_ImplicitConversionMatch(left, leftType, leftQual, &mymatch.conv[0])) {
+ if (!right || CExpr_ImplicitConversionMatch(right, rightType, rightQual, &mymatch.conv[1])) {
+ if (right) {
+ for (scan = matches; scan; scan = scan->next) {
+ if (
+ !scan->object &&
+ is_typesame(scan->type, leftType) &&
+ scan->qual == leftQual &&
+ is_typesame(scan->type2, rightType) &&
+ scan->qual2 == rightQual
+ )
+ return matches;
+ }
+ }
+
+ mymatch.next = matches;
+ mymatch.object = NULL;
+ mymatch.specialfunc = NULL;
+ mymatch.type = leftType;
+ mymatch.qual = leftQual;
+ mymatch.type2 = rightType;
+ mymatch.qual2 = rightQual;
+
+ matches = lalloc(sizeof(Match));
+ *matches = mymatch;
+ }
+ }
+
+ return matches;
+}
+
+static Match *CExpr_CheckIncDecBuiltin(Match *matches, short token, ENode *expr1, ENode *expr2) {
+ Object *object;
+ Type *type;
+ TypeFunc *tfunc;
+ ConversionIterator convIter;
+
+ if (IS_TYPE_CLASS(expr1->rtype)) {
+ CExpr_ConversionIteratorInit(&convIter, TYPE_CLASS(expr1->rtype));
+ while ((object = CExpr_ConversionIteratorNext(&convIter))) {
+ tfunc = TYPE_FUNC(object->type);
+ if (IS_TYPE_REFERENCE(tfunc->functype)) {
+ type = TPTR_TARGET(tfunc->functype);
+ switch (type->type) {
+ case TYPEINT:
+ if (type == TYPE(&stbool) && token == TK_DECREMENT)
+ break;
+ case TYPEFLOAT:
+ case TYPEPOINTER:
+ if (!CParser_IsConst(type, tfunc->qual)) {
+ matches = CExpr_MatchBuiltin(
+ matches,
+ expr1, type, tfunc->qual,
+ expr2, expr2 ? TYPE(&stsignedint) : NULL, 0
+ );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return matches;
+}
+
+static Match *CExpr_CheckUnaryBuiltin(Match *matches, short token, ENode *expr) {
+ ConversionTypeList *typelist;
+ Type *type;
+ int typenum;
+
+ switch (token) {
+ case TK_INCREMENT:
+ case TK_DECREMENT:
+ return CExpr_CheckIncDecBuiltin(matches, token, expr, NULL);
+
+ case '!':
+ matches = CExpr_MatchBuiltin(matches, expr, TYPE(&stbool), 0, NULL, NULL, 0);
+ break;
+
+ case '~':
+ typenum = 0;
+ while ((type = CExpr_NextPromotedIntegralType(&typenum))) {
+ matches = CExpr_MatchBuiltin(matches, expr, type, 0, NULL, NULL, 0);
+ }
+ break;
+
+ case '*':
+ case '+':
+ for (typelist = CExpr_BuildConversionTypeList(expr); typelist; typelist = typelist->next) {
+ if (IS_TYPE_POINTER_ONLY(typelist->type))
+ matches = CExpr_MatchBuiltin(matches, expr, typelist->type, typelist->qual, NULL, NULL, 0);
+ }
+ if (token != '+')
+ break;
+
+ case '-':
+ typenum = 0;
+ while ((type = CExpr_NextPromotedArithmeticType(&typenum))) {
+ matches = CExpr_MatchBuiltin(matches, expr, type, 0, NULL, NULL, 0);
+ }
+ break;
+ }
+
+ return matches;
+}
+
+static Match *CExpr_CheckBinaryBuiltin(Match *matches, ENode *left, short token, ENode *right) {
+ int typenum1;
+ int typenum2;
+ Type *type1;
+ Type *type2;
+ Type *ptrdiff;
+ Boolean allowPtrDiffOnRight;
+ Boolean allowPtrCV;
+ Boolean allowPtrDiffOnLeft;
+ Boolean allowMemberPtrs;
+ Boolean allowEnum;
+ ConversionTypeList *leftList;
+ ConversionTypeList *rightList;
+ ConversionTypeList *scan;
+
+ switch (token) {
+ case TK_INCREMENT:
+ case TK_DECREMENT:
+ return CExpr_CheckIncDecBuiltin(matches, token, left, right);
+
+ case '*':
+ case '+':
+ case '-':
+ case '/':
+ case ':':
+ case '<':
+ case '>':
+ case TK_LOGICAL_EQ:
+ case TK_LOGICAL_NE:
+ case TK_LESS_EQUAL:
+ case TK_GREATER_EQUAL:
+ typenum1 = 0;
+ while ((type1 = CExpr_NextPromotedArithmeticType(&typenum1))) {
+ typenum2 = 0;
+ while ((type2 = CExpr_NextPromotedArithmeticType(&typenum2))) {
+ matches = CExpr_MatchBuiltin(matches, left, type1, 0, right, type2, 0);
+ }
+ }
+ break;
+
+ case '%':
+ case '&':
+ case '^':
+ case '|':
+ case TK_SHL:
+ case TK_SHR:
+ typenum1 = 0;
+ while ((type1 = CExpr_NextPromotedIntegralType(&typenum1))) {
+ typenum2 = 0;
+ while ((type2 = CExpr_NextPromotedIntegralType(&typenum2))) {
+ matches = CExpr_MatchBuiltin(matches, left, type1, 0, right, type2, 0);
+ }
+ }
+ return matches;
+
+ case TK_LOGICAL_OR:
+ case TK_LOGICAL_AND:
+ return CExpr_MatchBuiltin(matches, left, TYPE(&stbool), 0, right, TYPE(&stbool), 0);
+ }
+
+ allowEnum = 0;
+ allowMemberPtrs = 0;
+ allowPtrCV = 0;
+ allowPtrDiffOnLeft = 0;
+ allowPtrDiffOnRight = 0;
+
+ switch (token) {
+ case '+':
+ case '[':
+ allowPtrDiffOnLeft = 1;
+ allowPtrDiffOnRight = 1;
+ break;
+ case '-':
+ allowPtrCV = 1;
+ allowPtrDiffOnRight = 1;
+ break;
+ case ':':
+ case TK_LOGICAL_EQ:
+ case TK_LOGICAL_NE:
+ allowMemberPtrs = 1;
+ case '<':
+ case '>':
+ case TK_LESS_EQUAL:
+ case TK_GREATER_EQUAL:
+ allowPtrCV = 1;
+ allowEnum = 1;
+ break;
+ default:
+ return matches;
+ }
+
+ leftList = CExpr_BuildConversionTypeList(left);
+ rightList = CExpr_BuildConversionTypeList(right);
+ ptrdiff = CABI_GetPtrDiffTType();
+
+ for (scan = leftList; ; scan = scan->next) {
+ if (!scan) {
+ scan = rightList;
+ if (!rightList)
+ break;
+ rightList = NULL;
+ }
+
+ type1 = scan->type;
+ if (IS_TYPE_REFERENCE(type1))
+ type1 = TPTR_TARGET(type1);
+
+ switch (type1->type) {
+ case TYPEENUM:
+ if (allowEnum)
+ matches = CExpr_MatchBuiltin(matches, left, type1, scan->qual, right, type1, scan->qual);
+ break;
+
+ case TYPEPOINTER:
+ if (allowPtrDiffOnRight)
+ matches = CExpr_MatchBuiltin(matches, left, type1, scan->qual, right, ptrdiff, 0);
+ if (allowPtrDiffOnLeft)
+ matches = CExpr_MatchBuiltin(matches, left, ptrdiff, 0, right, type1, scan->qual);
+ if (allowPtrCV) {
+ if (IS_TYPE_POINTER_ONLY(TPTR_TARGET(type1))) {
+ type2 = galloc(sizeof(TypePointer));
+ *TYPE_POINTER(type2) = *TYPE_POINTER(type1);
+ TPTR_QUAL(type2) |= Q_CONST | Q_VOLATILE;
+ matches = CExpr_MatchBuiltin(matches, left, type2, scan->qual, right, type2, scan->qual);
+ } else {
+ matches = CExpr_MatchBuiltin(matches, left, type1, Q_CONST | Q_VOLATILE, right, type1, Q_CONST | Q_VOLATILE);
+ }
+ }
+ break;
+
+ case TYPEMEMBERPOINTER:
+ if (allowMemberPtrs)
+ matches = CExpr_MatchBuiltin(matches, left, type1, scan->qual, right, type1, scan->qual);
+ break;
+ }
+ }
+
+ return matches;
+}
+
+static Boolean CExpr_MatchOperands(ENode *left, Type *leftType, UInt32 leftQual, ENode *right, Type *rightType, UInt32 rightQual, ImplicitConv *twoResults, Boolean flag) {
+ if (flag) {
+ if (!CExpr_StandardConversionMatch(left, leftType, leftQual, 1, &twoResults[0].u.ic3.standardConv))
+ return 0;
+ twoResults[0].type = ICT_3;
+ } else {
+ if (!CExpr_ImplicitConversionMatch(left, leftType, leftQual, &twoResults[0]))
+ return 0;
+ }
+
+ if (right) {
+ if (!CExpr_ImplicitConversionMatch(right, rightType, rightQual, &twoResults[1]))
+ return 0;
+ }
+
+ return 1;
+}
+
+Boolean CExpr_CondOperatorMatch(ENode *left, ENode *right, Conversion *conv) {
+ Match *match;
+
+ if ((match = CExpr_CheckBinaryBuiltin(NULL, left, ':', right))) {
+ match = CExpr_FindBestMatch(match, 1, GetHashNameNode("operator?:"), NULL, NULL);
+ CError_ASSERT(2931, !match->object);
+
+ conv->x0 = NULL;
+ conv->left = CExpr_Convert(left, match->type, match->qual, 0, 1);
+ conv->right = CExpr_Convert(right, match->type2, match->qual2, 0, 1);
+ return 1;
+ }
+
+ return 0;
+}
+
+Boolean CExpr_OperatorMatch(short token, ENode *left, ENode *right, Conversion *conv) {
+ HashNameNode *name;
+ ENodeList *argExprs;
+ BClassList *path;
+ int hasArg;
+ Match *matches;
+ Object *object;
+ Object *specialfunc;
+ NameSpaceObjectList *list;
+ Type *leftType;
+ UInt32 leftQual;
+ Type *rightType;
+ UInt32 rightQual;
+ NameResult pr;
+ NameSpaceObjectList myList;
+ Match myMatch;
+
+ if (!IS_TYPE_CLASS(left->rtype)) {
+ if (!IS_TYPE_ENUM(left->rtype)) {
+ if (!right || !(IS_TYPE_CLASS(right->rtype) || IS_TYPE_ENUM(right->rtype)))
+ return 0;
+ }
+ } else {
+ CDecl_CompleteType(left->rtype);
+ }
+
+ name = CMangler_OperatorName(token);
+ path = NULL;
+
+ argExprs = lalloc(sizeof(ENodeList));
+ argExprs->node = left;
+ if (right) {
+ argExprs->next = lalloc(sizeof(ENodeList));
+ argExprs->next->node = right;
+ argExprs->next->next = NULL;
+ hasArg = 1;
+ } else {
+ argExprs->next = NULL;
+ hasArg = 0;
+ }
+
+ matches = NULL;
+
+ if (IS_TYPE_CLASS(left->rtype) && CScope_FindClassMemberObject(TYPE_CLASS(left->rtype), &pr, name)) {
+ if (token != '=' || (pr.bcl_18->type == left->rtype && !pr.bcl_18->next)) {
+ if (pr.obj_10) {
+ myList.next = NULL;
+ myList.object = pr.obj_10;
+ pr.nsol_14 = &myList;
+ } else {
+ CError_ASSERT(3009, pr.nsol_14);
+ }
+
+ for (list = pr.nsol_14; list; list = list->next) {
+ object = OBJECT(list->object);
+ if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) {
+ if (TYPE_FUNC(object->type)->flags & FUNC_IS_TEMPL) {
+ specialfunc = object;
+ object = CTempl_DeduceFromFunctionCall(object, NULL, argExprs->next);
+ if (!object)
+ continue;
+ } else {
+ specialfunc = NULL;
+ }
+
+ leftType = CExpr_GetImplictObjectParamType(object, &leftQual);
+ if (right) {
+ if (!CExpr_HasNParams(object, 1))
+ continue;
+ rightType = CExpr_GetParamType(object, 0, &rightQual);
+ } else {
+ if (!CExpr_HasNParams(object, 0))
+ continue;
+ }
+
+ if (CExpr_MatchOperands(left, leftType, leftQual, right, rightType, rightQual, myMatch.conv, 1)) {
+ myMatch.object = object;
+ myMatch.specialfunc = specialfunc;
+ myMatch.next = matches;
+ matches = lalloc(sizeof(Match));
+ *matches = myMatch;
+ path = pr.bcl_18;
+ }
+ }
+ }
+ }
+ }
+
+ if (CScope_FindNonClassObject(cscope_current, &pr, name)) {
+ if (pr.obj_10) {
+ myList.next = NULL;
+ myList.object = pr.obj_10;
+ pr.nsol_14 = &myList;
+ }
+ } else {
+ pr.nsol_14 = NULL;
+ }
+
+ if (copts.arg_dep_lookup)
+ pr.nsol_14 = CScope_ArgumentDependentNameLookup(pr.nsol_14, name, argExprs, 1);
+
+ for (list = pr.nsol_14; list; list = list->next) {
+ object = OBJECT(list->object);
+ if (object->otype == OT_OBJECT && IS_TYPE_NONMETHOD(object->type)) {
+ if (TYPE_FUNC(object->type)->flags & FUNC_IS_TEMPL) {
+ specialfunc = object;
+ object = CTempl_DeduceFromFunctionCall(object, NULL, argExprs);
+ if (!object)
+ continue;
+ } else {
+ specialfunc = NULL;
+ }
+
+ leftType = CExpr_GetParamType(object, 0, &leftQual);
+ if (right) {
+ if (!CExpr_HasNParams(object, 2))
+ continue;
+ rightType = CExpr_GetParamType(object, 1, &rightQual);
+ } else {
+ if (!CExpr_HasNParams(object, 1))
+ continue;
+ }
+
+ if (CExpr_MatchOperands(left, leftType, leftQual, right, rightType, rightQual, myMatch.conv, 0)) {
+ myMatch.object = object;
+ myMatch.specialfunc = specialfunc;
+ myMatch.next = matches;
+ matches = lalloc(sizeof(Match));
+ *matches = myMatch;
+ }
+ }
+ }
+
+ if (right)
+ matches = CExpr_CheckBinaryBuiltin(matches, left, token, right);
+ else
+ matches = CExpr_CheckUnaryBuiltin(matches, token, left);
+
+ if (matches) {
+ conv->x0 = NULL;
+ conv->left = NULL;
+ conv->right = NULL;
+
+ matches = CExpr_FindBestMatch(matches, hasArg, name, NULL, argExprs);
+ object = matches->object;
+ if (!object) {
+ if (IS_TYPE_CLASS(left->rtype))
+ conv->left = CExpr_Convert(left, matches->type, matches->qual, 0, 1);
+ else
+ conv->left = left;
+
+ if (right) {
+ if (IS_TYPE_CLASS(right->rtype))
+ conv->right = CExpr_Convert(right, matches->type2, matches->qual2, 0, 1);
+ else
+ conv->right = right;
+ }
+
+ return 1;
+ }
+
+ if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(object->type))) {
+ CError_ASSERT(3125, path);
+ left = CExpr_GenericFuncCall(path, argExprs->node, 0, object, NULL, NULL, argExprs->next, 0, 0, 1);
+ } else {
+ left = CExpr_GenericFuncCall(NULL, NULL, 0, object, NULL, NULL, argExprs, 0, 0, 1);
+ }
+
+ conv->x0 = checkreference(left);
+ return 1;
+ }
+
+ return 0;
+}
+
+static ENode *CExpr_ClassCopyInit(TypeClass *tclass, ENode *expr1, ENode *expr2) {
+ Object *best;
+ NameSpaceObjectList *list;
+ ObjectList *objlist;
+ ObjectList *objlistEntry;
+ ENodeList *argExprs;
+ FuncArg *arg;
+ Type *type;
+ Object *object;
+ ImplicitConv bestConv;
+ ImplicitConv conv;
+ BClassList path;
+ ConversionIterator convIter;
+
+ best = NULL;
+ objlist = NULL;
+
+ for (list = CClass_Constructor(tclass); list; list = list->next) {
+ object = OBJECT(list->object);
+ if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type) && !(object->qual & Q_EXPLICIT)) {
+ arg = TYPE_FUNC(object->type)->args;
+
+ CError_ASSERT(3199, arg);
+ arg = arg->next;
+
+ if (tclass->flags & CLASS_HAS_VBASES) {
+ CError_ASSERT(3203, arg);
+ arg = arg->next;
+ }
+
+ if (
+ arg &&
+ arg != &elipsis &&
+ (!arg->next || arg->next->dexpr) &&
+ CExpr_ImplicitConversionMatch(expr2, arg->type, arg->qual, &conv)
+ )
+ {
+ if (!best || CExpr_IsBetterImplicitConv(&conv, &bestConv)) {
+ best = object;
+ bestConv = conv;
+ objlist = NULL;
+ } else if (!CExpr_IsBetterImplicitConv(&bestConv, &conv)) {
+ objlistEntry = lalloc(sizeof(ObjectList));
+ objlistEntry->next = objlist;
+ objlistEntry->object = object;
+ objlist = objlistEntry;
+ }
+ }
+ }
+ }
+
+ if (IS_TYPE_CLASS(expr2->rtype)) {
+ CExpr_ConversionIteratorInit(&convIter, TYPE_CLASS(expr2->rtype));
+ while ((object = CExpr_ConversionIteratorNext(&convIter))) {
+ type = TYPE_FUNC(object->type)->functype;
+ if (IS_TYPE_REFERENCE(type))
+ type = TPTR_TARGET(type);
+
+ if (
+ IS_TYPE_CLASS(type) &&
+ (tclass == TYPE_CLASS(type) || CClass_IsBaseClass(tclass, TYPE_CLASS(type), NULL, 0, 0))
+ )
+ {
+ CError_ASSERT(3248, TYPE_FUNC(object->type)->args &&
+ IS_TYPE_POINTER_ONLY(TYPE_FUNC(object->type)->args->type));
+
+ type = galloc(sizeof(TypePointer));
+ *TYPE_POINTER(type) = *TYPE_POINTER(TYPE_FUNC(object->type)->args->type);
+ TPTR_QUAL(type) = Q_REFERENCE;
+ if (CExpr_ImplicitConversionMatch(expr2, type, TYPE_FUNC(object->type)->args->qual, &conv)) {
+ if (!best || CExpr_IsBetterImplicitConv(&conv, &bestConv)) {
+ best = object;
+ bestConv = conv;
+ objlist = NULL;
+ } else if (!CExpr_IsBetterImplicitConv(&bestConv, &conv)) {
+ objlistEntry = lalloc(sizeof(ObjectList));
+ objlistEntry->next = objlist;
+ objlistEntry->object = object;
+ objlist = objlistEntry;
+ }
+ }
+ }
+ }
+ }
+
+ if (objlist)
+ CError_OverloadedFunctionError(best, objlist);
+
+ if (!best) {
+ CError_Error(CErrorStr209, expr2->rtype, ENODE_QUALS(expr2), tclass, 0);
+ return expr1;
+ }
+
+ CError_ASSERT(3284, IS_TYPE_POINTER_ONLY(expr1->rtype));
+
+ expr1 = makemonadicnode(expr1, EINDIRECT);
+ expr1->rtype = TYPE(tclass);
+
+ argExprs = lalloc(sizeof(ENodeList));
+ argExprs->node = expr2;
+ if (tclass->flags & CLASS_HAS_VBASES) {
+ argExprs->next = lalloc(sizeof(ENodeList));
+ argExprs->next->next = NULL;
+ argExprs->next->node = intconstnode(TYPE(&stsignedshort), 1);
+ } else {
+ argExprs->next = NULL;
+ }
+
+ path.next = NULL;
+ path.type = TYPE(tclass);
+ expr1 = CExpr_GenericFuncCall(&path, expr1, 0, best, NULL, NULL, argExprs, 0, 0, 1);
+
+ if (ENODE_IS2(expr1, EFUNCCALL, EFUNCCALLP))
+ expr1->rtype = CDecl_NewPointerType(TYPE(tclass));
+
+ expr1 = makemonadicnode(expr1, EINDIRECT);
+ expr1->rtype = TYPE(tclass);
+ return expr1;
+}
diff --git a/compiler_and_linker/FrontEnd/C/CFunc.c b/compiler_and_linker/FrontEnd/C/CFunc.c
new file mode 100644
index 0000000..38cfab3
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CFunc.c
@@ -0,0 +1,3224 @@
+#include "compiler/CFunc.h"
+#include "compiler/CABI.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CException.h"
+#include "compiler/CExpr.h"
+#include "compiler/CInit.h"
+#include "compiler/CInline.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CSOM.h"
+#include "compiler/CTemplateTools.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/Exceptions.h"
+#include "compiler/FuncLevelAsmPPC.h"
+#include "compiler/InlineAsmPPC.h"
+#include "compiler/ObjGenMachO.h"
+#include "compiler/Switch.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/types.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+struct CFuncSave {
+ CScopeSave scope;
+ ObjectList *arguments;
+ ObjectList *locals;
+ CLabel *labels;
+ Statement *curstmt;
+ DeclBlock *firstblock;
+ DeclBlock *currentblock;
+ ExceptionAction *cexcept_dobjstack;
+ CLabel *sinit_label;
+ ENode *ainit_expr;
+ CtorChain *ctor_chain;
+ ParserTryBlock *trychain;
+ TempNodeCB cinit_tempnodefunc;
+ HashNameNode *tkidentifier;
+ Object *sinit_first_object;
+ FileOffsetInfo cparser_fileoffset;
+ TStreamElement symdecltoken;
+ SInt32 functionbodyoffset;
+ HashNameNode *functionbodypath;
+ SInt32 symdecloffset;
+ SInt32 symdeclend;
+ SInt32 sourceoffset;
+ HashNameNode *sourcefilepath;
+ SInt32 curstmtvalue;
+ NameObjCheckCB name_obj_check;
+ FuncArg *check_arglist;
+ short blockcount;
+ short localcount;
+ short tk;
+ AccessType global_access;
+ Boolean cexcept_hasdobjects;
+ Boolean ainit_only_one;
+ Boolean cfunc_is_extern_c;
+ Boolean temp_reference_init;
+};
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+FuncArg elipsis;
+FuncArg oldstyle;
+ObjectList *arguments;
+ObjectList *locals;
+short localcount;
+SInt32 curstmtvalue;
+SInt32 sourceoffset;
+HashNameNode *sourcefilepath;
+SInt32 functionbodyoffset;
+HashNameNode *functionbodypath;
+InitExpr *init_expressions;
+CLabel *Labels;
+CtorChain *ctor_chain;
+Statement *curstmt;
+static short temp_destructor_object_regmem;
+static short temp_destructor_objects;
+static short temp_expression_has_conditionals;
+static DeclBlock *firstblock;
+static DeclBlock *currentblock;
+static short blockcount;
+static Object *sinit_first_object;
+static CLabel *sinit_label;
+static Boolean ainit_only_one;
+static ENode *ainit_expr;
+static FuncArg *check_arglist;
+static Boolean cfunc_is_extern_c;
+static short cfunc_staticvarcount;
+static void *destroyobjects;
+static Boolean cfunc_hasdtortemp;
+
+// forward decls
+static void statement(DeclThing *thing);
+
+static void CFunc_LoopIncrement(void) {
+ if (curstmtvalue >= 0x1000) {
+ if (curstmtvalue >= 0xF000)
+ curstmtvalue++;
+ else
+ curstmtvalue += 0x1000;
+ } else {
+ curstmtvalue <<= 3;
+ }
+}
+
+static void CFunc_LoopDecrement(void) {
+ if (curstmtvalue > 0x1000) {
+ if (curstmtvalue > 0xF000)
+ curstmtvalue--;
+ else
+ curstmtvalue -= 0x1000;
+ } else {
+ curstmtvalue >>= 3;
+ }
+
+ if (curstmtvalue < 1)
+ curstmtvalue = 1;
+}
+
+DeclBlock *CFunc_NewDeclBlock(void) {
+ DeclBlock *block;
+ NameSpace *nspace;
+
+ block = lalloc(sizeof(DeclBlock));
+ if (firstblock) {
+ currentblock->next = block;
+ currentblock = block;
+ } else {
+ firstblock = block;
+ currentblock = block;
+ }
+
+ block->index = blockcount++;
+ block->parent_nspace = cscope_current;
+ block->dobjstack = cexcept_dobjstack;
+
+ nspace = CScope_NewListNameSpace(NULL, 0);
+ nspace->parent = cscope_current;
+ cscope_current = nspace;
+
+ return block;
+}
+
+void CFunc_RestoreBlock(DeclBlock *block) {
+ if (curstmt && curstmt->dobjstack != cexcept_dobjstack) {
+ Statement *stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = nullnode();
+ }
+
+ cscope_current = block->parent_nspace;
+ cexcept_dobjstack = block->dobjstack;
+}
+
+void CFunc_SetupLocalVarInfo(Object *obj) {
+ obj->u.var.info = CodeGen_GetNewVarInfo();
+ obj->u.var.info->func = cscope_currentfunc;
+
+ if (obj->sclass == TK_REGISTER) {
+ if (!copts.optimizesize)
+ obj->u.var.info->usage = 100;
+ else
+ obj->u.var.info->usage = 5;
+ }
+
+ if (obj->type && is_volatile_object(obj))
+ obj->u.var.info->noregister = 1;
+}
+
+static void adjustargumenttype(DeclInfo *declinfo) {
+ switch (declinfo->thetype->type) {
+ case TYPECLASS:
+ if (TYPE_CLASS(declinfo->thetype)->sominfo) {
+ CError_Error(CErrorStr284);
+ declinfo->thetype = TYPE(&stsignedint);
+ }
+ break;
+ case TYPEFUNC:
+ makethetypepointer(declinfo, 0);
+ return;
+ case TYPEARRAY:
+ declinfo->thetype = CDecl_NewPointerType(TPTR_TARGET(declinfo->thetype));
+ return;
+ case TYPETEMPLATE:
+ if (TYPE_TEMPLATE(declinfo->thetype)->dtype == TEMPLDEP_ARRAY)
+ declinfo->thetype = CDecl_NewPointerType(TYPE_TEMPLATE(declinfo->thetype)->u.array.type);
+ return;
+ }
+
+ if (!CanCreateObject(declinfo->thetype))
+ declinfo->thetype = TYPE(&stsignedint);
+}
+
+static FuncArg *CFunc_IsInArgList(FuncArg *list, HashNameNode *name) {
+ while (list) {
+ if (name == list->name)
+ return list;
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+static Object *CFunc_IsInObjList(ObjectList *list, HashNameNode *name) {
+ while (list) {
+ if (name == list->object->name)
+ return list->object;
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+static void CFunc_AppendArg(FuncArg **list, FuncArg *arg) {
+ FuncArg *tail;
+
+ if ((tail = *list)) {
+ while (tail->next)
+ tail = tail->next;
+ tail->next = arg;
+ } else {
+ *list = arg;
+ }
+}
+
+static void identifier_list(DeclInfo *declinfo) {
+ FuncArg *arg;
+
+ declinfo->x45 = 1;
+
+ while (1) {
+ if (tk != TK_IDENTIFIER) {
+ CError_Error(CErrorStr121);
+ } else {
+ if (CFunc_IsInArgList(declinfo->x18, tkidentifier))
+ CError_Error(CErrorStr122, tkidentifier->name);
+
+ arg = CParser_NewFuncArg();
+ arg->name = tkidentifier;
+ CFunc_AppendArg(&declinfo->x18, arg);
+ declinfo->x44 = 1;
+ }
+
+ if ((tk = lex()) != ',')
+ break;
+ tk = lex();
+ }
+}
+
+static Boolean defarg_name_obj_check(HashNameNode *name, Object *obj) {
+ FuncArg *arg;
+
+ if (name) {
+ for (arg = check_arglist; arg; arg = arg->next) {
+ if (arg->name == name) {
+ CError_Error(CErrorStr205);
+ return 0;
+ }
+ }
+ }
+
+ if (obj && obj->datatype == DLOCAL) {
+ CError_Error(CErrorStr205);
+ return 0;
+ }
+
+ return 1;
+}
+
+ENode *CFunc_DefaultArg(Type *type, UInt32 qual, FuncArg *args) {
+ TStreamElement *element;
+ ENode *expr;
+ ENode *templdepexpr;
+
+ name_obj_check = defarg_name_obj_check;
+ check_arglist = args;
+ expr = conv_assignment_expression();
+ name_obj_check = NULL;
+
+ if (
+ !CTemplTool_IsTemplateArgumentDependentExpression(expr) &&
+ !CTemplTool_IsTemplateArgumentDependentType(type)
+ )
+ {
+ expr = argumentpromotion(expr, type, qual, 1);
+ } else {
+ element = CPrep_CurStreamElement();
+ if (element && element->tokenfile) {
+ templdepexpr = CExpr_NewTemplDepENode(TDE_SOURCEREF);
+ templdepexpr->data.templdep.u.sourceref.expr = expr;
+ templdepexpr->data.templdep.u.sourceref.token = galloc(sizeof(TStreamElement));
+ *templdepexpr->data.templdep.u.sourceref.token = *element;
+ expr = templdepexpr;
+ }
+ }
+
+ return CInline_CopyExpression(expr, CopyMode1);
+}
+
+static FuncArg *parameter_list(DeclInfo *declinfo) {
+ Boolean flag26;
+ FuncArg *args;
+ FuncArg *arg;
+ DeclInfo my_di;
+ Boolean isArray;
+
+ args = NULL;
+ flag26 = 1;
+
+ while (1) {
+ if (tk == TK_ELLIPSIS) {
+ if (flag26) {
+ if (!copts.cplusplus && copts.ANSIstrict)
+ CError_Warning(CErrorStr127);
+ args = &elipsis;
+ } else {
+ CFunc_AppendArg(&args, &elipsis);
+ }
+
+ tk = lex();
+ return args;
+ }
+
+ memclrw(&my_di, sizeof(my_di));
+ CParser_GetDeclSpecs(&my_di, 0);
+ if (my_di.x48)
+ CError_Error(CErrorStr127);
+
+ if (
+ my_di.storageclass &&
+ my_di.storageclass != TK_REGISTER &&
+ (!copts.cplusplus || my_di.storageclass != TK_AUTO)
+ )
+ {
+ CError_Error(CErrorStr127);
+ my_di.storageclass = 0;
+ }
+
+ my_di.name = NULL;
+
+ scandeclarator(&my_di);
+
+ if (flag26) {
+ flag26 = 0;
+ if (my_di.thetype == &stvoid) {
+ if (my_di.storageclass || my_di.qual || my_di.name)
+ CError_Error(CErrorStr127);
+ return NULL;
+ }
+ }
+
+ isArray = IS_TYPE_ARRAY(my_di.thetype);
+ adjustargumenttype(&my_di);
+
+ if (my_di.name) {
+ if (args && CFunc_IsInArgList(args, my_di.name))
+ CError_Error(CErrorStr122, my_di.name->name);
+ } else {
+ my_di.name = no_name_node;
+ }
+
+ if (my_di.thetype == &stvoid)
+ CError_Error(CErrorStr126);
+
+ arg = CParser_NewFuncArg();
+ arg->name = my_di.name;
+ arg->type = my_di.thetype;
+ arg->qual = my_di.qual;
+ arg->sclass = my_di.storageclass;
+ arg->is_array = isArray;
+ CFunc_AppendArg(&args, arg);
+
+ if (copts.cplusplus && tk == '=') {
+ tk = lex();
+ arg->dexpr = CFunc_DefaultArg(arg->type, arg->qual, args);
+ }
+
+ if (tk != ',') {
+ if (tk != TK_ELLIPSIS || !copts.cplusplus)
+ return args;
+ } else {
+ tk = lex();
+ }
+ }
+}
+
+Boolean CFunc_ParseFakeArgList(Boolean flag) {
+ DeclInfo di;
+
+ if (tk == TK_ELLIPSIS)
+ return 1;
+
+ do {
+ memclrw(&di, sizeof(di));
+ CParser_GetDeclSpecs(&di, 0);
+
+ if (di.x48)
+ return 0;
+
+ scandeclarator(&di);
+
+ if (tk == '=') {
+ tk = lex();
+ assignment_expression();
+ }
+
+ switch (tk) {
+ case TK_ELLIPSIS:
+ return 1;
+ case ',':
+ if (!flag)
+ tk = lex();
+ else
+ return 1;
+ break;
+ default:
+ return 0;
+ }
+ } while (tk != TK_ELLIPSIS);
+
+ return 1;
+}
+
+FuncArg *parameter_type_list(DeclInfo *declinfo) {
+ FuncArg *args;
+ NameSpace *nspace;
+ Boolean save_in_func_arglist;
+
+ declinfo->x44 = 0;
+ declinfo->x45 = 0;
+ declinfo->x1C = NULL;
+
+ if (tk == TK_ELLIPSIS || isdeclaration(0, 0, 0, 0)) {
+ if (!copts.cplusplus) {
+ nspace = CScope_NewListNameSpace(NULL, 0);
+ nspace->parent = cscope_current;
+ cscope_current = nspace;
+
+ save_in_func_arglist = in_func_arglist;
+ in_func_arglist = 1;
+ args = parameter_list(declinfo);
+ in_func_arglist = save_in_func_arglist;
+
+ cscope_current = nspace->parent;
+
+ if (!CScope_IsEmptyNameSpace(nspace))
+ declinfo->x1C = nspace;
+ } else {
+ args = parameter_list(declinfo);
+ }
+ } else if (copts.cplusplus) {
+ args = NULL;
+ if (tk != ')')
+ CError_Error(CErrorStr127);
+ } else {
+ identifier_list(declinfo);
+ args = &oldstyle;
+ }
+
+ return args;
+}
+
+CLabel *findlabel(void) {
+ CLabel *scan;
+
+ for (scan = Labels; scan; scan = scan->next) {
+ if (tkidentifier == scan->name)
+ return scan;
+ }
+
+ return NULL;
+}
+
+CLabel *newlabel(void) {
+ CLabel *label = lalloc(sizeof(CLabel));
+ memclrw(label, sizeof(CLabel));
+
+ label->name = label->uniquename = CParser_GetUniqueName();
+ return label;
+}
+
+Statement *CFunc_AppendStatement(StatementType sttype) {
+ Statement *stmt = lalloc(sizeof(Statement));
+
+ stmt->next = NULL;
+ stmt->type = sttype;
+ stmt->value = curstmtvalue;
+ stmt->flags = 0;
+ stmt->sourceoffset = sourceoffset;
+ stmt->sourcefilepath = sourcefilepath;
+ stmt->dobjstack = cexcept_dobjstack;
+
+ curstmt->next = stmt;
+ curstmt = stmt;
+ return stmt;
+}
+
+Statement *CFunc_InsertStatement(StatementType sttype, Statement *after) {
+ Statement *stmt = lalloc(sizeof(Statement));
+
+ stmt->next = after->next;
+ after->next = stmt;
+ stmt->type = sttype;
+ stmt->value = after->value;
+ stmt->flags = 0;
+ stmt->sourceoffset = after->sourceoffset;
+ stmt->sourcefilepath = after->sourcefilepath;
+ stmt->dobjstack = after->dobjstack;
+
+ return stmt;
+}
+
+Statement *CFunc_InsertBeforeStatement(StatementType sttype, Statement *before) {
+ Statement *stmt = lalloc(sizeof(Statement));
+
+ *stmt = *before;
+ before->next = stmt;
+ before->type = sttype;
+ before->flags = 0;
+
+ return before;
+}
+
+void CheckCLabels(void) {
+ CLabel *scan;
+
+ for (scan = Labels; scan; scan = scan->next) {
+ if (!scan->stmt)
+ CError_Error(CErrorStr159, scan->name->name);
+ }
+}
+
+Object *create_temp_object(Type *type) {
+ Object *object = CParser_NewLocalDataObject(NULL, 1);
+ object->name = CParser_GetUniqueName();
+ object->type = type;
+ CFunc_SetupLocalVarInfo(object);
+ return object;
+}
+
+ENode *create_temp_node(Type *type) {
+ ENode *node;
+
+ if (cinit_tempnodefunc)
+ return cinit_tempnodefunc(type, 0);
+
+ node = CExpr_NewETEMPNode(type, 0);
+ if (IS_TYPE_CLASS(type) && CClass_Destructor(TYPE_CLASS(type)))
+ node->data.temp.needs_dtor = 1;
+ return node;
+}
+
+ENode *create_temp_node2(Type *type) {
+ ENode *node;
+
+ if (cinit_tempnodefunc)
+ return cinit_tempnodefunc(type, 1);
+
+ node = CExpr_NewETEMPNode(type, 0);
+ node->data.temp.needs_dtor = 1;
+ return node;
+}
+
+static ENode *CFunc_DestroyReverse(ENode *expr, DtorTemp *list) {
+ expr = makediadicnode(expr, CABI_DestroyObject(list->dtor, create_objectrefnode(list->object), CABIDestroy1, 1, 0), ECOMMA);
+ expr->rtype = &stvoid;
+ if (list->next)
+ expr = CFunc_DestroyReverse(expr, list->next);
+ return expr;
+}
+
+static ENode *CFunc_TempTransDestroy(ENode *expr, DtorTemp *list, Boolean flag) {
+ Object *tempobj;
+
+ if (flag) {
+ CError_ASSERT(738, !(IS_TYPE_CLASS(expr->rtype) && CClass_Destructor(TYPE_CLASS(expr->rtype))));
+ tempobj = create_temp_object(expr->rtype);
+ expr = makediadicnode(create_objectnode(tempobj), expr, EASS);
+ }
+
+ expr = CFunc_DestroyReverse(expr, list);
+
+ if (flag) {
+ expr = makediadicnode(expr, create_objectnode(tempobj), ECOMMA);
+ expr->rtype = tempobj->type;
+ }
+
+ return expr;
+}
+
+void CFunc_WarnUnused(void) {
+ if (copts.warn_unusedvar) {
+ ObjectList *list;
+ for (list = locals; list; list = list->next) {
+ if (
+ !(list->object->flags & OBJECT_USED) &&
+ !IsTempName(list->object->name) &&
+ !(list->object->qual & Q_INLINE_DATA)
+ )
+ {
+ CError_SetErrorToken(&list->object->u.var.info->deftoken);
+ CError_Warning(CErrorStr182, &list->object->name->name);
+ }
+ }
+ }
+
+ if (copts.warn_unusedarg) {
+ ObjectList *list;
+ for (list = arguments; list; list = list->next) {
+ if (
+ !(list->object->flags & OBJECT_USED) &&
+ !IsTempName(list->object->name) &&
+ list->object->name != this_name_node &&
+ list->object->name != self_name_node
+ )
+ {
+ CError_SetErrorToken(&symdecltoken);
+ CError_Warning(CErrorStr182, &list->object->name->name);
+ }
+ }
+ }
+}
+
+void CFunc_CodeCleanup(Statement *stmt) {
+ if (cscope_currentclass && cscope_currentclass->sominfo)
+ CSOM_InitSOMSelf(cscope_currentclass, stmt);
+
+ CFunc_WarnUnused();
+ CExcept_ExceptionTansform(stmt);
+}
+
+static Boolean DestructorNeeded(ExceptionAction *ea, ExceptionAction *end) {
+ while (ea) {
+ if (CExcept_ActionNeedsDestruction(ea))
+ return 1;
+ if (ea == end)
+ break;
+ ea = ea->prev;
+ }
+
+ return 0;
+}
+
+static Statement *DestructLocals(Statement *stmt, ExceptionAction *ea, ExceptionAction *end) {
+ while (ea) {
+ stmt = CExcept_ActionCleanup(ea, stmt);
+ if (ea == end)
+ break;
+ ea = ea->prev;
+ }
+
+ return stmt;
+}
+
+static Boolean NeedsDestruction(Statement *stmt1, Statement *stmt2) {
+ ExceptionAction *ea2;
+ ExceptionAction *ea1;
+ ExceptionAction *scan;
+
+ ea1 = stmt1->dobjstack;
+ ea2 = stmt2->dobjstack;
+
+ for (scan = ea2; scan; scan = scan->prev) {
+ if (scan == ea1)
+ return 0;
+ }
+
+ while (ea1 && ea1 != ea2) {
+ if (CExcept_ActionNeedsDestruction(ea1))
+ return 1;
+ ea1 = ea1->prev;
+ }
+
+ return 0;
+}
+
+static ExceptionAction *FindLastNonCommonStackObj(Statement *stmt1, Statement *stmt2) {
+ ExceptionAction *ea1;
+ ExceptionAction *ea2;
+
+ for (ea2 = stmt2->dobjstack; ea2; ea2 = ea2->prev) {
+ for (ea1 = stmt1->dobjstack; ea1; ea1 = ea1->prev) {
+ if (ea1->prev == ea2)
+ return ea1;
+ }
+ }
+
+ return NULL;
+}
+
+static void DestructorReturnTransform(Statement *stmt1, Statement *stmt2) {
+ Statement *stmt;
+ Object *tempobj;
+
+ if (stmt1->dobjstack != stmt2->dobjstack && NeedsDestruction(stmt1, stmt2))
+ stmt1 = DestructLocals(stmt1, stmt1->dobjstack, FindLastNonCommonStackObj(stmt1, stmt2));
+
+ if (DestructorNeeded(stmt2->dobjstack, NULL)) {
+ if (CMach_GetFunctionResultClass(TYPE_FUNC(cscope_currentfunc->type)) != 1) {
+ tempobj = create_temp_object(stmt2->expr->rtype);
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt1);
+ stmt->expr = makediadicnode(create_objectnode(tempobj), stmt2->expr, EASS);
+ stmt->sourceoffset = stmt2->sourceoffset;
+ stmt->sourcefilepath = stmt2->sourcefilepath;
+ DestructLocals(stmt, stmt2->dobjstack, NULL);
+ stmt2->expr = create_objectnode(tempobj);
+ } else {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt1);
+ stmt->expr = stmt2->expr;
+ stmt->sourceoffset = stmt2->sourceoffset;
+ stmt->sourcefilepath = stmt2->sourcefilepath;
+ DestructLocals(stmt, stmt2->dobjstack, NULL);
+ stmt2->expr = nullnode();
+ }
+ }
+}
+
+static Statement *DestructorIfTransform(Statement *stmt) {
+ CLabel *label;
+ Statement *newStmt;
+
+ if (stmt->type == ST_IFGOTO)
+ stmt->type = ST_IFNGOTO;
+ else
+ stmt->type = ST_IFGOTO;
+
+ label = newlabel();
+ newStmt = DestructLocals(stmt, stmt->dobjstack, FindLastNonCommonStackObj(stmt, stmt->label->stmt));
+ newStmt = CFunc_InsertStatement(ST_GOTO, newStmt);
+ newStmt->label = stmt->label;
+ newStmt = CFunc_InsertStatement(ST_LABEL, newStmt);
+ newStmt->label = label;
+ label->stmt = newStmt;
+ stmt->label = label;
+ newStmt->dobjstack = stmt->dobjstack;
+ return newStmt;
+}
+
+static Boolean IsSubStack(ExceptionAction *exc1, ExceptionAction *exc2) {
+ if (!exc1)
+ return 1;
+
+ while (exc2) {
+ if (exc2 == exc1)
+ return 1;
+ exc2 = exc2->prev;
+ }
+
+ return 0;
+}
+
+static void CFunc_CheckInitSkip(Statement *stmt, ExceptionAction *exc) {
+ if (stmt->dobjstack != exc && !IsSubStack(exc, stmt->dobjstack)) {
+ while (exc) {
+ if (CExcept_ActionNeedsDestruction(exc) && exc->type != EAT_ACTIVECATCHBLOCK) {
+ CError_Warning(CErrorStr211);
+ break;
+ }
+ exc = exc->prev;
+ }
+ }
+}
+
+void CFunc_DestructorCleanup(Statement *stmt) {
+ Statement *scan;
+ Statement *next;
+ SwitchCase *swcase;
+
+ if (copts.cplusplus) {
+ for (scan = stmt; scan; scan = scan->next) {
+ switch (scan->type) {
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_EXPRESSION:
+ case ST_RETURN:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_GOTOEXPR:
+ case ST_ASM:
+ break;
+ case ST_SWITCH:
+ CFunc_CheckInitSkip(scan, ((SwitchInfo *) scan->label)->defaultlabel->stmt->dobjstack);
+ for (swcase = ((SwitchInfo *) scan->label)->cases; swcase; swcase = swcase->next) {
+ CFunc_CheckInitSkip(scan, swcase->label->stmt->dobjstack);
+ }
+ break;
+ case ST_GOTO:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ CFunc_CheckInitSkip(scan, scan->label->stmt->dobjstack);
+ break;
+ default:
+ CError_FATAL(1045);
+ }
+ }
+
+ if (cexcept_hasdobjects) {
+ while (1) {
+ next = stmt->next;
+ if (!next) {
+ if (stmt->type != ST_RETURN && stmt->dobjstack)
+ DestructLocals(stmt, stmt->dobjstack, NULL);
+ return;
+ }
+
+ switch (next->type) {
+ case ST_GOTO:
+ if (
+ stmt->dobjstack != next->label->stmt->dobjstack &&
+ NeedsDestruction(stmt, next->label->stmt)
+ )
+ {
+ DestructLocals(stmt, stmt->dobjstack, FindLastNonCommonStackObj(stmt, next->label->stmt));
+ }
+ stmt = next;
+ continue;
+
+ case ST_RETURN:
+ if (next->expr && DestructorNeeded(stmt->dobjstack, NULL)) {
+ DestructorReturnTransform(stmt, next);
+ } else if (stmt->dobjstack) {
+ DestructLocals(stmt, stmt->dobjstack, NULL);
+ }
+ stmt = next;
+ continue;
+ }
+
+ switch (stmt->type) {
+ case ST_GOTO:
+ case ST_SWITCH:
+ case ST_RETURN:
+ case ST_GOTOEXPR:
+ break;
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_EXPRESSION:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_ASM:
+ if (
+ stmt->dobjstack != next->dobjstack &&
+ NeedsDestruction(stmt, next)
+ )
+ {
+ DestructLocals(stmt, stmt->dobjstack, FindLastNonCommonStackObj(stmt, next));
+ }
+ break;
+ default:
+ CError_FATAL(1109);
+ }
+
+ switch (next->type) {
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_EXPRESSION:
+ case ST_SWITCH:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_ASM:
+ stmt = next;
+ continue;
+
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ if (
+ next->dobjstack != next->label->stmt->dobjstack &&
+ NeedsDestruction(next, next->label->stmt)
+ )
+ {
+ stmt = DestructorIfTransform(next);
+ } else {
+ stmt = next;
+ }
+ break;
+
+ default:
+ CError_FATAL(1138);
+ }
+ }
+ }
+ }
+}
+
+static void scancase(DeclThing *thing) {
+ SwitchCase *swcase;
+ Statement *stmt;
+ CInt64 min;
+ CInt64 max;
+
+ if (!thing->switchinfo) {
+ CError_Error(CErrorStr169);
+ return;
+ }
+
+ tk = lex();
+ min = CExpr_IntConstConvert(thing->switchinfo->x8, thing->switchinfo->x8, CExpr_IntegralConstExpr());
+ if (!copts.ANSIstrict && tk == TK_ELLIPSIS) {
+ tk = lex();
+ max = CExpr_IntConstConvert(thing->switchinfo->x8, thing->switchinfo->x8, CExpr_IntegralConstExpr());
+ if (CInt64_Greater(min, max))
+ CError_Error(CErrorStr366);
+ if (thing->switchinfo->x8->size == stsignedlonglong.size)
+ CError_Error(CErrorStr368);
+ } else {
+ max = min;
+ }
+
+ for (swcase = thing->switchinfo->cases; swcase; swcase = swcase->next) {
+ if (CInt64_GreaterEqual(swcase->min, min) && CInt64_LessEqual(swcase->min, max))
+ CError_Error(CErrorStr172);
+ if (CInt64_GreaterEqual(swcase->max, min) && CInt64_LessEqual(swcase->max, max))
+ CError_Error(CErrorStr172);
+ if (CInt64_Less(swcase->min, min) && CInt64_Greater(swcase->max, max))
+ CError_Error(CErrorStr172);
+ }
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = newlabel();
+ stmt->label->stmt = stmt;
+
+ swcase = lalloc(sizeof(SwitchCase));
+ swcase->min = min;
+ swcase->label = stmt->label;
+ swcase->next = thing->switchinfo->cases;
+ thing->switchinfo->cases = swcase;
+ swcase->max = max;
+
+ if (tk != ':')
+ CError_ErrorSkip(CErrorStr170);
+ else
+ tk = lex();
+
+ statement(thing);
+}
+
+static void CFunc_NameLocalStaticDataObject(Object *obj, char *str) {
+ char buf[64];
+ HashNameNode *name;
+
+ if (!(cscope_currentfunc && (cscope_currentfunc->qual & Q_INLINE)) || CParser_HasInternalLinkage(cscope_currentfunc)) {
+ obj->name = CParser_AppendUniqueName(str);
+ } else {
+ sprintf(buf, "$localstatic%" PRId32 "$", cfunc_staticvarcount++);
+ name = CMangler_GetLinkName(cscope_currentfunc);
+ name = CParser_NameConcat(buf, name->name);
+ name = CParser_NameConcat(str, name->name);
+ obj->name = name;
+ obj->qual |= Q_20000;
+ obj->sclass = 0;
+ }
+}
+
+static void sinit_insert_expr(ENode *expr) {
+ Statement *stmt;
+
+ if (!sinit_first_object) {
+ sinit_first_object = CParser_NewCompilerDefDataObject();
+ sinit_first_object->type = TYPE(&stsignedchar);
+ sinit_first_object->sclass = TK_STATIC;
+ CFunc_NameLocalStaticDataObject(sinit_first_object, "init");
+ CInit_DeclareData(sinit_first_object, NULL, NULL, sinit_first_object->type->size);
+
+ sinit_label = newlabel();
+ stmt = CFunc_AppendStatement(ST_IFGOTO);
+ stmt->expr = create_objectnode(sinit_first_object);
+ stmt->label = sinit_label;
+ }
+
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = expr;
+}
+
+static void ainit_insert_expr(ENode *expr) {
+ Statement *stmt;
+
+ if (ainit_only_one) {
+ if (ainit_expr) {
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = ainit_expr;
+ }
+ ainit_expr = expr;
+ } else {
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = expr;
+ }
+}
+
+static ENode *ainit_register_object(Type *type, Object *local, SInt32 offset, Boolean flag) {
+ return CExcept_RegisterDestructorObject(local, offset, CClass_Destructor(TYPE_CLASS(type)), flag);
+}
+
+static void CFunc_LocalDataDeclarator(DeclInfo *di, TStreamElement *deftoken, Boolean flag1, Boolean flag2) {
+ Object *object;
+ Object *aliasObject;
+ NameSpace *globalNS;
+ NameSpaceObjectList *nsol;
+ NameSpaceName *nsname;
+ Statement *stmt;
+
+ if (di->nspace)
+ CError_Error(CErrorStr121);
+
+ CDecl_CompleteType(di->thetype);
+
+ object = NULL;
+
+ if ((nsol = CScope_FindName(cscope_current, di->name))) {
+ switch (nsol->object->otype) {
+ case OT_OBJECT:
+ object = OBJECT(nsol->object);
+ break;
+ case OT_NAMESPACE:
+ CError_Error(CErrorStr321);
+ return;
+ case OT_ENUMCONST:
+ case OT_TYPE:
+ CError_Error(CErrorStr322);
+ break;
+ case OT_TYPETAG:
+ break;
+ default:
+ CError_FATAL(1344);
+ }
+ }
+
+ if (object)
+ CError_Error(CErrorStr333, object);
+
+ if (di->storageclass == TK_EXTERN) {
+ object = NULL;
+ globalNS = CScope_FindGlobalNS(cscope_current);
+ if ((nsol = CScope_FindName(globalNS, di->name))) {
+ switch (nsol->object->otype) {
+ case OT_OBJECT:
+ object = OBJECT(nsol->object);
+ break;
+ case OT_NAMESPACE:
+ CError_Error(CErrorStr321);
+ return;
+ case OT_ENUMCONST:
+ case OT_TYPE:
+ CError_Error(CErrorStr322);
+ break;
+ case OT_TYPETAG:
+ break;
+ default:
+ CError_FATAL(1381);
+ }
+ }
+
+ if (object) {
+ if (
+ !is_typesame(di->thetype, object->type) ||
+ (di->qual & (Q_CONST | Q_VOLATILE | Q_PASCAL | Q_20000 | Q_WEAK | Q_ALIGNED_MASK)) != (object->qual & (Q_CONST | Q_VOLATILE | Q_PASCAL | Q_20000 | Q_WEAK | Q_ALIGNED_MASK))
+ )
+ {
+ CError_Error(CErrorStr249, di->name->name, object->type, object->qual, di->thetype, di->qual);
+ }
+ } else {
+ object = CParser_NewGlobalDataObject(di);
+ object->nspace = globalNS;
+ }
+
+ CParser_NewAliasObject(object, 0);
+ return;
+ }
+
+ if (di->storageclass != TK_STATIC)
+ object = CParser_NewObject(di);
+ else
+ object = CParser_NewGlobalDataObject(di);
+
+ object->name = di->name;
+ object->type = di->thetype;
+ object->qual = di->qual;
+ object->sclass = di->storageclass;
+
+ switch (di->storageclass) {
+ case TK_STATIC:
+ if (flag1) {
+ CError_Error(CErrorStr177);
+ return;
+ }
+ if (flag2)
+ CError_Error(CErrorStr174);
+
+ if (CanCreateObject(di->thetype)) {
+ CError_QualifierCheck(di->qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_20000 | Q_WEAK | Q_ALIGNED_MASK));
+ CParser_NewAliasObject(object, 0);
+ object->nspace = cscope_root;
+ object->datatype = DDATA;
+ CFunc_NameLocalStaticDataObject(object, object->name->name);
+
+ if (copts.cplusplus) {
+ sinit_first_object = NULL;
+ CInit_InitializeStaticData(object, sinit_insert_expr);
+ if (sinit_first_object) {
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = makediadicnode(
+ create_objectnode(sinit_first_object),
+ intconstnode(TYPE(&stsignedchar), 1),
+ EASS);
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = sinit_label;
+ sinit_label->stmt = stmt;
+ }
+ } else {
+ CInit_InitializeData(object);
+ }
+ }
+ break;
+
+ case 0:
+ case TK_AUTO:
+ case TK_REGISTER:
+ if (CanCreateObject(di->thetype)) {
+ CError_QualifierCheck(di->qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_ALIGNED_MASK));
+ object->datatype = DLOCAL;
+ CFunc_SetupLocalVarInfo(object);
+
+ object->u.var.info->deftoken = *deftoken;
+ if (object->sclass == TK_REGISTER && flag1)
+ object->u.var.info->usage = 100;
+
+ CScope_AddObject(cscope_current, object->name, OBJ_BASE(object));
+
+ if (!flag1) {
+ if (IS_TYPE_SOM_CLASS(di->thetype)) {
+ CSOM_InitAutoClass(object);
+ } else {
+ CInit_InitializeAutoData(object, ainit_insert_expr, ainit_register_object);
+ if (object->type != di->thetype && (IS_TYPE_STRUCT(object->type) || IS_TYPE_CLASS(object->type))) {
+ CError_ASSERT(1478, !cscope_current->is_hash);
+ CError_ASSERT(1479, nsname = CScope_FindNameSpaceName(cscope_current, object->name));
+ CError_ASSERT(1480, nsname->first.object == OBJ_BASE(object));
+ CError_ASSERT(1481, !nsname->first.next);
+ nsname->name = CParser_AppendUniqueName(object->name->name);
+
+ aliasObject = CParser_NewAliasObject(object, 0);
+ aliasObject->type = di->thetype;
+ }
+ }
+ }
+
+ if (object->datatype == DLOCAL) {
+ ObjectList *list = lalloc(sizeof(ObjectList));
+ list->object = object;
+ list->next = locals;
+ locals = list;
+ }
+
+ IsCompleteType(di->thetype);
+ }
+ break;
+
+ default:
+ CError_FATAL(1504);
+ }
+}
+
+static ENode *CFunc_ParseLocalDeclarationList(Boolean flag1, Boolean flag2, Boolean flag3, Boolean flag4) {
+ Type *type;
+ UInt32 qual;
+ DeclInfo di;
+ TStreamElement deftoken;
+
+ ainit_expr = NULL;
+ ainit_only_one = flag2;
+
+ while (flag2 || isdeclaration(copts.cplusplus, 0, 0, 0)) {
+ CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath);
+
+ memclrw(&di, sizeof(di));
+ di.is_extern_c = cfunc_is_extern_c;
+ CParser_GetDeclSpecs(&di, 0);
+
+ if (IS_TYPE_TEMPLATE(di.thetype)) {
+ CError_Error(CErrorStr146);
+ di.thetype = TYPE(&stsignedint);
+ }
+
+ type = di.thetype;
+ qual = di.qual;
+
+ if (tk != ';') {
+ while (1) {
+ deftoken = *CPrep_CurStreamElement();
+ di.name = NULL;
+ scandeclarator(&di);
+
+ if (di.name) {
+ if (di.storageclass != TK_TYPEDEF) {
+ if (IS_TYPE_FUNC(di.thetype)) {
+ if (!CDecl_FunctionDeclarator(&di, CScope_FindGlobalNS(cscope_current), 0, 0))
+ break;
+ } else {
+ CFunc_LocalDataDeclarator(&di, &deftoken, flag1, flag2);
+ }
+ } else {
+ CDecl_TypedefDeclarator(&di);
+ }
+ } else {
+ CError_Error(CErrorStr134);
+ }
+
+ if (tk == ';')
+ break;
+
+ if (tk != ',') {
+ if (!flag2)
+ CError_Error(CErrorStr123);
+ break;
+ }
+
+ di.nspace = NULL;
+ di.thetype = type;
+ di.qual = qual;
+ tk = lex();
+ }
+ } else {
+ CParser_CheckAnonymousUnion(&di, 1);
+ }
+
+ if (flag2)
+ break;
+ if (flag4)
+ break;
+ tk = lex();
+ }
+
+ if (flag2) {
+ if (!ainit_expr) {
+ if (!flag3) {
+ CError_Error(CErrorStr141);
+ ainit_expr = nullnode();
+ }
+ } else {
+ ainit_expr = checkreference(ainit_expr);
+ }
+ }
+
+ return ainit_expr;
+}
+
+static void makeifstatement(ENode *expr, CLabel *label1, CLabel *label2, Boolean flag1, Boolean flag2) {
+ Statement *stmt;
+ CLabel *tmplabel;
+
+ if (!expr) {
+ if (flag1) {
+ stmt = CFunc_AppendStatement(ST_GOTO);
+ stmt->label = label1;
+ return;
+ }
+ return;
+ }
+
+ if (
+ ENODE_IS(expr, ETYPCON) &&
+ IS_TYPE_INT(expr->rtype) &&
+ IS_TYPE_INT(expr->data.monadic->rtype) &&
+ expr->rtype->size >= expr->data.monadic->rtype->size
+ )
+ expr = expr->data.monadic;
+
+ if (isnotzero(expr)) {
+ if (flag1) {
+ stmt = CFunc_AppendStatement(ST_GOTO);
+ stmt->label = label1;
+ return;
+ }
+ return;
+ }
+
+ if (iszero(expr)) {
+ if (!flag1) {
+ stmt = CFunc_AppendStatement(ST_GOTO);
+ stmt->label = label1;
+ return;
+ }
+ return;
+ }
+
+ if (ENODE_IS(expr, ELOGNOT)) {
+ makeifstatement(expr->data.monadic, label1, label2, !flag1, flag2);
+ return;
+ }
+
+ if (ENODE_IS(expr, ELOR)) {
+ tmplabel = newlabel();
+ if (flag1) {
+ makeifstatement(expr->data.diadic.left, label1, tmplabel, 1, flag2);
+ tmplabel->stmt = CFunc_AppendStatement(ST_LABEL);
+ tmplabel->stmt->label = tmplabel;
+ makeifstatement(expr->data.diadic.right, label1, label2, 1, flag2);
+ return;
+ } else {
+ makeifstatement(expr->data.diadic.left, label2, tmplabel, 1, flag2);
+ tmplabel->stmt = CFunc_AppendStatement(ST_LABEL);
+ tmplabel->stmt->label = tmplabel;
+ makeifstatement(expr->data.diadic.right, label1, label2, 0, flag2);
+ return;
+ }
+ }
+
+ if (ENODE_IS(expr, ELAND)) {
+ tmplabel = newlabel();
+ if (flag1) {
+ makeifstatement(expr->data.diadic.left, label2, tmplabel, 0, flag2);
+ tmplabel->stmt = CFunc_AppendStatement(ST_LABEL);
+ tmplabel->stmt->label = tmplabel;
+ makeifstatement(expr->data.diadic.right, label1, label2, 1, flag2);
+ return;
+ } else {
+ makeifstatement(expr->data.diadic.left, label1, tmplabel, 0, flag2);
+ tmplabel->stmt = CFunc_AppendStatement(ST_LABEL);
+ tmplabel->stmt->label = tmplabel;
+ makeifstatement(expr->data.diadic.right, label1, label2, 0, flag2);
+ return;
+ }
+ }
+
+ stmt = CFunc_AppendStatement(ST_IFGOTO);
+ stmt->label = label1;
+ stmt->expr = expr;
+ if (!flag1)
+ stmt->type = ST_IFNGOTO;
+ if (flag2)
+ stmt->flags = stmt->flags | StmtFlag_4;
+}
+
+static void CFunc_HasDtorTempCallBack(ENode *expr) {
+ if (expr->data.temp.needs_dtor || expr->data.temp.uniqueid)
+ cfunc_hasdtortemp = 1;
+}
+
+static void ifstatement(Boolean flag1, ENode *expr, CLabel *label, Boolean flag2) {
+ Statement *stmt;
+ CLabel *tmplabel;
+
+ if (expr && copts.cplusplus && copts.exceptions) {
+ cfunc_hasdtortemp = 0;
+ CExpr_SearchExprTree(expr, CFunc_HasDtorTempCallBack, 1, ETEMP);
+ if (cfunc_hasdtortemp) {
+ stmt = CFunc_AppendStatement(flag1 ? ST_IFGOTO : ST_IFNGOTO);
+ stmt->label = label;
+ stmt->expr = expr;
+ if (flag2)
+ stmt->flags = stmt->flags | StmtFlag_4;
+ return;
+ }
+ }
+
+ tmplabel = newlabel();
+ makeifstatement(expr, label, tmplabel, flag1, flag2);
+ tmplabel->stmt = CFunc_AppendStatement(ST_LABEL);
+ tmplabel->stmt->label = tmplabel;
+}
+
+Statement *CFunc_GenerateLoop(Statement *stmt, Type *type, ENode *lowerBound, ENode *upperBound, ENode *increment1, ENode *increment2, ENode *(*callback)(ENode *, ENode *)) {
+ ENode *var1;
+ ENode *var2;
+ CLabel *label;
+ ENode *ind;
+ ENode *ind2;
+ Statement *s;
+
+ var1 = CExpr_NewETEMPNode(type, 1);
+ ind = lalloc(sizeof(ENode));
+ *ind = *var1;
+ ind = makemonadicnode(ind, EINDIRECT);
+ ind->rtype = type;
+
+ // initialise var1 to lowerBound
+ if (stmt) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ s = stmt;
+ } else {
+ s = CFunc_AppendStatement(ST_EXPRESSION);
+ }
+ s->expr = makediadicnode(ind, lowerBound, EASS);
+
+ if (increment2) {
+ var2 = CExpr_NewETEMPNode(type, 1);
+ ind = lalloc(sizeof(ENode));
+ *ind = *var2;
+ ind = makemonadicnode(ind, EINDIRECT);
+ ind->rtype = type;
+
+ // initialise var2 to upperBound
+ if (stmt) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ s = stmt;
+ } else {
+ s = CFunc_AppendStatement(ST_EXPRESSION);
+ }
+ s->expr = makediadicnode(ind, upperBound, EASS);
+ }
+
+ // label for loop body
+ label = newlabel();
+ if (stmt) {
+ stmt = CFunc_InsertStatement(ST_LABEL, stmt);
+ s = stmt;
+ } else {
+ s = CFunc_AppendStatement(ST_LABEL);
+ }
+ s->label = label;
+ label->stmt = s;
+
+ if (callback) {
+ ind = lalloc(sizeof(ENode));
+ *ind = *var1;
+ ind = makemonadicnode(ind, EINDIRECT);
+ ind->rtype = type;
+
+ if (increment2) {
+ ind2 = lalloc(sizeof(ENode));
+ *ind2 = *var2;
+ ind2 = makemonadicnode(ind2, EINDIRECT);
+ ind2->rtype = type;
+ } else {
+ ind2 = NULL;
+ }
+
+ // generate a loop body
+ if ((ind = callback(ind, ind2))) {
+ if (stmt) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ s = stmt;
+ } else {
+ s = CFunc_AppendStatement(ST_EXPRESSION);
+ }
+ s->expr = ind;
+ }
+ }
+
+ if (increment1) {
+ ind = lalloc(sizeof(ENode));
+ *ind = *var1;
+ ind = makemonadicnode(ind, EINDIRECT);
+ ind->rtype = type;
+
+ // add increment1 to var1
+ if (stmt) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ s = stmt;
+ } else {
+ s = CFunc_AppendStatement(ST_EXPRESSION);
+ }
+ s->expr = makediadicnode(ind, increment1, EADDASS);
+
+ if (increment2) {
+ ind = lalloc(sizeof(ENode));
+ *ind = *var2;
+ ind = makemonadicnode(ind, EINDIRECT);
+ ind->rtype = type;
+
+ // add increment2 to var2
+ if (stmt) {
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ s = stmt;
+ } else {
+ s = CFunc_AppendStatement(ST_EXPRESSION);
+ }
+ s->expr = makediadicnode(ind, increment2, EADDASS);
+ }
+ }
+
+ ind = lalloc(sizeof(ENode));
+ *ind = *var1;
+ ind = makemonadicnode(ind, EINDIRECT);
+ ind->rtype = type;
+
+ // loop if var1 < upperBound
+ if (stmt) {
+ stmt = CFunc_InsertStatement(ST_IFGOTO, stmt);
+ s = stmt;
+ } else {
+ s = CFunc_AppendStatement(ST_IFGOTO);
+ }
+ s->expr = makediadicnode(ind, upperBound, ELESS);
+ s->expr->rtype = TYPE(&stbool);
+ s->label = label;
+ s->flags = StmtFlag_4;
+
+ return stmt;
+}
+
+static Boolean checklabel(void) {
+ HashNameNode *savename;
+ short savesize;
+ short token;
+
+ savename = tkidentifier;
+ savesize = tksize;
+ token = lookahead();
+ tkidentifier = savename;
+ tksize = savesize;
+
+ return token == ':';
+}
+
+static ENode *returnstatementadjust(ENode *expr, Type *type, UInt32 qual) {
+ Object *object;
+ ENode *expr2;
+ ENode *objexpr;
+ ObjectList *list;
+ ENodeList *exprlist;
+
+ for (list = arguments; list; list = list->next) {
+ if (list->object->name == temp_argument_name)
+ break;
+ }
+
+ CError_ASSERT(1907, list);
+
+ object = list->object;
+ if ((expr2 = CExpr_IsTempConstruction(expr, type, &objexpr)) && ENODE_IS(objexpr, ETEMP)) {
+ *objexpr = *create_objectnode(object);
+ return expr2;
+ }
+
+ if (IS_TYPE_CLASS(type)) {
+ expr2 = create_objectnode(object);
+ exprlist = lalloc(sizeof(ENodeList));
+ exprlist->next = NULL;
+ exprlist->node = expr;
+ return CExpr_ConstructObject(TYPE_CLASS(type), expr2, exprlist, 1, 1, 0, 1, 0);
+ }
+
+ expr2 = create_objectnode(object);
+ expr2 = makemonadicnode(expr2, EINDIRECT);
+ expr2->rtype = type;
+
+ return makediadicnode(expr2, CExpr_AssignmentPromotion(expr, type, qual, 1), EASS);
+}
+
+static void CFunc_AutoResultCheck(ENode *expr) {
+ while (1) {
+ while (ENODE_IS(expr, ECOMMA))
+ expr = expr->data.diadic.right;
+
+ switch (expr->type) {
+ case EOBJREF:
+ if (expr->data.objref->datatype != DLOCAL)
+ break;
+ case ETEMP:
+ CError_Warning(CErrorStr326);
+ break;
+ case EADD:
+ case ESUB:
+ CFunc_AutoResultCheck(expr->data.diadic.left);
+ expr = expr->data.diadic.right;
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+}
+
+static void statement(DeclThing *thing) {
+ Statement *stmt;
+ Statement *stmt2;
+ CLabel *label;
+ DeclBlock *block;
+ ENode *expr;
+ HashNameNode *name;
+ DeclThing subthing;
+
+ CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath);
+
+ switch (tk) {
+ case TK_RETURN:
+ tk = lex();
+ if (
+ (thing->thetype == &stvoid && !copts.cplusplus) ||
+ CClass_IsConstructor(cscope_currentfunc) ||
+ CClass_IsDestructor(cscope_currentfunc)
+ )
+ {
+ if (tk != ';') {
+ CError_Error(CErrorStr315);
+ expression();
+ }
+
+ stmt = CFunc_AppendStatement(ST_RETURN);
+ stmt->expr = NULL;
+ CError_ResetErrorSkip();
+ tk = lex();
+ return;
+ }
+
+ if (tk == ';') {
+ if (thing->thetype != &stvoid && (copts.pedantic || copts.cplusplus))
+ CError_Warning(CErrorStr184);
+
+ stmt = CFunc_AppendStatement(ST_RETURN);
+ stmt->expr = NULL;
+ CError_ResetErrorSkip();
+ tk = lex();
+ return;
+ }
+
+ if (copts.old_argmatch)
+ expr = expression();
+ else
+ expr = s_expression();
+
+ if (thing->thetype == &stvoid) {
+ if (expr->rtype != &stvoid)
+ CError_Error(CErrorStr315);
+
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = expr;
+
+ stmt = CFunc_AppendStatement(ST_RETURN);
+ stmt->expr = NULL;
+ } else {
+ if (CMach_GetFunctionResultClass(TYPE_FUNC(cscope_currentfunc->type)) == 1)
+ expr = returnstatementadjust(expr, thing->thetype, thing->qual);
+ else
+ expr = CExpr_AssignmentPromotion(expr, thing->thetype, thing->qual, 1);
+
+ stmt = CFunc_AppendStatement(ST_RETURN);
+ stmt->expr = expr;
+
+ if (IS_TYPE_POINTER_ONLY(thing->thetype))
+ CFunc_AutoResultCheck(expr);
+ }
+
+ break;
+
+ case TK_CASE:
+ scancase(thing);
+ return;
+
+ case TK_DEFAULT:
+ if (!thing->switchinfo) {
+ CError_Error(CErrorStr169);
+ return;
+ }
+
+ if (lex() != ':')
+ CError_ErrorSkip(CErrorStr170);
+ else
+ tk = lex();
+
+ if (thing->switchinfo->defaultlabel)
+ CError_ErrorSkip(CErrorStr173);
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = newlabel();
+ stmt->label->stmt = stmt;
+ thing->switchinfo->defaultlabel = stmt->label;
+ statement(thing);
+ return;
+
+ case TK_SWITCH:
+ if (lex() != '(')
+ CError_ErrorSkip(CErrorStr114);
+ else
+ tk = lex();
+
+ if (copts.cplusplus && !copts.ARMscoping && isdeclaration(1, 0, 0, '=')) {
+ block = CFunc_NewDeclBlock();
+ expr = CFunc_ParseLocalDeclarationList(0, 1, 0, 0);
+ if (CScope_IsEmptyNameSpace(cscope_current)) {
+ CFunc_RestoreBlock(block);
+ block = NULL;
+ }
+ } else {
+ expr = expression();
+ block = NULL;
+ }
+
+ stmt = CFunc_AppendStatement(ST_SWITCH);
+ stmt->expr = CExpr_ConvertToIntegral(expr);
+
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+
+ stmt->label = (CLabel *) lalloc(sizeof(SwitchInfo));
+ ((SwitchInfo *) stmt->label)->defaultlabel = NULL;
+ ((SwitchInfo *) stmt->label)->cases = NULL;
+ ((SwitchInfo *) stmt->label)->x8 = stmt->expr->rtype;
+
+ label = newlabel();
+ subthing = *thing;
+ subthing.loopBreak = label;
+ subthing.switchinfo = (SwitchInfo *) stmt->label;
+ CFunc_CompoundStatement(&subthing);
+
+ if (!subthing.switchinfo->defaultlabel)
+ subthing.switchinfo->defaultlabel = label;
+
+ if (!subthing.switchinfo->cases) {
+ stmt->type = ST_EXPRESSION;
+ stmt2 = lalloc(sizeof(Statement));
+ *stmt2 = *stmt;
+ stmt->next = stmt2;
+ stmt2->type = ST_GOTO;
+ stmt2->label = subthing.switchinfo->defaultlabel;
+ stmt2->dobjstack = cexcept_dobjstack;
+ }
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = label;
+ label->stmt = stmt;
+
+ if (block)
+ CFunc_RestoreBlock(block);
+ return;
+
+ case TK_GOTO:
+ if ((tk = lex()) != TK_IDENTIFIER) {
+ if (tk == '*' && !copts.ANSIstrict) {
+ tk = lex();
+ stmt = CFunc_AppendStatement(ST_GOTOEXPR);
+ stmt->expr = expression();
+ if (!IS_TYPE_POINTER_ONLY(stmt->expr->rtype)) {
+ CError_Error(CErrorStr146);
+ stmt->expr = nullnode();
+ stmt->expr->rtype = TYPE(&void_ptr);
+ }
+ } else {
+ CError_Error(CErrorStr107);
+ return;
+ }
+ } else {
+ stmt = CFunc_AppendStatement(ST_GOTO);
+ if (!(stmt->label = findlabel())) {
+ stmt->label = newlabel();
+ stmt->label->next = Labels;
+ Labels = stmt->label;
+ stmt->label->name = tkidentifier;
+ }
+ tk = lex();
+ }
+ break;
+
+ case TK_BREAK:
+ if (thing->loopBreak) {
+ stmt = CFunc_AppendStatement(ST_GOTO);
+ stmt->label = thing->loopBreak;
+ } else {
+ CError_Error(CErrorStr169);
+ }
+ tk = lex();
+ break;
+
+ case TK_CONTINUE:
+ if (thing->loopContinue) {
+ stmt = CFunc_AppendStatement(ST_GOTO);
+ stmt->label = thing->loopContinue;
+ } else {
+ CError_Error(CErrorStr169);
+ }
+ tk = lex();
+ break;
+
+ case TK_FOR: {
+ CLabel *forLabel1;
+ CLabel *forLabel2;
+ CLabel *forLabel3;
+ ENode *forCond;
+ ENode *forInc;
+
+ if (lex() != '(')
+ CError_ErrorSkip(CErrorStr114);
+ else
+ tk = lex();
+
+ block = NULL;
+ if (tk != ';') {
+ if (!copts.cplusplus || !isdeclaration(1, 0, 0, 0)) {
+ expr = expression();
+ CExpr_CheckUnusedExpression(expr);
+ } else {
+ if (!copts.ARMscoping)
+ block = CFunc_NewDeclBlock();
+ expr = CFunc_ParseLocalDeclarationList(0, 1, 1, 0);
+ if (block && CScope_IsEmptyNameSpace(cscope_current)) {
+ CFunc_RestoreBlock(block);
+ block = NULL;
+ }
+ }
+
+ if (expr) {
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = expr;
+ }
+
+ if (tk == ';')
+ CError_ResetErrorSkip();
+ else
+ CError_Error(CErrorStr123);
+ } else {
+ CError_ResetErrorSkip();
+ }
+
+ if ((tk = lex()) != ';') {
+ if (copts.cplusplus && !copts.ARMscoping && isdeclaration(1, 0, 0, '=')) {
+ if (!block)
+ block = CFunc_NewDeclBlock();
+ expr = CFunc_ParseLocalDeclarationList(0, 1, 0, 0);
+ if (CScope_IsEmptyNameSpace(cscope_current)) {
+ CFunc_RestoreBlock(block);
+ block = NULL;
+ }
+ } else {
+ expr = expression();
+ CExpr_CheckUnwantedAssignment(expr);
+ }
+
+ forCond = CExpr_ConvertToCondition(expr);
+
+ if (tk == ';')
+ CError_ResetErrorSkip();
+ else
+ CError_Error(CErrorStr123);
+ } else {
+ CError_ResetErrorSkip();
+ forCond = NULL;
+ }
+
+ if ((tk = lex()) != ')') {
+ forInc = expression();
+ CExpr_CheckUnusedExpression(forInc);
+ if (tk == ')')
+ CError_ResetErrorSkip();
+ else
+ CError_Error(CErrorStr115);
+ } else {
+ CError_ResetErrorSkip();
+ forInc = NULL;
+ }
+
+ if (copts.warn_possunwant) {
+ spaceskip = 0;
+ if ((tk = lex()) == ';' && !spaceskip)
+ CError_Warning(CErrorStr206);
+ } else {
+ tk = lex();
+ }
+
+ if (forCond) {
+ stmt = CFunc_AppendStatement(ST_GOTO);
+ label = newlabel();
+ stmt->label = label;
+ } else {
+ label = newlabel();
+ }
+
+ CFunc_LoopIncrement();
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ forLabel1 = stmt->label = newlabel();
+ forLabel1->stmt = stmt;
+
+ forLabel2 = newlabel();
+ forLabel3 = newlabel();
+
+ subthing = *thing;
+ subthing.loopContinue = forLabel3;
+ subthing.loopBreak = forLabel2;
+
+ if (tk != '{') {
+ DeclBlock *b = CFunc_NewDeclBlock();
+ CFunc_CompoundStatement(&subthing);
+ CFunc_RestoreBlock(b);
+ } else {
+ CFunc_CompoundStatement(&subthing);
+ }
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = forLabel3;
+ forLabel3->stmt = stmt;
+
+ if (forInc) {
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = forInc;
+ }
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = label;
+ label->stmt = stmt;
+
+ ifstatement(1, forCond, forLabel1, 1);
+ CFunc_LoopDecrement();
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = forLabel2;
+ forLabel2->stmt = stmt;
+
+ if (block)
+ CFunc_RestoreBlock(block);
+
+ return;
+ }
+
+ case TK_DO: {
+ CLabel *label1;
+ CLabel *label2;
+ CLabel *label3;
+
+ CFunc_LoopIncrement();
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ label1 = stmt->label = newlabel();
+ label1->stmt = stmt;
+
+ label2 = newlabel();
+ label3 = newlabel();
+
+ subthing = *thing;
+ subthing.loopContinue = label2;
+ subthing.loopBreak = label3;
+
+ tk = lex();
+ CFunc_CompoundStatement(&subthing);
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = label2;
+ label2->stmt = stmt;
+
+ if (tk != TK_WHILE)
+ CError_Error(CErrorStr105);
+
+ if (lex() != '(')
+ CError_ErrorSkip(CErrorStr114);
+ else
+ tk = lex();
+
+ expr = CExpr_ConvertToCondition(expression());
+ CExpr_CheckUnwantedAssignment(expr);
+
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+
+ ifstatement(1, expr, label1, 1);
+
+ CFunc_LoopDecrement();
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = label3;
+ label3->stmt = stmt;
+ break;
+ }
+
+ case TK_WHILE: {
+ CLabel *label1;
+ CLabel *label2;
+ CLabel *label3;
+
+ if ((tk = lex()) != '(')
+ CError_ErrorSkip(CErrorStr114);
+ else
+ tk = lex();
+
+ if (copts.cplusplus && !copts.ARMscoping && isdeclaration(1, 0, 0, '=')) {
+ block = CFunc_NewDeclBlock();
+ expr = CFunc_ParseLocalDeclarationList(0, 1, 0, 0);
+ if (CScope_IsEmptyNameSpace(cscope_current)) {
+ CFunc_RestoreBlock(block);
+ block = NULL;
+ }
+ } else {
+ expr = expression();
+ block = NULL;
+ CExpr_CheckUnwantedAssignment(expr);
+ }
+ expr = CExpr_ConvertToCondition(expr);
+
+ if (tk != ')') {
+ CError_ErrorSkip(CErrorStr115);
+ } else {
+ if (copts.warn_possunwant) {
+ spaceskip = 0;
+ if ((tk = lex()) == ';' && !spaceskip)
+ CError_Warning(CErrorStr206);
+ } else {
+ tk = lex();
+ }
+ }
+
+ stmt = CFunc_AppendStatement(ST_GOTO);
+ label1 = newlabel();
+ stmt->label = label1;
+
+ CFunc_LoopIncrement();
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ label2 = stmt->label = newlabel();
+ label2->stmt = stmt;
+
+ label3 = newlabel();
+
+ subthing = *thing;
+ subthing.loopContinue = label1;
+ subthing.loopBreak = label3;
+
+ CFunc_CompoundStatement(&subthing);
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = label1;
+ label1->stmt = stmt;
+
+ ifstatement(1, expr, label2, 1);
+
+ CFunc_LoopDecrement();
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = label3;
+ label3->stmt = stmt;
+
+ if (block)
+ CFunc_RestoreBlock(block);
+ return;
+ }
+
+ case TK_IF: {
+ CLabel *label1;
+ if ((tk = lex()) != '(')
+ CError_ErrorSkip(CErrorStr114);
+ else
+ tk = lex();
+
+ if (copts.cplusplus && !copts.ARMscoping && isdeclaration(1, 0, 0, '=')) {
+ block = CFunc_NewDeclBlock();
+ expr = CFunc_ParseLocalDeclarationList(0, 1, 0, 0);
+ if (CScope_IsEmptyNameSpace(cscope_current)) {
+ CFunc_RestoreBlock(block);
+ block = NULL;
+ }
+ } else {
+ expr = expression();
+ block = NULL;
+ CExpr_CheckUnwantedAssignment(expr);
+ }
+
+ expr = CExpr_ConvertToCondition(expr);
+
+ label1 = newlabel();
+ ifstatement(0, expr, label1, 0);
+
+ if (tk != ')') {
+ CError_ErrorSkip(CErrorStr115);
+ } else {
+ if (copts.warn_possunwant) {
+ spaceskip = 0;
+ if ((tk = lex()) == ';' && !spaceskip)
+ CError_Warning(CErrorStr206);
+ } else {
+ tk = lex();
+ }
+ }
+
+ CFunc_CompoundStatement(thing);
+
+ if (tk == TK_ELSE) {
+ if (copts.warn_possunwant) {
+ spaceskip = 0;
+ if ((tk = lex()) == ';' && !spaceskip)
+ CError_Warning(CErrorStr206);
+ } else {
+ tk = lex();
+ }
+
+ stmt = CFunc_AppendStatement(ST_GOTO);
+ label = stmt->label = newlabel();
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = label1;
+ label1->stmt = stmt;
+
+ CFunc_CompoundStatement(thing);
+
+ label1 = label;
+ }
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = label1;
+ label1->stmt = stmt;
+
+ if (block)
+ CFunc_RestoreBlock(block);
+
+ return;
+ }
+
+ case '{':
+ CFunc_CompoundStatement(thing);
+ return;
+
+ case TK_ASM:
+ if (copts.cplusplus || !copts.ANSIstrict) {
+ tk = lex();
+ volatileasm = 0;
+
+ if (tk == TK_VOLATILE || (tk == TK_IDENTIFIER && !strcmp(tkidentifier->name, "__volatile__"))) {
+ tk = lex();
+ volatileasm = 1;
+ }
+
+ if (tk == '(') {
+ InlineAsm_Assemble();
+ if (tk == ')') {
+ tk = lex();
+ break;
+ } else {
+ CError_Error(CErrorStr115);
+ return;
+ }
+ }
+
+ if (tk == '{') {
+ InlineAsm_Assemble();
+ if (tk != '}') {
+ CError_Error(CErrorStr130);
+ return;
+ }
+ if ((tk = lex()) == ';')
+ tk = lex();
+ CError_ResetErrorSkip();
+ return;
+ }
+
+ CError_Error(CErrorStr114);
+ } else {
+ CError_Error(CErrorStr121);
+ }
+ return;
+
+ case TK_TRY:
+ tk = lex();
+ CExcept_ScanTryBlock(thing, 0);
+ return;
+
+ case TK_USING:
+ if ((tk = lex()) == TK_NAMESPACE) {
+ tk = lex();
+ CScope_ParseUsingDirective(cscope_current);
+ } else {
+ CScope_ParseUsingDeclaration(cscope_current, 0, 0);
+ }
+ return;
+
+ case TK_NAMESPACE:
+ if ((tk = lex()) != TK_IDENTIFIER) {
+ CError_Error(CErrorStr107);
+ return;
+ }
+ name = tkidentifier;
+ if ((tk = lex()) != '=') {
+ CError_Error(CErrorStr121);
+ return;
+ }
+
+ CScope_ParseNameSpaceAlias(name);
+ break;
+
+ case ';':
+ break;
+
+ case TK_IDENTIFIER:
+ if (checklabel()) {
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ if ((stmt->label = findlabel())) {
+ if (stmt->label->stmt)
+ CError_Error(CErrorStr171, tkidentifier->name);
+ } else {
+ stmt->label = newlabel();
+ stmt->label->next = Labels;
+ Labels = stmt->label;
+ stmt->label->name = tkidentifier;
+ }
+
+ stmt->label->stmt = stmt;
+ tk = lex();
+ tk = lex();
+ statement(thing);
+ return;
+ }
+ tk = TK_IDENTIFIER;
+
+ default:
+ if (copts.cplusplus && isdeclaration(1, 0, 0, 0)) {
+ CFunc_ParseLocalDeclarationList(0, 0, 0, 1);
+ tk = lex();
+ return;
+ }
+
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = expression();
+ CExpr_CheckUnusedExpression(stmt->expr);
+ }
+
+ if (tk == ';') {
+ CPrep_TokenStreamFlush();
+ tk = lex();
+ CError_ResetErrorSkip();
+ } else {
+ CError_ErrorSkip(CErrorStr123);
+ }
+}
+
+void CFunc_CompoundStatement(DeclThing *thing) {
+ DeclBlock *block;
+
+ block = CFunc_NewDeclBlock();
+
+ if (tk == '{') {
+ tk = lex();
+ if (!copts.cplusplus && isdeclaration(0, 0, 0, 0))
+ CFunc_ParseLocalDeclarationList(0, 0, 0, 0);
+
+ while (tk != '}')
+ statement(thing);
+
+ CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath);
+ tk = lex();
+ } else {
+ statement(thing);
+ }
+
+ CFunc_RestoreBlock(block);
+}
+
+static void CFunc_InsertArgumentCopyConversion(Object *obj, Type *type1, Type *type2, Boolean flag) {
+ Object *newobj;
+ Statement *stmt;
+ ENode *expr;
+ NameSpaceObjectList *nsol;
+ ObjectList *list;
+
+ newobj = lalloc(sizeof(Object));
+ *newobj = *obj;
+ newobj->type = type2;
+
+ CFunc_SetupLocalVarInfo(newobj);
+
+ obj->name = CParser_GetUniqueName();
+ if (flag)
+ obj->type = CDecl_NewPointerType(type1);
+ else
+ obj->type = type1;
+
+ CError_ASSERT(2527, (nsol = CScope_FindName(cscope_current, newobj->name)) && nsol->object == OBJ_BASE(obj));
+ nsol->object = OBJ_BASE(newobj);
+
+ list = lalloc(sizeof(ObjectList));
+ list->object = newobj;
+ list->next = locals;
+ locals = list;
+
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ expr = create_objectnode(obj);
+ if (flag) {
+ expr->rtype = CDecl_NewPointerType(type1);
+ expr = makemonadicnode(expr, EINDIRECT);
+ }
+ expr->rtype = type1;
+
+ if (type1 != type2)
+ expr = promote(expr, type2);
+
+ stmt->expr = makediadicnode(create_objectnode(newobj), expr, EASS);
+}
+
+static void CFunc_AdjustOldStyleArgs(void) {
+ ObjectList *list;
+
+ for (list = arguments; list; list = list->next) {
+ if (IS_TYPE_FLOAT(list->object->type) && list->object->type->size < stdouble.size)
+ CFunc_InsertArgumentCopyConversion(list->object, TYPE(&stdouble), list->object->type, 0);
+ }
+}
+
+void CFunc_SetupNewFuncArgs(Object *func, FuncArg *args) {
+ Object *obj;
+ ObjectList *newlist;
+
+ arguments = NULL;
+
+ if (args != &elipsis && args != &oldstyle) {
+ newlist = NULL;
+
+ while (args && args != &elipsis) {
+ IsCompleteType(args->type);
+
+ obj = CParser_NewLocalDataObject(NULL, 0);
+ obj->name = !args->name ? no_name_node : args->name;
+ obj->type = args->type;
+ obj->qual = args->qual;
+ obj->sclass = args->sclass;
+
+ CFunc_SetupLocalVarInfo(obj);
+
+ if (IS_TYPE_CLASS(obj->type) && CClass_ReferenceArgument(TYPE_CLASS(obj->type))) {
+ obj->type = CDecl_NewPointerType(obj->type);
+ TPTR_QUAL(obj->type) = Q_REFERENCE | Q_RESTRICT;
+ }
+
+ if (obj->name == no_name_node && copts.ANSIstrict && !copts.cplusplus && !(func->qual & Q_MANGLE_NAME))
+ CError_Error(CErrorStr127);
+
+ if (newlist) {
+ newlist->next = lalloc(sizeof(ObjectList));
+ newlist = newlist->next;
+ } else {
+ newlist = lalloc(sizeof(ObjectList));
+ arguments = newlist;
+ }
+
+ newlist->next = NULL;
+ newlist->object = obj;
+
+ args = args->next;
+ }
+ }
+}
+
+static ObjectList *CFunc_CopyObjectList(const FuncArg *args) {
+ Object *obj;
+ ObjectList *list;
+ ObjectList *last;
+
+ list = NULL;
+
+ while (args) {
+ if (list) {
+ last->next = lalloc(sizeof(ObjectList));
+ last = last->next;
+ } else {
+ last = lalloc(sizeof(ObjectList));
+ list = last;
+ }
+
+ obj = CParser_NewLocalDataObject(NULL, 0);
+ obj->name = args->name;
+ obj->type = args->type;
+ obj->qual = args->qual;
+ obj->sclass = args->sclass;
+ CFunc_SetupLocalVarInfo(obj);
+
+ last->object = obj;
+ last->next = NULL;
+
+ args = args->next;
+ }
+
+ return list;
+}
+
+static void SetupFunctionArguments(Object *func, DeclInfo *di, Statement *firstStmt) {
+ ObjectList *list;
+ Object *resultobj;
+ Object *obj;
+ Type *type;
+ DeclInfo my_di;
+
+ if (TYPE_FUNC(func->type)->args) {
+ if (di->x45) {
+ arguments = CFunc_CopyObjectList(di->x18);
+ while (1) {
+ if (tk == '{')
+ break;
+
+ memclrw(&my_di, sizeof(my_di));
+ CParser_GetDeclSpecs(&my_di, 0);
+
+ type = my_di.thetype;
+ if (my_di.storageclass && my_di.storageclass != TK_REGISTER)
+ CError_Error(CErrorStr127);
+
+ while (1) {
+ my_di.thetype = type;
+ my_di.name = NULL;
+ scandeclarator(&my_di);
+ if (!my_di.name) {
+ CError_Error(CErrorStr107);
+ break;
+ }
+
+ adjustargumenttype(&my_di);
+ IsCompleteType(my_di.thetype);
+
+ if ((obj = CFunc_IsInObjList(arguments, my_di.name))) {
+ if (obj->type)
+ CError_Error(CErrorStr333, obj);
+ obj->type = my_di.thetype;
+ obj->sclass = my_di.storageclass;
+ obj->qual = my_di.qual;
+ } else {
+ CError_Error(CErrorStr127);
+ }
+
+ if (tk != ',')
+ break;
+ tk = lex();
+ }
+
+ if (tk != ';')
+ CError_ErrorSkip(CErrorStr123);
+ else
+ tk = lex();
+ }
+
+ for (list = arguments; list; list = list->next) {
+ if (!list->object->type)
+ list->object->type = TYPE(&stsignedint);
+ }
+ } else {
+ CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
+ }
+ }
+
+ if (CMach_GetFunctionResultClass(TYPE_FUNC(func->type)) == 1) {
+ resultobj = CParser_NewLocalDataObject(NULL, 0);
+ resultobj->name = temp_argument_name;
+ resultobj->type = CDecl_NewPointerType(TYPE_FUNC(func->type)->functype);
+ CFunc_SetupLocalVarInfo(resultobj);
+
+ list = lalloc(sizeof(ObjectList));
+ list->object = resultobj;
+ if (CABI_GetStructResultArgumentIndex(TYPE_FUNC(func->type))) {
+ CError_ASSERT(2797, arguments);
+ list->next = arguments->next;
+ arguments->next = list;
+ } else {
+ list->next = arguments;
+ arguments = list;
+ }
+ }
+
+ for (list = arguments; list; list = list->next) {
+ NameSpaceObjectList *nsol = CScope_InsertName(cscope_current, list->object->name);
+ nsol->object = OBJ_BASE(list->object);
+ }
+}
+
+NameSpace *CFunc_FuncGenSetup(Statement *stmt, Object *func) {
+ NameSpace *nspace;
+ DeclBlock *block;
+
+ nspace = CScope_NewListNameSpace(NULL, 0);
+ nspace->parent = cscope_current;
+ cscope_current = nspace;
+
+ arguments = NULL;
+ locals = NULL;
+ Labels = NULL;
+
+ localcount = 0;
+ cfunc_staticvarcount = 0;
+
+ CExcept_Setup();
+
+ memclrw(stmt, sizeof(Statement));
+ curstmt = stmt;
+ stmt->type = ST_NOP;
+ curstmtvalue = 1;
+ stmt->value = 1;
+
+ blockcount = 0;
+ block = lalloc(sizeof(DeclBlock));
+ memclrw(block, sizeof(DeclBlock));
+ block->index = blockcount++;
+ block->parent_nspace = cscope_current;
+
+ firstblock = block;
+ currentblock = block;
+
+ return nspace;
+}
+
+CFuncSave *CFunc_GetGlobalCompilerState(void) {
+ CFuncSave *state;
+
+ if (!cscope_currentfunc && !cscope_currentclass && cscope_current == cscope_root)
+ return NULL;
+
+ locklheap();
+ state = lalloc(sizeof(CFuncSave));
+
+ CScope_SetNameSpaceScope(cscope_root, &state->scope);
+
+ state->arguments = arguments;
+ arguments = NULL;
+
+ state->locals = locals;
+ locals = NULL;
+
+ state->labels = Labels;
+ Labels = NULL;
+
+ state->curstmt = curstmt;
+ curstmt = NULL;
+
+ state->firstblock = firstblock;
+ firstblock = NULL;
+
+ state->currentblock = currentblock;
+ currentblock = NULL;
+
+ state->cexcept_dobjstack = cexcept_dobjstack;
+ cexcept_dobjstack = NULL;
+
+ state->sinit_label = sinit_label;
+ sinit_label = NULL;
+
+ state->ainit_expr = ainit_expr;
+ ainit_expr = NULL;
+
+ state->ctor_chain = ctor_chain;
+ ctor_chain = NULL;
+
+ state->cinit_tempnodefunc = cinit_tempnodefunc;
+ cinit_tempnodefunc = NULL;
+
+ state->trychain = trychain;
+ trychain = NULL;
+
+ state->cparser_fileoffset = cparser_fileoffset;
+ state->symdecltoken = symdecltoken;
+
+ state->functionbodyoffset = functionbodyoffset;
+ functionbodyoffset = 0;
+
+ state->functionbodypath = functionbodypath;
+ functionbodypath = NULL;
+
+ state->symdecloffset = symdecloffset;
+ symdecloffset = 0;
+
+ state->symdeclend = symdeclend;
+
+ state->sourceoffset = sourceoffset;
+ sourceoffset = 0;
+
+ state->sourcefilepath = sourcefilepath;
+ sourcefilepath = NULL;
+
+ state->curstmtvalue = curstmtvalue;
+ curstmtvalue = 0;
+
+ state->name_obj_check = name_obj_check;
+ name_obj_check = NULL;
+
+ state->check_arglist = check_arglist;
+ check_arglist = NULL;
+
+ state->blockcount = blockcount;
+ blockcount = 0;
+
+ state->localcount = localcount;
+ localcount = 0;
+
+ state->tk = tk;
+ state->tkidentifier = tkidentifier;
+
+ state->global_access = global_access;
+
+ state->cexcept_hasdobjects = cexcept_hasdobjects;
+ cexcept_hasdobjects = 0;
+
+ state->sinit_first_object = sinit_first_object;
+ sinit_first_object = NULL;
+
+ state->ainit_only_one = ainit_only_one;
+ ainit_only_one = 0;
+
+ state->cfunc_is_extern_c = cfunc_is_extern_c;
+ cfunc_is_extern_c = 0;
+
+ state->temp_reference_init = temp_reference_init;
+
+ return state;
+}
+
+void CFunc_SetGlobalCompilerState(CFuncSave *state) {
+ if (state) {
+ CScope_RestoreScope(&state->scope);
+
+ arguments = state->arguments;
+ locals = state->locals;
+ Labels = state->labels;
+ curstmt = state->curstmt;
+ firstblock = state->firstblock;
+ currentblock = state->currentblock;
+ cexcept_dobjstack = state->cexcept_dobjstack;
+ sinit_label = state->sinit_label;
+ ainit_expr = state->ainit_expr;
+ ctor_chain = state->ctor_chain;
+ cinit_tempnodefunc = state->cinit_tempnodefunc;
+ trychain = state->trychain;
+ name_obj_check = state->name_obj_check;
+ check_arglist = state->check_arglist;
+ curstmtvalue = state->curstmtvalue;
+ cparser_fileoffset = state->cparser_fileoffset;
+ symdecltoken = state->symdecltoken;
+ functionbodyoffset = state->functionbodyoffset;
+ functionbodypath = state->functionbodypath;
+ symdecloffset = state->symdecloffset;
+ symdeclend = state->symdeclend;
+ sourceoffset = state->sourceoffset;
+ sourcefilepath = state->sourcefilepath;
+ blockcount = state->blockcount;
+ tk = state->tk;
+ tkidentifier = state->tkidentifier;
+ global_access = state->global_access;
+ localcount = state->localcount;
+ cexcept_hasdobjects = state->cexcept_hasdobjects;
+ sinit_first_object = state->sinit_first_object;
+ ainit_only_one = state->ainit_only_one;
+ cfunc_is_extern_c = state->cfunc_is_extern_c;
+ temp_reference_init = state->temp_reference_init;
+
+ unlocklheap();
+ }
+}
+
+void CFunc_Gen(Statement *stmt, Object *func, UInt8 unk) {
+ Boolean flag;
+ CI_FuncData packed;
+
+ if ((TYPE_FUNC(func->type)->flags & FUNC_FLAGS_400000) && !anyerrors) {
+ CInline_PackIFunctionData(&packed, stmt, func);
+ flag = 1;
+ } else {
+ flag = 0;
+ }
+
+ CInline_GenFunc(stmt, func, unk);
+
+ if (flag)
+ CClass_DefineCovariantFuncs(func, &packed);
+}
+
+static void CFunc_CheckCtorInitializer(TypeClass *tclass, CtorChain *chain) {
+ ObjMemberVar *ivar;
+ CtorChain *scan;
+
+ if (tclass->mode != CLASS_MODE_UNION) {
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ if (IS_TYPE_REFERENCE(ivar->type)) {
+ for (scan = chain; scan; scan = scan->next) {
+ if (scan->what == CtorChain_MemberVar && scan->u.membervar == ivar)
+ break;
+ }
+
+ if (!scan)
+ CError_Error(CErrorStr256, ivar->name->name);
+ } else if (CParser_IsConst(ivar->type, ivar->qual)) {
+ for (scan = chain; scan; scan = scan->next) {
+ if (scan->what == CtorChain_MemberVar && scan->u.membervar == ivar)
+ break;
+ }
+
+ if (!scan && !IS_TYPE_CLASS(ivar->type))
+ CError_Error(CErrorStr255, ivar->name->name);
+ }
+ }
+ }
+}
+
+void CFunc_CheckClassCtors(TypeClass *tclass) {
+ CFunc_CheckCtorInitializer(tclass, NULL);
+}
+
+static void CFunc_ParseCtorInitializer(void) {
+ CtorChain *chain;
+ ENodeList *args;
+ TypeClass *tclass;
+ ObjMemberVar *ivar;
+ ClassList *base;
+ VClassList *vbase;
+ ENode *expr;
+ Type *origtype;
+
+ ctor_chain = NULL;
+
+ if (tk == ':') {
+ do {
+ tclass = NULL;
+ switch ((tk = lex())) {
+ case TK_IDENTIFIER:
+ for (ivar = cscope_currentclass->ivars; ivar; ivar = ivar->next) {
+ if (ivar->name == tkidentifier && lookahead() == '(')
+ goto do_ivar;
+ }
+ for (base = cscope_currentclass->bases; base; base = base->next) {
+ if (base->base->classname == tkidentifier) {
+ if (lookahead() == '(') {
+ tclass = base->base;
+ tk = lex();
+ } else {
+ tkidentifier = base->base->classname;
+ }
+ break;
+ }
+ }
+ break;
+
+ case TK_COLON_COLON:
+ break;
+
+ default:
+ CError_Error(CErrorStr212);
+ return;
+ }
+
+ if (!tclass)
+ tclass = CClass_GetQualifiedClass();
+
+ if (tclass) {
+ for (vbase = cscope_currentclass->vbases; vbase; vbase = vbase->next) {
+ if (vbase->base == tclass)
+ break;
+ }
+
+ if (vbase) {
+ for (chain = ctor_chain; chain; chain = chain->next) {
+ if (chain->what == CtorChain_VBase && chain->u.vbase == vbase) {
+ CError_Error(CErrorStr212);
+ return;
+ }
+ }
+
+ chain = lalloc(sizeof(CtorChain));
+ chain->what = CtorChain_VBase;
+ chain->u.vbase = vbase;
+ } else {
+ for (base = cscope_currentclass->bases; base; base = base->next) {
+ if (base->base == tclass)
+ break;
+ }
+
+ if (base) {
+ for (chain = ctor_chain; chain; chain = chain->next) {
+ if (chain->what == CtorChain_Base && chain->u.base == base) {
+ CError_Error(CErrorStr212);
+ return;
+ }
+ }
+
+ chain = lalloc(sizeof(CtorChain));
+ chain->what = CtorChain_Base;
+ chain->u.base = base;
+ } else {
+ CError_Error(CErrorStr212);
+ return;
+ }
+ }
+ } else {
+ for (ivar = cscope_currentclass->ivars; ivar; ivar = ivar->next) {
+ if (ivar->name == tkidentifier)
+ break;
+ }
+
+ if (ivar) {
+ do_ivar:
+ for (chain = ctor_chain; chain; chain = chain->next) {
+ if (chain->what == CtorChain_MemberVar && chain->u.membervar == ivar)
+ CError_Error(CErrorStr212);
+ }
+
+ chain = lalloc(sizeof(CtorChain));
+ chain->what = CtorChain_MemberVar;
+ chain->u.membervar = ivar;
+ } else {
+ CError_Error(CErrorStr212);
+ return;
+ }
+
+ tk = lex();
+ }
+
+ if (tk != '(') {
+ CError_Error(CErrorStr114);
+ return;
+ }
+
+ tk = lex();
+ args = CExpr_ScanExpressionList(1);
+
+ if (tk != ')') {
+ CError_Error(CErrorStr115);
+ return;
+ }
+
+ switch (chain->what) {
+ case CtorChain_Base:
+ expr = CABI_MakeThisExpr(NULL, chain->u.base->offset);
+ chain->objexpr = CExpr_ConstructObject(chain->u.base->base, expr, args, 1, 0, 0, 0, 1);
+ break;
+ case CtorChain_VBase:
+ expr = CABI_MakeThisExpr(chain->u.vbase->base, chain->u.vbase->offset);
+ chain->objexpr = CExpr_ConstructObject(chain->u.vbase->base, expr, args, 1, 0, 0, 0, 1);
+ break;
+ case CtorChain_MemberVar:
+ expr = CABI_MakeThisExpr(cscope_currentclass, chain->u.membervar->offset);
+ expr->flags = chain->u.membervar->qual & ENODE_FLAG_QUALS;
+ switch (chain->u.membervar->type->type) {
+ case TYPECLASS:
+ chain->objexpr = CExpr_ConstructObject(TYPE_CLASS(chain->u.membervar->type), expr, args, 1, 1, 0, 1, 1);
+ break;
+ case TYPEARRAY:
+ if (args) {
+ CError_Error(CErrorStr212);
+ continue;
+ }
+ chain->objexpr = NULL;
+ break;
+ default:
+ if (!args) {
+ args = lalloc(sizeof(ENodeList));
+ args->next = NULL;
+ args->node = CExpr_DoExplicitConversion(chain->u.membervar->type, chain->u.membervar->qual, NULL);
+ }
+ if (args->next) {
+ CError_Error(CErrorStr212);
+ return;
+ }
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = chain->u.membervar->type;
+ if (IS_TYPE_BITFIELD(origtype = expr->rtype)) {
+ expr->data.monadic = makemonadicnode(expr->data.monadic, EBITFIELD);
+ expr->data.monadic->rtype = origtype;
+ expr->rtype = TYPE_BITFIELD(origtype)->bitfieldtype;
+ }
+
+ chain->objexpr = makediadicnode(expr, CExpr_AssignmentPromotion(args->node, expr->rtype, expr->flags, 1), EASS);
+ }
+ break;
+ default:
+ CError_FATAL(3286);
+ }
+
+ chain->next = ctor_chain;
+ ctor_chain = chain;
+ } while ((tk = lex()) == ',');
+ }
+}
+
+static void CFunc_FunctionRedefinedCheck(Object *func) {
+ if (TYPE_FUNC(func->type)->flags & FUNC_AUTO_GENERATED)
+ CError_Error(CErrorStr333, func);
+
+ if ((TYPE_FUNC(func->type)->flags & FUNC_DEFINED) && func->datatype != DINLINEFUNC)
+ CError_Error(CErrorStr333, func);
+
+ TYPE_FUNC(func->type)->flags |= FUNC_DEFINED;
+}
+
+static Object *CFunc_DeclareFuncName(char *str, HashNameNode *name) {
+ Object *obj;
+ Object *aliasobj;
+ DeclInfo di;
+
+ memclrw(&di, sizeof(di));
+ di.name = name;
+ di.storageclass = TK_STATIC;
+ di.qual = Q_CONST;
+ di.thetype = CDecl_NewArrayType(TYPE(&stchar), strlen(str) + 1);
+
+ obj = CParser_NewGlobalDataObject(&di);
+ aliasobj = CParser_NewAliasObject(obj, 0);
+ obj->nspace = cscope_root;
+ obj->datatype = DDATA;
+ CFunc_NameLocalStaticDataObject(obj, obj->name->name);
+
+ return aliasobj;
+}
+
+void CFunc_ParseFuncDef(Object *func, DeclInfo *di, TypeClass *tclass, Boolean is_method, Boolean is_static, NameSpace *nspace) {
+ Boolean has_try;
+ Object *nameobj_func;
+ Object *nameobj_FUNCTION;
+ Object *nameobj_pretty;
+ char *prettyname;
+ Statement *stmt18;
+ Statement *stmt16;
+ Statement firstStmt;
+ DeclThing thing;
+ CScopeSave scope;
+
+ nameobj_func = NULL;
+ nameobj_FUNCTION = NULL;
+ nameobj_pretty = NULL;
+ prettyname = NULL;
+
+ CError_ASSERT(3373, IS_TYPE_FUNC(func->type));
+
+ CFunc_FunctionRedefinedCheck(func);
+ CParser_UpdateObject(func, di);
+
+ if (!is_method) {
+ CScope_SetFunctionScope(func, &scope);
+ if (tclass)
+ cscope_current = tclass->nspace;
+ } else {
+ CScope_SetMethodScope(func, tclass, is_static, &scope);
+ }
+
+ if (nspace)
+ cscope_current = nspace;
+
+ if (cscope_currentclass)
+ CClass_MemberDef(func, cscope_currentclass);
+
+ cfunc_is_extern_c = di->is_extern_c;
+
+ CError_ASSERT(3392, IS_TYPE_FUNC(func->type));
+ if (di->x45 && (func->qual & Q_ASM))
+ CError_Error(CErrorStr176);
+
+ if (cparamblkptr->precompile == 1 && !(func->qual & Q_INLINE))
+ CError_ErrorTerm(CErrorStr180);
+
+ if (di->x49)
+ CError_Error(CErrorStr127);
+
+ CFunc_FuncGenSetup(&firstStmt, func);
+ if (!IS_TYPE_VOID(TYPE_FUNC(func->type)->functype))
+ IsCompleteType(TYPE_FUNC(func->type)->functype);
+
+ SetupFunctionArguments(func, di, &firstStmt);
+
+ stmt18 = curstmt;
+ CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath);
+ functionbodyoffset = sourceoffset;
+ firstStmt.sourceoffset = sourceoffset;
+ functionbodypath = sourcefilepath;
+ firstStmt.sourcefilepath = sourcefilepath;
+
+ if (di->x45)
+ CFunc_AdjustOldStyleArgs();
+
+ if (di->x1C)
+ CScope_MergeNameSpace(cscope_current, di->x1C);
+
+ if (tk == TK_TRY) {
+ tk = lex();
+ has_try = 1;
+ } else {
+ has_try = 0;
+ }
+
+ if (CClass_IsConstructor(func)) {
+ CError_ASSERT(3445, cscope_currentclass);
+ CFunc_ParseCtorInitializer();
+ CFunc_CheckCtorInitializer(cscope_currentclass, ctor_chain);
+ }
+
+ CPrep_TokenStreamFlush();
+
+ if (!(func->qual & Q_ASM)) {
+ if (tk == '{') {
+ if (!has_try)
+ tk = lex();
+ } else {
+ CError_ErrorSkip(CErrorStr135);
+ has_try = 0;
+ }
+
+ if (func->name) {
+ nameobj_func = CFunc_DeclareFuncName(func->name->name, GetHashNameNode("__func__"));
+ nameobj_FUNCTION = CFunc_DeclareFuncName(func->name->name, GetHashNameNode("__FUNCTION__"));
+ prettyname = CError_GetObjectName(func);
+ nameobj_pretty = CFunc_DeclareFuncName(prettyname, GetHashNameNode("__PRETTY_FUNCTION__"));
+ }
+
+ if (!copts.cplusplus)
+ CFunc_ParseLocalDeclarationList(0, 0, 0, 0);
+
+ thing.switchinfo = NULL;
+ thing.loopContinue = NULL;
+ thing.loopBreak = NULL;
+ thing.thetype = TYPE_FUNC(func->type)->functype;
+ thing.qual = TYPE_FUNC(func->type)->qual;
+
+ if (has_try) {
+ CExcept_ScanTryBlock(&thing, CClass_IsConstructor(func) || CClass_IsDestructor(func));
+ if (tk != 0)
+ CPrep_UnLex();
+ tk = '}';
+ } else {
+ while (tk != '}')
+ statement(&thing);
+ }
+
+ stmt16 = curstmt;
+
+ if (stmt16->type != ST_RETURN && stmt16->type != ST_GOTO) {
+ CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath);
+ CFunc_AppendStatement(ST_RETURN);
+
+ curstmt->dobjstack = NULL;
+ curstmt->expr = NULL;
+
+ if (
+ (copts.cplusplus || copts.c9x) &&
+ !strcmp(func->name->name, "main") &&
+ TYPE_FUNC(func->type)->functype == TYPE(&stsignedint)
+ )
+ curstmt->expr = intconstnode(TYPE(&stsignedint), 0);
+
+ if (
+ stmt16->type == ST_EXPRESSION &&
+ stmt16->expr->type == EFUNCCALL &&
+ stmt16->expr->rtype == &stvoid &&
+ (stmt16->expr->flags & ENODE_FLAG_VOLATILE)
+ )
+ curstmt->flags = curstmt->flags | StmtFlag_8;
+ }
+
+ CheckCLabels();
+
+ if (nameobj_func && (nameobj_func->flags & OBJECT_USED))
+ CInit_DeclareData(nameobj_func->u.alias.object, func->name->name, NULL, strlen(func->name->name) + 1);
+ if (nameobj_FUNCTION && (nameobj_FUNCTION->flags & OBJECT_USED))
+ CInit_DeclareData(nameobj_FUNCTION->u.alias.object, func->name->name, NULL, strlen(func->name->name) + 1);
+ if (nameobj_pretty && (nameobj_pretty->flags & OBJECT_USED))
+ CInit_DeclareData(nameobj_pretty->u.alias.object, prettyname, NULL, strlen(prettyname) + 1);
+
+ if (!fatalerrors) {
+ if (CClass_IsConstructor(func))
+ CABI_TransConstructor(func, stmt18, cscope_currentclass, NULL, has_try);
+ if (CClass_IsDestructor(func))
+ CABI_TransDestructor(func, func, &firstStmt, cscope_currentclass, 0);
+
+ CFunc_DestructorCleanup(&firstStmt);
+ CFunc_CodeCleanup(&firstStmt);
+ symdeclend = CPrep_GetFileOffsetInfo(&cparser_fileoffset);
+ CFunc_Gen(&firstStmt, func, di->x45);
+ }
+ } else {
+ if (tk == '{') {
+ in_assembler = 1;
+ tk = lex();
+ in_assembler = 0;
+ } else {
+ CError_ErrorSkip(CErrorStr135);
+ }
+
+ CFunc_ParseLocalDeclarationList(1, 0, 0, 0);
+ Assembler(func);
+ }
+
+ if (tk != '}')
+ CError_Error(CErrorStr130);
+
+ CScope_RestoreScope(&scope);
+}
+
+void InitExpr_Register(ENode *expr, Object *object) {
+ InitExpr *initexpr;
+ InitExpr *scan;
+
+ if (
+ cparamblkptr->precompile == 1 &&
+ object->sclass != TK_STATIC &&
+ !(object->qual & (Q_20000 | Q_WEAK))
+ )
+ {
+ CError_Error(CErrorStr180);
+ return;
+ }
+
+ if (copts.suppress_init_code)
+ return;
+
+ initexpr = galloc(sizeof(InitExpr));
+ initexpr->next = NULL;
+ initexpr->object = object;
+ initexpr->expr = CInline_CopyExpression(expr, CopyMode1);
+
+ if (init_expressions) {
+ scan = init_expressions;
+ while (scan->next)
+ scan = scan->next;
+ scan->next = initexpr;
+ } else {
+ init_expressions = initexpr;
+ }
+}
+
+void CFunc_GenerateDummyFunction(Object *func) {
+ NameSpace *nspace;
+ Boolean saveDebugInfo;
+ Statement firstStmt;
+
+ if (!anyerrors) {
+ nspace = CFunc_FuncGenSetup(&firstStmt, NULL);
+
+ saveDebugInfo = copts.filesyminfo;
+ copts.filesyminfo = 0;
+
+ CFunc_CodeCleanup(&firstStmt);
+ CFunc_Gen(&firstStmt, func, 0);
+
+ cscope_current = nspace->parent;
+ copts.filesyminfo = saveDebugInfo;
+ }
+}
+
+void CFunc_GenerateSingleExprFunc(Object *func, ENode *expr) {
+ NameSpace *nspace;
+ Boolean saveDebugInfo;
+ Statement firstStmt;
+ Statement *stmt;
+
+ if (cparamblkptr->precompile == 1) {
+ CError_Error(CErrorStr180);
+ return;
+ }
+
+ if (!anyerrors) {
+ nspace = CFunc_FuncGenSetup(&firstStmt, func);
+
+ saveDebugInfo = copts.filesyminfo;
+ copts.filesyminfo = 0;
+
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = expr;
+
+ CFunc_CodeCleanup(&firstStmt);
+ CInline_GenFunc(&firstStmt, func, 0);
+
+ cscope_current = nspace->parent;
+ copts.filesyminfo = saveDebugInfo;
+ }
+}
+
+void CFunc_GenerateDummyCtorFunc(Object *func, Object *real_ctor) {
+ ENode *expr;
+ NameSpace *nspace;
+ FuncArg *arg1;
+ FuncArg *arg0;
+ ENodeList *list;
+ Boolean saveDebugInfo;
+ Statement firstStmt;
+ Statement *stmt;
+
+ if (cparamblkptr->precompile == 1) {
+ CError_Error(CErrorStr180);
+ return;
+ }
+
+ if (!anyerrors) {
+ cscope_currentfunc = func;
+
+ nspace = CFunc_FuncGenSetup(&firstStmt, func);
+
+ saveDebugInfo = copts.filesyminfo;
+ copts.filesyminfo = 0;
+
+ CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args);
+
+ expr = CExpr_NewENode(EFUNCCALL);
+ expr->type = EFUNCCALL;
+ expr->cost = 200;
+ expr->rtype = TYPE(&void_ptr);
+ expr->data.funccall.funcref = CExpr_MakeObjRefNode(real_ctor, 0);
+ expr->data.funccall.functype = TYPE_FUNC(func->type);
+
+ CError_ASSERT(3716, IS_TYPE_FUNC(real_ctor->type));
+ CError_ASSERT(3717, TYPE_FUNC(real_ctor->type)->flags & FUNC_METHOD);
+ CError_ASSERT(3718, arg0 = TYPE_FUNC(real_ctor->type)->args);
+ CError_ASSERT(3720, arg1 = arg0->next);
+ CError_ASSERT(3721, arguments);
+
+ list = lalloc(sizeof(ENodeList));
+ expr->data.funccall.args = list;
+ list->node = create_objectnode(arguments->object);
+
+ if (TYPE_METHOD(real_ctor->type)->theclass->flags & CLASS_HAS_VBASES) {
+ CError_ASSERT(3727, arg1 = arg1->next);
+ CError_ASSERT(3728, arguments->next);
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->node = create_objectnode(arguments->next->object);
+ }
+
+ while (arg1) {
+ CError_ASSERT(3737, arg1->dexpr);
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->node = CExpr_GetDefaultArgument(expr->data.funccall.funcref, arg1);
+ arg1 = arg1->next;
+ }
+
+ list->next = NULL;
+
+ stmt = CFunc_AppendStatement(ST_RETURN);
+ stmt->expr = expr;
+
+ CFunc_CodeCleanup(&firstStmt);
+ CInline_GenFunc(&firstStmt, func, 0);
+
+ cscope_current = nspace->parent;
+ cscope_currentfunc = NULL;
+ copts.filesyminfo = saveDebugInfo;
+ }
+}
diff --git a/compiler_and_linker/FrontEnd/C/CInit.c b/compiler_and_linker/FrontEnd/C/CInit.c
new file mode 100644
index 0000000..c2d2299
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CInit.c
@@ -0,0 +1,3082 @@
+#include "compiler/CInit.h"
+#include "compiler/CABI.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CException.h"
+#include "compiler/CExpr.h"
+#include "compiler/CInline.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrec.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CScope.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/ObjGenMachO.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+TempNodeCB cinit_tempnodefunc;
+InitInfo *cinit_initinfo;
+static PooledString *cinit_stringlist;
+static PooledString *cinit_pooledstringlist;
+static PooledString *cinit_pooledwstringlist;
+static ObjectList *cinit_tentative;
+static TypeClass *cinit_loop_class;
+static ENodeList *cinit_fdtnode;
+static Boolean cinit_fdtambig;
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct CInit_1C {
+ struct CInit_1C *next;
+ Type *type;
+ ENode *expr;
+ SInt32 offset;
+} CInit_1C;
+
+typedef struct CInit_Stuff {
+ struct CInit_Stuff *x0;
+ struct CInit_Stuff *x4;
+ char *buffer;
+ SInt32 xC;
+ SInt32 size;
+ SInt32 bufferSize;
+ SInt32 x18;
+ CInit_1C *x1C;
+ OLinkList *list;
+ Boolean flag;
+} CInit_Stuff;
+
+typedef enum {
+ Stage0,
+ Stage1,
+ Stage2,
+ Stage3,
+ Stage4
+} Stage;
+
+typedef struct CInit_Stuff2 {
+ ENode *expr;
+ ENode myexpr;
+ Stage stage;
+ Boolean x23;
+ SInt32 x24;
+ Type *type;
+} CInit_Stuff2;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+// forward decls
+static void CInit_InitType(CInit_Stuff *s, CInit_Stuff2 *s2, Type *type, UInt32 qual, Boolean flag);
+static void CInit_Type(Type *type, UInt32 qual, Boolean flag);
+
+void CInit_Init(void) {
+ cinit_tempnodefunc = NULL;
+ cinit_initinfo = NULL;
+ cinit_stringlist = NULL;
+ cinit_pooledstringlist = NULL;
+ cinit_pooledwstringlist = NULL;
+ cinit_tentative = NULL;
+}
+
+static void CInit_SetupInitInfo(InitInfo *info, Object *obj) {
+ memclrw(info, sizeof(InitInfo));
+ info->obj = obj;
+ info->next = cinit_initinfo;
+ cinit_initinfo = info;
+}
+
+static void CInit_CleanupInitInfo(InitInfo *info) {
+ cinit_initinfo = info->next;
+}
+
+static void CInit_SetupInitInfoBuffer(Type *type) {
+ SInt32 size = type->size;
+ cinit_initinfo->size = size;
+
+ if (!size)
+ size = 512;
+ else if (size & 1)
+ size++;
+
+ cinit_initinfo->buffer = lalloc(size);
+ cinit_initinfo->bufferSize = size;
+ memclrw(cinit_initinfo->buffer, size);
+}
+
+static void CInit_SetData(void *data, SInt32 offset, SInt32 size) {
+ SInt32 end;
+ char *buffer;
+
+ end = offset + size;
+ if (end > cinit_initinfo->size)
+ cinit_initinfo->size = end;
+
+ if (end > cinit_initinfo->bufferSize) {
+ if (cinit_initinfo->obj->type->size == 0) {
+ if (end < 8000)
+ end += 0x400;
+ else
+ end += 0x4000;
+ }
+ if (end & 1)
+ end++;
+
+ buffer = lalloc(end);
+ memclrw(buffer, end);
+ memcpy(buffer, cinit_initinfo->buffer, cinit_initinfo->bufferSize);
+ cinit_initinfo->buffer = buffer;
+ cinit_initinfo->bufferSize = end;
+ }
+
+ if (data)
+ memcpy(cinit_initinfo->buffer + offset, data, size);
+}
+
+typedef struct CInit_Initializer {
+ struct CInit_Initializer *next;
+ struct CInit_Initializer *sublist;
+ ENode *expr;
+ TStreamElement element;
+} CInit_Initializer;
+
+static CInit_Initializer *CInit_ParseInitializerList(void) {
+ CInit_Initializer *r30;
+ CInit_Initializer *r29;
+ CInit_Initializer *tmp;
+
+ if ((tk = lex()) == '}')
+ return NULL;
+
+ r30 = NULL;
+ do {
+ if (r30) {
+ tmp = lalloc(sizeof(CInit_Initializer));
+ r29->next = tmp;
+ r29 = tmp;
+ }
+ if (!r30) {
+ r30 = r29 = lalloc(sizeof(CInit_Initializer));
+ }
+ r29->next = NULL;
+
+ if (tk == '{') {
+ r29->element = *CPrep_CurStreamElement();
+ r29->sublist = CInit_ParseInitializerList();
+ r29->expr = NULL;
+ tk = lex();
+ } else {
+ r29->sublist = NULL;
+ r29->expr = conv_assignment_expression();
+ r29->element = *CPrep_CurStreamElement();
+ }
+
+ if (tk == '}')
+ return r30;
+
+ if (tk != ',') {
+ CError_Error(CErrorStr116);
+ return r30;
+ }
+ } while ((tk = lex()) != '}');
+
+ return r30;
+}
+
+static CInit_Initializer *CInit_ParseInitializerClause(void) {
+ CInit_Initializer *init;
+
+ init = lalloc(sizeof(CInit_Initializer));
+ init->next = NULL;
+ if (tk != '{') {
+ init->sublist = NULL;
+ init->expr = conv_assignment_expression();
+ init->element = *CPrep_CurStreamElement();
+ } else {
+ init->element = *CPrep_CurStreamElement();
+ init->expr = NULL;
+ init->sublist = CInit_ParseInitializerList();
+ tk = lex();
+ }
+
+ return init;
+}
+
+static ENode *CInit_ParseInitializer(ENode *expr) {
+ CInt64 save_int;
+ Float save_float;
+ SInt32 save_size;
+ short t;
+
+ switch (tk) {
+ case TK_INTCONST:
+ case TK_FLOATCONST:
+ save_int = tkintconst;
+ save_float = tkfloatconst;
+ save_size = tksize;
+ t = lookahead();
+ tkintconst = save_int;
+ tkfloatconst = save_float;
+ tksize = save_size;
+
+ switch (t) {
+ case ',':
+ case ';':
+ case '}':
+ memclrw(expr, sizeof(ENode));
+ switch (tk) {
+ case TK_INTCONST:
+ expr->type = EINTCONST;
+ expr->rtype = atomtype();
+ expr->data.intval = tkintconst;
+ break;
+ case TK_FLOATCONST:
+ expr->type = EFLOATCONST;
+ expr->rtype = atomtype();
+ expr->data.floatval = tkfloatconst;
+ break;
+ }
+ tk = lex();
+ CPrep_TokenStreamFlush();
+ return expr;
+ }
+ }
+
+ expr = assignment_expression();
+ CPrep_TokenStreamFlush();
+ return expr;
+}
+
+static Stage CInit_ParseNextInit(CInit_Stuff2 *s) {
+ DeclInfo di;
+ short t;
+
+ s->expr = NULL;
+ if (tk == ';') {
+ s->stage = Stage4;
+ return Stage4;
+ }
+ switch (s->stage) {
+ case Stage0:
+ if (s->x23) {
+ if (tk == '(') {
+ tk = lex();
+ CParser_GetDeclSpecs(&di, 1);
+ s->type = di.thetype;
+ if (tk == ')')
+ tk = lex();
+ else
+ CError_Error(CErrorStr115);
+
+ if (tk == '(')
+ tk = lex();
+ else
+ CError_Error(CErrorStr114);
+ s->x24++;
+ t = lookahead();
+ if (t == TK_UU_VECTOR || (t == TK_IDENTIFIER && !strcmp("vector", tkidentifier->name)))
+ CInit_ParseNextInit(s);
+ s->stage = Stage1;
+ return Stage1;
+ }
+ } else {
+ if (tk == '{') {
+ tk = lex();
+ s->x24 = 0;
+ s->stage = Stage1;
+ return Stage1;
+ }
+ }
+ s->expr = CInit_ParseInitializer(&s->myexpr);
+ s->stage = Stage2;
+ return Stage2;
+ case Stage1:
+ break;
+ case Stage2:
+ case Stage3:
+ if (tk == ',') {
+ tk = lex();
+ break;
+ }
+ if (s->x24) {
+ if (tk != ')')
+ CError_Error(CErrorStr174);
+ if (s->x24 > 1) {
+ s->x24--;
+ tk = lex();
+ CInit_ParseNextInit(s);
+ }
+ } else {
+ if (tk != '}')
+ CError_Error(CErrorStr174);
+ }
+ s->stage = Stage3;
+ return Stage3;
+ default:
+ CError_FATAL(389);
+ }
+
+ switch (tk) {
+ case '{':
+ tk = lex();
+ s->stage = Stage1;
+ return Stage1;
+ case '}':
+ s->stage = Stage3;
+ return Stage3;
+ case '(':
+ if (s->x23) {
+ tk = lex();
+ s->stage = Stage1;
+ return Stage1;
+ }
+ case ')':
+ if (s->x23 && s->x24) {
+ if (s->x24 > 1) {
+ s->x24--;
+ tk = lex();
+ CInit_ParseNextInit(s);
+ }
+ s->stage = Stage3;
+ return Stage3;
+ }
+ default:
+ s->expr = CInit_ParseInitializer(&s->myexpr);
+ s->stage = Stage2;
+ return Stage2;
+ }
+}
+
+static void CInit_CloseInitList(void) {
+ if (tk == ',' && copts.cplusplus)
+ tk = lex();
+
+ if (tk != '}')
+ CError_ErrorSkip(CErrorStr130);
+ else
+ tk = lex();
+}
+
+static Boolean CInit_IsAllZero(char *buf, SInt32 size) {
+ SInt32 i;
+
+ if (copts.explicit_zero_data)
+ return 0;
+
+ for (i = 0; i < size; i++)
+ if (buf[i]) return 0;
+
+ return 1;
+}
+
+static Boolean CInit_ClassNeedsConstruction(TypeClass *tclass) {
+ return CClass_Constructor(tclass) || CClass_Destructor(tclass);
+}
+
+static Boolean CInit_IsSimpleStructArrayInit(Type *type) {
+ switch (type->type) {
+ case TYPESTRUCT:
+ return 1;
+ case TYPEARRAY:
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+ if (!IS_TYPE_CLASS(type))
+ return 1;
+ case TYPECLASS:
+ return !CInit_ClassNeedsConstruction(TYPE_CLASS(type));
+ default:
+ return 0;
+ }
+}
+
+static Boolean CInit_IsSimpleInit(Type *type) {
+ switch (type->type) {
+ case TYPEPOINTER:
+ return (TYPE_POINTER(type)->qual & Q_REFERENCE) == 0;
+ case TYPEARRAY:
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+ if (!IS_TYPE_CLASS(type))
+ return 1;
+ case TYPECLASS:
+ return !CInit_ClassNeedsConstruction(TYPE_CLASS(type));
+ default:
+ return 1;
+ }
+}
+
+static Object *CInit_GetInitObject(Object *obj) {
+ if (obj->datatype == DALIAS) {
+ CError_ASSERT(521, !obj->u.alias.offset);
+ obj = obj->u.alias.object;
+ }
+ return obj;
+}
+
+static Object *CInit_CreateStaticDataObject(Type *type, UInt32 qual, HashNameNode *name) {
+ Object *obj;
+ DeclInfo di;
+
+ memclrw(&di, sizeof(DeclInfo));
+ di.thetype = type;
+ di.name = name ? name : CParser_GetUniqueName();
+ di.qual = qual;
+ di.storageclass = TK_STATIC;
+ di.is_extern_c = 1;
+
+ obj = CParser_NewGlobalDataObject(&di);
+ obj->nspace = cscope_root;
+ return obj;
+}
+
+static Type *CInit_GetRegMemType(void) {
+ return CDecl_NewStructType(void_ptr.size * 3, CMach_GetTypeAlign((Type *) &void_ptr));
+}
+
+static Object *CInit_CreateStaticData(Type *type) {
+ Object *obj = CInit_CreateStaticDataObject(type, 0, NULL);
+ CInit_DeclareData(obj, NULL, NULL, obj->type->size);
+ return obj;
+}
+
+static void CInit_InitNonConst(CInit_Stuff *s, Type *type, ENode *expr) {
+ CInit_1C *entry;
+ CInit_1C *scan;
+ MWVector128 *vec;
+
+ if (s->x4->flag || IS_TYPE_VECTOR(type)) {
+ if (IS_TYPE_VECTOR(type) && ENODE_IS(expr, EVECTOR128CONST)) {
+ vec = (MWVector128 *) (s->buffer + s->size);
+ *vec = expr->data.vector128val;
+ CMach_InitVectorMem(type, *vec, vec, 1);
+ }
+
+ entry = lalloc(sizeof(CInit_1C));
+ memclrw(entry, sizeof(CInit_1C));
+ entry->next = NULL;
+ entry->type = type;
+ entry->expr = expr;
+ entry->offset = s->xC + s->size;
+ if ((scan = s->x4->x1C)) {
+ while (scan->next)
+ scan = scan->next;
+ scan->next = entry;
+ } else {
+ s->x4->x1C = entry;
+ }
+ } else {
+ CError_Error(CErrorStr124);
+ }
+}
+
+static CInit_Stuff *CInit_GrowBuffer(CInit_Stuff *s, SInt32 size) {
+ CInit_Stuff *newbuf;
+
+ newbuf = lalloc(sizeof(CInit_Stuff));
+ memclrw(newbuf, sizeof(CInit_Stuff));
+ newbuf->x4 = s->x4;
+ newbuf->buffer = lalloc(size);
+ newbuf->xC = s->xC + s->size;
+ newbuf->bufferSize = size;
+ s->x0 = newbuf;
+ memset(newbuf->buffer, 0, newbuf->bufferSize);
+ return newbuf;
+}
+
+Boolean CInit_RelocInitCheck(ENode *expr, Object **objptr, CInt64 *valptr, Boolean flag) {
+ Object *objcheck1;
+ Object *objcheck2;
+ CInt64 valcheck1;
+ CInt64 valcheck2;
+
+ *objptr = NULL;
+ valptr->lo = 0;
+ valptr->hi = 0;
+
+ while (1) {
+ switch (expr->type) {
+ case EINTCONST:
+ *valptr = expr->data.intval;
+ return 1;
+ case EOBJREF:
+ objcheck1 = CInit_GetInitObject(expr->data.objref);
+ if (objcheck1->datatype == DLOCAL && !flag)
+ return 0;
+ *objptr = objcheck1;
+ return 1;
+ case ESTRINGCONST:
+ CInit_RewriteString(expr, 0);
+ continue;
+ case ETYPCON:
+ do {
+ if (expr->rtype->size != expr->data.monadic->rtype->size)
+ return 0;
+ expr = expr->data.monadic;
+ if (!IS_TYPE_POINTER_ONLY(expr->rtype) && !IS_TYPE_INT(expr->rtype))
+ return 0;
+ } while (ENODE_IS(expr, ETYPCON));
+ continue;
+ case EADD:
+ if (!CInit_RelocInitCheck(expr->data.diadic.left, &objcheck1, &valcheck1, flag))
+ return 0;
+ if (!CInit_RelocInitCheck(expr->data.diadic.right, &objcheck2, &valcheck2, flag))
+ return 0;
+
+ if (objcheck1) {
+ if (objcheck2)
+ return 0;
+ *objptr = objcheck1;
+ } else {
+ *objptr = objcheck1;
+ }
+
+ *valptr = CMach_CalcIntDiadic(TYPE(&stunsignedlong), valcheck1, '+', valcheck2);
+ return 1;
+ case ESUB:
+ if (!CInit_RelocInitCheck(expr->data.diadic.left, &objcheck1, &valcheck1, flag))
+ return 0;
+ if (!CInit_RelocInitCheck(expr->data.diadic.right, &objcheck2, &valcheck2, flag))
+ return 0;
+
+ if (objcheck2)
+ return 0;
+
+ *objptr = objcheck1;
+ *valptr = CMach_CalcIntDiadic(TYPE(&stunsignedlong), valcheck1, '-', valcheck2);
+ return 1;
+ default:
+ return 0;
+ }
+ }
+}
+
+static void CInit_InitTypePointer(CInit_Stuff *s, ENode *expr, TypePointer *tptr, UInt32 qual) {
+ Object *obj;
+ CInt64 val;
+ OLinkList *list;
+
+ expr = CExpr_AssignmentPromotion(expr, TYPE(tptr), qual & (Q_CONST | Q_VOLATILE), 1);
+ if (IS_TYPE_POINTER_ONLY(expr->rtype) || ENODE_IS(expr, EINTCONST)) {
+ if (CInit_RelocInitCheck(expr, &obj, &val, 0)) {
+ if (obj) {
+ list = lalloc(sizeof(OLinkList));
+ list->next = s->x4->list;
+ list->obj = obj;
+ list->somevalue = CInt64_GetULong(&val);
+ list->offset = s->xC + s->size;
+ s->x4->list = list;
+ } else {
+ CMach_InitIntMem(TYPE(&stunsignedlong), val, s->buffer + s->size);
+ }
+ } else {
+ CInit_InitNonConst(s, TYPE(tptr), expr);
+ }
+ } else {
+ CError_Error(CErrorStr174);
+ }
+}
+
+static void CInit_InitTypeInt(CInit_Stuff *s, ENode *expr, TypeIntegral *tint, UInt32 qual) {
+ expr = CExpr_AssignmentPromotion(expr, TYPE(tint), qual & (Q_CONST | Q_VOLATILE), 1);
+ if (IS_TYPE_INT(expr->rtype)) {
+ if (ENODE_IS(expr, EINTCONST)) {
+ CMach_InitIntMem(TYPE(tint), expr->data.intval, s->buffer + s->size);
+ } else if (ENODE_IS(expr, ETYPCON) && IS_TYPE_POINTER_ONLY(expr->data.monadic->rtype) && expr->rtype->size == 4 && (copts.cplusplus || !copts.ANSIstrict)) {
+ CInit_InitTypePointer(s, expr->data.monadic, TYPE_POINTER(expr->data.monadic->rtype), qual);
+ } else {
+ CInit_InitNonConst(s, TYPE(tint), expr);
+ }
+ } else {
+ CError_Error(CErrorStr174);
+ }
+}
+
+static void CInit_InitTypeFloat(CInit_Stuff *s, ENode *expr, TypeIntegral *tint, UInt32 qual) {
+ expr = CExpr_AssignmentPromotion(expr, TYPE(tint), qual & (Q_CONST | Q_VOLATILE), 1);
+ if (IS_TYPE_FLOAT(expr->rtype)) {
+ if (ENODE_IS(expr, EFLOATCONST)) {
+ CMach_InitFloatMem(TYPE(tint), expr->data.floatval, s->buffer + s->size);
+ } else {
+ CInit_InitNonConst(s, TYPE(tint), expr);
+ }
+ } else {
+ CError_Error(CErrorStr174);
+ }
+}
+
+static void CInit_InitTypeEnum(CInit_Stuff *s, ENode *expr, TypeEnum *tenum, UInt32 qual) {
+ expr = CExpr_AssignmentPromotion(expr, TYPE(tenum), qual & (Q_CONST | Q_VOLATILE), 1);
+ if (IS_TYPE_ENUM(expr->rtype)) {
+ if (ENODE_IS(expr, EINTCONST)) {
+ CMach_InitIntMem(tenum->enumtype, expr->data.intval, s->buffer + s->size);
+ } else {
+ CInit_InitNonConst(s, TYPE(tenum), expr);
+ }
+ } else {
+ CError_Error(CErrorStr174);
+ }
+}
+
+static void CInit_InitTypeMemberPointer(CInit_Stuff *s, ENode *expr, TypeMemberPointer *tmptr, UInt32 qual) {
+ expr = CExpr_AssignmentPromotion(expr, TYPE(tmptr), qual & (Q_CONST | Q_VOLATILE), 1);
+ if (ENODE_IS(expr, EINTCONST)) {
+ CMach_InitIntMem(TYPE(&stsignedlong), expr->data.intval, s->buffer + s->size);
+ } else {
+ CInit_InitNonConst(s, TYPE(tmptr), expr);
+ }
+}
+
+static void CInit_SetBitfield(TypeBitfield *tbitfield, UInt8 *buffer, CInt64 val) {
+ int i;
+ int pos;
+ int step;
+
+ if (copts.littleendian) {
+ pos = tbitfield->offset;
+ step = 1;
+ } else {
+ pos = tbitfield->bitlength + tbitfield->offset - 1;
+ step = -1;
+ }
+ for (i = 0; i < tbitfield->bitlength; i++, pos += step) {
+ if (CInt64_GetULong(&val) & 1) {
+ if (copts.littleendian) {
+ buffer[pos >> 3] |= 1 << (pos & 7);
+ } else {
+ buffer[pos >> 3] |= 0x80 >> (pos & 7);
+ }
+ }
+ val = CInt64_ShrU(val, cint64_one);
+ }
+}
+
+static void CInit_InitTypeBitfield(CInit_Stuff *s, ENode *expr, TypeBitfield *tbitfield, UInt32 qual) {
+ Type *inner;
+
+ inner = tbitfield->bitfieldtype;
+ if (IS_TYPE_ENUM(inner))
+ inner = TYPE_ENUM(inner)->enumtype;
+ expr = CExpr_AssignmentPromotion(expr, inner, qual & (Q_CONST | Q_VOLATILE), 1);
+
+ if (IS_TYPE_INT(expr->rtype)) {
+ if (ENODE_IS(expr, EINTCONST)) {
+ CInit_SetBitfield(tbitfield, (UInt8 *) s->buffer + s->size, expr->data.intval);
+ } else {
+ CInit_InitNonConst(s, TYPE(tbitfield), expr);
+ }
+ } else {
+ CError_Error(CErrorStr174);
+ }
+}
+
+static void CInit_InitTypeArray(CInit_Stuff *s, CInit_Stuff2 *s2, TypePointer *tptr, UInt32 qual, Boolean errorflag) {
+ SInt32 targetsize;
+ SInt32 start;
+ SInt32 i;
+ Boolean flag;
+ Boolean is_zero_size;
+ SInt32 size;
+ SInt32 tmp;
+ Boolean is_char_ptr;
+ Boolean is_wchar_ptr;
+
+ is_zero_size = tptr->size == 0;
+ targetsize = tptr->target->size;
+ if (!targetsize) {
+ CError_Error(CErrorStr145);
+ return;
+ }
+
+ is_char_ptr = IS_TYPE_INT(tptr->target) && (targetsize == 1);
+ is_wchar_ptr = IS_TYPE_INT(tptr->target) && (targetsize == stwchar.size);
+ switch (s2->stage) {
+ case Stage1:
+ flag = 1;
+ if (CInit_ParseNextInit(s2) == Stage3) {
+ if (is_zero_size)
+ CError_Error(CErrorStr174);
+ tk = lex();
+ return;
+ }
+ break;
+ case Stage2:
+ flag = 0;
+ break;
+ }
+ switch (s2->stage) {
+ case Stage1:
+ case Stage2:
+ break;
+ default:
+ CError_Error(CErrorStr174);
+ return;
+ }
+
+ if (s2->stage == Stage2)
+ s2->expr = pointer_generation(s2->expr);
+
+ if (s2->stage == Stage2 && ENODE_IS(s2->expr, ESTRINGCONST) && (is_char_ptr || is_wchar_ptr)) {
+ if (IS_TYPE_POINTER_ONLY(s2->expr->rtype) && tptr->target->size != TYPE_POINTER(s2->expr->rtype)->target->size)
+ CError_Warning(CErrorStr174);
+ size = tmp = s2->expr->data.string.size;
+ if (is_zero_size) {
+ tptr->size = s2->expr->data.string.size;
+ if (s->bufferSize < tmp)
+ s = CInit_GrowBuffer(s, tmp);
+ memcpy(s->buffer, s2->expr->data.string.data, size);
+ s->size = size;
+ } else {
+ if (s2->expr->data.string.size > tptr->size) {
+ if (copts.cplusplus || (s2->expr->data.string.size - 1) > tptr->size)
+ CError_Error(CErrorStr147);
+ s2->expr->data.string.size = tptr->size;
+ size = tptr->size;
+ }
+ memcpy(s->buffer + s->size, s2->expr->data.string.data, size);
+ }
+ } else {
+ if (!flag && errorflag) {
+ CError_Error(CErrorStr174);
+ return;
+ }
+
+ start = s->size;
+ i = 0;
+ while (1) {
+ if (is_zero_size) {
+ size = (i + 1) * targetsize;
+ s->size = start + size - targetsize - s->xC;
+ if (s->size + targetsize > s->bufferSize)
+ s = CInit_GrowBuffer(s, targetsize * 16);
+ CInit_InitType(s, s2, tptr->target, qual, 0);
+ tptr->size = size;
+ s->size = start + size - s->xC;
+ } else {
+ if (tptr->size <= i * targetsize) {
+ i--;
+ CError_Error(CErrorStr147);
+ }
+ s->size = start + i * targetsize;
+ CInit_InitType(s, s2, tptr->target, qual, 0);
+ if (!flag && tptr->size <= (i + 1) * targetsize)
+ break;
+ }
+
+ switch (CInit_ParseNextInit(s2)) {
+ case Stage1:
+ case Stage2:
+ break;
+ case Stage3:
+ if (flag)
+ tk = lex();
+ return;
+ default:
+ CError_Error(CErrorStr130);
+ return;
+ }
+
+ i++;
+ }
+ }
+
+ if (flag) {
+ switch (CInit_ParseNextInit(s2)) {
+ case Stage3:
+ tk = lex();
+ return;
+ case Stage2:
+ CError_Error(CErrorStr147);
+ return;
+ default:
+ CError_Error(CErrorStr130);
+ }
+ }
+}
+
+static void CInit_InitTypeStruct(CInit_Stuff *s, CInit_Stuff2 *s2, const TypeStruct *tstruct, UInt32 qual, Boolean errorflag) {
+ StructMember *member;
+ SInt32 start;
+ Boolean flag;
+ SInt32 count;
+ TypePointer arraytype;
+ MWVector128 *vecp;
+ int i;
+
+ count = 0;
+ if (s2->type)
+ tstruct = TYPE_STRUCT(s2->type);
+
+ if (!(member = tstruct->members)) {
+ CError_Error(CErrorStr145);
+ return;
+ }
+
+ switch (s2->stage) {
+ case Stage1:
+ flag = 1;
+ if (CInit_ParseNextInit(s2) == Stage3) {
+ tk = lex();
+ return;
+ }
+ break;
+ case Stage2:
+ flag = 0;
+ break;
+ }
+
+ switch (s2->stage) {
+ case Stage1:
+ case Stage2:
+ break;
+ default:
+ CError_Error(CErrorStr174);
+ return;
+ }
+
+ if (!flag && s2->stage == Stage2 && (errorflag || s2->expr->rtype == TYPE(tstruct))) {
+ s2->expr = CExpr_AssignmentPromotion(s2->expr, TYPE(tstruct), qual, 1);
+ if (IS_TYPE_STRUCT(s2->expr->rtype))
+ CInit_InitNonConst(s, TYPE(tstruct), s2->expr);
+ return;
+ }
+
+ start = s->size;
+ while (1) {
+ s->size = start + member->offset;
+ if (!member->type->size) {
+ if (!errorflag || !IS_TYPE_ARRAY(member->type)) {
+ CError_Error(CErrorStr147);
+ if (!IS_TYPE_ARRAY(member->type))
+ return;
+ }
+
+ arraytype = *TYPE_POINTER(member->type);
+ CInit_InitTypeArray(s, s2, &arraytype, member->qual, 1);
+ s->x18 = arraytype.size;
+ } else {
+ CInit_InitType(s, s2, member->type, member->qual, 0);
+ }
+
+ count++;
+ if (IS_TYPESTRUCT_VECTOR(tstruct) && s2->expr)
+ CError_ASSERT(1218, !ENODE_IS(s2->expr, EVECTOR128CONST));
+
+ do {
+ member = member->next;
+ } while (member && (member->qual & Q_WEAK));
+
+ if (!member || tstruct->stype == STRUCT_TYPE_UNION) {
+ if (flag) {
+ switch (CInit_ParseNextInit(s2)) {
+ case Stage3:
+ if (IS_TYPESTRUCT_VECTOR(tstruct)) {
+ vecp = (MWVector128 *) (s->buffer + start);
+ CMach_InitVectorMem(TYPE(tstruct), *vecp, vecp, 0);
+ }
+ tk = lex();
+ return;
+ case Stage2:
+ CError_Error(CErrorStr147);
+ return;
+ default:
+ CError_Error(CErrorStr130);
+ return;
+ }
+ }
+ return;
+ } else {
+ switch (CInit_ParseNextInit(s2)) {
+ case Stage1:
+ case Stage2:
+ continue;
+ case Stage3:
+ if (flag)
+ tk = lex();
+ if (IS_TYPESTRUCT_VECTOR(tstruct)) {
+ switch (TYPE_STRUCT(tstruct)->stype) {
+ case STRUCT_VECTOR_UCHAR:
+ case STRUCT_VECTOR_SCHAR:
+ case STRUCT_VECTOR_BCHAR:
+ if (count != 16) {
+ if (count == 1) {
+ UInt8 val, *p;
+ p = (UInt8 *) s->buffer;
+ val = p[0];
+ for (i = 1; i < 16; i++)
+ p[i] = val;
+ } else {
+ CError_Error(CErrorStr174);
+ }
+ }
+ break;
+ case STRUCT_VECTOR_USHORT:
+ case STRUCT_VECTOR_SSHORT:
+ case STRUCT_VECTOR_BSHORT:
+ case STRUCT_VECTOR_PIXEL:
+ if (count != 8) {
+ if (count == 1) {
+ SInt16 val, *p;
+ p = (SInt16 *) s->buffer;
+ val = p[0];
+ for (i = 1; i < 8; i++)
+ p[i] = val;
+ } else {
+ CError_Error(CErrorStr174);
+ }
+ }
+ break;
+ case STRUCT_VECTOR_UINT:
+ case STRUCT_VECTOR_SINT:
+ case STRUCT_VECTOR_BINT:
+ case STRUCT_VECTOR_FLOAT:
+ if (count != 4) {
+ if (count == 1) {
+ UInt32 val, *p;
+ p = (UInt32 *) s->buffer;
+ val = p[0];
+ for (i = 1; i < 4; i++)
+ p[i] = val;
+ } else {
+ CError_Error(CErrorStr174);
+ }
+ }
+ break;
+ }
+ }
+ return;
+ default:
+ CError_Error(CErrorStr174);
+ return;
+ }
+ }
+ }
+}
+
+static ObjMemberVar *CInit_FindNextMember(ObjMemberVar *ivar) {
+ ObjMemberVar *scan = ivar;
+ while (1) {
+ scan = scan->next;
+ if (!scan)
+ return NULL;
+ if (!scan->anonunion)
+ return scan;
+ if (scan->offset > ivar->offset)
+ return scan;
+ if (IS_TYPE_BITFIELD(scan->type) && IS_TYPE_BITFIELD(ivar->type) && TYPE_BITFIELD(scan->type)->offset != TYPE_BITFIELD(ivar->type)->offset)
+ return scan;
+ }
+}
+
+static void CInit_InitTypeClass(CInit_Stuff *s, CInit_Stuff2 *s2, TypeClass *tclass, UInt32 qual, Boolean errorflag) {
+ ObjMemberVar *ivar;
+ SInt32 start;
+ Boolean flag;
+ SInt32 last_offset;
+ TypePointer arraytype;
+
+ if (tclass->bases || tclass->vtable) {
+ CError_Error(CErrorStr174);
+ return;
+ }
+
+ switch (s2->stage) {
+ case Stage1:
+ flag = 1;
+ if (CInit_ParseNextInit(s2) == Stage3) {
+ tk = lex();
+ return;
+ }
+ break;
+ case Stage2:
+ flag = 0;
+ break;
+ }
+
+ switch (s2->stage) {
+ case Stage1:
+ case Stage2:
+ break;
+ default:
+ CError_Error(CErrorStr174);
+ return;
+ }
+
+ if (!flag && s2->stage == Stage2 && (errorflag || s2->expr->rtype == TYPE(tclass) || CExpr_CanImplicitlyConvert(s2->expr, TYPE(tclass), 0))) {
+ s2->expr = CExpr_AssignmentPromotion(s2->expr, TYPE(tclass), qual, 1);
+ if (IS_TYPE_CLASS(s2->expr->rtype))
+ CInit_InitNonConst(s, TYPE(tclass), s2->expr);
+ return;
+ }
+
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ if (ivar->access != ACCESSPUBLIC) {
+ CError_Error(CErrorStr174);
+ break;
+ }
+ }
+
+ if (!(ivar = tclass->ivars)) {
+ CError_Error(CErrorStr147);
+ return;
+ }
+ start = s->size;
+ while (1) {
+ s->size = start + ivar->offset;
+ if (!ivar->type->size) {
+ if (!errorflag || !IS_TYPE_ARRAY(ivar->type)) {
+ CError_Error(CErrorStr147);
+ if (!IS_TYPE_ARRAY(ivar->type))
+ return;
+ }
+
+ arraytype = *TYPE_POINTER(ivar->type);
+ CInit_InitTypeArray(s, s2, &arraytype, ivar->qual, 1);
+ s->x18 = arraytype.size;
+ } else {
+ CInit_InitType(s, s2, ivar->type, ivar->qual, 0);
+ }
+
+ last_offset = ivar->offset;
+ if (!(ivar = CInit_FindNextMember(ivar)) || (tclass->mode == CLASS_MODE_UNION && ivar->offset == last_offset)) {
+ if (flag) {
+ switch (CInit_ParseNextInit(s2)) {
+ case Stage3:
+ tk = lex();
+ return;
+ case Stage2:
+ CError_Error(CErrorStr147);
+ return;
+ default:
+ CError_Error(CErrorStr130);
+ return;
+ }
+ }
+ return;
+ } else {
+ switch (CInit_ParseNextInit(s2)) {
+ case Stage1:
+ case Stage2:
+ continue;
+ case Stage3:
+ if (flag)
+ tk = lex();
+ break;
+ default:
+ CError_Error(CErrorStr174);
+ }
+ return;
+ }
+ }
+}
+
+static void CInit_InitType(CInit_Stuff *s, CInit_Stuff2 *s2, Type *type, UInt32 qual, Boolean errorflag) {
+ Boolean flag;
+
+ switch (type->type) {
+ case TYPEVOID:
+ CError_Error(CErrorStr174);
+ break;
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPEBITFIELD:
+ case TYPEMEMBERPOINTER:
+ case TYPEPOINTER:
+ switch (s2->stage) {
+ case Stage1:
+ flag = 1;
+ CInit_ParseNextInit(s2);
+ break;
+ case Stage2:
+ flag = 0;
+ break;
+ }
+ if (s2->stage != Stage2) {
+ CError_Error(CErrorStr174);
+ return;
+ }
+
+ switch (type->type) {
+ case TYPEINT:
+ CInit_InitTypeInt(s, s2->expr, TYPE_INTEGRAL(type), qual);
+ break;
+ case TYPEFLOAT:
+ CInit_InitTypeFloat(s, s2->expr, TYPE_INTEGRAL(type), qual);
+ break;
+ case TYPEENUM:
+ CInit_InitTypeEnum(s, s2->expr, TYPE_ENUM(type), qual);
+ break;
+ case TYPEPOINTER:
+ CInit_InitTypePointer(s, s2->expr, TYPE_POINTER(type), qual);
+ break;
+ case TYPEMEMBERPOINTER:
+ CInit_InitTypeMemberPointer(s, s2->expr, TYPE_MEMBER_POINTER(type), qual);
+ break;
+ case TYPEBITFIELD:
+ CInit_InitTypeBitfield(s, s2->expr, TYPE_BITFIELD(type), qual);
+ break;
+ default:
+ CError_FATAL(1542);
+ }
+
+ if (flag) {
+ switch (CInit_ParseNextInit(s2)) {
+ case Stage3:
+ tk = lex();
+ break;
+ case Stage2:
+ CError_Error(CErrorStr147);
+ break;
+ default:
+ CError_Error(CErrorStr130);
+ }
+ }
+ break;
+ case TYPESTRUCT:
+ CInit_InitTypeStruct(s, s2, TYPE_STRUCT(type), qual, errorflag);
+ break;
+ case TYPEARRAY:
+ CInit_InitTypeArray(s, s2, TYPE_POINTER(type), qual, errorflag);
+ break;
+ case TYPECLASS:
+ CInit_InitTypeClass(s, s2, TYPE_CLASS(type), qual, errorflag);
+ break;
+ default:
+ CError_FATAL(1573);
+ }
+}
+
+static void CInit_InitData(CInit_Stuff *s, Type *type, UInt32 qual, Boolean flag) {
+ CInit_Stuff2 s2;
+ SInt32 size;
+ CInit_Stuff *tmp;
+ char *buffer;
+
+ locklheap();
+ memclrw(s, sizeof(CInit_Stuff));
+ s->x4 = s;
+ if (type->size == 0) {
+ if (IS_TYPE_ARRAY(type))
+ s->bufferSize = 16 * TYPE_POINTER(type)->target->size;
+ else
+ CError_Error(CErrorStr145);
+ } else {
+ s->bufferSize = type->size;
+ }
+
+ s->buffer = lalloc(s->bufferSize);
+ memset(s->buffer, 0, s->bufferSize);
+ s->flag = flag;
+
+ s2.stage = Stage0;
+ s2.x23 = 0;
+ if (IS_TYPE_VECTOR(type)) {
+ s2.x23 = 1;
+ s->flag = 1;
+ }
+ if (IS_TYPE_ARRAY(type) && IS_TYPE_VECTOR(TYPE_POINTER(type)->target)) {
+ s->flag = 1;
+ }
+
+ s2.type = NULL;
+ s2.x24 = 0;
+ CInit_ParseNextInit(&s2);
+ CInit_InitType(s, &s2, type, qual, 1);
+
+ if ((size = type->size + s->x18)) {
+ if (s->x0) {
+ buffer = lalloc(size);
+ for (tmp = s; tmp; tmp = tmp->x0) {
+ CError_ASSERT(1647, (tmp->xC + tmp->size) <= size);
+ memcpy(buffer + tmp->xC, tmp->buffer, tmp->size);
+ }
+ s->buffer = buffer;
+ }
+ } else {
+ CError_Error(CErrorStr174);
+ }
+
+ s->size = size;
+ s->x0 = NULL;
+ unlocklheap();
+}
+
+static ENode *CInit_InitConcat(ENode *a1, ENode *a2, SInt32 offset, Type *type, ENode *a5) {
+ ENode *r30;
+ ENode *r28;
+ ENode *tmp;
+
+ r28 = lalloc(sizeof(ENode));
+ *r28 = *a2;
+ if (offset)
+ r28 = makediadicnode(r28, intconstnode(TYPE(&stunsignedlong), offset), EADD);
+
+ if (IS_TYPE_BITFIELD(type)) {
+ tmp = makemonadicnode(r28, EBITFIELD);
+ tmp->rtype = type;
+ tmp = makemonadicnode(tmp, EINDIRECT);
+ tmp->rtype = TYPE_BITFIELD(type)->bitfieldtype;
+ } else {
+ tmp = makemonadicnode(r28, EINDIRECT);
+ tmp->rtype = type;
+ }
+
+ r30 = makediadicnode(tmp, a5, EASS);
+ if (!a1) {
+ return r30;
+ } else {
+ tmp = makediadicnode(a1, r30, ECOMMA);
+ tmp->rtype = r30->rtype;
+ return tmp;
+ }
+}
+
+static ENode *CInit_RegisterDtorObject(Type *type, Object *dtor, ENode *objexpr) {
+ ENode *expr;
+
+ if (copts.no_static_dtors)
+ return objexpr;
+
+ expr = lalloc(sizeof(ENode));
+ expr->type = EFUNCCALL;
+ expr->cost = 4;
+ expr->flags = 0;
+ expr->rtype = CDecl_NewPointerType(type);
+ expr->data.funccall.funcref = create_objectrefnode(Xgreg_func);
+ expr->data.funccall.functype = TYPE_FUNC(Xgreg_func->type);
+ expr->data.funccall.args = lalloc(sizeof(ENodeList));
+ expr->data.funccall.args->node = objexpr;
+ expr->data.funccall.args->next = lalloc(sizeof(ENodeList));
+ expr->data.funccall.args->next->node = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1));
+ expr->data.funccall.args->next->next = lalloc(sizeof(ENodeList));
+ expr->data.funccall.args->next->next->node = create_objectrefnode(CInit_CreateStaticData(CInit_GetRegMemType()));
+ expr->data.funccall.args->next->next->next = NULL;
+
+ return expr;
+}
+
+static Boolean CInit_ConstructGlobalObject(Object *obj, TypeClass *tclass, ENode *valueexpr, SInt32 offset, Boolean flag) {
+ NameSpaceObjectList *ctor;
+ Object *dtor;
+ ENodeList *list;
+ ENode *expr;
+ Boolean ctorflag;
+
+ ctor = CClass_Constructor(tclass);
+ dtor = CClass_Destructor(tclass);
+ if (!ctor && !dtor)
+ return 0;
+
+ if (flag && !ctor && tk == '=' && lookahead() == '{')
+ return 0;
+
+ if (flag && tk == '(') {
+ tk = lex();
+ list = CExpr_ScanExpressionList(1);
+ if (tk == ')')
+ tk = lex();
+ else
+ CError_Error(CErrorStr115);
+ } else if (valueexpr) {
+ list = lalloc(sizeof(ENodeList));
+ list->node = valueexpr;
+ list->next = NULL;
+ } else {
+ list = NULL;
+ }
+
+ expr = create_objectrefnode(obj);
+ if (offset)
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD);
+
+ if (ctor) {
+ ctorflag = 1;
+ if (tk == '=') {
+ ctorflag = 0;
+ if (list)
+ CError_Error(CErrorStr174);
+
+ list = lalloc(sizeof(ENodeList));
+ list->next = NULL;
+ tk = lex();
+ list->node = conv_assignment_expression();
+ }
+
+ expr = CExpr_ConstructObject(tclass, expr, list, 0, 1, 0, 1, ctorflag);
+ if (expr->rtype->type != TYPEPOINTER) {
+ CError_Error(CErrorStr174);
+ return 1;
+ }
+ } else {
+ if (list)
+ CError_Error(CErrorStr174);
+ }
+
+ if (dtor)
+ expr = CInit_RegisterDtorObject(TYPE(tclass), dtor, expr);
+
+ if (cinit_initinfo->x16)
+ cinit_initinfo->init_expr_register_cb(expr);
+ else
+ InitExpr_Register(expr, obj);
+
+ return 1;
+}
+
+static Boolean CInit_ConstructAutoObject(TypeClass *tclass, ENode *expr, SInt32 offset, Boolean flag) {
+ ENodeList *r30;
+ ENode *r29;
+ NameSpaceObjectList *ctor;
+ Object *dtor;
+ Boolean r24;
+
+ ctor = CClass_Constructor(tclass);
+ dtor = CClass_Destructor(tclass);
+ if (!ctor && !dtor)
+ return 0;
+
+ if (dtor)
+ CClass_CheckStaticAccess(NULL, tclass, dtor->access);
+
+ if (flag && !ctor && tk == '=' && lookahead() == '{')
+ return 0;
+
+ if (flag && tk == '(') {
+ tk = lex();
+ r30 = CExpr_ScanExpressionList(1);
+ if (tk == ')')
+ tk = lex();
+ else
+ CError_Error(CErrorStr115);
+ } else if (expr) {
+ r30 = lalloc(sizeof(ENodeList));
+ r30->node = expr;
+ r30->next = NULL;
+ } else {
+ r30 = NULL;
+ }
+
+ if (ctor) {
+ r24 = 1;
+ if (tk == '=') {
+ if (r30)
+ CError_Error(CErrorStr174);
+ r30 = lalloc(sizeof(ENodeList));
+ r30->next = NULL;
+ tk = lex();
+ r30->node = conv_assignment_expression();
+ r24 = 0;
+ }
+
+ if (!dtor) {
+ r29 = create_objectrefnode(cinit_initinfo->obj1C);
+ if (offset)
+ r29 = makediadicnode(r29, intconstnode(TYPE(&stunsignedlong), offset), EADD);
+ } else {
+ r29 = cinit_initinfo->register_object_cb(TYPE(tclass), cinit_initinfo->obj1C, offset, 0);
+ }
+
+ r29 = CExpr_ConstructObject(tclass, r29, r30, 0, 1, 0, 1, r24);
+ if (!IS_TYPE_POINTER_ONLY(r29->rtype)) {
+ CError_Error(CErrorStr174);
+ return 1;
+ }
+ r29 = makemonadicnode(r29, EINDIRECT);
+ r29->rtype = TYPE_POINTER(r29->rtype)->target;
+ cinit_initinfo->insert_expr_cb(r29);
+ } else {
+ if (r30)
+ CError_Error(CErrorStr174);
+ if (dtor)
+ r29 = cinit_initinfo->register_object_cb(TYPE(tclass), cinit_initinfo->obj1C, offset, 0);
+ cinit_initinfo->insert_expr_cb(r29);
+ }
+
+ return 1;
+}
+
+static void CInit_ExprPointer(TypePointer *tptr, ENode *expr) {
+ Object *obj;
+ CInt64 val;
+ OLinkList *list;
+
+ if (CInit_RelocInitCheck(expr, &obj, &val, 0)) {
+ if (obj) {
+ list = lalloc(sizeof(OLinkList));
+ list->next = cinit_initinfo->list;
+ list->obj = obj;
+ list->somevalue = CInt64_GetULong(&val);
+ list->offset = cinit_initinfo->expr_offset;
+ cinit_initinfo->list = list;
+ } else {
+ CMach_InitIntMem(TYPE(&stunsignedlong), val, cinit_initinfo->buffer + cinit_initinfo->expr_offset);
+ }
+ } else if (cinit_initinfo->expr_cb) {
+ cinit_initinfo->expr_cb(TYPE(tptr), expr, 0);
+ cinit_initinfo->expr_cb_called = 1;
+ } else {
+ CError_Error(CErrorStr124);
+ }
+
+ cinit_initinfo->expr_offset += 4;
+}
+
+static void CInit_ExprInt(TypeIntegral *tint, ENode *expr) {
+ if (ENODE_IS(expr, EINTCONST)) {
+ CMach_InitIntMem(TYPE(tint), expr->data.intval, cinit_initinfo->buffer + cinit_initinfo->expr_offset);
+ } else if (ENODE_IS(expr, ETYPCON) && IS_TYPE_POINTER_ONLY(expr->data.monadic->rtype) && expr->rtype->size == 4 && (copts.cplusplus || !copts.ANSIstrict)) {
+ CInit_ExprPointer(TYPE_POINTER(expr->data.monadic->rtype), expr->data.monadic);
+ } else if (cinit_initinfo->expr_cb) {
+ cinit_initinfo->expr_cb(TYPE(tint), expr, 0);
+ cinit_initinfo->expr_cb_called = 1;
+ } else {
+ CError_Error(CErrorStr124);
+ }
+
+ cinit_initinfo->expr_offset += tint->size;
+}
+
+static void CInit_ExprFloat(TypeIntegral *tint, ENode *expr) {
+ if (ENODE_IS(expr, EFLOATCONST)) {
+ CMach_InitFloatMem(TYPE(tint), expr->data.floatval, cinit_initinfo->buffer + cinit_initinfo->expr_offset);
+ } else if (cinit_initinfo->expr_cb) {
+ cinit_initinfo->expr_cb(TYPE(tint), expr, 0);
+ cinit_initinfo->expr_cb_called = 1;
+ } else {
+ CError_Error(CErrorStr124);
+ }
+
+ cinit_initinfo->expr_offset += tint->size;
+}
+
+static void CInit_ExprEnum(TypeEnum *tenum, ENode *expr) {
+ if (ENODE_IS(expr, EINTCONST)) {
+ CMach_InitIntMem(tenum->enumtype, expr->data.intval, cinit_initinfo->buffer + cinit_initinfo->expr_offset);
+ } else if (cinit_initinfo->expr_cb) {
+ cinit_initinfo->expr_cb(TYPE(tenum), expr, 0);
+ cinit_initinfo->expr_cb_called = 1;
+ } else {
+ CError_Error(CErrorStr124);
+ }
+
+ cinit_initinfo->expr_offset += tenum->size;
+}
+
+static void CInit_ExprMemberPointer(TypeMemberPointer *tmptr, ENode *expr) {
+ if (ENODE_IS(expr, EINTCONST)) {
+ CMach_InitIntMem(TYPE(&stsignedlong), expr->data.intval, cinit_initinfo->buffer + cinit_initinfo->expr_offset);
+ } else if (cinit_initinfo->expr_cb) {
+ cinit_initinfo->expr_cb(TYPE(tmptr), expr, 0);
+ cinit_initinfo->expr_cb_called = 1;
+ } else {
+ CError_Error(CErrorStr124);
+ }
+
+ cinit_initinfo->expr_offset += tmptr->size;
+}
+
+static void CInit_TypeExpr(Type *type, ENode *expr) {
+ switch (type->type) {
+ case TYPEINT:
+ CInit_ExprInt(TYPE_INTEGRAL(type), expr);
+ break;
+ case TYPEFLOAT:
+ CInit_ExprFloat(TYPE_INTEGRAL(type), expr);
+ break;
+ case TYPEENUM:
+ CInit_ExprEnum(TYPE_ENUM(type), expr);
+ break;
+ case TYPEPOINTER:
+ CInit_ExprPointer(TYPE_POINTER(type), expr);
+ break;
+ case TYPEMEMBERPOINTER:
+ CInit_ExprMemberPointer(TYPE_MEMBER_POINTER(type), expr);
+ break;
+ case TYPESTRUCT:
+ case TYPECLASS:
+ if (cinit_initinfo->expr_cb) {
+ cinit_initinfo->expr_cb(type, expr, 0);
+ cinit_initinfo->expr_cb_called = 1;
+ } else {
+ CError_Error(CErrorStr124);
+ }
+ break;
+ case TYPEARRAY:
+ CError_Error(CErrorStr174);
+ break;
+ default:
+ CError_FATAL(2082);
+ }
+}
+
+static void CInit_Bitfield(TypeBitfield *tbitfield) {
+ Boolean r30;
+ ENode *expr;
+ ENode myexpr;
+
+ r30 = tk == '{';
+ if (r30)
+ tk = lex();
+
+ expr = CInit_ParseInitializer(&myexpr);
+ expr = CExpr_AssignmentPromotion(
+ expr,
+ IS_TYPE_ENUM(tbitfield->bitfieldtype) ? TYPE_ENUM(tbitfield->bitfieldtype)->enumtype : tbitfield->bitfieldtype,
+ 0,
+ 1);
+ if (ENODE_IS(expr, EINTCONST))
+ CInit_SetBitfield(tbitfield, (UInt8 *) cinit_initinfo->buffer + cinit_initinfo->expr_offset, expr->data.intval);
+ else
+ CError_Error(CErrorStr124);
+
+ if (r30)
+ CInit_CloseInitList();
+}
+
+static void CInit_Array(TypePointer *tptr, UInt32 qual, Boolean flag) {
+ SInt32 start;
+ SInt32 i;
+ SInt32 targetsize1;
+ SInt32 targetsize2;
+ Boolean in_block;
+ Boolean is_char_ptr;
+ Boolean needs_construction;
+ Boolean is_wchar_ptr;
+
+ targetsize1 = tptr->target->size;
+ targetsize2 = tptr->target->size;
+ if (!tptr->target->size) {
+ if (!IS_TYPE_ARRAY(tptr->target)) {
+ CError_Error(CErrorStr145);
+ return;
+ }
+ targetsize1 = tptr->target->size;
+ targetsize2 = tptr->target->size;
+ if (!tptr->target->size) {
+ CError_Error(CErrorStr145);
+ return;
+ }
+ }
+
+ is_char_ptr = IS_TYPE_INT(tptr->target) && (tptr->target->size == 1);
+ is_wchar_ptr = IS_TYPE_INT(tptr->target) && (tptr->target->size == stwchar.size);
+
+ in_block = 1;
+ if (flag && !(tk == TK_STRING && is_char_ptr) && !(tk == TK_STRING_WIDE && is_wchar_ptr)) {
+ if (tk != '{') {
+ CError_ErrorSkip(CErrorStr135);
+ return;
+ }
+ tk = lex();
+ } else {
+ if (tk == '{')
+ tk = lex();
+ else
+ in_block = 0;
+ }
+
+ if ((tk == TK_STRING && is_char_ptr) || (tk == TK_STRING_WIDE && is_wchar_ptr)) {
+ if (tptr->size) {
+ if (tksize > tptr->size) {
+ if (copts.cplusplus || (tksize - (is_wchar_ptr ? stwchar.size : 1)) > tptr->size)
+ CError_Error(CErrorStr147);
+ tksize = tptr->size;
+ }
+ memcpy(cinit_initinfo->buffer + cinit_initinfo->expr_offset, tkstring, tksize);
+ } else {
+ tptr->size = tksize;
+ CInit_SetData(tkstring, cinit_initinfo->expr_offset, tptr->size);
+ }
+ cinit_initinfo->expr_offset += tptr->size;
+ tk = lex();
+ if (in_block)
+ CInit_CloseInitList();
+ return;
+ }
+
+ if (IS_TYPE_CLASS(tptr->target) && CInit_ClassNeedsConstruction(TYPE_CLASS(tptr->target)))
+ needs_construction = 1;
+ else
+ needs_construction = 0;
+
+ start = cinit_initinfo->expr_offset;
+ i = 0;
+ while (1) {
+ if (tk == '}') {
+ innerloop:
+ if (tptr->size) {
+ if (needs_construction) {
+ while (tptr->size > (i * targetsize1)) {
+ cinit_initinfo->expr_offset = start + i * targetsize2;
+ if (cinit_initinfo->expr_cb) {
+ cinit_initinfo->expr_cb(tptr->target, NULL, 1);
+ cinit_initinfo->expr_cb_called = 1;
+ } else {
+ CError_Error(CErrorStr174);
+ }
+ i++;
+ }
+ }
+ } else {
+ tptr->size = i * targetsize1;
+ }
+ cinit_initinfo->expr_offset = start + tptr->size;
+ if (in_block)
+ tk = lex();
+ return;
+ }
+
+ if (!tptr->size) {
+ cinit_initinfo->expr_offset = start + i * targetsize2;
+ CInit_SetData(NULL, cinit_initinfo->expr_offset, targetsize2);
+ if (needs_construction) {
+ if (cinit_initinfo->expr_cb) {
+ cinit_initinfo->expr_cb(tptr->target, conv_assignment_expression(), 1);
+ cinit_initinfo->expr_cb_called = 1;
+ } else {
+ CError_Error(CErrorStr174);
+ }
+ } else {
+ CInit_Type(tptr->target, qual, 0);
+ }
+ } else {
+ if (tptr->size <= i * targetsize1) {
+ i--;
+ CError_Error(CErrorStr147);
+ }
+
+ cinit_initinfo->expr_offset = start + i * targetsize2;
+ if (needs_construction) {
+ if (cinit_initinfo->expr_cb) {
+ cinit_initinfo->expr_cb(tptr->target, conv_assignment_expression(), 1);
+ cinit_initinfo->expr_cb_called = 1;
+ } else {
+ CError_Error(CErrorStr174);
+ }
+ } else {
+ CInit_Type(tptr->target, qual, 0);
+ }
+
+ if (!in_block) {
+ if (tptr->size <= (i + 1) * targetsize1)
+ return;
+ }
+ }
+
+ if (tk != '}') {
+ if (tk != ',') {
+ CError_ErrorSkip(CErrorStr121);
+ in_block = 0;
+ i++;
+ goto innerloop;
+ }
+ tk = lex();
+ }
+ i++;
+ }
+}
+
+static void CInit_Struct(TypeStruct *tstruct, Boolean flag) {
+ StructMember *member;
+ SInt32 start;
+ Boolean in_block;
+
+ if (!(member = tstruct->members)) {
+ CError_Error(CErrorStr145);
+ return;
+ }
+
+ if (tstruct->stype == STRUCT_TYPE_UNION) {
+ if (tk == '{') {
+ tk = lex();
+ CInit_Type(member->type, member->qual, 0);
+ if (tk == '}')
+ tk = lex();
+ } else {
+ CInit_Type(member->type, member->qual, 0);
+ }
+ return;
+ }
+
+ if (IS_TYPE_VECTOR(tstruct) && tk != '{') {
+ CInit_TypeExpr(TYPE(tstruct), CExpr_AssignmentPromotion(conv_assignment_expression(), TYPE(tstruct), 0, 1));
+ return;
+ }
+
+ if (tk != '{') {
+ if (flag)
+ CError_ErrorSkip(CErrorStr135);
+ in_block = 0;
+ } else {
+ in_block = 1;
+ tk = lex();
+ }
+
+ start = cinit_initinfo->expr_offset;
+ while (1) {
+ if (tk == '}')
+ break;
+
+ cinit_initinfo->expr_offset = start + member->offset;
+ if (!member->type->size && IS_TYPE_ARRAY(member->type)) {
+ CError_Error(CErrorStr147);
+ break;
+ }
+
+ CInit_Type(member->type, member->qual, 0);
+ if (tk == '}')
+ break;
+
+ if (tk != ',') {
+ CError_Error(CErrorStr121);
+ break;
+ }
+
+ do {
+ member = member->next;
+ } while (member && (member->qual & Q_WEAK));
+
+ if (!member) {
+ if (!in_block)
+ break;
+ if ((tk = lex()) != '}') {
+ CError_Error(CErrorStr147);
+ break;
+ }
+ } else {
+ tk = lex();
+ }
+ }
+
+ cinit_initinfo->expr_offset = start + tstruct->size;
+ if (tk == '}' && in_block)
+ tk = lex();
+}
+
+static void CInit_Class(TypeClass *tclass, Boolean flag) {
+ ObjMemberVar *ivar;
+ SInt32 start;
+ Boolean in_block;
+
+ if (tk == '{') {
+ in_block = 1;
+ tk = lex();
+ } else {
+ in_block = 0;
+ }
+
+ if (tclass->bases || tclass->vtable) {
+ CError_Error(CErrorStr174);
+ return;
+ }
+
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ if (ivar->access != ACCESSPUBLIC)
+ break;
+ }
+
+ if (!ivar && !CClass_Constructor(tclass) && (!CClass_Destructor(tclass) || in_block)) {
+ if ((ivar = tclass->ivars)) {
+ start = cinit_initinfo->expr_offset;
+ while (1) {
+ if (tk == '}')
+ break;
+
+ if (!ivar->type->size && IS_TYPE_ARRAY(ivar->type)) {
+ CError_Error(CErrorStr147);
+ break;
+ }
+
+ cinit_initinfo->expr_offset = start + ivar->offset;
+ CInit_Type(ivar->type, ivar->qual, 0);
+
+ if (tk == '}')
+ break;
+
+ if (tk != ',') {
+ CError_Error(CErrorStr121);
+ break;
+ }
+
+ do {
+ ivar = ivar->next;
+ } while (ivar && ivar->anonunion);
+
+ if (!ivar) {
+ if (!in_block)
+ break;
+ if ((tk = lex()) != '}') {
+ CError_Error(CErrorStr147);
+ break;
+ }
+ } else {
+ tk = lex();
+ }
+ }
+ } else {
+ if (in_block && tk != '}')
+ CError_Error(CErrorStr147);
+ }
+ } else {
+ if (in_block)
+ CError_Error(CErrorStr174);
+ CInit_TypeExpr(TYPE(tclass), CExpr_AssignmentPromotion(conv_assignment_expression(), TYPE(tclass), 0, 1));
+ }
+
+ cinit_initinfo->expr_offset = start + tclass->size;
+ if (tk == '}' && in_block)
+ tk = lex();
+}
+
+static void CInit_Type(Type *type, UInt32 qual, Boolean flag) {
+ ENode *expr;
+ ENode myexpr;
+
+ switch (type->type) {
+ case TYPEVOID:
+ CError_Error(CErrorStr174);
+ break;
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPEPOINTER:
+ case TYPEMEMBERPOINTER:
+ if (tk == '{') {
+ tk = lex();
+ expr = CInit_ParseInitializer(&myexpr);
+ expr = CExpr_AssignmentPromotion(expr, type, qual & (Q_CONST | Q_VOLATILE), 1);
+ CInit_CloseInitList();
+ } else {
+ expr = CInit_ParseInitializer(&myexpr);
+ expr = CExpr_AssignmentPromotion(expr, type, qual & (Q_CONST | Q_VOLATILE), 1);
+ }
+ CInit_TypeExpr(type, expr);
+ break;
+ case TYPEBITFIELD:
+ CInit_Bitfield(TYPE_BITFIELD(type));
+ break;
+ case TYPEARRAY:
+ CInit_Array(TYPE_POINTER(type), qual, flag);
+ break;
+ case TYPESTRUCT:
+ CInit_Struct(TYPE_STRUCT(type), flag);
+ break;
+ case TYPECLASS:
+ CInit_Class(TYPE_CLASS(type), flag);
+ break;
+ default:
+ CError_FATAL(2482);
+ }
+}
+
+static void CInit_GlobalStaticInit(Type *type, ENode *valueexpr, Boolean flag) {
+ ENode *expr;
+ ENode *tmp;
+
+ cinit_initinfo->x15 = 1;
+ if (flag) {
+ CInit_ConstructGlobalObject(cinit_initinfo->obj, TYPE_CLASS(type), valueexpr, cinit_initinfo->expr_offset, 0);
+ } else {
+ expr = create_objectrefnode(cinit_initinfo->obj);
+ if (!IS_TYPE_POINTER_ONLY(expr->rtype)) {
+ CError_Error(CErrorStr174);
+ return;
+ }
+ TYPE_POINTER(expr->rtype)->target = type;
+
+ if (cinit_initinfo->expr_offset)
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), cinit_initinfo->expr_offset), EADD);
+
+ tmp = makemonadicnode(expr, EINDIRECT);
+ tmp->rtype = type;
+ expr = makediadicnode(tmp, valueexpr, EASS);
+ if (cinit_initinfo->x16)
+ cinit_initinfo->init_expr_register_cb(expr);
+ else
+ InitExpr_Register(expr, cinit_initinfo->obj);
+ }
+}
+
+static void CInit_AutoInit(Type *type, ENode *valueexpr, Boolean flag) {
+ ENode *expr;
+ ENode *tmp;
+ Type *copy;
+ SInt32 size;
+
+ if (flag) {
+ CInit_ConstructAutoObject(TYPE_CLASS(type), valueexpr, cinit_initinfo->expr_offset, 0);
+ } else {
+ if (IS_TYPE_ARRAY(type) && (type->size & 1)) {
+ copy = galloc(sizeof(TypePointer));
+ *TYPE_POINTER(copy) = *TYPE_POINTER(type);
+ type = copy;
+ copy->size++;
+ }
+ expr = create_objectrefnode(cinit_initinfo->obj1C);
+ if (!IS_TYPE_POINTER_ONLY(expr->rtype)) {
+ CError_Error(CErrorStr174);
+ return;
+ }
+ TYPE_POINTER(expr->rtype)->target = type;
+
+ if (cinit_initinfo->expr_offset)
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), cinit_initinfo->expr_offset), EADD);
+
+ tmp = makemonadicnode(expr, EINDIRECT);
+ tmp->rtype = type;
+ expr = makediadicnode(tmp, valueexpr, EASS);
+ if (!copts.cplusplus)
+ CError_Error(CErrorStr124);
+ cinit_initinfo->insert_expr_cb(expr);
+ }
+}
+
+static SInt32 CInit_AdjustObjectDataSize(Object *obj) {
+ if (obj->type->size <= 1)
+ return obj->type->size;
+ if (obj->type->size & 1)
+ return obj->type->size + 1;
+ else
+ return obj->type->size;
+}
+
+static ENode *CInit_GenericData(Object *obj, Type *type, UInt32 qual, ExprCB expr_cb, Boolean flag) {
+ Object *r31;
+ ENode *expr;
+ ENode *tmpexpr;
+ Type *inner;
+ Type *copy;
+ SInt32 size;
+ Boolean lastflag;
+ SInt16 cv;
+
+ cinit_initinfo->expr_cb = expr_cb;
+ expr = NULL;
+
+ if (tk == '(') {
+ if (IS_TYPE_ARRAY(type))
+ CError_Error(CErrorStr174);
+ tk = lex();
+ expr = CExpr_AssignmentPromotion(assignment_expression(), type, qual, 1);
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+ goto jump_ahead;
+ }
+
+ tk = lex();
+ switch (type->type) {
+ case TYPECLASS:
+ if (tk == '{' && CClass_Constructor(TYPE_CLASS(type)))
+ CError_Error(CErrorStr174);
+ case TYPESTRUCT:
+ if (tk != '{')
+ goto generic_type;
+ case TYPEARRAY:
+ if (!obj) {
+ if (IS_TYPE_ARRAY(type)) {
+ inner = type;
+ while (IS_TYPE_ARRAY(inner))
+ inner = TYPE_POINTER(inner)->target;
+
+ if (IS_TYPE_CLASS(inner) && CInit_ClassNeedsConstruction(TYPE_CLASS(inner))) {
+ CInit_SetupInitInfoBuffer(type);
+ cinit_initinfo->obj = cinit_initinfo->obj1C;
+ CInit_Type(type, cinit_initinfo->obj->qual, 1);
+ return 0;
+ }
+ if (type->size & 1) {
+ copy = galloc(sizeof(TypePointer));
+ *TYPE_POINTER(copy) = *TYPE_POINTER(type);
+ type = copy;
+ type->size++;
+ }
+ }
+
+ obj = CInit_CreateStaticDataObject(type, qual, NULL);
+ cinit_initinfo->obj = obj;
+ expr = create_objectnode(obj);
+ cinit_initinfo->obj1C = obj;
+ }
+ CInit_SetupInitInfoBuffer(type);
+ CInit_Type(type, obj->qual, 1);
+ CError_ASSERT(2639, obj->type->size == (size = cinit_initinfo->size));
+ if (cinit_initinfo->list || !CInit_IsAllZero(cinit_initinfo->buffer, size)) {
+ CInit_AdjustObjectDataSize(obj);
+ CInit_DeclareData(obj, cinit_initinfo->buffer, cinit_initinfo->list, obj->type->size);
+ } else {
+ CInit_AdjustObjectDataSize(obj);
+ CInit_DeclareData(obj, NULL, NULL, obj->type->size);
+ }
+ return expr;
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPEPOINTER:
+ case TYPEMEMBERPOINTER:
+ generic_type:
+ if (obj)
+ cv = obj->qual & Q_CV;
+ else
+ cv = cinit_initinfo->obj1C->qual & Q_CV;
+
+ if (tk == '{') {
+ tk = lex();
+ expr = assignment_expression();
+ CInit_CloseInitList();
+ } else {
+ expr = assignment_expression();
+ }
+ expr = CExpr_AssignmentPromotion(expr, type, cv, 1);
+ jump_ahead:
+ if (obj == NULL)
+ r31 = cinit_initinfo->obj1C;
+ else
+ r31 = obj;
+
+ if (is_const_object(r31)) {
+ switch (r31->type->type) {
+ case TYPEINT:
+ case TYPEENUM:
+ if (ENODE_IS(expr, EINTCONST)) {
+ r31->u.data.u.intconst = expr->data.intval;
+ goto common_8068C;
+ }
+ break;
+ case TYPEFLOAT:
+ if (ENODE_IS(expr, EFLOATCONST)) {
+ Float fl;
+ r31->u.data.u.floatconst = galloc(sizeof(Float));
+ fl = CMach_CalcFloatConvert(r31->type, expr->data.floatval);
+ *r31->u.data.u.floatconst = fl;
+ goto common_8068C;
+ }
+ break;
+ case TYPEPOINTER:
+ tmpexpr = expr;
+ while (ENODE_IS(tmpexpr, ETYPCON))
+ tmpexpr = tmpexpr->data.monadic;
+ if (!ENODE_IS(tmpexpr, EINTCONST))
+ break;
+ r31->u.data.u.intconst = tmpexpr->data.intval;
+ common_8068C:
+ r31->qual |= Q_INLINE_DATA;
+ if (!obj) {
+ r31->sclass = TK_STATIC;
+ r31->datatype = DDATA;
+ r31->u.data.linkname = CParser_AppendUniqueName(r31->name->name);
+ } else if (r31->sclass != TK_STATIC || (r31->flags & OBJECT_FLAGS_2)) {
+ CInit_ExportConst(r31);
+ }
+ return NULL;
+ }
+ }
+
+ if (!obj || (flag && copts.cplusplus)) {
+ if (obj) {
+ IsCompleteType(obj->type);
+ CError_ASSERT(2747, obj->type->size == type->size);
+ CInit_DeclareData(obj, NULL, NULL, obj->type->size);
+ }
+ return expr;
+ }
+
+ CInit_SetupInitInfoBuffer(type);
+ CInit_TypeExpr(type, expr);
+ CError_ASSERT(2756, obj->type->size == cinit_initinfo->size);
+
+ IsCompleteType(obj->type);
+ CInit_AdjustObjectDataSize(obj);
+ lastflag = !cinit_initinfo->x15 && is_const_object(r31);
+ if (cinit_initinfo->list || !CInit_IsAllZero(cinit_initinfo->buffer, obj->type->size)) {
+ if (lastflag)
+ CInit_DeclareReadOnlyData(obj, cinit_initinfo->buffer, cinit_initinfo->list, obj->type->size);
+ else
+ CInit_DeclareData(obj, cinit_initinfo->buffer, cinit_initinfo->list, obj->type->size);
+ } else {
+ if (lastflag)
+ CInit_DeclareReadOnlyData(obj, NULL, NULL, obj->type->size);
+ else
+ CInit_DeclareData(obj, NULL, NULL, obj->type->size);
+ }
+ break;
+
+ default:
+ CError_FATAL(2776);
+ }
+
+ return NULL;
+}
+
+void CInit_ExportConst(Object *obj) {
+ char buffer[64];
+
+ if (obj->flags & OBJECT_DEFINED)
+ return;
+
+ switch (obj->type->type) {
+ case TYPEINT:
+ CMach_InitIntMem(obj->type, obj->u.data.u.intconst, buffer);
+ break;
+ case TYPEENUM:
+ CMach_InitIntMem(TYPE_ENUM(obj->type)->enumtype, obj->u.data.u.intconst, buffer);
+ break;
+ case TYPEPOINTER:
+ CMach_InitIntMem(TYPE(&stunsignedlong), obj->u.data.u.intconst, buffer);
+ break;
+ case TYPEFLOAT:
+ CMach_InitFloatMem(obj->type, *obj->u.data.u.floatconst, buffer);
+ break;
+ default:
+ CError_FATAL(2807);
+ }
+
+ if (is_const_object(obj))
+ CInit_DeclareReadOnlyData(obj, buffer, NULL, obj->type->size);
+ else
+ CInit_DeclareData(obj, buffer, NULL, obj->type->size);
+}
+
+static ENode *CInit_ClassInitLoopCallBack(ENode *expr) {
+ return CExpr_ConstructObject(cinit_loop_class, expr, NULL, 0, 1, 0, 1, 1);
+}
+
+Statement *CInit_ConstructClassArray(Statement *stmt, TypeClass *tclass, Object *ctor, Object *dtor, ENode *firstarg, SInt32 count) {
+ ENode *dtor_expr;
+
+ if (stmt)
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ else
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+
+ if (dtor)
+ dtor_expr = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1));
+ else
+ dtor_expr = nullnode();
+
+ stmt->expr = CExpr_FuncCallSix(
+ carr_func,
+ firstarg,
+ create_objectrefnode(ctor),
+ dtor_expr,
+ intconstnode(TYPE(&stunsignedlong), tclass->size),
+ intconstnode(TYPE(&stunsignedlong), count),
+ NULL
+ );
+
+ return stmt;
+}
+
+static void CInit_InitializeClassArray(Object *obj, TypeClass *tclass, Boolean flag) {
+ Object *ctor;
+ Object *dtor;
+ SInt32 count;
+ SInt32 i;
+ ENode *expr;
+ SInt32 offset;
+ ENode *dtor_expr;
+ Statement *stmt;
+ TypeFunc *tfunc;
+ Object *funcobj;
+
+ dtor = CClass_Destructor(tclass);
+ count = obj->type->size / tclass->size;
+ if (CClass_Constructor(tclass)) {
+ ctor = CClass_DefaultConstructor(tclass);
+ if (!ctor) {
+ ctor = CClass_DummyDefaultConstructor(tclass);
+ if (!ctor) {
+ CError_Error(CErrorStr203);
+ return;
+ }
+ }
+ } else {
+ ctor = NULL;
+ }
+
+ if (count <= 1 || (!flag && count <= 8)) {
+ if (flag) {
+ for (i = 0; i < count; i++) {
+ CInit_ConstructGlobalObject(obj, tclass, NULL, i * tclass->size, 0);
+ }
+ } else {
+ for (i = 0; i < count; i++) {
+ offset = i * tclass->size;
+ expr = create_objectrefnode(obj);
+ if (offset)
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD);
+ if (ctor)
+ expr = CExpr_ConstructObject(tclass, expr, NULL, 0, 1, 0, 1, 1);
+ cinit_initinfo->insert_expr_cb(expr);
+ if (dtor)
+ CExcept_RegisterDestructorObject(obj, offset, dtor, 1);
+ }
+ if (dtor) {
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = nullnode();
+ }
+ }
+ } else {
+ if (ctor) {
+ if (!flag && !dtor) {
+ CInit_ConstructClassArray(NULL, tclass, ctor, dtor, create_objectrefnode(obj), count);
+ expr = nullnode();
+ } else {
+ if (dtor)
+ dtor_expr = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1));
+ else
+ dtor_expr = nullnode();
+ expr = CExpr_FuncCallSix(
+ carr_func,
+ create_objectrefnode(obj),
+ create_objectrefnode(ctor),
+ dtor_expr,
+ intconstnode(TYPE(&stunsignedlong), tclass->size),
+ intconstnode(TYPE(&stunsignedlong), count),
+ NULL
+ );
+ }
+ } else {
+ expr = nullnode();
+ }
+
+ if (flag) {
+ if (dtor && !copts.no_static_dtors) {
+ tfunc = galloc(sizeof(TypeFunc));
+ memclrw(tfunc, sizeof(TypeFunc));
+ tfunc->type = TYPEFUNC;
+ tfunc->functype = &stvoid;
+ CDecl_SetFuncFlags(tfunc, 1);
+
+ funcobj = CParser_NewCompilerDefFunctionObject();
+ funcobj->name = CParser_AppendUniqueName("__arraydtor");
+ funcobj->type = TYPE(tfunc);
+ funcobj->sclass = TK_STATIC;
+ funcobj->qual = Q_INLINE;
+
+ CParser_RegisterSingleExprFunction(funcobj, funccallexpr(
+ darr_func,
+ create_objectrefnode(obj),
+ create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1)),
+ intconstnode(TYPE(&stsignedlong), tclass->size),
+ intconstnode(TYPE(&stsignedlong), count)
+ ));
+
+ expr = makediadicnode(expr, nullnode(), ECOMMA);
+ expr->rtype = TYPE(&void_ptr);
+
+ expr = funccallexpr(
+ Xgreg_func,
+ expr,
+ create_objectrefnode(funcobj),
+ create_objectrefnode(CInit_CreateStaticData(CInit_GetRegMemType())),
+ NULL
+ );
+ }
+ if (cinit_initinfo->x16)
+ cinit_initinfo->init_expr_register_cb(expr);
+ else
+ InitExpr_Register(expr, obj);
+ } else {
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = expr;
+ if (dtor) {
+ CExcept_RegisterLocalArray(stmt, obj, dtor, count, tclass->size);
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = nullnode();
+ }
+ }
+ }
+}
+
+static ENode *CInit_AutoTempNode(Type *type, Boolean flag) {
+ ENode *node;
+ node = CExpr_NewETEMPNode(type, 0);
+ if (IS_TYPE_CLASS(type) && CClass_Destructor(TYPE_CLASS(type)))
+ node->data.temp.needs_dtor = 1;
+ return node;
+}
+
+static ENode *CInit_GlobalTempNode(Type *type, Boolean flag) {
+ Object *dtor;
+ ENode *node;
+ ENode *funcnode;
+
+ node = create_objectrefnode(CInit_CreateStaticData(type));
+ if (IS_TYPE_CLASS(type) && (dtor = CClass_Destructor(TYPE_CLASS(type))) && !copts.no_static_dtors) {
+ if (flag)
+ CError_Error(CErrorStr190);
+
+ funcnode = galloc(sizeof(ENode));
+ funcnode->type = EFUNCCALL;
+ funcnode->cost = 200;
+ funcnode->flags = 0;
+ funcnode->rtype = CDecl_NewPointerType(type);
+ funcnode->data.funccall.funcref = create_objectrefnode(Xgreg_func);
+ funcnode->data.funccall.functype = TYPE_FUNC(Xgreg_func->type);
+ funcnode->data.funccall.args = lalloc(sizeof(ENodeList));
+ funcnode->data.funccall.args->node = node;
+ funcnode->data.funccall.args->next = lalloc(sizeof(ENodeList));
+ funcnode->data.funccall.args->next->node = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1));
+ funcnode->data.funccall.args->next->next = lalloc(sizeof(ENodeList));
+ funcnode->data.funccall.args->next->next->node = create_objectrefnode(CInit_CreateStaticData(CInit_GetRegMemType()));;
+ funcnode->data.funccall.args->next->next->next = NULL;
+ node = funcnode;
+ }
+ return node;
+}
+
+static void CInit_RefInit(Type *type, ENode *expr, Boolean flag) {
+ ENode *objexpr;
+
+ objexpr = create_objectrefnode(cinit_initinfo->obj);
+ if (!IS_TYPE_POINTER_ONLY(objexpr->rtype)) {
+ CError_Error(CErrorStr174);
+ return;
+ }
+ TYPE_POINTER(objexpr->rtype)->target = type;
+
+ if (cinit_initinfo->expr_offset)
+ objexpr = makediadicnode(objexpr, intconstnode(TYPE(&stunsignedlong), cinit_initinfo->expr_offset), EADD);
+
+ objexpr = makemonadicnode(objexpr, EINDIRECT);
+ objexpr->rtype = type;
+
+ expr = makediadicnode(objexpr, expr, EASS);
+ if (cinit_initinfo->x16)
+ cinit_initinfo->init_expr_register_cb(expr);
+ else
+ InitExpr_Register(expr, cinit_initinfo->obj);
+}
+
+static Boolean CInit_IsDtorTemp(ENode *expr) {
+ return ENODE_IS(expr, ETEMP) && expr->data.temp.needs_dtor;
+}
+
+static void CInit_FindDtorTemp(ENode *expr) {
+ ENodeList *list;
+
+ while (ENODE_IS(expr, ECOMMA))
+ expr = expr->data.diadic.right;
+
+ if (IS_TYPE_POINTER_ONLY(expr->rtype) && IS_TYPE_CLASS(TYPE_POINTER(expr->rtype)->target)) {
+ switch (expr->type) {
+ case ETYPCON:
+ CInit_FindDtorTemp(expr->data.monadic);
+ break;
+ case EADD:
+ case ESUB:
+ CInit_FindDtorTemp(expr->data.diadic.left);
+ CInit_FindDtorTemp(expr->data.diadic.right);
+ break;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ if ((list = expr->data.funccall.args)) {
+ if (CInit_IsDtorTemp(list->node) || ((list = list->next) && CInit_IsDtorTemp(list->node))) {
+ if (!cinit_fdtnode)
+ cinit_fdtnode = list;
+ else
+ cinit_fdtambig = 1;
+ }
+ }
+ break;
+ }
+ }
+}
+
+static void CInit_RefTempTransform(Type *type, ENode *expr) {
+ Object *obj;
+
+ CError_ASSERT(3164, IS_TYPE_POINTER_ONLY(type));
+
+ if (IS_TYPE_CLASS(TYPE_POINTER(type)->target)) {
+ cinit_fdtnode = NULL;
+ cinit_fdtambig = 0;
+ CInit_FindDtorTemp(expr);
+ if (cinit_fdtnode) {
+ CError_ASSERT(3172, !cinit_fdtambig);
+ obj = create_temp_object(cinit_fdtnode->node->data.temp.type);
+ cinit_initinfo->register_object_cb(cinit_fdtnode->node->data.temp.type, obj, 0, 0);
+ cinit_fdtnode->node = create_objectrefnode(obj);
+ }
+ }
+}
+
+static Boolean CInit_InitReference(Object *obj, Boolean flag) {
+ ENode *expr;
+
+ if (tk == '=') {
+ cinit_tempnodefunc = flag ? CInit_AutoTempNode : CInit_GlobalTempNode;
+ tk = lex();
+ expr = CExpr_AssignmentPromotion(assignment_expression(), obj->type, obj->qual & (Q_CONST | Q_VOLATILE), 1);
+ cinit_tempnodefunc = NULL;
+
+ if (flag) {
+ CInit_RefTempTransform(obj->type, expr);
+ expr = makediadicnode(create_objectnode2(obj), expr, EASS);
+ cinit_initinfo->insert_expr_cb(expr);
+ } else {
+ cinit_initinfo->expr_cb = CInit_RefInit;
+ CInit_SetupInitInfoBuffer(obj->type);
+ CInit_ExprPointer(TYPE_POINTER(obj->type), expr);
+ CError_ASSERT(3213, obj->type->size == cinit_initinfo->size);
+
+ if (cinit_initinfo->list || !CInit_IsAllZero(cinit_initinfo->buffer, obj->type->size)) {
+ IsCompleteType(obj->type);
+ CInit_AdjustObjectDataSize(obj);
+ CInit_DeclareData(obj, cinit_initinfo->buffer, cinit_initinfo->list, obj->type->size);
+ } else {
+ IsCompleteType(obj->type);
+ CInit_AdjustObjectDataSize(obj);
+ CInit_DeclareData(obj, NULL, NULL, obj->type->size);
+ }
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+ENode *CInit_AutoObject(Object *obj, Type *type, UInt32 qual) {
+ CInit_Stuff s;
+ CInit_1C *entry;
+ ENode *expr;
+ ENode *indirect_expr;
+ ENode *obj_expr;
+ ENode *const_expr;
+ Type *newtype;
+ Object *newobj;
+
+ CInit_InitData(&s, type, qual, copts.cplusplus || copts.gcc_extensions || copts.c9x || !obj);
+ if (!obj && !cscope_currentfunc) {
+ obj = CParser_NewCompilerDefDataObject();
+ obj->name = CParser_GetUniqueName();
+ obj->type = type;
+ obj->qual = qual;
+ obj->sclass = TK_STATIC;
+ CScope_AddGlobalObject(obj);
+ }
+
+ if (IS_TYPE_VECTOR(type) && !s.x1C) {
+ if (obj)
+ obj_expr = create_objectrefnode(obj);
+ else
+ obj_expr = CExpr_NewETEMPNode(type, 1);
+
+ const_expr = CExpr_NewENode(EVECTOR128CONST);
+ const_expr->rtype = type;
+ const_expr->data.vector128val = *((MWVector128 *) s.buffer);
+
+ indirect_expr = makemonadicnode(obj_expr, EINDIRECT);
+ indirect_expr->rtype = type;
+
+ expr = makediadicnode(indirect_expr, const_expr, EASS);
+ if (!obj) {
+ ENode *tmp = lalloc(sizeof(ENode));
+ *tmp = *obj_expr;
+ tmp = makemonadicnode(tmp, EINDIRECT);
+ tmp->rtype = type;
+ tmp->flags = qual & ENODE_FLAG_QUALS;
+ expr = makecommaexpression(expr, tmp);
+ }
+ return expr;
+ }
+
+ if (s.x18) {
+ type = CDecl_NewStructType(type->size + s.x18, CMach_GetTypeAlign(type));
+ if (obj)
+ obj->type = type;
+ }
+
+ if (obj)
+ obj_expr = create_objectrefnode(obj);
+ else
+ obj_expr = CExpr_NewETEMPNode(type, 1);
+
+ newtype = type;
+ if (IS_TYPE_ARRAY(type))
+ newtype = CDecl_NewStructType(type->size, CMach_GetTypeAlign(type));
+ newobj = CInit_CreateStaticDataObject(newtype, 0, NULL);
+ if (s.list || !CInit_IsAllZero(s.buffer, s.size))
+ CInit_DeclareReadOnlyData(newobj, s.buffer, s.list, s.size);
+ else
+ CInit_DeclareReadOnlyData(newobj, NULL, NULL, s.size);
+
+ indirect_expr = makemonadicnode(obj_expr, EINDIRECT);
+ indirect_expr->rtype = newtype;
+ expr = makediadicnode(indirect_expr, create_objectnode(newobj), EASS);
+
+ for (entry = s.x1C; entry; entry = entry->next) {
+ expr = CInit_InitConcat(expr, obj_expr, entry->offset, entry->type, entry->expr);
+ }
+
+ if (!obj) {
+ ENode *tmp = lalloc(sizeof(ENode));
+ *tmp = *obj_expr;
+ tmp = makemonadicnode(tmp, EINDIRECT);
+ tmp->rtype = type;
+ tmp->flags = qual & ENODE_FLAG_QUALS;
+ expr = makecommaexpression(expr, tmp);
+ } else if (IS_TYPE_ARRAY(type)) {
+ expr = makecommaexpression(expr, create_objectnode(obj));
+ }
+
+ return expr;
+}
+
+static void CInit_GlobalObject(Object *obj) {
+ CInit_Stuff s;
+ CInit_1C *entry;
+ ENode *obj_expr;
+ ENode *expr;
+
+ CInit_InitData(&s, obj->type, obj->qual, copts.cplusplus);
+ obj_expr = create_objectrefnode(obj);
+
+ IsCompleteType(obj->type);
+
+ if (!s.x1C && is_const_object(obj))
+ CInit_DeclareReadOnlyData(obj, s.buffer, s.list, s.size);
+ else
+ CInit_DeclareData(obj, s.buffer, s.list, s.size);
+
+ if (s.x1C) {
+ entry = s.x1C;
+ expr = NULL;
+ while (entry) {
+ if (!ENODE_IS(entry->expr, EVECTOR128CONST))
+ expr = CInit_InitConcat(expr, obj_expr, entry->offset, entry->type, entry->expr);
+ entry = entry->next;
+ }
+
+ if (expr)
+ InitExpr_Register(expr, obj);
+ }
+}
+
+void CInit_InitializeAutoData(Object *obj, InsertExprCB insert_cb, RegisterObjectCB register_cb) {
+ ENode *expr;
+ Type *type;
+ InitInfo initinfo;
+
+ if (CInit_IsSimpleStructArrayInit(obj->type)) {
+ if (tk == '=' || (tk == '(' && copts.cplusplus)) {
+ if (tk == '(') {
+ tk = lex();
+ expr = conv_assignment_expression();
+ if (tk != ')')
+ CError_Error(CErrorStr115);
+ tk = lex();
+ } else if (tk == '=' && ((tk = lex()) == '{' || IS_TYPE_ARRAY(obj->type))) {
+ insert_cb(CInit_AutoObject(obj, obj->type, obj->qual));
+ return;
+ } else {
+ expr = conv_assignment_expression();
+ }
+ expr = CExpr_AssignmentPromotion(expr, obj->type, obj->qual & (Q_CONST | Q_VOLATILE), 1);
+ insert_cb(makediadicnode(create_objectnode2(obj), expr, EASS));
+ } else if (copts.cplusplus && is_const_object(obj)) {
+ CError_Error(CErrorStr224);
+ }
+
+ return;
+ }
+
+ CInit_SetupInitInfo(&initinfo, obj);
+ initinfo.obj1C = obj;
+ initinfo.insert_expr_cb = insert_cb;
+ initinfo.register_object_cb = register_cb;
+
+ if (IS_TYPE_CLASS(obj->type) && CInit_ConstructAutoObject(TYPE_CLASS(obj->type), NULL, 0, 1)) {
+ CInit_CleanupInitInfo(&initinfo);
+ return;
+ }
+
+ if (IS_TYPE_REFERENCE(obj->type) && CInit_InitReference(obj, 1)) {
+ CInit_CleanupInitInfo(&initinfo);
+ return;
+ }
+
+ if (tk != '=' && (tk != '(' || !copts.cplusplus)) {
+ if (IS_TYPE_ARRAY(obj->type)) {
+ type = obj->type;
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+ if (IS_TYPE_CLASS(type)) {
+ if (CInit_ClassNeedsConstruction(TYPE_CLASS(type))) {
+ CInit_InitializeClassArray(obj, TYPE_CLASS(type), 0);
+ CInit_CleanupInitInfo(&initinfo);
+ return;
+ }
+ CFunc_CheckClassCtors(TYPE_CLASS(type));
+ }
+ }
+
+ if (IS_TYPE_CLASS(obj->type))
+ CFunc_CheckClassCtors(TYPE_CLASS(obj->type));
+
+ if ((IS_TYPE_REFERENCE(obj->type) || is_const_object(obj)) && copts.cplusplus)
+ CError_Error(CErrorStr224);
+ } else {
+ if (obj->type->size || IS_TYPE_ARRAY(obj->type)) {
+ if ((expr = CInit_GenericData(NULL, obj->type, obj->qual, CInit_AutoInit, 0)))
+ insert_cb(makediadicnode(create_objectnode2(obj), expr, EASS));
+ } else {
+ CError_Error(CErrorStr145);
+ }
+ }
+
+ if (IS_TYPE_CLASS(obj->type) && CClass_Destructor(TYPE_CLASS(obj->type)))
+ register_cb(obj->type, obj, 0, 0);
+
+ CInit_CleanupInitInfo(&initinfo);
+}
+
+void CInit_InitializeStaticData(Object *obj, InitExprRegisterCB cb) {
+ ENode *expr;
+ Type *type;
+ InitInfo initinfo;
+ CInit_Stuff s;
+ CInit_1C *entry;
+ ENode *obj_expr;
+
+ if (CInit_IsSimpleStructArrayInit(obj->type)) {
+ if (tk == '=' || (tk == '(' && copts.cplusplus)) {
+ if (tk == '=')
+ tk = lex();
+ CInit_InitData(&s, obj->type, obj->qual, copts.cplusplus);
+
+ IsCompleteType(obj->type);
+
+ if (!s.x1C && is_const_object(obj))
+ CInit_DeclareReadOnlyData(obj, s.buffer, s.list, s.size);
+ else
+ CInit_DeclareData(obj, s.buffer, s.list, s.size);
+
+ if (s.x1C) {
+ obj_expr = create_objectrefnode(obj);
+ entry = s.x1C;
+ expr = NULL;
+ while (entry) {
+ expr = CInit_InitConcat(expr, obj_expr, entry->offset, entry->type, entry->expr);
+ entry = entry->next;
+ }
+ cb(expr);
+ }
+ } else {
+ if (copts.cplusplus && is_const_object(obj))
+ CError_Error(CErrorStr224);
+
+ if (is_const_object(obj))
+ CInit_DeclareReadOnlyData(obj, NULL, NULL, obj->type->size);
+ else
+ CInit_DeclareData(obj, NULL, NULL, obj->type->size);
+ }
+ return;
+ }
+
+ CInit_SetupInitInfo(&initinfo, obj);
+ initinfo.x16 = 1;
+ initinfo.init_expr_register_cb = cb;
+
+ if (IS_TYPE_CLASS(obj->type) && CInit_ConstructGlobalObject(obj, TYPE_CLASS(obj->type), NULL, 0, 1)) {
+ IsCompleteType(obj->type);
+ CInit_DeclareData(obj, NULL, NULL, obj->type->size);
+ CInit_CleanupInitInfo(&initinfo);
+ return;
+ }
+
+ if (IS_TYPE_REFERENCE(obj->type) && CInit_InitReference(obj, 0)) {
+ CInit_CleanupInitInfo(&initinfo);
+ return;
+ }
+
+ if (tk != '=' && (tk != '(' || !copts.cplusplus)) {
+ if (IsCompleteType(obj->type))
+ CInit_DeclareData(obj, NULL, NULL, obj->type->size);
+
+ if (IS_TYPE_ARRAY(obj->type)) {
+ type = obj->type;
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+ if (IS_TYPE_CLASS(type)) {
+ if (CInit_ClassNeedsConstruction(TYPE_CLASS(type))) {
+ CInit_InitializeClassArray(obj, TYPE_CLASS(type), 1);
+ CInit_CleanupInitInfo(&initinfo);
+ return;
+ }
+ CFunc_CheckClassCtors(TYPE_CLASS(type));
+ }
+ }
+
+ if (IS_TYPE_CLASS(obj->type))
+ CFunc_CheckClassCtors(TYPE_CLASS(obj->type));
+
+ if ((IS_TYPE_REFERENCE(obj->type) || is_const_object(obj)) && copts.cplusplus)
+ CError_Error(CErrorStr224);
+ } else {
+ if (obj->type->size || IS_TYPE_ARRAY(obj->type)) {
+ if ((expr = CInit_GenericData(obj, obj->type, obj->qual, CInit_GlobalStaticInit, 1)))
+ cb(makediadicnode(create_objectnode2(obj), expr, EASS));
+ } else {
+ CError_Error(CErrorStr145);
+ }
+ }
+
+ CInit_CleanupInitInfo(&initinfo);
+}
+
+void CInit_InitializeData(Object *obj) {
+ Object *dtor;
+ ObjectList *list;
+ CInt64 val;
+ InitInfo initinfo;
+ Boolean needs_construction;
+ Type *type;
+
+ if (tk == ':') {
+ tk = lex();
+ obj->datatype = DABSOLUTE;
+ val = CExpr_IntegralConstExpr();
+ obj->u.address = CInt64_GetULong(&val);
+ return;
+ }
+
+ if (tk != '=' && (tk != '(' || !copts.cplusplus)) {
+ if (obj->sclass != TK_EXTERN) {
+ if (!copts.cplusplus) {
+ if (IsCompleteType(obj->type)) {
+ for (list = cinit_tentative; list; list = list->next) {
+ if (list->object == obj)
+ break;
+ }
+ if (!list) {
+ list = galloc(sizeof(ObjectList));
+ list->object = obj;
+ list->next = cinit_tentative;
+ cinit_tentative = list;
+ obj->qual |= Q_1000000;
+ }
+ }
+ } else {
+ if (obj->flags & OBJECT_DEFINED)
+ CError_Error(CErrorStr329, obj);
+ obj->flags = obj->flags | OBJECT_DEFINED;
+
+ needs_construction = 0;
+ if (IS_TYPE_ARRAY(obj->type)) {
+ type = obj->type;
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+ if (IS_TYPE_CLASS(type)) {
+ if (CInit_ClassNeedsConstruction(TYPE_CLASS(type))) {
+ CInit_SetupInitInfo(&initinfo, obj);
+ CInit_InitializeClassArray(obj, TYPE_CLASS(type), 1);
+ CInit_CleanupInitInfo(&initinfo);
+ needs_construction = 1;
+ } else {
+ CFunc_CheckClassCtors(TYPE_CLASS(type));
+ }
+ }
+ } else {
+ if (IS_TYPE_CLASS(obj->type)) {
+ if (CInit_ClassNeedsConstruction(TYPE_CLASS(obj->type))) {
+ CInit_SetupInitInfo(&initinfo, obj);
+ CInit_ConstructGlobalObject(obj, TYPE_CLASS(obj->type), NULL, 0, 0);
+ CInit_CleanupInitInfo(&initinfo);
+ needs_construction = 1;
+ } else {
+ CFunc_CheckClassCtors(TYPE_CLASS(obj->type));
+ }
+ }
+ }
+
+ if (!needs_construction && copts.cplusplus) {
+ if (IS_TYPE_REFERENCE(obj->type) || is_const_object(obj))
+ CError_Error(CErrorStr224);
+ }
+ if (IsCompleteType(obj->type))
+ CInit_DeclareData(obj, NULL, NULL, obj->type->size);
+ }
+ }
+ return;
+ }
+
+ if (obj->flags & OBJECT_DEFINED)
+ CError_Error(CErrorStr329, obj);
+
+ if (CInit_IsSimpleStructArrayInit(obj->type)) {
+ if (tk == '=')
+ tk = lex();
+ else
+ CError_Error(CErrorStr121);
+ CInit_GlobalObject(obj);
+ return;
+ }
+
+ CInit_SetupInitInfo(&initinfo, obj);
+ if (IS_TYPE_CLASS(obj->type) && CInit_ConstructGlobalObject(obj, TYPE_CLASS(obj->type), NULL, 0, 1)) {
+ IsCompleteType(obj->type);
+ CInit_DeclareData(obj, NULL, NULL, obj->type->size);
+ CInit_CleanupInitInfo(&initinfo);
+ return;
+ }
+
+ if (IS_TYPE_REFERENCE(obj->type) && CInit_InitReference(obj, 0)) {
+ CInit_CleanupInitInfo(&initinfo);
+ return;
+ }
+
+ if (obj->type->size == 0 && !IS_TYPE_ARRAY(obj->type)) {
+ CError_Error(CErrorStr145);
+ CInit_CleanupInitInfo(&initinfo);
+ return;
+ }
+
+ if (copts.cplusplus)
+ CInit_GenericData(obj, obj->type, obj->qual, &CInit_GlobalStaticInit, 0);
+ else
+ CInit_GenericData(obj, obj->type, obj->qual, NULL, 0);
+
+ if (IS_TYPE_CLASS(obj->type) && (dtor = CClass_Destructor(TYPE_CLASS(obj->type))))
+ InitExpr_Register(CInit_RegisterDtorObject(obj->type, dtor, create_objectrefnode(obj)), obj);
+
+ CInit_CleanupInitInfo(&initinfo);
+}
+
+Object *CInit_DeclareString(char *data, SInt32 size, Boolean ispascal, Boolean iswide) {
+ PooledString *str;
+ Object *obj;
+ PooledString *scan;
+
+ if (!copts.dont_reuse_strings) {
+ for (scan = cinit_stringlist; scan; scan = scan->next) {
+ if (scan->size == size && scan->ispascal == ispascal && scan->iswide == iswide && !memcmp(scan->data, data, size))
+ return scan->obj;
+ }
+ }
+
+ obj = CParser_NewCompilerDefDataObject();
+ obj->name = CParser_GetUniqueName();
+ if (iswide) {
+ obj->type = CDecl_NewArrayType(CParser_GetWCharType(), size);
+ } else {
+ obj->type = CDecl_NewArrayType(ispascal ? TYPE(&stunsignedchar) : TYPE(&stchar), size);
+ }
+ obj->sclass = TK_STATIC;
+ CScope_AddGlobalObject(obj);
+
+ if (!iswide && !ispascal && size == (strlen(data) + 1))
+ obj->section = SECT_TEXT_CSTRING;
+ else
+ obj->section = SECT_CONST;
+
+ if (copts.readonly_strings)
+ CInit_DeclareReadOnlyData(obj, data, NULL, obj->type->size);
+ else
+ CInit_DeclareData(obj, data, NULL, obj->type->size);
+
+ str = galloc(sizeof(PooledString));
+ str->next = cinit_stringlist;
+ cinit_stringlist = str;
+ str->obj = obj;
+ str->offset = 0;
+ str->size = size;
+ str->ispascal = ispascal;
+ str->iswide = iswide;
+ str->data = galloc(size);
+ memcpy(str->data, data, size);
+
+ return obj;
+}
+
+PooledString *CInit_DeclarePooledString(char *data, SInt32 size, Boolean ispascal) {
+ PooledString *str;
+ Object *obj;
+ PooledString *scan;
+ SInt32 offset;
+
+ if (!copts.dont_reuse_strings) {
+ for (scan = cinit_pooledstringlist; scan; scan = scan->next) {
+ if (scan->size == size && scan->ispascal == ispascal && !memcmp(scan->data, data, size))
+ return scan;
+ }
+ }
+
+ if (cinit_pooledstringlist) {
+ obj = cinit_pooledstringlist->obj;
+ offset = cinit_pooledstringlist->offset + cinit_pooledstringlist->size;
+ } else {
+ obj = CInit_CreateStaticDataObject(
+ CDecl_NewArrayType(ispascal ? TYPE(&stunsignedchar) : TYPE(&stchar), size),
+ 0, GetHashNameNodeExport("@stringBase0"));
+ obj->section = SECT_CONST;
+ offset = 0;
+ }
+
+ str = galloc(sizeof(PooledString));
+ str->next = cinit_pooledstringlist;
+ cinit_pooledstringlist = str;
+ str->obj = obj;
+ str->offset = offset;
+ str->size = size;
+ str->ispascal = ispascal;
+ str->data = galloc(size);
+ memcpy(str->data, data, size);
+ return str;
+}
+
+PooledString *CInit_DeclarePooledWString(char *data, SInt32 size) {
+ PooledString *str;
+ Object *obj;
+ PooledString *scan;
+ SInt32 offset;
+
+ if (!copts.dont_reuse_strings) {
+ for (scan = cinit_pooledwstringlist; scan; scan = scan->next) {
+ if (scan->size == size && !memcmp(scan->data, data, size))
+ return scan;
+ }
+ }
+
+ if (cinit_pooledwstringlist) {
+ obj = cinit_pooledwstringlist->obj;
+ offset = cinit_pooledwstringlist->offset + cinit_pooledwstringlist->size;
+ } else {
+ obj = CInit_CreateStaticDataObject(
+ CDecl_NewArrayType(CParser_GetWCharType(), size),
+ 0, GetHashNameNodeExport("@wstringBase0"));
+ obj->section = SECT_CONST;
+ offset = 0;
+ }
+
+ str = galloc(sizeof(PooledString));
+ str->next = cinit_pooledwstringlist;
+ cinit_pooledwstringlist = str;
+ str->obj = obj;
+ str->offset = offset;
+ str->size = size;
+ str->ispascal = 0;
+ str->data = galloc(size);
+ memcpy(str->data, data, size);
+ return str;
+}
+
+void CInit_RewriteString(ENode *expr, Boolean flag) {
+ PooledString *str;
+ Boolean is_wide;
+
+ if (cparamblkptr->precompile == 1)
+ CError_Error(CErrorStr180);
+
+ CError_ASSERT(4220, expr->rtype->type == TYPEPOINTER);
+
+ is_wide = TYPE_POINTER(expr->rtype)->target->size != 1;
+ if (copts.poolstrings) {
+ if (is_wide)
+ str = CInit_DeclarePooledWString(expr->data.string.data, expr->data.string.size);
+ else
+ str = CInit_DeclarePooledString(expr->data.string.data, expr->data.string.size, expr->data.string.ispascal);
+
+ if (str->offset) {
+ expr->type = EADD;
+ expr->data.diadic.right = intconstnode(TYPE(&stunsignedlong), str->offset);
+ expr->data.diadic.left = create_objectrefnode(str->obj);
+ expr->cost = 1;
+ } else {
+ expr->type = EOBJREF;
+ expr->data.objref = str->obj;
+ }
+ } else {
+ expr->type = EOBJREF;
+ expr->data.objref = CInit_DeclareString(expr->data.string.data, expr->data.string.size, expr->data.string.ispascal, is_wide);
+ }
+}
+
+void CInit_DeclarePooledStrings(void) {
+ SInt32 size;
+ char *buffer;
+ PooledString *str;
+
+ size = 0;
+ for (str = cinit_pooledstringlist; str; str = str->next)
+ size += str->size;
+
+ if (size) {
+ cinit_pooledstringlist->obj->type = CDecl_NewArrayType(TYPE(&stchar), size);
+ buffer = galloc(size);
+ for (str = cinit_pooledstringlist; str; str = str->next)
+ memcpy(buffer + str->offset, str->data, str->size);
+
+ if (copts.readonly_strings)
+ CInit_DeclareReadOnlyData(cinit_pooledstringlist->obj, buffer, NULL, size);
+ else
+ CInit_DeclareData(cinit_pooledstringlist->obj, buffer, NULL, size);
+ }
+
+ size = 0;
+ for (str = cinit_pooledwstringlist; str; str = str->next)
+ size += str->size;
+
+ if (size) {
+ cinit_pooledwstringlist->obj->type = CDecl_NewArrayType(CParser_GetWCharType(), size);
+ buffer = galloc(size);
+ for (str = cinit_pooledwstringlist; str; str = str->next)
+ memcpy(buffer + str->offset, str->data, str->size);
+
+ if (copts.readonly_strings)
+ CInit_DeclareReadOnlyData(cinit_pooledwstringlist->obj, buffer, NULL, size);
+ else
+ CInit_DeclareData(cinit_pooledwstringlist->obj, buffer, NULL, size);
+ }
+}
+
+static void declaredata(Object *obj, void *data, OLinkList *list, SInt32 size, Boolean is_readonly) {
+ OLinkList *scan;
+ UInt32 qual;
+
+ qual = obj->qual;
+
+ if (cparamblkptr->precompile == 1) {
+ PreComp_StaticData(obj, data, list, size);
+ } else {
+ obj->flags = obj->flags | OBJECT_DEFINED;
+ if (!fatalerrors) {
+ for (scan = list; scan; scan = scan->next)
+ CInline_ObjectAddrRef(scan->obj);
+ if (copts.filesyminfo)
+ CPrep_SetSourceFile(&cparser_fileoffset);
+ if (is_readonly)
+ ObjGen_DeclareReadOnlyData(obj, data, list, size);
+ else
+ ObjGen_DeclareData(obj, data, list, size);
+ obj->qual = qual;
+ }
+ }
+}
+
+void CInit_DeclareData(Object *obj, void *data, OLinkList *list, SInt32 size) {
+ declaredata(obj, data, list, size, 0);
+}
+
+void CInit_DeclareReadOnlyData(Object *obj, void *data, OLinkList *list, SInt32 size) {
+ declaredata(obj, data, list, size, 1);
+}
+
+void CInit_DefineTentativeData(void) {
+ ObjectList *list;
+
+ for (list = cinit_tentative; list; list = list->next) {
+ if (!(list->object->flags & OBJECT_DEFINED))
+ CInit_DeclareData(list->object, NULL, NULL, list->object->type->size);
+ }
+
+ cinit_tentative = NULL;
+}
diff --git a/compiler_and_linker/FrontEnd/C/CInline.c b/compiler_and_linker/FrontEnd/C/CInline.c
new file mode 100644
index 0000000..de51ab7
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CInline.c
@@ -0,0 +1,4206 @@
+#include "compiler/CInline.h"
+#include "compiler/CABI.h"
+#include "compiler/CClass.h"
+#include "compiler/CError.h"
+#include "compiler/CException.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInit.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/COptimizer.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CTemplateNew.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/Exceptions.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/ObjGenMachO.h"
+#include "compiler/Switch.h"
+#include "compiler/enode.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/templates.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct IDTrans {
+ struct IDTrans *next;
+ SInt32 from;
+ SInt32 to;
+} IDTrans;
+
+typedef struct LabelTrans {
+ struct LabelTrans *next;
+ CLabel **labelptr;
+ short id;
+} LabelTrans;
+
+typedef struct UIDTemp {
+ struct UIDTemp *next;
+ Object *object;
+ SInt32 uid;
+} UIDTemp;
+
+typedef struct CI_Export {
+ struct CI_Export *next;
+ Object *object;
+ CI_FuncData *funcdata;
+ Boolean xC;
+} CI_Export;
+
+typedef struct AObject {
+ Object *object;
+ ENode *expr1;
+ ENode *expr2;
+} AObject;
+
+typedef struct CI_StmtLink {
+ struct CI_StmtLink *next;
+ Statement *stmt;
+ CI_Statement *ciStmt;
+} CI_StmtLink;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static CInlineCopyMode enode_copymode;
+static Boolean enode_globalcopy;
+static IDTrans *enode_idtrans;
+static Object **local_dobjects;
+static AObject *local_aobjects;
+static CI_Var *loc_args;
+static CI_Var *loc_vars;
+static Boolean inline_expanded;
+static Boolean any_inline_expanded;
+static short cinline_level;
+static LabelTrans *cinline_label_trans;
+static Statement *cinline_first_stmt;
+static ENode *cinline_stmtlevelexpr[16];
+static short cinline_stmtlevelexprs;
+static Boolean cinline_unconditionalpart;
+static Boolean cinline_serialize_stmt;
+static CI_Export *cinline_exportlist; // type?
+static CI_Action *cinline_actionlist;
+CI_Action *cinline_tactionlist;
+static ObjectList *cinline_freflist;
+static Boolean cinline_gendeps;
+static Statement *cinline_serial_stmt;
+static Statement *cinline_cur_serial_stmt;
+static UIDTemp *cinline_uid_temps;
+static Boolean cinline_has_sideeffect;
+static SInt32 inline_max_size;
+static Boolean recursive_inline;
+static Object *expanding_function;
+static Boolean cinline_funccallfound;
+
+// forward decls
+static ENode *CInline_FoldConst(ENode *expr);
+static ENode *CInline_CopyNodes(ENode *node);
+static SInt32 CInline_EstimateSizeOfFunc(CI_FuncData *funcdata, SInt32 size, SInt32 level);
+static ENode *CInline_SerializeExpr(ENode *expr);
+static void CInline_AddFRefList_InlineFunc(CI_FuncData *data);
+
+void CInline_Init(void) {
+ cinline_exportlist = NULL;
+ cinline_actionlist = NULL;
+ cinline_tactionlist = NULL;
+ cinline_gendeps = 0;
+}
+
+static ENode *CInline_MakeNotNot(ENode *expr) {
+ expr = CInline_FoldConst(expr);
+
+ if (!ENODE_IS(expr, EINTCONST)) {
+ expr = makemonadicnode(expr, ELOGNOT);
+ expr->rtype = CParser_GetBoolType();
+ expr = makemonadicnode(expr, ELOGNOT);
+ } else {
+ expr->data.intval = CInt64_Not(CInt64_Not(expr->data.intval));
+ }
+
+ return expr;
+}
+
+static ENode *CInline_FoldConst(ENode *expr) {
+ ENode *inner;
+ ENode *right;
+ ENode *left;
+ ENodeList *list;
+
+ switch (expr->type) {
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EPRECOMP:
+ case ETEMP:
+ case ELABEL:
+ case EOBJLIST:
+ case EINSTRUCTION:
+ case EVECTOR128CONST:
+ return expr;
+
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ expr->data.monadic = CInline_FoldConst(expr->data.monadic);
+ inner = expr->data.monadic;
+ switch (inner->type) {
+ case EINTCONST:
+ if (!ENODE_IS(expr, ELOGNOT)) {
+ inner->data.intval = CMach_CalcIntMonadic(
+ expr->rtype, CParser_GetOperator(expr->type), inner->data.intval);
+ } else {
+ inner->data.intval = CInt64_Not(inner->data.intval);
+ }
+ inner->rtype = expr->rtype;
+ return inner;
+
+ case EFLOATCONST:
+ if (ENODE_IS(expr, ELOGNOT)) {
+ inner->type = EINTCONST;
+ CInt64_SetLong(&inner->data.intval, CMach_FloatIsZero(inner->data.floatval));
+ } else {
+ inner->data.floatval = CMach_CalcFloatMonadic(
+ expr->rtype, CParser_GetOperator(expr->type), inner->data.floatval);
+ }
+ inner->rtype = expr->rtype;
+ return inner;
+ }
+
+ return expr;
+
+ case ETYPCON:
+ expr->data.monadic = CInline_FoldConst(expr->data.monadic);
+ switch (expr->data.monadic->type) {
+ case EINTCONST:
+ switch (expr->rtype->type) {
+ case TYPEFLOAT:
+ expr->type = EFLOATCONST;
+ expr->data.floatval = CMach_CalcFloatConvertFromInt(
+ expr->data.monadic->rtype, expr->data.monadic->data.intval);
+ return expr;
+
+ case TYPEINT:
+ expr->type = EINTCONST;
+ expr->data.intval = CExpr_IntConstConvert(
+ expr->rtype, expr->data.monadic->rtype, expr->data.monadic->data.intval);
+ break;
+ }
+ break;
+
+ case EFLOATCONST:
+ switch (expr->rtype->type) {
+ case TYPEFLOAT:
+ expr->type = EFLOATCONST;
+ expr->data.floatval = CMach_CalcFloatConvert(
+ expr->rtype, expr->data.monadic->data.floatval);
+ return expr;
+
+ case TYPEINT:
+ expr->type = EINTCONST;
+ expr->data.intval = CMach_CalcIntConvertFromFloat(
+ expr->rtype, expr->data.monadic->data.floatval);
+ return expr;
+ }
+ break;
+ }
+
+ return expr;
+
+ case EPOSTINC:
+ case EPOSTDEC:
+ expr->data.monadic = CInline_FoldConst(expr->data.monadic);
+ switch (expr->data.monadic->type) {
+ case EINTCONST:
+ case EFLOATCONST:
+ expr->data.monadic->rtype = expr->rtype;
+ return expr->data.monadic;
+ }
+
+ return expr;
+
+ case EPREINC:
+ case EPREDEC:
+ case EINDIRECT:
+ case EFORCELOAD:
+ case EBITFIELD:
+ expr->data.monadic = CInline_FoldConst(expr->data.monadic);
+ return expr;
+
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ case EADD:
+ case ESUB:
+ case ESHL:
+ case ESHR:
+ case EAND:
+ case EXOR:
+ case EOR:
+ expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
+ expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
+ if ((left = expr->data.diadic.left)->type == (right = expr->data.diadic.right)->type) {
+ switch (left->type) {
+ case EINTCONST:
+ left->data.intval = CMach_CalcIntDiadic(
+ expr->rtype,
+ expr->data.diadic.left->data.intval,
+ CParser_GetOperator(expr->type),
+ right->data.intval);
+ left->rtype = expr->rtype;
+ return left;
+
+ case EFLOATCONST:
+ left->data.floatval = CMach_CalcFloatDiadic(
+ expr->rtype,
+ expr->data.diadic.left->data.floatval,
+ CParser_GetOperator(expr->type),
+ right->data.floatval);
+ left->rtype = expr->rtype;
+ return left;
+ }
+ }
+
+ return expr;
+
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ case ENOTEQU:
+ expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
+ expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
+ if ((left = expr->data.diadic.left)->type == (right = expr->data.diadic.right)->type) {
+ switch (left->type) {
+ case EINTCONST:
+ left->data.intval = CMach_CalcIntDiadic(
+ left->rtype,
+ expr->data.diadic.left->data.intval,
+ CParser_GetOperator(expr->type),
+ right->data.intval);
+ left->rtype = expr->rtype;
+ return left;
+
+ case EFLOATCONST:
+ CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(
+ left->rtype,
+ expr->data.diadic.left->data.floatval,
+ CParser_GetOperator(expr->type),
+ right->data.floatval
+ ));
+ left->type = EINTCONST;
+ left->rtype = expr->rtype;
+ return left;
+ }
+ }
+
+ return expr;
+
+ case ELAND:
+ expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
+ if (iszero(expr->data.diadic.left))
+ return expr->data.diadic.left;
+ if (isnotzero(expr->data.diadic.left))
+ return CInline_MakeNotNot(expr->data.diadic.right);
+
+ expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
+ if (isnotzero(expr->data.diadic.right))
+ return CInline_MakeNotNot(expr->data.diadic.left);
+
+ return expr;
+
+ case ELOR:
+ expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
+ if (iszero(expr->data.diadic.left))
+ return CInline_MakeNotNot(expr->data.diadic.right);
+ if (isnotzero(expr->data.diadic.left))
+ return CInline_MakeNotNot(expr->data.diadic.left);
+
+ expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
+ if (iszero(expr->data.diadic.right))
+ return CInline_MakeNotNot(expr->data.diadic.left);
+
+ return expr;
+
+ 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 EROTL:
+ case EROTR:
+ expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left);
+ expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right);
+ return expr;
+
+ case ECOND:
+ expr->data.cond.cond = CInline_FoldConst(expr->data.cond.cond);
+ if (isnotzero(expr->data.cond.cond))
+ return CInline_FoldConst(expr->data.cond.expr1);
+ if (iszero(expr->data.cond.cond))
+ return CInline_FoldConst(expr->data.cond.expr2);
+
+ expr->data.cond.expr1 = CInline_FoldConst(expr->data.cond.expr1);
+ expr->data.cond.expr2 = CInline_FoldConst(expr->data.cond.expr2);
+ return expr;
+
+ case EMFPOINTER:
+ expr->data.mfpointer.accessnode = CInline_FoldConst(expr->data.mfpointer.accessnode);
+ expr->data.mfpointer.mfpointer = CInline_FoldConst(expr->data.mfpointer.mfpointer);
+ return expr;
+
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ expr->data.funccall.funcref = CInline_FoldConst(expr->data.funccall.funcref);
+ for (list = expr->data.funccall.args; list; list = list->next)
+ list->node = CInline_FoldConst(list->node);
+ return expr;
+
+ case ENULLCHECK:
+ expr->data.nullcheck.nullcheckexpr = CInline_FoldConst(expr->data.nullcheck.nullcheckexpr);
+ expr->data.nullcheck.condexpr = CInline_FoldConst(expr->data.nullcheck.condexpr);
+ return expr;
+
+ case EMEMBER:
+ if (expr->data.emember->expr)
+ expr->data.emember->expr = CInline_FoldConst(expr->data.emember->expr);
+ return expr;
+
+ default:
+ CError_FATAL(421);
+ return expr;
+ }
+}
+
+// unknown name
+CW_INLINE SInt32 CInline_GetLocalID2(Object *object) {
+ ObjectList *list;
+ SInt32 counter;
+
+ for (list = locals, counter = 0; list; list = list->next) {
+ if (list->object->datatype == DLOCAL) {
+ if (list->object == object)
+ return counter;
+ counter++;
+ }
+ }
+
+ return -1;
+}
+
+SInt32 CInline_GetLocalID(Object *object) {
+ ObjectList *list;
+ SInt32 counter;
+
+ if (object) {
+ for (list = arguments, counter = 0; list; list = list->next, counter++) {
+ if (list->object == object) {
+ loc_args[counter].xD = 1;
+ loc_args[counter].xE = 0;
+ return counter - 0x7FFFFFFF;
+ }
+ }
+
+ counter = CInline_GetLocalID2(object);
+ CError_ASSERT(465, counter >= 0);
+ loc_vars[counter].xD = 1;
+ return counter + 1;
+ }
+
+ return 0;
+}
+
+static Boolean CInline_IsTrivialExpression(ENode *expr) {
+ while (1) {
+ switch (expr->type) {
+ case EINTCONST:
+ case EFLOATCONST:
+ case EOBJREF:
+ case EARGOBJ:
+ case ELOCOBJ:
+ case EOBJLIST:
+ case EVECTOR128CONST:
+ return 0;
+
+ case ESTRINGCONST:
+ return copts.dont_reuse_strings;
+
+ case EMEMBER:
+ if (expr->data.emember->expr)
+ return CInline_IsTrivialExpression(expr->data.emember->expr);
+ return 0;
+
+ case EINDIRECT:
+ if (ENODE_IS(expr->data.monadic, EOBJREF)) {
+ if (expr->data.monadic->data.objref->datatype == DLOCAL &&
+ !(expr->data.monadic->data.objref->flags & OBJECT_FLAGS_2))
+ return 0;
+
+ if (is_const_object(expr->data.monadic->data.objref))
+ return 0;
+
+ return 1;
+ }
+
+ return 1;
+
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EFORCELOAD:
+ case EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ case EMFPOINTER:
+ case ENULLCHECK:
+ case EPRECOMP:
+ case ETEMP:
+ case ELABEL:
+ case EINSTRUCTION:
+ return 1;
+
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case ETYPCON:
+ case EBITFIELD:
+ expr = expr->data.monadic;
+ continue;
+
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ 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 ECOMMA:
+ case EROTL:
+ case EROTR:
+ if (CInline_IsTrivialExpression(expr->data.diadic.left))
+ return 1;
+ expr = expr->data.diadic.right;
+ continue;
+
+ case ECOND:
+ if (CInline_IsTrivialExpression(expr->data.cond.cond))
+ return 1;
+ if (CInline_IsTrivialExpression(expr->data.cond.expr1))
+ return 1;
+ expr = expr->data.cond.expr2;
+ continue;
+
+ default:
+ CError_FATAL(582);
+ }
+ }
+}
+
+Boolean CInline_ExpressionHasSideEffect(ENode *expr) {
+ while (1) {
+ switch (expr->type) {
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EPRECOMP:
+ case ETEMP:
+ case EARGOBJ:
+ case ELOCOBJ:
+ case ELABEL:
+ case EOBJLIST:
+ case EVECTOR128CONST:
+ return 0;
+
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ case EINSTRUCTION:
+ return 1;
+
+ case EINDIRECT:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case EFORCELOAD:
+ case ETYPCON:
+ case EBITFIELD:
+ expr = expr->data.monadic;
+ continue;
+
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ 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 ECOMMA:
+ case EROTL:
+ case EROTR:
+ if (CInline_ExpressionHasSideEffect(expr->data.diadic.left))
+ return 1;
+ expr = expr->data.diadic.right;
+ continue;
+
+ case EMEMBER:
+ if (expr->data.emember->expr)
+ return CInline_ExpressionHasSideEffect(expr->data.emember->expr);
+ return 0;
+
+ case EMFPOINTER:
+ if (CInline_ExpressionHasSideEffect(expr->data.mfpointer.accessnode))
+ return 1;
+ expr = expr->data.mfpointer.mfpointer;
+ continue;
+
+ case ENULLCHECK:
+ if (CInline_ExpressionHasSideEffect(expr->data.nullcheck.nullcheckexpr))
+ return 1;
+ expr = expr->data.nullcheck.condexpr;
+ continue;
+
+ case ECOND:
+ if (CInline_ExpressionHasSideEffect(expr->data.cond.cond))
+ return 1;
+ if (CInline_ExpressionHasSideEffect(expr->data.cond.expr1))
+ return 1;
+ expr = expr->data.cond.expr2;
+ continue;
+
+ default:
+ CError_FATAL(689);
+ }
+ }
+}
+
+static ENode *CInline_CopyExpressionSave(ENode *expr) {
+ CInlineCopyMode save_copymode;
+ Boolean save_globalcopy;
+ IDTrans *save_idtrans;
+
+ save_globalcopy = enode_globalcopy;
+ enode_globalcopy = 1;
+
+ save_copymode = enode_copymode;
+ enode_copymode = CopyMode4;
+
+ save_idtrans = enode_idtrans;
+ enode_idtrans = NULL;
+
+ expr = CInline_CopyNodes(expr);
+
+ enode_globalcopy = save_globalcopy;
+ enode_copymode = save_copymode;
+ enode_idtrans = save_idtrans;
+
+ return expr;
+}
+
+static SInt32 CInline_TranslateID(SInt32 id) {
+ IDTrans *trans;
+
+ for (trans = enode_idtrans; trans; trans = trans->next) {
+ if (trans->from == id)
+ return trans->to;
+ }
+
+ trans = lalloc(sizeof(IDTrans));
+ trans->next = enode_idtrans;
+ enode_idtrans = trans;
+
+ trans->from = id;
+ trans->to = CParser_GetUniqueID();
+
+ return trans->to;
+}
+
+static short CInline_GetLabelStatementNumber(HashNameNode *name) {
+ Statement *stmt;
+ short i;
+
+ for (stmt = cinline_first_stmt, i = 0; stmt; stmt = stmt->next, i++) {
+ if (stmt->type == ST_LABEL && stmt->label->uniquename == name)
+ return i;
+ }
+
+ CError_FATAL(742);
+ return 0;
+}
+
+static ENodeList *CInline_CopyNodeList(ENodeList *list) {
+ ENodeList *copy;
+ ENodeList *first;
+ ENodeList *last;
+
+ first = NULL;
+ while (list) {
+ if (enode_globalcopy)
+ copy = galloc(sizeof(ENodeList));
+ else
+ copy = lalloc(sizeof(ENodeList));
+
+ copy->node = CInline_CopyNodes(list->node);
+ copy->next = NULL;
+
+ if (first) {
+ last->next = copy;
+ last = copy;
+ } else {
+ first = last = copy;
+ }
+
+ list = list->next;
+ }
+
+ return first;
+}
+
+static EMemberInfo *CInline_CopyEMemberInfo(EMemberInfo *mi) {
+ EMemberInfo *copy;
+
+ if (enode_globalcopy)
+ copy = galloc(sizeof(EMemberInfo));
+ else
+ copy = lalloc(sizeof(EMemberInfo));
+
+ *copy = *mi;
+ if (copy->path)
+ copy->path = CClass_GetPathCopy(copy->path, enode_globalcopy);
+ if (copy->expr)
+ copy->expr = CInline_CopyNodes(copy->expr);
+
+ return copy;
+}
+
+static ENode *CInline_CopyNodes(ENode *node) {
+ ENode *copy;
+
+ if (enode_globalcopy)
+ copy = galloc(sizeof(ENode));
+ else
+ copy = lalloc(sizeof(ENode));
+
+ while (1) {
+ *copy = *node;
+ switch (copy->type) {
+ case ETEMPLDEP:
+ switch (copy->data.templdep.subtype) {
+ case TDE_PARAM:
+ case TDE_SIZEOF:
+ case TDE_ALIGNOF:
+ case TDE_QUALNAME:
+ case TDE_OBJ:
+ break;
+ case TDE_CAST:
+ copy->data.templdep.u.cast.args = CInline_CopyNodeList(copy->data.templdep.u.cast.args);
+ break;
+ case TDE_SOURCEREF:
+ copy->data.templdep.u.sourceref.expr = CInline_CopyNodes(copy->data.templdep.u.sourceref.expr);
+ break;
+ case TDE_ADDRESS_OF:
+ copy->data.templdep.u.monadic = CInline_CopyNodes(copy->data.templdep.u.monadic);
+ break;
+ default:
+ CError_FATAL(840);
+ }
+ break;
+
+ case ETEMP:
+ if (enode_copymode == CopyMode3 && copy->data.temp.uniqueid)
+ copy->data.temp.uniqueid = CInline_TranslateID(copy->data.temp.uniqueid);
+ break;
+
+ case ELABEL:
+ switch (enode_copymode) {
+ case CopyMode2:
+ copy->data.precompid = CInline_GetLabelStatementNumber(copy->data.label->uniquename);
+ return copy;
+ case CopyMode3:
+ case CopyMode4: {
+ LabelTrans *trans = lalloc(sizeof(LabelTrans));
+ trans->next = cinline_label_trans;
+ cinline_label_trans = trans;
+ trans->id = copy->data.precompid;
+ trans->labelptr = &copy->data.label;
+ return copy;
+ }
+ }
+ break;
+
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJLIST:
+ case EINSTRUCTION:
+ case EVECTOR128CONST:
+ break;
+
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case EFORCELOAD:
+ case ETYPCON:
+ case EBITFIELD:
+ copy->data.monadic = CInline_CopyNodes(copy->data.monadic);
+ break;
+
+ ENODE_CASE_DIADIC_ALL:
+ copy->data.diadic.left = CInline_CopyNodes(copy->data.diadic.left);
+ copy->data.diadic.right = CInline_CopyNodes(copy->data.diadic.right);
+ break;
+
+ case ECOND:
+ copy->data.cond.cond = CInline_CopyNodes(copy->data.cond.cond);
+ copy->data.cond.expr1 = CInline_CopyNodes(copy->data.cond.expr1);
+ copy->data.cond.expr2 = CInline_CopyNodes(copy->data.cond.expr2);
+ break;
+
+ case EMFPOINTER:
+ copy->data.mfpointer.accessnode = CInline_CopyNodes(copy->data.mfpointer.accessnode);
+ copy->data.mfpointer.mfpointer = CInline_CopyNodes(copy->data.mfpointer.mfpointer);
+ break;
+
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ copy->data.funccall.funcref = CInline_CopyNodes(copy->data.funccall.funcref);
+ copy->data.funccall.args = CInline_CopyNodeList(copy->data.funccall.args);
+ break;
+
+ case ENULLCHECK:
+ copy->data.nullcheck.precompid = CInline_TranslateID(copy->data.nullcheck.precompid);
+ copy->data.nullcheck.nullcheckexpr = CInline_CopyNodes(copy->data.nullcheck.nullcheckexpr);
+ copy->data.nullcheck.condexpr = CInline_CopyNodes(copy->data.nullcheck.condexpr);
+ break;
+
+ case EPRECOMP:
+ copy->data.precompid = CInline_TranslateID(copy->data.precompid);
+ break;
+
+ case EINDIRECT:
+ if (
+ enode_copymode == CopyMode4 &&
+ ENODE_IS(copy->data.monadic, EARGOBJ) &&
+ local_aobjects[copy->data.monadic->data.longval].object == NULL
+ )
+ {
+ CError_ASSERT(910, local_aobjects[copy->data.monadic->data.longval].expr1);
+ copy = CInline_CopyExpressionSave(local_aobjects[copy->data.monadic->data.longval].expr1);
+ if (copy->rtype != node->rtype) {
+ if (IS_TYPE_INT(copy->rtype) && IS_TYPE_INT(node->rtype))
+ copy = makemonadicnode(copy, ETYPCON);
+ copy->rtype = node->rtype;
+ }
+ return copy;
+ }
+
+ copy->data.monadic = CInline_CopyNodes(copy->data.monadic);
+ break;
+
+ case EOBJREF:
+ if (enode_copymode == CopyMode2) {
+ ObjectList *list;
+ int i;
+
+ if (node->data.objref->datatype == DALIAS) {
+ CExpr_AliasTransform(node);
+ continue;
+ }
+
+ if (node->data.objref->datatype == DDATA)
+ return copy;
+
+ for (list = arguments, i = 0; list; list = list->next, i++) {
+ if (list->object == copy->data.objref) {
+ copy->type = EARGOBJ;
+ copy->data.longval = i;
+ return copy;
+ }
+ }
+
+ i = CInline_GetLocalID2(copy->data.objref);
+ if (i >= 0) {
+ copy->type = ELOCOBJ;
+ copy->data.longval = i;
+ return copy;
+ }
+
+ if (node->data.objref->datatype == DLOCAL)
+ CError_FATAL(949);
+ }
+ break;
+
+ case EARGOBJ:
+ switch (enode_copymode) {
+ case CopyMode4:
+ CError_ASSERT(957, local_aobjects[copy->data.longval].object);
+ copy->type = EOBJREF;
+ copy->data.objref = local_aobjects[copy->data.longval].object;
+ return copy;
+
+ case CopyMode3: {
+ ObjectList *list;
+ int i;
+ for (list = arguments, i = 0; list; list = list->next, i++) {
+ if (i == copy->data.longval) {
+ copy->type = EOBJREF;
+ copy->data.objref = list->object;
+ CError_ASSERT(966, copy->data.objref);
+ return copy;
+ }
+ }
+ }
+
+ default:
+ CError_FATAL(971);
+ }
+
+ case ELOCOBJ:
+ switch (enode_copymode) {
+ case CopyMode4:
+ copy->type = EOBJREF;
+ copy->data.objref = local_dobjects[copy->data.longval];
+ return copy;
+
+ case CopyMode3: {
+ ObjectList *list;
+ int i;
+ for (list = locals, i = 0; list; list = list->next, i++) {
+ if (i == copy->data.longval) {
+ copy->type = EOBJREF;
+ copy->data.objref = list->object;
+ CError_ASSERT(986, copy->data.objref);
+ return copy;
+ }
+ }
+ }
+
+ default:
+ CError_FATAL(991);
+ }
+ break;
+
+ case ENEWEXCEPTION:
+ case ENEWEXCEPTIONARRAY:
+ copy->data.newexception.initexpr = CInline_CopyNodes(copy->data.newexception.initexpr);
+ copy->data.newexception.tryexpr = CInline_CopyNodes(copy->data.newexception.tryexpr);
+ break;
+
+ case EINITTRYCATCH:
+ copy->data.itc.initexpr = CInline_CopyNodes(copy->data.itc.initexpr);
+ copy->data.itc.tryexpr = CInline_CopyNodes(copy->data.itc.tryexpr);
+ copy->data.itc.catchexpr = CInline_CopyNodes(copy->data.itc.catchexpr);
+ copy->data.itc.result = CInline_CopyNodes(copy->data.itc.result);
+ break;
+
+ case EMEMBER:
+ copy->data.emember = CInline_CopyEMemberInfo(copy->data.emember);
+ break;
+
+ default:
+ CError_FATAL(1015);
+ }
+
+ return copy;
+ }
+}
+
+static void CInline_CheckUsage(ENode *expr, Boolean flag) {
+ ENodeList *list;
+ ENode *inner;
+
+ while (1) {
+ switch (expr->type) {
+ case EARGOBJ:
+ loc_args[expr->data.longval].xD = 1;
+ loc_args[expr->data.longval].xE = 0;
+ return;
+
+ case ELOCOBJ:
+ loc_vars[expr->data.longval].xD = 1;
+ return;
+
+ case EINDIRECT:
+ if (ENODE_IS((inner = expr->data.monadic), EARGOBJ)) {
+ loc_args[inner->data.longval].xD = 1;
+ if (flag)
+ loc_args[inner->data.longval].xE = 0;
+ return;
+ }
+ expr = expr->data.monadic;
+ flag = 0;
+ continue;
+
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case EFORCELOAD:
+ case ETYPCON:
+ case EBITFIELD:
+ expr = expr->data.monadic;
+ flag = 0;
+ continue;
+
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ expr = expr->data.monadic;
+ flag = 1;
+ continue;
+
+ case EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ CInline_CheckUsage(expr->data.diadic.left, 1);
+ expr = expr->data.diadic.right;
+ flag = 0;
+ continue;
+
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ 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 ECOMMA:
+ case EROTL:
+ case EROTR:
+ CInline_CheckUsage(expr->data.diadic.left, 0);
+ expr = expr->data.diadic.right;
+ flag = 0;
+ continue;
+
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EPRECOMP:
+ case ETEMP:
+ case ELABEL:
+ case EOBJLIST:
+ case EVECTOR128CONST:
+ return;
+
+ case EMEMBER:
+ if (expr->data.emember->expr)
+ CInline_CheckUsage(expr->data.emember->expr, 0);
+ return;
+
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ CInline_CheckUsage(expr->data.funccall.funcref, 0);
+ for (list = expr->data.funccall.args; list; list = list->next)
+ CInline_CheckUsage(list->node, 0);
+ return;
+
+ case ENULLCHECK:
+ CInline_CheckUsage(expr->data.nullcheck.nullcheckexpr, 0);
+ expr = expr->data.nullcheck.condexpr;
+ flag = 0;
+ continue;
+
+ case EMFPOINTER:
+ CInline_CheckUsage(expr->data.mfpointer.accessnode, 0);
+ expr = expr->data.mfpointer.mfpointer;
+ flag = 0;
+ continue;
+
+ case ECOND:
+ CInline_CheckUsage(expr->data.cond.cond, 0);
+ CInline_CheckUsage(expr->data.cond.expr1, 0);
+ expr = expr->data.cond.expr2;
+ flag = 0;
+ continue;
+
+ case EINSTRUCTION:
+ return;
+
+ default:
+ CError_FATAL(1146);
+ }
+ }
+}
+
+ENode *CInline_CopyExpression(ENode *expr, CInlineCopyMode mode) {
+ enode_copymode = mode;
+
+ switch (mode) {
+ case CopyMode0:
+ case CopyMode4:
+ enode_idtrans = NULL;
+ enode_globalcopy = 0;
+ expr = CInline_CopyNodes(expr);
+ break;
+ case CopyMode3:
+ enode_globalcopy = 0;
+ expr = CInline_CopyNodes(expr);
+ break;
+ case CopyMode1:
+ enode_idtrans = NULL;
+ enode_globalcopy = 1;
+ expr = CInline_CopyNodes(expr);
+ break;
+ case CopyMode2:
+ enode_idtrans = NULL;
+ enode_globalcopy = 1;
+ expr = CInline_CopyNodes(expr);
+ CInline_CheckUsage(expr, 0);
+ break;
+ }
+
+ return expr;
+}
+
+static UInt8 CInline_GetObjectSFlags(Object *object) {
+ UInt8 flags;
+
+ switch (object->sclass) {
+ case 0:
+ flags = CI_SFLAGS_NoClass;
+ break;
+ case TK_REGISTER:
+ flags = CI_SFLAGS_Register;
+ break;
+ case TK_AUTO:
+ flags = CI_SFLAGS_Auto;
+ break;
+ default:
+ CError_FATAL(1204);
+ }
+
+ if (object->flags & OBJECT_FLAGS_2)
+ flags |= CI_SFLAGS_HasObjectFlag2;
+
+ return flags;
+}
+
+static void CInline_SetObjectSFlags(Object *object, UInt8 sflags) {
+ if (sflags & CI_SFLAGS_HasObjectFlag2) {
+ object->flags |= OBJECT_FLAGS_2;
+ sflags &= ~CI_SFLAGS_HasObjectFlag2;
+ }
+
+ switch (sflags) {
+ case CI_SFLAGS_NoClass:
+ object->sclass = 0;
+ break;
+ case CI_SFLAGS_Register:
+ object->sclass = TK_REGISTER;
+ break;
+ case CI_SFLAGS_Auto:
+ object->sclass = TK_AUTO;
+ break;
+ default:
+ CError_FATAL(1229);
+ }
+}
+
+static Object *CInline_NewLocalObject(Type *type, short qual, UInt8 sflags, int unk) {
+ Object *object = CParser_NewLocalDataObject(NULL, 1);
+ object->name = CParser_GetUniqueName();
+ object->type = type;
+ object->qual = qual;
+ CInline_SetObjectSFlags(object, sflags);
+ CFunc_SetupLocalVarInfo(object);
+ return object;
+}
+
+static ENode *CInline_FuncArgConvert(ENode *expr) {
+ ENode *copy;
+
+ switch (expr->type) {
+ case EOBJREF:
+ copy = lalloc(sizeof(ENode));
+ *copy = *expr;
+ return copy;
+ case ETEMP:
+ CError_FATAL(1272);
+ }
+
+ return NULL;
+}
+
+static ENode *CInline_RefArgTransform(ENode *expr, Boolean flag) {
+ ENodeList *arg;
+
+ while (ENODE_IS(expr, ECOMMA))
+ expr = expr->data.diadic.right;
+
+ switch (expr->type) {
+ case EOBJREF:
+ case ETEMP:
+ if (flag)
+ return CInline_FuncArgConvert(expr);
+ break;
+
+ case EFUNCCALL:
+ if (IS_TYPE_POINTER_ONLY(expr->rtype) && IS_TYPE_CLASS(TPTR_TARGET(expr->rtype))) {
+ if (
+ ENODE_IS(expr->data.funccall.funcref, EOBJREF) &&
+ CClass_IsConstructor(expr->data.funccall.funcref->data.objref) &&
+ expr->data.funccall.args
+ )
+ return CInline_FuncArgConvert(expr->data.funccall.args->node);
+
+ if (
+ TPTR_TARGET(expr->rtype) == expr->data.funccall.functype->functype &&
+ CMach_GetFunctionResultClass(expr->data.funccall.functype) == 1 &&
+ (arg = expr->data.funccall.args)
+ )
+ {
+ switch (CABI_GetStructResultArgumentIndex(expr->data.funccall.functype)) {
+ case 0:
+ break;
+ case 1:
+ if ((arg = arg->next))
+ break;
+ CError_FATAL(1313);
+ default:
+ CError_FATAL(1314);
+ }
+
+ return CInline_FuncArgConvert(arg->node);
+ }
+ }
+ break;
+ }
+
+ return NULL;
+}
+
+static ENode *CInline_SetupArgsExpression(Object *object, CI_FuncData *data, ENodeList *list) {
+ ENode *commaNodes;
+ CI_Var *var;
+ ENodeList *scan;
+ ENode *expr;
+ SInt32 i;
+ Boolean is_oldstyle;
+
+ is_oldstyle = 0;
+ if (TYPE_FUNC(object->type)->args == &oldstyle)
+ is_oldstyle = 1;
+
+ local_dobjects = lalloc(sizeof(Object *) * data->numlocals);
+ local_aobjects = lalloc(sizeof(AObject) * data->numarguments);
+
+ for (i = 0, var = data->locals; i < data->numlocals; i++, var++) {
+ if (var->xD) {
+ object = CInline_NewLocalObject(var->type, var->qual, var->sflags, 0);
+ local_dobjects[i] = object;
+ if (!var->xE)
+ object->flags |= OBJECT_FLAGS_2;
+ } else {
+ local_dobjects[i] = NULL;
+ }
+ }
+
+ for (i = 0, var = data->arguments, scan = list; i < data->numarguments; i++, var++) {
+ local_aobjects[i].expr2 = NULL;
+
+ if (!var->xD) {
+ local_aobjects[i].object = NULL;
+ local_aobjects[i].expr1 = NULL;
+ } else if (
+ scan &&
+ var->xE &&
+ !CInline_IsTrivialExpression(scan->node) &&
+ (!is_oldstyle || scan->node->rtype->size == var->type->size)
+ )
+ {
+ local_aobjects[i].object = NULL;
+ local_aobjects[i].expr1 = scan->node;
+ } else if (
+ scan &&
+ var->xE &&
+ IS_TYPE_REFERENCE(var->type) &&
+ (expr = CInline_RefArgTransform(scan->node, 1))
+ )
+ {
+ local_aobjects[i].object = NULL;
+ local_aobjects[i].expr1 = expr;
+ local_aobjects[i].expr2 = scan->node;
+ } else {
+ local_aobjects[i].object = CInline_NewLocalObject(var->type, var->qual, var->sflags, 0);
+ local_aobjects[i].expr1 = NULL;
+ }
+
+ if (scan)
+ scan = scan->next;
+ }
+
+ commaNodes = NULL;
+
+ for (i = 0, scan = list; scan; scan = scan->next, i++) {
+ if (i >= data->numarguments) {
+ if (!commaNodes)
+ commaNodes = scan->node;
+ else
+ commaNodes = makecommaexpression(scan->node, commaNodes);
+ } else if (!local_aobjects[i].object || local_aobjects[i].expr2) {
+ if (local_aobjects[i].expr2) {
+ if (!commaNodes)
+ commaNodes = local_aobjects[i].expr2;
+ else
+ commaNodes = makecommaexpression(local_aobjects[i].expr2, commaNodes);
+ } else if (!local_aobjects[i].expr1 && CInline_IsTrivialExpression(scan->node)) {
+ commaNodes = !commaNodes ? scan->node : makecommaexpression(scan->node, commaNodes);
+ CError_ASSERT(1470, !ENODE_IS(scan->node, EPRECOMP));
+ }
+ } else {
+ if (is_oldstyle && scan->node->rtype->size != local_aobjects[i].object->type->size) {
+ scan->node = makemonadicnode(scan->node, ETYPCON);
+ scan->node->rtype = local_aobjects[i].object->type;
+ }
+
+ expr = makediadicnode(create_objectnode2(local_aobjects[i].object), scan->node, EASS);
+ if (!commaNodes)
+ commaNodes = expr;
+ else
+ commaNodes = makecommaexpression(expr, commaNodes);
+ }
+ }
+
+ return commaNodes;
+}
+
+static void CInline_ReturnCheckCB(ENode *expr) {
+ cinline_has_sideeffect = 1;
+}
+
+static ENode *CInline_ReturnCheck(ENode *expr) {
+ ENode *copy;
+
+ if (ENODE_IS(expr, EFORCELOAD))
+ return expr;
+
+ cinline_has_sideeffect = 0;
+ CExpr_SearchExprTree(expr, CInline_ReturnCheckCB, 3, EINDIRECT, EFUNCCALL, EFUNCCALLP);
+
+ if (!cinline_has_sideeffect)
+ return expr;
+
+ copy = lalloc(sizeof(ENode));
+ *copy = *expr;
+ copy->type = EFORCELOAD;
+
+ copy->data.monadic = expr;
+ return copy;
+}
+
+static ENode *CInline_ReturnMemResult(Object *object) {
+ int index = CABI_GetStructResultArgumentIndex(TYPE_FUNC(object->type));
+ if (local_aobjects[index].object == NULL)
+ return CInline_CopyExpressionSave(local_aobjects[index].expr1);
+ else
+ return create_objectnode(local_aobjects[index].object);
+}
+
+static ENode *CInline_InlineFunctionExpression(ENode *expr) {
+ Object *object;
+ CI_FuncData *funcdata;
+ short i;
+ Boolean flag26;
+ ENode *argsExpr;
+
+ object = expr->data.funccall.funcref->data.objref;
+ if (object->datatype == DALIAS)
+ object = object->u.alias.object;
+
+ funcdata = object->u.func.u.ifuncdata;
+ if (!funcdata)
+ return expr;
+
+ if (funcdata->can_inline < CI_CanInline6) {
+ if (funcdata->can_inline == CI_CanInline3) {
+ if (cinline_unconditionalpart && cinline_stmtlevelexprs < 16)
+ cinline_stmtlevelexpr[cinline_stmtlevelexprs++] = expr;
+ cinline_serialize_stmt = 1;
+ }
+ return expr;
+ }
+
+ flag26 = CMach_GetFunctionResultClass(TYPE_FUNC(object->type)) == 1;
+ argsExpr = CInline_SetupArgsExpression(object, funcdata, expr->data.funccall.args);
+
+ for (i = 0; i < funcdata->numstatements; i++) {
+ switch (funcdata->statements[i].type) {
+ case ST_RETURN:
+ if (funcdata->statements[i].u.expr) {
+ ENode *copy = CInline_CopyExpression(funcdata->statements[i].u.expr, CopyMode4);
+ if (flag26) {
+ if (argsExpr)
+ argsExpr = makecommaexpression(argsExpr, copy);
+ else
+ argsExpr = copy;
+
+ argsExpr = makecommaexpression(argsExpr, CInline_ReturnMemResult(object));
+ } else {
+ if (argsExpr)
+ argsExpr = makecommaexpression(argsExpr, CInline_ReturnCheck(copy));
+ else
+ argsExpr = CInline_ReturnCheck(copy);
+ }
+ }
+ break;
+ case ST_EXPRESSION:
+ if (argsExpr)
+ argsExpr = makecommaexpression(argsExpr, CInline_CopyExpression(funcdata->statements[i].u.expr, CopyMode4));
+ else
+ argsExpr = CInline_CopyExpression(funcdata->statements[i].u.expr, CopyMode4);
+ break;
+
+ default:
+ CError_FATAL(1632);
+ }
+ }
+
+ if (!argsExpr)
+ argsExpr = nullnode();
+ if (!IS_TYPE_VOID(expr->rtype))
+ argsExpr->rtype = expr->rtype;
+
+ inline_expanded = 1;
+ return CInline_FoldConst(argsExpr);
+}
+
+static Boolean CInline_CanExpand(ENode *expr) {
+ TypeFunc *tfunc;
+ Object *object;
+
+ object = expr->data.objref;
+ tfunc = TYPE_FUNC(object->type);
+
+ if (
+ IS_TYPE_FUNC(tfunc) &&
+ ((object->qual & Q_INLINE) || (tfunc->flags & FUNC_FLAGS_800)) &&
+ (object->datatype == DFUNC || (object->datatype == DVFUNC && (expr->flags & ENODE_FLAG_80)))
+ )
+ return 1;
+
+ return 0;
+}
+
+static SInt32 CInline_EstimateSizeOfExpr(ENode *expr, SInt32 size, SInt32 level) {
+ ENodeList *list;
+
+ switch (expr->type) {
+ ENODE_CASE_MONADIC:
+ size = CInline_EstimateSizeOfExpr(expr->data.monadic, size, level) + 1;
+ break;
+
+ ENODE_CASE_DIADIC_ALL:
+ size = CInline_EstimateSizeOfExpr(expr->data.diadic.left, size, level);
+ if (size <= inline_max_size)
+ size = CInline_EstimateSizeOfExpr(expr->data.diadic.right, size, level) + 1;
+ break;
+
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ if (
+ ENODE_IS(expr->data.funccall.funcref, EOBJREF) &&
+ expr->data.funccall.funcref->data.objref->u.func.u.ifuncdata &&
+ CInline_CanExpand(expr->data.funccall.funcref)
+ )
+ {
+ recursive_inline |= expr->data.funccall.funcref->data.objref == expanding_function;
+ if (level == 0) {
+ if (!recursive_inline)
+ size = inline_max_size + 1;
+ } else {
+ size = CInline_EstimateSizeOfFunc(expr->data.funccall.funcref->data.objref->u.func.u.ifuncdata, size, level - 1);
+ }
+ } else {
+ size++;
+ }
+
+ for (list = expr->data.funccall.args; list; list = list->next) {
+ if (size > inline_max_size)
+ break;
+
+ size = CInline_EstimateSizeOfExpr(list->node, size, level);
+ }
+ break;
+
+ case ECOND:
+ size = CInline_EstimateSizeOfExpr(expr->data.cond.cond, size, level);
+ if (size <= inline_max_size)
+ size = CInline_EstimateSizeOfExpr(expr->data.cond.expr1, size, level) + 1;
+ if (size <= inline_max_size)
+ size = CInline_EstimateSizeOfExpr(expr->data.cond.expr2, size, level) + 1;
+ break;
+
+ case ENULLCHECK:
+ size = CInline_EstimateSizeOfExpr(expr->data.nullcheck.nullcheckexpr, size, level);
+ if (size <= inline_max_size)
+ size = CInline_EstimateSizeOfExpr(expr->data.nullcheck.condexpr, size, level) + 1;
+ break;
+
+ case EMFPOINTER:
+ size = CInline_EstimateSizeOfExpr(expr->data.mfpointer.accessnode, size, level);
+ if (size <= inline_max_size)
+ size = CInline_EstimateSizeOfExpr(expr->data.mfpointer.mfpointer, size, level) + 1;
+ break;
+
+ case EMEMBER:
+ if (expr->data.emember->expr)
+ size = CInline_EstimateSizeOfExpr(expr->data.emember->expr, size, level) + 1;
+ break;
+
+ default:
+ size++;
+ }
+
+ return size;
+}
+
+static SInt32 CInline_EstimateSizeOfFunc(CI_FuncData *funcdata, SInt32 size, SInt32 level) {
+ CI_Statement *stmt;
+ SInt32 i;
+
+ size += funcdata->numstatements;
+ if (size > inline_max_size)
+ return size;
+
+ for (i = 0, stmt = funcdata->statements; i < funcdata->numstatements; i++, stmt++) {
+ switch (stmt->type) {
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_GOTO:
+ case ST_ASM:
+ break;
+ case ST_EXPRESSION:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_GOTOEXPR:
+ size = CInline_EstimateSizeOfExpr(stmt->u.expr, size, level);
+ break;
+ case ST_SWITCH:
+ size = CInline_EstimateSizeOfExpr(stmt->u.switchdata->expr, size, level);
+ break;
+ case ST_RETURN:
+ if (stmt->u.expr)
+ size = CInline_EstimateSizeOfExpr(stmt->u.expr, size, level);
+ break;
+ default:
+ CError_FATAL(1840);
+ }
+
+ if (size > inline_max_size)
+ break;
+ }
+
+ return size;
+}
+
+static SInt32 EstimateExpandedSizeOfExpr(ENode *expr, SInt32 level) {
+ ENodeList *list;
+ SInt32 size;
+
+ size = 0;
+
+ switch (expr->type) {
+ ENODE_CASE_MONADIC:
+ size = EstimateExpandedSizeOfExpr(expr->data.monadic, level) + 1;
+ break;
+
+ ENODE_CASE_DIADIC_ALL:
+ size = EstimateExpandedSizeOfExpr(expr->data.diadic.left, level) + 1;
+ size += EstimateExpandedSizeOfExpr(expr->data.diadic.right, level);
+ break;
+
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ if (
+ ENODE_IS(expr->data.funccall.funcref, EOBJREF) &&
+ expr->data.funccall.funcref->data.objref->u.func.u.ifuncdata &&
+ CInline_CanExpand(expr->data.funccall.funcref)
+ )
+ {
+ if (level) {
+ SInt32 est = CInline_EstimateSizeOfFunc(expr->data.funccall.funcref->data.objref->u.func.u.ifuncdata, size, level - 1);
+ if (est > inline_max_size)
+ size++;
+ else
+ size += est;
+ } else {
+ size++;
+ }
+ } else {
+ size++;
+ }
+
+ for (list = expr->data.funccall.args; list; list = list->next)
+ size += EstimateExpandedSizeOfExpr(list->node, level);
+ break;
+
+ case ECOND:
+ size = EstimateExpandedSizeOfExpr(expr->data.cond.cond, level) + 1;
+ size += EstimateExpandedSizeOfExpr(expr->data.cond.expr1, level);
+ size += EstimateExpandedSizeOfExpr(expr->data.cond.expr2, level);
+ break;
+
+ case ENULLCHECK:
+ size = EstimateExpandedSizeOfExpr(expr->data.nullcheck.nullcheckexpr, level) + 1;
+ size += EstimateExpandedSizeOfExpr(expr->data.nullcheck.condexpr, level);
+ break;
+
+ case EMFPOINTER:
+ size = EstimateExpandedSizeOfExpr(expr->data.mfpointer.accessnode, level) + 1;
+ size += EstimateExpandedSizeOfExpr(expr->data.mfpointer.mfpointer, level);
+ break;
+
+ case EMEMBER:
+ if (expr->data.emember->expr)
+ size = EstimateExpandedSizeOfExpr(expr->data.emember->expr, level);
+ break;
+
+ default:
+ size++;
+ }
+
+ return size;
+}
+
+static SInt32 EstimateExpandedSizeOfFunction(Statement *stmt) {
+ SInt32 size;
+ SInt32 level;
+
+ level = copts.inlinelevel;
+ if (!level)
+ level = 8;
+
+ size = 0;
+
+ while (stmt) {
+ switch (stmt->type) {
+ case ST_NOP:
+ break;
+ case ST_EXPRESSION:
+ case ST_SWITCH:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_GOTOEXPR:
+ size++;
+ size += EstimateExpandedSizeOfExpr(stmt->expr, level);
+ break;
+ case ST_RETURN:
+ size++;
+ if (stmt->expr)
+ size = EstimateExpandedSizeOfExpr(stmt->expr, level);
+ break;
+ case ST_LABEL:
+ case ST_GOTO:
+ case ST_ASM:
+ size++;
+ break;
+ default:
+ CError_FATAL(2015);
+ }
+
+ stmt = stmt->next;
+ }
+
+ return size;
+}
+
+static Boolean CInline_InlineFunctionCheck(ENode *expr) {
+ Object *object;
+ SInt32 level;
+ CI_FuncData *funcdata;
+
+ object = expr->data.objref;
+ if (object->datatype == DALIAS)
+ object = object->u.alias.object;
+
+ if (
+ IS_TYPE_FUNC(object->type) &&
+ ((object->qual & Q_INLINE) || (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_800)) &&
+ (object->datatype == DFUNC || (object->datatype == DVFUNC && (expr->flags & ENODE_FLAG_80)))
+ )
+ {
+ if (copts.alwaysinline)
+ return 1;
+
+ if (copts.inline_bottom_up) {
+ if (!object->u.func.u.ifuncdata)
+ return 0;
+
+ level = (copts.inlinelevel == 0) ? (7 - cinline_level) : (copts.inlinelevel - cinline_level - 1);
+ if ((object->qual & Q_INLINE) && level == 0)
+ return 1;
+
+ if (CInline_EstimateSizeOfFunc(object->u.func.u.ifuncdata, 0, level) > inline_max_size)
+ return 0;
+ } else if (cinline_level > 0 && copts.inlinelevel == 0) {
+ funcdata = object->u.func.u.ifuncdata;
+ if (!funcdata)
+ return 0;
+
+ if (funcdata->numstatements > 10)
+ return 0;
+ if (cinline_level > 1 && funcdata->numstatements > 7)
+ return 0;
+ if (cinline_level > 2 && funcdata->numstatements > 3)
+ return 0;
+ }
+
+ return 1;
+ } else {
+ return 0;
+ }
+
+ return 0;
+}
+
+static ENode *CInline_ExpandExpression(ENode *expr) {
+ ENodeList *list;
+ Boolean save;
+
+ switch (expr->type) {
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EINDIRECT:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case ETYPCON:
+ case EBITFIELD:
+ expr->data.monadic = CInline_ExpandExpression(expr->data.monadic);
+ break;
+
+ case EFORCELOAD:
+ expr->data.monadic = CInline_ExpandExpression(expr->data.monadic);
+ if (ENODE_IS(expr->data.monadic, EFORCELOAD))
+ expr->data.monadic = expr->data.monadic->data.monadic;
+ break;
+
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ 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 EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case EPMODULO:
+ case EROTL:
+ case EROTR:
+ expr->data.diadic.left = CInline_ExpandExpression(expr->data.diadic.left);
+ expr->data.diadic.right = CInline_ExpandExpression(expr->data.diadic.right);
+ break;
+
+ case ELAND:
+ case ELOR:
+ case ECOMMA:
+ expr->data.diadic.left = CInline_ExpandExpression(expr->data.diadic.left);
+ save = cinline_unconditionalpart;
+ cinline_unconditionalpart = 0;
+ expr->data.diadic.right = CInline_ExpandExpression(expr->data.diadic.right);
+ cinline_unconditionalpart = save;
+ break;
+
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ expr->data.funccall.funcref = CInline_ExpandExpression(expr->data.funccall.funcref);
+ for (list = expr->data.funccall.args; list; list = list->next)
+ list->node = CInline_ExpandExpression(list->node);
+
+ if (ENODE_IS(expr->data.funccall.funcref, EOBJREF) && CInline_InlineFunctionCheck(expr->data.funccall.funcref))
+ expr = CInline_InlineFunctionExpression(expr);
+ break;
+
+ case ENULLCHECK:
+ expr->data.nullcheck.nullcheckexpr = CInline_ExpandExpression(expr->data.nullcheck.nullcheckexpr);
+ save = cinline_unconditionalpart;
+ cinline_unconditionalpart = 0;
+ expr->data.nullcheck.condexpr = CInline_ExpandExpression(expr->data.nullcheck.condexpr);
+ cinline_unconditionalpart = save;
+ break;
+
+ case EMFPOINTER:
+ expr->data.mfpointer.accessnode = CInline_ExpandExpression(expr->data.mfpointer.accessnode);
+ expr->data.mfpointer.mfpointer = CInline_ExpandExpression(expr->data.mfpointer.mfpointer);
+ break;
+
+ case ECOND:
+ expr->data.cond.cond = CInline_ExpandExpression(expr->data.cond.cond);
+ save = cinline_unconditionalpart;
+ cinline_unconditionalpart = 0;
+ expr->data.cond.expr1 = CInline_ExpandExpression(expr->data.cond.expr1);
+ expr->data.cond.expr2 = CInline_ExpandExpression(expr->data.cond.expr2);
+ cinline_unconditionalpart = save;
+ break;
+
+ case EMEMBER:
+ if (expr->data.emember->expr)
+ expr = CInline_ExpandExpression(expr->data.emember->expr);
+ else
+ expr = nullnode();
+ break;
+
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EPRECOMP:
+ case ELABEL:
+ case EOBJLIST:
+ case EINSTRUCTION:
+ case EVECTOR128CONST:
+ break;
+
+ default:
+ CError_FATAL(2235);
+ }
+
+ return expr;
+}
+
+static Statement *CInline_NewStatement(StatementType sttype) {
+ Statement *stmt = lalloc(sizeof(Statement));
+ memclrw(stmt, sizeof(Statement));
+
+ stmt->type = sttype;
+ if (cinline_serial_stmt)
+ cinline_cur_serial_stmt->next = stmt;
+ else
+ cinline_serial_stmt = stmt;
+ cinline_cur_serial_stmt = stmt;
+
+ return stmt;
+}
+
+static ENode *CInline_LoadToTemp(ENode *expr, Object **objectptr) {
+ Object *object;
+
+ object = *objectptr;
+ if (!object) {
+ switch (expr->rtype->type) {
+ case TYPEVOID:
+ return expr;
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPESTRUCT:
+ case TYPECLASS:
+ case TYPEMEMBERPOINTER:
+ case TYPEPOINTER:
+ object = create_temp_object(expr->rtype);
+ *objectptr = object;
+ break;
+ default:
+ CError_FATAL(2288);
+ }
+ }
+
+ return makediadicnode(create_objectnode(object), expr, EASS);
+}
+
+static ENode *CInline_SerializeEFORCELOAD(ENode *expr) {
+ Statement *stmt;
+ Object *temp = NULL;
+
+ while (ENODE_IS(expr->data.monadic, EFORCELOAD)) {
+ expr->data.monadic = expr->data.monadic->data.monadic;
+ }
+
+ expr->data.monadic = CInline_SerializeExpr(expr->data.monadic);
+ stmt = CInline_NewStatement(ST_EXPRESSION);
+ stmt->expr = CInline_LoadToTemp(expr->data.monadic, &temp);
+ return create_objectnode(temp);
+}
+
+static ENode *CInline_SerializeECOMMA(ENode *expr) {
+ Statement *stmt;
+
+ expr->data.diadic.left = CInline_SerializeExpr(expr->data.diadic.left);
+ stmt = CInline_NewStatement(ST_EXPRESSION);
+ stmt->expr = expr->data.diadic.left;
+ return CInline_SerializeExpr(expr->data.diadic.right);
+}
+
+static ENode *CInline_SerializeELOR(ENode *expr) {
+ ENode *n;
+ Statement *stmt;
+ CLabel *label;
+ Object *temp = NULL;
+
+ label = newlabel();
+
+ n = makemonadicnode(CInline_SerializeExpr(expr->data.diadic.left), ELOGNOT);
+ n->rtype = expr->rtype;
+ n = makemonadicnode(n, ELOGNOT);
+ n = CInline_LoadToTemp(n, &temp);
+ stmt = CInline_NewStatement(ST_IFGOTO);
+ stmt->expr = n;
+ stmt->label = label;
+
+ n = makemonadicnode(CInline_SerializeExpr(expr->data.diadic.right), ELOGNOT);
+ n->rtype = expr->rtype;
+ n = makemonadicnode(n, ELOGNOT);
+ n = CInline_LoadToTemp(n, &temp);
+ stmt = CInline_NewStatement(ST_EXPRESSION);
+ stmt->expr = n;
+
+ stmt = CInline_NewStatement(ST_LABEL);
+ stmt->label = label;
+ label->stmt = stmt;
+
+ return create_objectnode(temp);
+}
+
+static ENode *CInline_SerializeELAND(ENode *expr) {
+ ENode *n;
+ Statement *stmt;
+ CLabel *label;
+ Object *temp = NULL;
+
+ label = newlabel();
+
+ n = makemonadicnode(CInline_SerializeExpr(expr->data.diadic.left), ELOGNOT);
+ n->rtype = expr->rtype;
+ n = makemonadicnode(n, ELOGNOT);
+ n = CInline_LoadToTemp(n, &temp);
+ stmt = CInline_NewStatement(ST_IFNGOTO);
+ stmt->expr = n;
+ stmt->label = label;
+
+ n = makemonadicnode(CInline_SerializeExpr(expr->data.diadic.right), ELOGNOT);
+ n->rtype = expr->rtype;
+ n = makemonadicnode(n, ELOGNOT);
+ n = CInline_LoadToTemp(n, &temp);
+ stmt = CInline_NewStatement(ST_EXPRESSION);
+ stmt->expr = n;
+
+ stmt = CInline_NewStatement(ST_LABEL);
+ stmt->label = label;
+ label->stmt = stmt;
+
+ return create_objectnode(temp);
+}
+
+static ENode *CInline_SerializeEPRECOMP(ENode *expr) {
+ UIDTemp *uidtemp;
+
+ uidtemp = cinline_uid_temps;
+ while (1) {
+ if (!uidtemp)
+ CError_FATAL(2449);
+ if (uidtemp->uid == expr->data.precompid)
+ return create_objectnode(uidtemp->object);
+ uidtemp = uidtemp->next;
+ }
+}
+
+static ENode *CInline_SerializeENULLCHECK(ENode *expr) {
+ Statement *stmt;
+ CLabel *label;
+ ENode *n;
+ Object *temp = NULL;
+ UIDTemp uidtemp;
+
+ label = newlabel();
+
+ n = CInline_SerializeExpr(expr->data.nullcheck.nullcheckexpr);
+ stmt = CInline_NewStatement(ST_IFNGOTO);
+ stmt->expr = CInline_LoadToTemp(n, &temp);
+ stmt->label = label;
+
+ uidtemp.next = cinline_uid_temps;
+ uidtemp.object = temp;
+ uidtemp.uid = expr->data.nullcheck.precompid;
+ cinline_uid_temps = &uidtemp;
+
+ n = CInline_SerializeExpr(expr->data.nullcheck.condexpr);
+ stmt = CInline_NewStatement(ST_EXPRESSION);
+ stmt->expr = CInline_LoadToTemp(n, &temp);
+
+ cinline_uid_temps = uidtemp.next;
+
+ stmt = CInline_NewStatement(ST_LABEL);
+ stmt->label = label;
+ label->stmt = stmt;
+
+ return create_objectnode(temp);
+}
+
+static ENode *CInline_SerializeECOND(ENode *expr) {
+ Statement *stmt;
+ CLabel *label1;
+ CLabel *label2;
+ ENode *n;
+ Object *temp = NULL;
+
+ label1 = newlabel();
+ label2 = newlabel();
+
+ n = CInline_SerializeExpr(expr->data.cond.cond);
+ stmt = CInline_NewStatement(ST_IFNGOTO);
+ stmt->expr = n;
+ stmt->label = label1;
+
+ n = CInline_SerializeExpr(expr->data.cond.expr1);
+ n = CInline_LoadToTemp(n, &temp);
+ stmt = CInline_NewStatement(ST_EXPRESSION);
+ stmt->expr = n;
+
+ stmt = CInline_NewStatement(ST_GOTO);
+ stmt->label = label2;
+
+ stmt = CInline_NewStatement(ST_LABEL);
+ stmt->label = label1;
+ label1->stmt = stmt;
+
+ n = CInline_SerializeExpr(expr->data.cond.expr2);
+ n = CInline_LoadToTemp(n, &temp);
+ stmt = CInline_NewStatement(ST_EXPRESSION);
+ stmt->expr = n;
+
+ stmt = CInline_NewStatement(ST_LABEL);
+ stmt->label = label2;
+ label2->stmt = stmt;
+
+ if (!temp) {
+ n = nullnode();
+ n->rtype = &stvoid;
+ return n;
+ }
+
+ return create_objectnode(temp);
+}
+
+static ENode *CInline_SerializeExpr(ENode *expr) {
+ ENodeList *list;
+
+ switch (expr->type) {
+ case EFORCELOAD:
+ return CInline_SerializeEFORCELOAD(expr);
+ case ECOMMA:
+ return CInline_SerializeECOMMA(expr);
+ case ELAND:
+ return CInline_SerializeELAND(expr);
+ case ELOR:
+ return CInline_SerializeELOR(expr);
+ case EPRECOMP:
+ return CInline_SerializeEPRECOMP(expr);
+ case ENULLCHECK:
+ return CInline_SerializeENULLCHECK(expr);
+ case ECOND:
+ return CInline_SerializeECOND(expr);
+
+ case EINITTRYCATCH:
+ expr->data.itc.initexpr = CInline_SerializeExpr(expr->data.itc.initexpr);
+ expr->data.itc.tryexpr = CInline_SerializeExpr(expr->data.itc.tryexpr);
+ expr->data.itc.catchexpr = CInline_SerializeExpr(expr->data.itc.catchexpr);
+ expr->data.itc.result = CInline_SerializeExpr(expr->data.itc.result);
+ return expr;
+
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EINDIRECT:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case ETYPCON:
+ case EBITFIELD:
+ expr->data.monadic = CInline_SerializeExpr(expr->data.monadic);
+ return expr;
+
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ 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 EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case EPMODULO:
+ case EROTL:
+ case EROTR:
+ expr->data.diadic.left = CInline_SerializeExpr(expr->data.diadic.left);
+ expr->data.diadic.right = CInline_SerializeExpr(expr->data.diadic.right);
+ return expr;
+
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case ELABEL:
+ case EOBJLIST:
+ case EINSTRUCTION:
+ case EVECTOR128CONST:
+ return expr;
+
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ expr->data.funccall.funcref = CInline_SerializeExpr(expr->data.funccall.funcref);
+ for (list = expr->data.funccall.args; list; list = list->next)
+ list->node = CInline_SerializeExpr(list->node);
+ return expr;
+
+ case EMFPOINTER:
+ // bug???
+ expr->data.mfpointer.accessnode = CInline_SerializeExpr(expr->data.mfpointer.accessnode);
+ expr->data.mfpointer.accessnode = CInline_SerializeExpr(expr->data.mfpointer.mfpointer);
+ return expr;
+
+ case EMEMBER:
+ if (expr->data.emember->expr)
+ return CInline_SerializeExpr(expr->data.emember->expr);
+ return expr;
+
+ default:
+ CError_FATAL(2684);
+ return expr;
+ }
+}
+
+void CInline_SerializeStatement(Statement *stmt) {
+ Statement *scan;
+ Statement *copy;
+
+ cinline_serial_stmt = NULL;
+ cinline_uid_temps = NULL;
+ stmt->expr = CInline_SerializeExpr(stmt->expr);
+
+ if (cinline_serial_stmt) {
+ for (scan = cinline_serial_stmt; scan; scan = scan->next) {
+ scan->value = stmt->value;
+ scan->dobjstack = stmt->dobjstack;
+ scan->sourceoffset = stmt->sourceoffset;
+ scan->sourcefilepath = stmt->sourcefilepath;
+ }
+
+ copy = CInline_NewStatement(ST_EXPRESSION);
+ *copy = *stmt;
+
+ *stmt = *cinline_serial_stmt;
+ }
+}
+
+static void CInline_UnpackSwitch(Statement *stmt, CI_Statement *packstmt, CLabel **labels) {
+ SwitchInfo *info;
+ SwitchCase *swcase;
+ short i;
+
+ info = lalloc(sizeof(SwitchInfo));
+ stmt->label = (CLabel *) info;
+ CError_ASSERT(2730, info->defaultlabel = labels[packstmt->u.switchdata->defaultlabelID]);
+ info->x8 = packstmt->u.switchdata->unkSwitch8;
+
+ for (i = 0; i < packstmt->u.switchdata->numcases; i++) {
+ if (i == 0) {
+ swcase = lalloc(sizeof(SwitchCase));
+ info->cases = swcase;
+ } else {
+ swcase->next = lalloc(sizeof(SwitchCase));
+ swcase = swcase->next;
+ }
+
+ swcase->next = NULL;
+ swcase->min = packstmt->u.switchdata->cases[i].min;
+ swcase->max = packstmt->u.switchdata->cases[i].max;
+ CError_ASSERT(2740, swcase->label = labels[packstmt->u.switchdata->cases[i].labelID]);
+ }
+}
+
+Object *CInline_GetLocalObj(SInt32 id, Boolean flag) {
+ ObjectList *list;
+
+ if (id) {
+ if (id & 0x80000000) {
+ id = (id & 0x7FFFFFFF) - 1;
+ if (flag) {
+ CError_ASSERT(2761, local_aobjects[id].object);
+ return local_aobjects[id].object;
+ }
+
+ for (list = arguments; list; list = list->next, id--) {
+ if (id == 0)
+ return list->object;
+ }
+
+ CError_FATAL(2765);
+ } else {
+ id--;
+ if (flag) {
+ CError_ASSERT(2772, local_dobjects[id]);
+ return local_dobjects[id];
+ }
+
+ for (list = locals; list; list = list->next, id--) {
+ if (id == 0)
+ return list->object;
+ }
+
+ CError_FATAL(2776);
+ }
+ }
+
+ return NULL;
+}
+
+static ExceptionAction *CInline_UnpackActions(CI_Statement *packstmt, Boolean flag) {
+ ExceptionAction *packexc;
+ ExceptionAction *last;
+ ExceptionAction *exc;
+
+ packexc = packstmt->dobjstack;
+ last = NULL;
+
+ while (packexc) {
+ exc = galloc(sizeof(ExceptionAction));
+ exc->prev = last;
+ last = exc;
+
+ exc->type = packexc->type;
+
+ switch (packexc->type) {
+ case EAT_DESTROYLOCAL:
+ exc->data.destroy_local.local = CInline_GetLocalObj((SInt32) packexc->data.destroy_local.local, flag);
+ exc->data.destroy_local.dtor = packexc->data.destroy_local.dtor;
+ break;
+ case EAT_DESTROYLOCALCOND:
+ exc->data.destroy_local_cond.local = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_cond.local, flag);
+ exc->data.destroy_local_cond.dtor = packexc->data.destroy_local_cond.dtor;
+ exc->data.destroy_local_cond.cond = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_cond.cond, flag);
+ break;
+ case EAT_DESTROYLOCALOFFSET:
+ exc->data.destroy_local_offset.local = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_offset.local, flag);
+ exc->data.destroy_local_offset.dtor = packexc->data.destroy_local_offset.dtor;
+ exc->data.destroy_local_offset.offset = packexc->data.destroy_local_offset.offset;
+ break;
+ case EAT_DESTROYLOCALPOINTER:
+ exc->data.destroy_local_pointer.pointer = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_pointer.pointer, flag);
+ exc->data.destroy_local_pointer.dtor = packexc->data.destroy_local_pointer.dtor;
+ break;
+ case EAT_DESTROYLOCALARRAY:
+ exc->data.destroy_local_array.localarray = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_array.localarray, flag);
+ exc->data.destroy_local_array.dtor = packexc->data.destroy_local_array.dtor;
+ exc->data.destroy_local_array.elements = packexc->data.destroy_local_array.elements;
+ exc->data.destroy_local_array.element_size = packexc->data.destroy_local_array.element_size;
+ break;
+ case EAT_DESTROYPARTIALARRAY:
+ exc->data.destroy_partial_array.arraypointer = CInline_GetLocalObj((SInt32) packexc->data.destroy_partial_array.arraypointer, flag);
+ exc->data.destroy_partial_array.arraycounter = CInline_GetLocalObj((SInt32) packexc->data.destroy_partial_array.arraycounter, flag);
+ exc->data.destroy_partial_array.dtor = CInline_GetLocalObj((SInt32) packexc->data.destroy_partial_array.dtor, flag);
+ exc->data.destroy_partial_array.element_size = CInline_GetLocalObj((SInt32) packexc->data.destroy_partial_array.element_size, flag);
+ break;
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYBASE:
+ exc->data.destroy_member.objectptr = CInline_GetLocalObj((SInt32) packexc->data.destroy_member.objectptr, flag);
+ exc->data.destroy_member.dtor = packexc->data.destroy_member.dtor;
+ exc->data.destroy_member.offset = packexc->data.destroy_member.offset;
+ break;
+ case EAT_DESTROYMEMBERCOND:
+ exc->data.destroy_member_cond.objectptr = CInline_GetLocalObj((SInt32) packexc->data.destroy_member_cond.objectptr, flag);
+ exc->data.destroy_member_cond.cond = CInline_GetLocalObj((SInt32) packexc->data.destroy_member_cond.cond, flag);
+ exc->data.destroy_member_cond.dtor = packexc->data.destroy_member_cond.dtor;
+ exc->data.destroy_member_cond.offset = packexc->data.destroy_member_cond.offset;
+ break;
+ case EAT_DESTROYMEMBERARRAY:
+ exc->data.destroy_member_array.objectptr = CInline_GetLocalObj((SInt32) packexc->data.destroy_member_array.objectptr, flag);
+ exc->data.destroy_member_array.dtor = packexc->data.destroy_member_array.dtor;
+ exc->data.destroy_member_array.offset = packexc->data.destroy_member_array.offset;
+ exc->data.destroy_member_array.elements = packexc->data.destroy_member_array.elements;
+ exc->data.destroy_member_array.element_size = packexc->data.destroy_member_array.element_size;
+ break;
+ case EAT_DELETEPOINTER:
+ case EAT_DELETELOCALPOINTER:
+ exc->data.delete_pointer.pointerobject = CInline_GetLocalObj((SInt32) packexc->data.delete_pointer.pointerobject, flag);
+ exc->data.delete_pointer.deletefunc = packexc->data.delete_pointer.deletefunc;
+ break;
+ case EAT_DELETEPOINTERCOND:
+ exc->data.delete_pointer_cond.pointerobject = CInline_GetLocalObj((SInt32) packexc->data.delete_pointer_cond.pointerobject, flag);
+ exc->data.delete_pointer_cond.deletefunc = packexc->data.delete_pointer_cond.deletefunc;
+ exc->data.delete_pointer_cond.cond = CInline_GetLocalObj((SInt32) packexc->data.delete_pointer_cond.cond, flag);
+ break;
+ case EAT_CATCHBLOCK: {
+ LabelTrans *trans;
+ exc->data.catch_block.catch_object = CInline_GetLocalObj((SInt32) packexc->data.catch_block.catch_object, flag);
+ exc->data.catch_block.catch_info_object = CInline_GetLocalObj((SInt32) packexc->data.catch_block.catch_info_object, flag);
+
+ trans = lalloc(sizeof(LabelTrans));
+ trans->next = cinline_label_trans;
+ cinline_label_trans = trans;
+
+ trans->id = (SInt32) packexc->data.catch_block.catch_label;
+ trans->labelptr = &exc->data.catch_block.catch_label;
+
+ exc->data.catch_block.catch_typeid = packexc->data.catch_block.catch_typeid;
+ exc->data.catch_block.catch_type = packexc->data.catch_block.catch_type;
+ exc->data.catch_block.catch_qual = packexc->data.catch_block.catch_qual;
+ break;
+ }
+ case EAT_ACTIVECATCHBLOCK:
+ exc->data.active_catch_block.catch_info_object = CInline_GetLocalObj((SInt32) packexc->data.active_catch_block.catch_info_object, flag);
+ break;
+ case EAT_SPECIFICATION: {
+ LabelTrans *trans;
+ exc->data.specification.unexp_ids = packexc->data.specification.unexp_ids;
+ exc->data.specification.unexp_id = packexc->data.specification.unexp_id;
+
+ trans = lalloc(sizeof(LabelTrans));
+ trans->next = cinline_label_trans;
+ cinline_label_trans = trans;
+
+ trans->id = (SInt32) packexc->data.specification.unexp_label;
+ trans->labelptr = &exc->data.specification.unexp_label;
+
+ exc->data.specification.unexp_info_object = CInline_GetLocalObj((SInt32) packexc->data.specification.unexp_info_object, flag);
+ break;
+ }
+ case EAT_TERMINATE:
+ break;
+ default:
+ CError_FATAL(2904);
+ }
+
+ packexc = packexc->prev;
+ }
+
+ return last;
+}
+
+static Statement *CInline_ExpandStatements(Object *funcobj, Statement *stmt, CI_FuncData *funcdata, ENode *funccall, CLabel *label, Object *resultobj, Boolean flag) {
+ CLabel **labels;
+ CI_Statement *packstmt;
+ short i;
+ CI_StmtLink *stmtLinks;
+ CI_StmtLink *link;
+ ENode *setupArgs;
+ Boolean is_result_class_1;
+ Statement origStmt;
+
+ origStmt = *stmt;
+ is_result_class_1 = CMach_GetFunctionResultClass(TYPE_FUNC(funcobj->type)) == 1;
+
+ if ((setupArgs = CInline_SetupArgsExpression(funcobj, funcdata, funccall->data.funccall.args))) {
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = CInline_FoldConst(setupArgs);
+ } else {
+ stmt->type = ST_NOP;
+ }
+
+ stmtLinks = NULL;
+ cinline_label_trans = NULL;
+
+ labels = lalloc(sizeof(CLabel *) * funcdata->numstatements);
+ memclrw(labels, sizeof(CLabel *) * funcdata->numstatements);
+
+ for (i = 0, packstmt = funcdata->statements; i < funcdata->numstatements; i++, packstmt++) {
+ stmt->next = lalloc(sizeof(Statement));
+ stmt = stmt->next;
+ *stmt = origStmt;
+
+ stmt->type = packstmt->type;
+ stmt->flags = packstmt->flags;
+ stmt->value += packstmt->value;
+
+ if (packstmt->dobjstack) {
+ ExceptionAction *unpacked = CInline_UnpackActions(packstmt, 1);
+ if (stmt->dobjstack) {
+ ExceptionAction *scan = unpacked;
+ while (scan->prev)
+ scan = scan->prev;
+ scan->prev = stmt->dobjstack;
+ }
+ stmt->dobjstack = unpacked;
+ }
+
+ switch (stmt->type) {
+ case ST_NOP:
+ break;
+
+ case ST_EXPRESSION:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_GOTOEXPR:
+ stmt->expr = CInline_FoldConst(CInline_CopyExpression(packstmt->u.expr, CopyMode4));
+ break;
+
+ case ST_RETURN:
+ if (packstmt->u.expr) {
+ stmt->expr = CInline_FoldConst(CInline_CopyExpression(packstmt->u.expr, CopyMode4));
+ if (is_result_class_1)
+ stmt->expr = makecommaexpression(stmt->expr, CInline_ReturnMemResult(funcobj));
+
+ if (resultobj) {
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = makediadicnode(create_objectnode2(resultobj), stmt->expr, EASS);
+ } else {
+ stmt->type = origStmt.type;
+ if (stmt->type == ST_EXPRESSION && !CInline_ExpressionHasSideEffect(stmt->expr))
+ stmt->type = ST_NOP;
+ }
+
+ if (label) {
+ stmt->next = lalloc(sizeof(Statement));
+ stmt = stmt->next;
+ *stmt = origStmt;
+ stmt->type = ST_GOTO;
+ stmt->label = label;
+ }
+ } else {
+ if (label) {
+ stmt->type = ST_GOTO;
+ stmt->label = label;
+ } else {
+ stmt->type = ST_NOP;
+ }
+ }
+ break;
+
+ case ST_LABEL:
+ labels[i] = stmt->label = newlabel();
+ stmt->label->stmt = stmt;
+ break;
+
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ stmt->expr = CInline_FoldConst(CInline_CopyExpression(packstmt->u.ifgoto.expr, CopyMode4));
+ case ST_GOTO:
+ link = lalloc(sizeof(CI_StmtLink));
+ link->next = stmtLinks;
+ stmtLinks = link;
+
+ link->stmt = stmt;
+ link->ciStmt = packstmt;
+ break;
+
+ case ST_SWITCH:
+ stmt->expr = CInline_FoldConst(CInline_CopyExpression(packstmt->u.switchdata->expr, CopyMode4));
+ case ST_ASM:
+ link = lalloc(sizeof(CI_StmtLink));
+ link->next = stmtLinks;
+ stmtLinks = link;
+
+ link->stmt = stmt;
+ link->ciStmt = packstmt;
+ break;
+
+ default:
+ CError_FATAL(3040);
+ }
+ }
+
+ if (label) {
+ stmt->next = lalloc(sizeof(Statement));
+ stmt = stmt->next;
+ *stmt = origStmt;
+
+ stmt->type = ST_LABEL;
+ stmt->label = label;
+ label->stmt = stmt;
+
+ if (flag) {
+ stmt->next = lalloc(sizeof(Statement));
+ stmt = stmt->next;
+ *stmt = origStmt;
+ }
+ }
+
+ while (stmtLinks) {
+ Statement *linkstmt = stmtLinks->stmt;
+ packstmt = stmtLinks->ciStmt;
+
+ switch (linkstmt->type) {
+ case ST_GOTO:
+ CError_ASSERT(3060, linkstmt->label = labels[packstmt->u.statementnum]);
+ break;
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ CError_ASSERT(3065, linkstmt->label = labels[packstmt->u.ifgoto.statementnum]);
+ break;
+ case ST_SWITCH:
+ CInline_UnpackSwitch(linkstmt, packstmt, labels);
+ break;
+ case ST_ASM:
+ InlineAsm_UnpackAsmStatement(linkstmt, labels, 1, packstmt->u.asmdata.data, packstmt->u.asmdata.size);
+ break;
+ default:
+ CError_FATAL(3076);
+ }
+
+ stmtLinks = stmtLinks->next;
+ }
+
+ while (cinline_label_trans) {
+ CError_ASSERT(3083, *cinline_label_trans->labelptr = labels[cinline_label_trans->id]);
+ cinline_label_trans = cinline_label_trans->next;
+ }
+
+ return stmt;
+}
+
+static Statement *CInline_InlineFunctionStatement(Statement *stmt, Boolean *changed) {
+ Object *object;
+ CI_FuncData *funcdata;
+ CLabel *label;
+
+ *changed = 0;
+
+ object = stmt->expr->data.funccall.funcref->data.objref;
+ if (object->datatype == DALIAS)
+ object = object->u.alias.object;
+
+ funcdata = object->u.func.u.ifuncdata;
+ if (!funcdata || funcdata->can_inline < CI_CanInline3)
+ return stmt;
+
+ if (stmt->type != ST_EXPRESSION) {
+ short i;
+ for (i = 0; i < (funcdata->numstatements - 1); i++) {
+ if (funcdata->statements[i].type == ST_RETURN)
+ return stmt;
+ }
+
+ if (funcdata->statements[funcdata->numstatements - 1].type != ST_RETURN)
+ return stmt;
+
+ label = NULL;
+ } else {
+ label = newlabel();
+ }
+
+ *changed = 1;
+ return CInline_ExpandStatements(object, stmt, funcdata, stmt->expr, label, NULL, 0);
+}
+
+static Statement *CInline_ExtractInlineFunction(Statement *stmt) {
+ ENode *expr;
+ CI_FuncData *funcdata;
+ short i;
+ Object *funcObject;
+ Object *resultObject;
+
+ for (i = 0; i < cinline_stmtlevelexprs; i++) {
+ expr = cinline_stmtlevelexpr[i];
+
+ funcObject = expr->data.funccall.funcref->data.objref;
+ if (funcObject->datatype == DALIAS)
+ funcObject = funcObject->u.alias.object;
+
+ if ((funcdata = funcObject->u.func.u.ifuncdata)) {
+ TypeFunc *tfunc = TYPE_FUNC(funcObject->type);
+ CError_ASSERT(3141, IS_TYPE_FUNC(tfunc));
+
+ if (!IS_TYPE_VOID(tfunc->functype)) {
+ if (CMach_GetFunctionResultClass(TYPE_FUNC(funcObject->type)) == 1)
+ resultObject = CInline_NewLocalObject(CDecl_NewPointerType(tfunc->functype), 0, 0, 0);
+ else
+ resultObject = CInline_NewLocalObject(tfunc->functype, 0, 0, 0);
+ } else {
+ resultObject = NULL;
+ }
+
+ stmt = CInline_ExpandStatements(funcObject, stmt, funcdata, expr, newlabel(), resultObject, 1);
+
+ if (resultObject)
+ *expr = *create_objectnode2(resultObject);
+ else
+ *expr = *nullnode();
+ }
+ }
+
+ return stmt;
+}
+
+static Statement *CInline_ExpandStatement(Statement *stmt) {
+ Boolean changed;
+
+ do {
+ changed = 0;
+
+ if (
+ stmt->type == ST_EXPRESSION &&
+ ENODE_IS(stmt->expr, EINDIRECT) &&
+ !CParser_IsVolatile(stmt->expr->rtype, ENODE_QUALS(stmt->expr))
+ )
+ {
+ stmt->expr = stmt->expr->data.monadic;
+ changed = 1;
+ if (ENODE_IS2(stmt->expr, EOBJREF, EBITFIELD))
+ stmt->expr = nullnode();
+ }
+
+ if (ENODE_IS(stmt->expr, ECOMMA)) {
+ Statement *newStmt = lalloc(sizeof(Statement));
+ *newStmt = *stmt;
+
+ stmt->next = newStmt;
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = stmt->expr->data.diadic.left;
+ newStmt->expr = newStmt->expr->data.diadic.right;
+
+ changed = 1;
+ }
+ } while (changed);
+
+ if (
+ ENODE_IS2(stmt->expr, EFUNCCALL, EFUNCCALLP) &&
+ ENODE_IS(stmt->expr->data.funccall.funcref, EOBJREF) &&
+ CInline_InlineFunctionCheck(stmt->expr->data.funccall.funcref)
+ )
+ {
+ stmt = CInline_InlineFunctionStatement(stmt, &changed);
+ if (changed) {
+ any_inline_expanded = 1;
+ return stmt;
+ }
+ }
+
+ inline_expanded = 0;
+ cinline_unconditionalpart = 1;
+ cinline_serialize_stmt = 0;
+ cinline_stmtlevelexprs = 0;
+ stmt->expr = CInline_ExpandExpression(stmt->expr);
+
+ if (cinline_serialize_stmt) {
+ cinline_unconditionalpart = 1;
+ cinline_serialize_stmt = 0;
+ cinline_stmtlevelexprs = 0;
+ CInline_SerializeStatement(stmt);
+ stmt->expr = CInline_ExpandExpression(stmt->expr);
+ }
+
+ if (inline_expanded) {
+ stmt->expr = CInline_FoldConst(stmt->expr);
+ any_inline_expanded = 1;
+ }
+
+ if (cinline_stmtlevelexprs) {
+ stmt = CInline_ExtractInlineFunction(stmt);
+ any_inline_expanded = 1;
+ }
+
+ return stmt;
+}
+
+static void CInline_ForceReverseSearch(ENode *) {
+ cinline_funccallfound = 1;
+}
+
+static ENode *CInline_ForceReverseEvaluation(ENode *expr) {
+ ENode *commanodes;
+ ENodeList *list;
+ int counter;
+ ENode *ass;
+ ENode *inner;
+ ENode *copy;
+
+ list = expr->data.funccall.args;
+ counter = 0;
+ commanodes = NULL;
+
+ while (list) {
+ cinline_funccallfound = 0;
+ inner = list->node;
+ CExpr_SearchExprTree(inner, CInline_ForceReverseSearch, 2, EFUNCCALL, EFUNCCALLP);
+
+ if (cinline_funccallfound && ++counter > 0) {
+ inner = create_objectrefnode(create_temp_object(inner->rtype));
+ copy = lalloc(sizeof(ENode));
+ *copy = *inner;
+
+ copy = makemonadicnode(copy, EINDIRECT);
+ copy->rtype = TPTR_TARGET(copy->rtype);
+
+ inner = makemonadicnode(inner, EINDIRECT);
+ inner->rtype = TPTR_TARGET(inner->rtype);
+
+ ass = makediadicnode(inner, copy, EASS);
+ list->node = copy;
+
+ if (commanodes)
+ commanodes = makediadicnode(ass, commanodes, ECOMMA);
+ else
+ commanodes = ass;
+ }
+
+ list = list->next;
+ }
+
+ if (commanodes) {
+ commanodes = makediadicnode(commanodes, expr, ECOMMA);
+ commanodes->rtype = expr->rtype;
+ return commanodes;
+ }
+
+ return expr;
+}
+
+static void CInline_ExportCheck(ENode *expr) {
+ while (1) {
+ switch (expr->type) {
+ case EOBJREF:
+ CInline_ObjectAddrRef(expr->data.objref);
+ if (expr->data.objref->datatype == DALIAS) {
+ CExpr_AliasTransform(expr);
+ continue;
+ }
+ return;
+
+ ENODE_CASE_MONADIC:
+ expr = expr->data.monadic;
+ continue;
+
+ ENODE_CASE_DIADIC_ALL:
+ CInline_ExportCheck(expr->data.diadic.left);
+ expr = expr->data.diadic.right;
+ continue;
+
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EPRECOMP:
+ case EINSTRUCTION:
+ case EVECTOR128CONST:
+ return;
+
+ case ELABEL:
+ if (expr->data.label->stmt)
+ expr->data.label->stmt->flags |= StmtFlag_1;
+ return;
+
+ case EFUNCCALL:
+ case EFUNCCALLP: {
+ ENodeList *list;
+ TypeClass *tclass;
+ SInt32 index;
+
+ for (list = expr->data.funccall.args; list; list = list->next)
+ CInline_ExportCheck(list->node);
+
+ expr = expr->data.funccall.funcref;
+ if (
+ copts.warn_notinlined &&
+ !copts.dontinline &&
+ ENODE_IS(expr, EOBJREF) &&
+ (expr->data.objref->qual & Q_INLINE) &&
+ expr->data.objref->datatype != DINLINEFUNC &&
+ !CParser_IsVirtualFunction(expr->data.objref, &tclass, &index)
+ )
+ CError_Warning(CErrorStr342, expr->data.objref);
+
+ continue;
+ }
+
+ case ENULLCHECK:
+ CInline_ExportCheck(expr->data.nullcheck.nullcheckexpr);
+ expr = expr->data.nullcheck.condexpr;
+ continue;
+
+ case EMFPOINTER:
+ *expr = *nullnode();
+ continue;
+
+ case ECOND:
+ CInline_ExportCheck(expr->data.cond.cond);
+ CInline_ExportCheck(expr->data.cond.expr1);
+ expr = expr->data.cond.expr2;
+ continue;
+
+ case EMEMBER:
+ if (expr->data.emember->expr) {
+ *expr = *expr->data.emember->expr;
+ continue;
+ }
+ case EOBJLIST:
+ *expr = *nullnode();
+ continue;
+
+ default:
+ CError_FATAL(3372);
+ }
+ }
+}
+
+static void CInline_Expand(Statement *stmt) {
+ Statement *scan;
+
+ if (!copts.dontinline && copts.inlinelevel >= 0) {
+ if (copts.inline_bottom_up) {
+ inline_max_size = copts.inlinemaxsize;
+ while (inline_max_size > 1 && EstimateExpandedSizeOfFunction(stmt) > copts.inlinemaxtotalsize)
+ inline_max_size >>= 1;
+ }
+
+ cinline_level = 0;
+ while (1) {
+ any_inline_expanded = 0;
+ for (scan = stmt; scan; scan = scan->next) {
+ switch (scan->type) {
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_GOTO:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_ASM:
+ break;
+ case ST_RETURN:
+ if (!scan->expr)
+ break;
+ case ST_EXPRESSION:
+ case ST_SWITCH:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ case ST_GOTOEXPR:
+ scan = CInline_ExpandStatement(scan);
+ break;
+ default:
+ CError_FATAL(3438);
+ }
+ }
+
+ if (!copts.inline_bottom_up && !any_inline_expanded)
+ break;
+
+ if (!copts.alwaysinline || copts.inline_bottom_up) {
+ if (copts.inlinelevel == 0) {
+ if (copts.inline_bottom_up) {
+ if ((cinline_level + 1) >= 8)
+ break;
+ } else {
+ if (cinline_level >= 3)
+ break;
+ }
+ } else {
+ if ((cinline_level + 1) >= copts.inlinelevel)
+ break;
+ }
+ }
+
+ if (CWDisplayLines(cparamblkptr->context, lines) != cwNoErr)
+ CError_UserBreak();
+
+ cinline_level++;
+ }
+ }
+
+ while (stmt) {
+ if (stmt->dobjstack)
+ CExcept_CheckStackRefs(stmt->dobjstack);
+
+ switch (stmt->type) {
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_GOTO:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_ASM:
+ break;
+ case ST_RETURN:
+ if (!stmt->expr)
+ break;
+ case ST_EXPRESSION:
+ case ST_SWITCH:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ case ST_GOTOEXPR:
+ CInline_ExportCheck(stmt->expr);
+ break;
+ default:
+ CError_FATAL(3501);
+ }
+
+ stmt = stmt->next;
+ }
+}
+
+SInt16 CInline_GetStatementNumber(Statement *first, Statement *stmt) {
+ SInt16 number = 0;
+
+ while (first) {
+ if (first == stmt)
+ return number;
+
+ first = first->next;
+ number++;
+ }
+
+ CError_FATAL(3517);
+ return 0;
+}
+
+static CI_Switch *CInline_PackSwitch(Statement *start, Statement *stmt) {
+ SwitchInfo *info;
+ SwitchCase *swcase;
+ short numcases;
+ CI_Switch *packed;
+
+ info = (SwitchInfo *) stmt->label;
+ swcase = info->cases;
+ numcases = 0;
+ while (swcase) {
+ swcase = swcase->next;
+ numcases++;
+ }
+
+ packed = galloc(sizeof(CI_Switch) + numcases * sizeof(CI_SwitchCase));
+ packed->expr = CInline_CopyExpression(stmt->expr, CopyMode2);
+ packed->defaultlabelID = CInline_GetStatementNumber(start, info->defaultlabel->stmt);
+ packed->unkSwitch8 = info->x8;
+ packed->numcases = numcases;
+
+ for (swcase = info->cases, numcases = 0; swcase; swcase = swcase->next, numcases++) {
+ packed->cases[numcases].labelID = CInline_GetStatementNumber(start, swcase->label->stmt);
+ packed->cases[numcases].min = swcase->min;
+ packed->cases[numcases].max = swcase->max;
+ }
+
+ return packed;
+}
+
+static UInt8 CInline_CanInline(Object *object, Statement *stmt) {
+ UInt8 resultClass;
+ FuncArg *arg;
+ UInt8 result;
+
+ resultClass = CMach_GetFunctionResultClass(TYPE_FUNC(object->type));
+ if (
+ resultClass &&
+ (resultClass != 1 || (IS_TYPE_CLASS(TYPE_FUNC(object->type)->functype) && CClass_Destructor(TYPE_CLASS(TYPE_FUNC(object->type)->functype))))
+ )
+ return CI_CanInline0;
+
+ for (arg = TYPE_FUNC(object->type)->args; arg; arg = arg->next) {
+ if (arg == &elipsis)
+ return CI_CanInline0;
+ if (arg == &oldstyle)
+ break;
+
+ if (IS_TYPE_CLASS(arg->type) && CClass_Destructor(TYPE_CLASS(arg->type)))
+ return CI_CanInline0;
+ }
+
+ result = CI_CanInline6;
+
+ while (stmt) {
+ if (stmt->dobjstack)
+ return CI_CanInline3;
+
+ switch (stmt->type) {
+ case ST_EXPRESSION:
+ break;
+ case ST_RETURN:
+ if (stmt->next || (stmt->expr == NULL && TYPE_FUNC(object->type)->functype != &stvoid))
+ result = CI_CanInline3;
+ break;
+ default:
+ result = CI_CanInline3;
+ }
+
+ stmt = stmt->next;
+ }
+
+ return result;
+}
+
+static ExceptionAction *CInline_PackActions(Statement *start, Statement *stmt) {
+ ExceptionAction *exc;
+ ExceptionAction *last;
+ ExceptionAction *packexc;
+
+ exc = stmt->dobjstack;
+ last = NULL;
+
+ while (exc) {
+ packexc = galloc(sizeof(ExceptionAction));
+ packexc->prev = last;
+ last = packexc;
+
+ packexc->type = exc->type;
+
+ switch (exc->type) {
+ case EAT_DESTROYLOCAL:
+ packexc->data.destroy_local.local = (void *) CInline_GetLocalID(exc->data.destroy_local.local);
+ packexc->data.destroy_local.dtor = exc->data.destroy_local.dtor;
+ break;
+ case EAT_DESTROYLOCALCOND:
+ packexc->data.destroy_local_cond.local = (void *) CInline_GetLocalID(exc->data.destroy_local_cond.local);
+ packexc->data.destroy_local_cond.dtor = exc->data.destroy_local_cond.dtor;
+ packexc->data.destroy_local_cond.cond = (void *) CInline_GetLocalID(exc->data.destroy_local_cond.cond);
+ break;
+ case EAT_DESTROYLOCALOFFSET:
+ packexc->data.destroy_local_offset.local = (void *) CInline_GetLocalID(exc->data.destroy_local_offset.local);
+ packexc->data.destroy_local_offset.dtor = exc->data.destroy_local_offset.dtor;
+ packexc->data.destroy_local_offset.offset = exc->data.destroy_local_offset.offset;
+ break;
+ case EAT_DESTROYLOCALPOINTER:
+ packexc->data.destroy_local_pointer.pointer = (void *) CInline_GetLocalID(exc->data.destroy_local_pointer.pointer);
+ packexc->data.destroy_local_pointer.dtor = exc->data.destroy_local_pointer.dtor;
+ break;
+ case EAT_DESTROYLOCALARRAY:
+ packexc->data.destroy_local_array.localarray = (void *) CInline_GetLocalID(exc->data.destroy_local_array.localarray);
+ packexc->data.destroy_local_array.dtor = exc->data.destroy_local_array.dtor;
+ packexc->data.destroy_local_array.elements = exc->data.destroy_local_array.elements;
+ packexc->data.destroy_local_array.element_size = exc->data.destroy_local_array.element_size;
+ break;
+ case EAT_DESTROYPARTIALARRAY:
+ packexc->data.destroy_partial_array.arraypointer = (void *) CInline_GetLocalID(exc->data.destroy_partial_array.arraypointer);
+ packexc->data.destroy_partial_array.arraycounter = (void *) CInline_GetLocalID(exc->data.destroy_partial_array.arraycounter);
+ packexc->data.destroy_partial_array.dtor = (void *) CInline_GetLocalID(exc->data.destroy_partial_array.dtor);
+ packexc->data.destroy_partial_array.element_size = (void *) CInline_GetLocalID(exc->data.destroy_partial_array.element_size);
+ break;
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYBASE:
+ packexc->data.destroy_member.objectptr = (void *) CInline_GetLocalID(exc->data.destroy_member.objectptr);
+ packexc->data.destroy_member.dtor = exc->data.destroy_member.dtor;
+ packexc->data.destroy_member.offset = exc->data.destroy_member.offset;
+ break;
+ case EAT_DESTROYMEMBERCOND:
+ packexc->data.destroy_member_cond.objectptr = (void *) CInline_GetLocalID(exc->data.destroy_member_cond.objectptr);
+ packexc->data.destroy_member_cond.cond = (void *) CInline_GetLocalID(exc->data.destroy_member_cond.cond);
+ packexc->data.destroy_member_cond.dtor = exc->data.destroy_member_cond.dtor;
+ packexc->data.destroy_member_cond.offset = exc->data.destroy_member_cond.offset;
+ break;
+ case EAT_DESTROYMEMBERARRAY:
+ packexc->data.destroy_member_array.objectptr = (void *) CInline_GetLocalID(exc->data.destroy_member_array.objectptr);
+ packexc->data.destroy_member_array.dtor = exc->data.destroy_member_array.dtor;
+ packexc->data.destroy_member_array.offset = exc->data.destroy_member_array.offset;
+ packexc->data.destroy_member_array.elements = exc->data.destroy_member_array.elements;
+ packexc->data.destroy_member_array.element_size = exc->data.destroy_member_array.element_size;
+ break;
+ case EAT_DELETEPOINTER:
+ case EAT_DELETELOCALPOINTER:
+ packexc->data.delete_pointer.pointerobject = (void *) CInline_GetLocalID(exc->data.delete_pointer.pointerobject);
+ packexc->data.delete_pointer.deletefunc = exc->data.delete_pointer.deletefunc;
+ break;
+ case EAT_DELETEPOINTERCOND:
+ packexc->data.delete_pointer_cond.pointerobject = (void *) CInline_GetLocalID(exc->data.delete_pointer_cond.pointerobject);
+ packexc->data.delete_pointer_cond.deletefunc = exc->data.delete_pointer_cond.deletefunc;
+ packexc->data.delete_pointer_cond.cond = (void *) CInline_GetLocalID(exc->data.delete_pointer_cond.cond);
+ break;
+ case EAT_CATCHBLOCK:
+ packexc->data.catch_block.catch_object = (void *) CInline_GetLocalID(exc->data.catch_block.catch_object);
+ packexc->data.catch_block.catch_info_object = (void *) CInline_GetLocalID(exc->data.catch_block.catch_info_object);
+ packexc->data.catch_block.catch_label = (void *) CInline_GetStatementNumber(start->next, exc->data.catch_block.catch_label->stmt);
+ packexc->data.catch_block.catch_typeid = exc->data.catch_block.catch_typeid;
+ packexc->data.catch_block.catch_type = exc->data.catch_block.catch_type;
+ packexc->data.catch_block.catch_qual = exc->data.catch_block.catch_qual;
+ break;
+ case EAT_ACTIVECATCHBLOCK:
+ packexc->data.active_catch_block.catch_info_object = (void *) CInline_GetLocalID(exc->data.active_catch_block.catch_info_object);
+ packexc->data.active_catch_block.call_dtor = exc->data.active_catch_block.call_dtor;
+ break;
+ case EAT_SPECIFICATION:
+ packexc->data.specification.unexp_ids = exc->data.specification.unexp_ids;
+ packexc->data.specification.unexp_id = exc->data.specification.unexp_id;
+ packexc->data.specification.unexp_label = (void *) CInline_GetStatementNumber(start->next, exc->data.specification.unexp_label->stmt);
+ packexc->data.specification.unexp_info_object = (void *) CInline_GetLocalID(exc->data.specification.unexp_info_object);
+ break;
+ case EAT_TERMINATE:
+ break;
+ default:
+ CError_FATAL(3720);
+ }
+
+ exc = exc->prev;
+ }
+
+ return last;
+}
+
+void CInline_PackIFunctionData(CI_FuncData *funcdata, Statement *stmt, Object *object) {
+ ObjectList *list;
+ CI_Var *var;
+ Statement *scan;
+ CI_Statement *packstmt;
+ int i;
+
+ cinline_first_stmt = stmt->next;
+ memclrw(funcdata, sizeof(CI_FuncData));
+
+ funcdata->can_inline = CInline_CanInline(object, stmt->next);
+
+ if (copts.filesyminfo) {
+ funcdata->fileoffset = cparser_fileoffset;
+ funcdata->fileoffset.is_inline = 1;
+ funcdata->symdecloffset = symdecloffset;
+ funcdata->functionbodyoffset = functionbodyoffset;
+ funcdata->functionbodypath = functionbodypath;
+ funcdata->symdeclend = symdeclend;
+ }
+
+ list = arguments;
+ i = 0;
+ while (list) {
+ list = list->next;
+ i++;
+ }
+
+ if ((funcdata->numarguments = i) > 0) {
+ loc_args = funcdata->arguments = galloc(sizeof(CI_Var) * i);
+ memclrw(funcdata->arguments, sizeof(CI_Var) * i);
+
+ for (list = arguments, var = funcdata->arguments; list; list = list->next, var++) {
+ var->name = list->object->name;
+ var->type = list->object->type;
+ var->qual = list->object->qual;
+ var->sflags = CInline_GetObjectSFlags(list->object);
+ var->xD = 0;
+ var->xE = 1;
+ }
+ }
+
+ list = locals;
+ i = 0;
+ while (list) {
+ if (list->object->datatype == DLOCAL)
+ i++;
+ list = list->next;
+ }
+
+ if ((funcdata->numlocals = i) > 0) {
+ loc_vars = funcdata->locals = galloc(sizeof(CI_Var) * i);
+ memclrw(funcdata->locals, sizeof(CI_Var) * i);
+
+ for (list = locals, var = funcdata->locals; list; list = list->next) {
+ if (list->object->datatype == DLOCAL) {
+ var->name = list->object->name;
+ var->type = list->object->type;
+ var->qual = list->object->qual;
+ var->sflags = CInline_GetObjectSFlags(list->object);
+ var->xD = 0;
+ var->xE = 0;
+ var++;
+ }
+ }
+ }
+
+ scan = stmt->next;
+ i = 0;
+ while (scan) {
+ scan = scan->next;
+ i++;
+ }
+
+ funcdata->numstatements = i;
+ funcdata->statements = galloc(sizeof(CI_Statement) * i);
+
+ for (scan = stmt->next, packstmt = funcdata->statements; scan; scan = scan->next, packstmt++) {
+ packstmt->type = scan->type;
+ packstmt->flags = scan->flags;
+ packstmt->value = scan->value;
+ packstmt->dobjstack = CInline_PackActions(stmt, scan);
+ packstmt->sourceoffset = scan->sourceoffset;
+ packstmt->sourcefilepath = scan->sourcefilepath;
+
+ switch (scan->type) {
+ case ST_NOP:
+ case ST_LABEL:
+ break;
+ case ST_EXPRESSION:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_GOTOEXPR:
+ packstmt->u.expr = CInline_CopyExpression(scan->expr, CopyMode2);
+ break;
+ case ST_RETURN:
+ if (scan->expr)
+ packstmt->u.expr = CInline_CopyExpression(scan->expr, CopyMode2);
+ else
+ packstmt->u.expr = NULL;
+ break;
+ case ST_GOTO:
+ packstmt->u.statementnum = CInline_GetStatementNumber(stmt->next, scan->label->stmt);
+ break;
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ packstmt->u.ifgoto.expr = CInline_CopyExpression(scan->expr, CopyMode2);
+ packstmt->u.ifgoto.statementnum = CInline_GetStatementNumber(stmt->next, scan->label->stmt);
+ break;
+ case ST_SWITCH:
+ packstmt->u.switchdata = CInline_PackSwitch(stmt->next, scan);
+ break;
+ case ST_ASM:
+ InlineAsm_PackAsmStatement(scan, stmt->next, &packstmt->u.asmdata.data, &packstmt->u.asmdata.size);
+ break;
+ default:
+ CError_FATAL(3862);
+ }
+ }
+}
+
+void CInline_UnpackIFunctionData(Object *object, CI_FuncData *funcdata, Statement *firstStmt) {
+ CLabel **labels;
+ CI_Var *var;
+ ObjectList *last;
+ Statement *stmt;
+ CI_Statement *packstmt;
+ int i;
+
+ cparser_fileoffset = funcdata->fileoffset;
+ symdecloffset = funcdata->symdecloffset;
+ functionbodyoffset = funcdata->functionbodyoffset;
+ functionbodypath = funcdata->functionbodypath;
+ symdeclend = funcdata->symdeclend;
+
+ for (i = 0, var = funcdata->arguments; i < funcdata->numarguments; i++, var++) {
+ if (i == 0) {
+ last = lalloc(sizeof(ObjectList));
+ arguments = last;
+ } else {
+ last->next = lalloc(sizeof(ObjectList));
+ last = last->next;
+ }
+
+ object = galloc(sizeof(Object));
+ memclrw(object, sizeof(Object));
+ last->object = object;
+ last->next = NULL;
+
+ object->otype = OT_OBJECT;
+ object->access = ACCESSPUBLIC;
+ object->datatype = DLOCAL;
+ object->name = var->name;
+ object->type = var->type;
+ object->qual = var->qual;
+ CInline_SetObjectSFlags(object, var->sflags);
+ CFunc_SetupLocalVarInfo(object);
+
+ if (funcdata->fileoffset.file) {
+ object->u.var.info->deftoken.tokenfile = funcdata->fileoffset.file;
+ object->u.var.info->deftoken.tokenoffset = funcdata->functionbodyoffset;
+ }
+ }
+
+ for (i = 0, var = funcdata->locals; i < funcdata->numlocals; i++, var++) {
+ if (i == 0) {
+ last = lalloc(sizeof(ObjectList));
+ locals = last;
+ } else {
+ last->next = lalloc(sizeof(ObjectList));
+ last = last->next;
+ }
+
+ object = galloc(sizeof(Object));
+ memclrw(object, sizeof(Object));
+ last->object = object;
+ last->next = NULL;
+
+ object->otype = OT_OBJECT;
+ object->access = ACCESSPUBLIC;
+ object->datatype = DLOCAL;
+ object->name = var->name;
+ object->type = var->type;
+ object->qual = var->qual;
+ CInline_SetObjectSFlags(object, var->sflags);
+ CFunc_SetupLocalVarInfo(object);
+
+ if (funcdata->fileoffset.file) {
+ object->u.var.info->deftoken.tokenfile = funcdata->fileoffset.file;
+ object->u.var.info->deftoken.tokenoffset = funcdata->functionbodyoffset;
+ }
+ }
+
+ enode_idtrans = NULL;
+ cinline_label_trans = NULL;
+
+ labels = lalloc(sizeof(CLabel *) * funcdata->numstatements);
+ memclrw(labels, sizeof(CLabel *) * funcdata->numstatements);
+
+ for (i = 0, stmt = firstStmt, packstmt = funcdata->statements; i < funcdata->numstatements; i++, packstmt++) {
+ stmt->next = lalloc(sizeof(Statement));
+ stmt = stmt->next;
+
+ stmt->type = packstmt->type;
+ stmt->flags = packstmt->flags;
+ stmt->value = packstmt->value;
+ stmt->sourceoffset = packstmt->sourceoffset;
+ stmt->sourcefilepath = packstmt->sourcefilepath;
+ stmt->dobjstack = CInline_UnpackActions(packstmt, 0);
+ stmt->next = NULL;
+
+ switch (stmt->type) {
+ case ST_NOP:
+ case ST_GOTO:
+ case ST_ASM:
+ break;
+ case ST_EXPRESSION:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_GOTOEXPR:
+ stmt->expr = CInline_CopyExpression(packstmt->u.expr, CopyMode3);
+ break;
+ case ST_RETURN:
+ if (packstmt->u.expr)
+ stmt->expr = CInline_CopyExpression(packstmt->u.expr, CopyMode3);
+ else
+ stmt->expr = NULL;
+ break;
+ case ST_LABEL:
+ labels[i] = stmt->label = newlabel();
+ stmt->label->stmt = stmt;
+ break;
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ stmt->expr = CInline_CopyExpression(packstmt->u.ifgoto.expr, CopyMode3);
+ break;
+ case ST_SWITCH:
+ stmt->expr = CInline_CopyExpression(packstmt->u.switchdata->expr, CopyMode3);
+ break;
+ default:
+ CError_FATAL(4017);
+ }
+ }
+
+ for (stmt = firstStmt->next, packstmt = funcdata->statements; stmt; stmt = stmt->next, packstmt++) {
+ switch (stmt->type) {
+ case ST_GOTO:
+ CError_ASSERT(4024, stmt->label = labels[packstmt->u.statementnum]);
+ break;
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ CError_ASSERT(4029, stmt->label = labels[packstmt->u.ifgoto.statementnum]);
+ break;
+ case ST_SWITCH:
+ CInline_UnpackSwitch(stmt, packstmt, labels);
+ break;
+ case ST_ASM:
+ InlineAsm_UnpackAsmStatement(stmt, labels, 0, packstmt->u.asmdata.data, packstmt->u.asmdata.size);
+ break;
+ }
+ }
+
+ cinline_first_stmt = firstStmt->next;
+
+ while (cinline_label_trans) {
+ CError_ASSERT(4045, *cinline_label_trans->labelptr = labels[cinline_label_trans->id]);
+ cinline_label_trans = cinline_label_trans->next;
+ }
+}
+
+static void CInline_GenIFunctionCode(Object *object, CI_FuncData *func, UInt8 unk) {
+ Boolean saveDebugInfo;
+ CScopeSave saveScope;
+ Statement firstStmt;
+
+ if (cparamblkptr->precompile != 1 && func) {
+ ObjGen_SetupSym();
+ CScope_SetFunctionScope(object, &saveScope);
+ CFunc_FuncGenSetup(&firstStmt, object);
+ CInline_UnpackIFunctionData(object, func, &firstStmt);
+
+ saveDebugInfo = copts.filesyminfo;
+ if (copts.nosyminline || (!symdecloffset && !symdeclend))
+ copts.filesyminfo = 0;
+
+ expanding_function = object;
+ recursive_inline = 0;
+ CInline_Expand(&firstStmt);
+
+ if (!anyerrors) {
+ if (copts.filesyminfo)
+ CPrep_SetSourceFile(&cparser_fileoffset);
+ CodeGen_Generator(&firstStmt, object, unk, 0);
+ }
+
+ CScope_RestoreScope(&saveScope);
+ copts.filesyminfo = saveDebugInfo;
+ }
+}
+
+void CInline_AddDefaultFunctionAction(Object *object) {
+ CI_Action *action;
+
+ for (action = cinline_actionlist; action; action = action->next) {
+ if (action->obj == object)
+ return;
+ }
+
+ action = galloc(sizeof(CI_Action));
+ memclrw(action, sizeof(CI_Action));
+
+ action->actiontype = CI_ActionDefaultFunc;
+ action->obj = object;
+
+ action->next = cinline_actionlist;
+ cinline_actionlist = action;
+}
+
+void CInline_AddInlineFunctionAction(Object *object, TypeClass *tclass, FileOffsetInfo *fileoffset, TokenStream *stream, Boolean flag) {
+ CI_Action *action;
+
+ for (action = flag ? cinline_tactionlist : cinline_actionlist; action; action = action->next) {
+ if (action->obj == object)
+ return;
+ }
+
+ CError_ASSERT(4132, IS_TYPE_FUNC(object->type));
+
+ TYPE_FUNC(object->type)->flags |= FUNC_IS_TEMPL_INSTANCE;
+
+ action = galloc(sizeof(CI_Action));
+ memclrw(action, sizeof(CI_Action));
+
+ action->actiontype = CI_ActionInlineFunc;
+ action->obj = object;
+ action->u.inlinefunc.tclass = tclass;
+ action->u.inlinefunc.fileoffset = *fileoffset;
+ action->u.inlinefunc.stream = *stream;
+
+ if (flag) {
+ action->next = cinline_tactionlist;
+ cinline_tactionlist = action;
+ TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_200000;
+ } else {
+ action->next = cinline_actionlist;
+ cinline_actionlist = action;
+ }
+}
+
+void CInline_AddMemberFunctionAction(Object *object, TemplClass *templ, TemplClassInst *inst, TemplateMember *tmemb) {
+ CI_Action *action;
+
+ for (action = cinline_tactionlist; action; action = action->next) {
+ if (action->obj == object)
+ return;
+ }
+
+ action = galloc(sizeof(CI_Action));
+ memclrw(action, sizeof(CI_Action));
+
+ action->actiontype = CI_ActionMemberFunc;
+ action->obj = object;
+ action->u.memberfunc.templ = templ;
+ action->u.memberfunc.inst = inst;
+ action->u.memberfunc.tmemb = tmemb;
+
+ action->next = cinline_tactionlist;
+ cinline_tactionlist = action;
+
+ TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_200000;
+}
+
+void CInline_AddTemplateFunctionAction(Object *object, TemplateFunction *func, TemplFuncInstance *inst) {
+ CI_Action *action;
+
+ for (action = cinline_tactionlist; action; action = action->next) {
+ if (action->obj == object)
+ return;
+ }
+
+ action = galloc(sizeof(CI_Action));
+ memclrw(action, sizeof(CI_Action));
+
+ action->actiontype = CI_ActionTemplateFunc;
+ action->obj = object;
+ action->u.templatefunc.func = func;
+ action->u.templatefunc.inst = inst;
+
+ action->next = cinline_tactionlist;
+ cinline_tactionlist = action;
+
+ TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_200000;
+}
+
+static void CInline_AddFRefList_Object(Object *object) {
+ ObjectList *list;
+
+ if (
+ !(object->datatype == DFUNC || object->datatype == DVFUNC) ||
+ (object->flags & OBJECT_DEFINED) ||
+ IS_TEMPL_FUNC(object->type)
+ )
+ return;
+
+ for (list = cinline_freflist; list; list = list->next) {
+ if (list->object == object)
+ return;
+ }
+
+ list = lalloc(sizeof(ObjectList));
+ list->object = object;
+ list->next = cinline_freflist;
+ cinline_freflist = list;
+
+ if ((object->qual & Q_INLINE) && object->u.func.u.ifuncdata)
+ CInline_AddFRefList_InlineFunc(object->u.func.u.ifuncdata);
+}
+
+static void CInline_AddFRefList_ExAction(ExceptionAction *exc) {
+ while (exc) {
+ switch (exc->type) {
+ case EAT_DESTROYLOCAL:
+ CInline_AddFRefList_Object(exc->data.destroy_local.dtor);
+ break;
+ case EAT_DESTROYLOCALCOND:
+ CInline_AddFRefList_Object(exc->data.destroy_local_cond.dtor);
+ break;
+ case EAT_DESTROYLOCALOFFSET:
+ CInline_AddFRefList_Object(exc->data.destroy_local_offset.dtor);
+ break;
+ case EAT_DESTROYLOCALPOINTER:
+ CInline_AddFRefList_Object(exc->data.destroy_local_pointer.dtor);
+ break;
+ case EAT_DESTROYLOCALARRAY:
+ CInline_AddFRefList_Object(exc->data.destroy_local_array.dtor);
+ break;
+ case EAT_DESTROYPARTIALARRAY:
+ CInline_AddFRefList_Object(exc->data.destroy_partial_array.dtor);
+ break;
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYBASE:
+ CInline_AddFRefList_Object(exc->data.destroy_member.dtor);
+ break;
+ case EAT_DESTROYMEMBERCOND:
+ CInline_AddFRefList_Object(exc->data.destroy_member_cond.dtor);
+ break;
+ case EAT_DESTROYMEMBERARRAY:
+ CInline_AddFRefList_Object(exc->data.destroy_member_array.dtor);
+ break;
+ case EAT_DELETEPOINTER:
+ case EAT_DELETELOCALPOINTER:
+ CInline_AddFRefList_Object(exc->data.delete_pointer.deletefunc);
+ break;
+ case EAT_DELETEPOINTERCOND:
+ CInline_AddFRefList_Object(exc->data.delete_pointer_cond.deletefunc);
+ break;
+ case EAT_CATCHBLOCK:
+ case EAT_ACTIVECATCHBLOCK:
+ case EAT_SPECIFICATION:
+ case EAT_TERMINATE:
+ break;
+ default:
+ CError_FATAL(4307);
+ }
+ exc = exc->prev;
+ }
+}
+
+static void CInline_AddFRefList_ExprCB(ENode *expr) {
+ CInline_AddFRefList_Object(expr->data.objref);
+}
+
+static void CInline_AddFRefList_Expr(ENode *expr) {
+ CExpr_SearchExprTree(expr, CInline_AddFRefList_ExprCB, 1, EOBJREF);
+}
+
+static void CInline_AddFRefList_Statement(Statement *stmt) {
+ while (stmt) {
+ if (stmt->dobjstack)
+ CInline_AddFRefList_ExAction(stmt->dobjstack);
+
+ switch (stmt->type) {
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_GOTO:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_ASM:
+ break;
+ case ST_RETURN:
+ if (!stmt->expr)
+ break;
+ case ST_EXPRESSION:
+ case ST_SWITCH:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ case ST_GOTOEXPR:
+ CInline_AddFRefList_Expr(stmt->expr);
+ break;
+ default:
+ CError_FATAL(4368);
+ }
+
+ stmt = stmt->next;
+ }
+}
+
+static void CInline_AddFRefList_InlineFunc(CI_FuncData *data) {
+ short i;
+ CI_Statement *stmt;
+ ExceptionAction *exc;
+
+ for (i = 0; i < data->numstatements; i++) {
+ stmt = data->statements + i;
+
+ switch (stmt->type) {
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_GOTO:
+ case ST_ASM:
+ break;
+ case ST_EXPRESSION:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_GOTOEXPR:
+ CInline_AddFRefList_Expr(stmt->u.expr);
+ break;
+ case ST_RETURN:
+ if (stmt->u.expr)
+ CInline_AddFRefList_Expr(stmt->u.expr);
+ break;
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ CInline_AddFRefList_Expr(stmt->u.ifgoto.expr);
+ break;
+ case ST_SWITCH:
+ CInline_AddFRefList_Expr(stmt->u.switchdata->expr);
+ break;
+ default:
+ CError_FATAL(4420);
+ }
+
+ for (exc = data->statements[i].dobjstack; exc; exc = exc->prev) {
+ switch (exc->type) {
+ case EAT_DESTROYLOCAL:
+ CInline_AddFRefList_Object(exc->data.destroy_local.dtor);
+ break;
+ case EAT_DESTROYLOCALCOND:
+ CInline_AddFRefList_Object(exc->data.destroy_local_cond.dtor);
+ break;
+ case EAT_DESTROYLOCALOFFSET:
+ CInline_AddFRefList_Object(exc->data.destroy_local_offset.dtor);
+ break;
+ case EAT_DESTROYLOCALPOINTER:
+ CInline_AddFRefList_Object(exc->data.destroy_local_pointer.dtor);
+ break;
+ case EAT_DESTROYLOCALARRAY:
+ CInline_AddFRefList_Object(exc->data.destroy_local_array.dtor);
+ break;
+ case EAT_DESTROYPARTIALARRAY:
+ break;
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYBASE:
+ CInline_AddFRefList_Object(exc->data.destroy_member.dtor);
+ break;
+ case EAT_DESTROYMEMBERCOND:
+ CInline_AddFRefList_Object(exc->data.destroy_member_cond.dtor);
+ break;
+ case EAT_DESTROYMEMBERARRAY:
+ CInline_AddFRefList_Object(exc->data.destroy_member_array.dtor);
+ break;
+ case EAT_DELETEPOINTER:
+ case EAT_DELETELOCALPOINTER:
+ CInline_AddFRefList_Object(exc->data.delete_pointer.deletefunc);
+ break;
+ case EAT_DELETEPOINTERCOND:
+ CInline_AddFRefList_Object(exc->data.delete_pointer_cond.deletefunc);
+ break;
+ case EAT_CATCHBLOCK:
+ case EAT_ACTIVECATCHBLOCK:
+ case EAT_SPECIFICATION:
+ case EAT_TERMINATE:
+ break;
+ default:
+ CError_FATAL(4470);
+ }
+ }
+ }
+}
+
+static void CInline_GenerateTemplateInline(Object *object) {
+ CI_Action **ptr;
+ CI_Action *action;
+
+ ptr = &cinline_tactionlist;
+ while ((action = *ptr)) {
+ if (object == action->obj) {
+ *ptr = action->next;
+ action->next = cinline_actionlist;
+ cinline_actionlist = action;
+
+ TYPE_FUNC(object->type)->flags &= ~FUNC_FLAGS_200000;
+ return;
+ }
+
+ ptr = &action->next;
+ }
+
+ CError_FATAL(4499);
+}
+
+void CInline_ObjectAddrRef(Object *object) {
+ CI_FuncData *funcdata;
+
+ object->flags |= OBJECT_FLAGS_2;
+
+ switch (object->datatype) {
+ case DFUNC:
+ case DVFUNC:
+ if (
+ (object->qual & Q_INLINE) &&
+ (funcdata = object->u.func.u.ifuncdata) &&
+ !(object->flags & OBJECT_DEFINED) &&
+ !(TYPE_FUNC(object->type)->flags & FUNC_IS_TEMPL)
+ )
+ {
+ CI_Export *export = galloc(sizeof(CI_Export));
+
+ export->object = object;
+ export->funcdata = funcdata;
+ export->xC = 0;
+
+ export->next = cinline_exportlist;
+ cinline_exportlist = export;
+
+ object->flags |= OBJECT_DEFINED;
+ return;
+ }
+ else if (
+ (TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED) &&
+ !(TYPE_FUNC(object->type)->flags & FUNC_DEFINED)
+ )
+ {
+ CInline_AddDefaultFunctionAction(object);
+ return;
+ }
+ else if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_200000)
+ {
+ CInline_GenerateTemplateInline(object);
+ return;
+ }
+ return;
+
+ case DALIAS:
+ CInline_ObjectAddrRef(object->u.alias.object);
+ return;
+
+ case DDATA:
+ if (object->qual & Q_INLINE_DATA)
+ CInit_ExportConst(object);
+
+ if (object->flags & OBJECT_LAZY) {
+ object->flags &= ~OBJECT_LAZY;
+ CParser_CallBackAction(object);
+ }
+ return;
+ }
+}
+
+static Boolean CInline_CheckDependencies(ObjectList *list) {
+ Object *object;
+ Boolean result;
+
+ result = 0;
+
+ while (list) {
+ object = list->object;
+
+ if (
+ (TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED) &&
+ !(TYPE_FUNC(object->type)->flags & FUNC_DEFINED)
+ )
+ {
+ CInline_AddDefaultFunctionAction(object);
+ result = 1;
+ }
+ else if (
+ (object->qual & Q_IS_TEMPLATED) &&
+ CTempl_InlineFunctionCheck(object)
+ )
+ {
+ result = 1;
+ }
+ else {
+ CI_Action *action;
+ for (action = cinline_actionlist; action; action = action->next) {
+ if (object == action->obj) {
+ result = 1;
+ break;
+ }
+ }
+
+ if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_200000) {
+ CInline_GenerateTemplateInline(object);
+ result = 1;
+ }
+ }
+
+ list = list->next;
+ }
+
+ return result;
+}
+
+static Boolean CInline_IsSmallFunction(Object *object, Statement *stmt) {
+ SInt32 statementCount;
+ ObjectList *list;
+ SInt32 localSize;
+
+ statementCount = 0;
+ while (stmt) {
+ if (stmt->type != ST_NOP && stmt->type != ST_LABEL)
+ statementCount++;
+ if (statementCount > 15)
+ return 0;
+ stmt = stmt->next;
+ }
+
+ for (list = locals, localSize = 0; list; list = list->next)
+ localSize += list->object->type->size;
+
+ if (localSize > 1024)
+ return 0;
+
+ return 1;
+}
+
+static Boolean CInline_NoFPLocals(void) {
+ ObjectList *list;
+
+ for (list = locals; list; list = list->next) {
+ if (IS_TYPE_FLOAT(list->object->type))
+ return 0;
+ }
+
+ return 1;
+}
+
+void CInline_GenFunc(Statement *stmt, Object *object, UInt8 unk) {
+ CI_FuncData *funcdata;
+ CI_Export *export;
+ Boolean flag24;
+ Boolean flag30;
+
+ TYPE_FUNC(object->type)->flags |= OBJECT_FLAGS_2;
+
+ flag24 = 0;
+ flag30 = 0;
+ if (!(object->qual & Q_INLINE)) {
+ if (
+ copts.auto_inline &&
+ !copts.dontinline &&
+ CInline_CanInline(object, stmt->next) &&
+ CInline_IsSmallFunction(object, stmt->next)
+ )
+ {
+ flag24 = 1;
+ flag30 = 1;
+ TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_800;
+ }
+ } else {
+ flag30 = 1;
+ }
+
+ if (flag30) {
+ COpt_SimpleOptimizer(object, stmt);
+
+ funcdata = galloc(sizeof(CI_FuncData));
+ CInline_PackIFunctionData(funcdata, stmt, object);
+
+ object->u.func.u.ifuncdata = funcdata;
+
+ if (!flag24 && !(object->flags & OBJECT_FLAGS_2)) {
+ if (cinline_gendeps) {
+ cinline_freflist = NULL;
+ CInline_AddFRefList_Statement(stmt);
+ CInline_CheckDependencies(cinline_freflist);
+ }
+ return;
+ }
+ }
+
+ object->flags |= OBJECT_DEFINED;
+
+ cinline_freflist = NULL;
+ CInline_AddFRefList_Statement(stmt);
+
+ if (CInline_CheckDependencies(cinline_freflist) || copts.defer_codegen) {
+ if (!flag30) {
+ funcdata = galloc(sizeof(CI_FuncData));
+ CInline_PackIFunctionData(funcdata, stmt, object);
+ } else {
+ funcdata = object->u.func.u.ifuncdata;
+ }
+
+ export = galloc(sizeof(CI_Export));
+ export->object = object;
+ export->funcdata = funcdata;
+ export->xC = unk;
+
+ export->next = cinline_exportlist;
+ cinline_exportlist = export;
+
+ return;
+ }
+
+ expanding_function = object;
+ recursive_inline = 0;
+ CInline_Expand(stmt);
+
+ if (copts.filesyminfo)
+ CPrep_SetSourceFile(&cparser_fileoffset);
+
+ if (!anyerrors)
+ CodeGen_Generator(stmt, object, unk, 0);
+}
+
+static void CInline_GenerateDefaultFunc(Object *object) {
+ TypeClass *tclass;
+
+ CError_ASSERT(4770, TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED);
+ CError_ASSERT(4771, TYPE_FUNC(object->type)->flags & FUNC_METHOD);
+
+ tclass = TYPE_METHOD(object->type)->theclass;
+
+ if (object == CClass_DefaultConstructor(tclass)) {
+ if (object->u.func.defargdata)
+ CABI_MakeDefaultArgConstructor(tclass, object);
+ else
+ CABI_MakeDefaultConstructor(tclass, object);
+ } else if (object == CClass_CopyConstructor(tclass)) {
+ CABI_MakeDefaultCopyConstructor(tclass, object);
+ } else if (object == CClass_AssignmentOperator(tclass)) {
+ CABI_MakeDefaultAssignmentOperator(tclass, object);
+ } else if (object == CClass_Destructor(tclass)) {
+ CABI_MakeDefaultDestructor(tclass, object);
+ } else {
+ CError_FATAL(4805);
+ }
+}
+
+static TemplClassInst *CInline_FindNestedTemplInst(TypeClass *tclass) {
+ NameSpace *nspace;
+
+ while (tclass) {
+ if ((tclass->flags & CLASS_IS_TEMPL_INST))
+ return TEMPL_CLASS_INST(tclass);
+
+ if (!copts.template_patch)
+ break;
+
+ nspace = tclass->nspace->parent;
+ tclass = NULL;
+ while (nspace) {
+ if (nspace->theclass) {
+ tclass = nspace->theclass;
+ break;
+ }
+ nspace = nspace->parent;
+ }
+ }
+
+ return NULL;
+}
+
+static void CInline_GenerateInlineFunc(CI_Action *action) {
+ Object *object;
+ TemplClassInst *inst;
+ DeclInfo di;
+ SInt32 streamState;
+
+ object = action->obj;
+
+ CPrep_StreamInsert(&action->u.inlinefunc.stream, &streamState);
+ cparser_fileoffset = action->u.inlinefunc.fileoffset;
+ symdecloffset = cparser_fileoffset.tokenline;
+
+ switch ((tk = lex())) {
+ case ':':
+ case '{':
+ case TK_TRY:
+ break;
+ default:
+ CError_FATAL(4860);
+ }
+
+ symdecltoken = *CPrep_CurStreamElement();
+
+ TYPE_FUNC(object->type)->flags &= ~FUNC_DEFINED;
+ if (IS_TYPE_METHOD(object->type) && (inst = CInline_FindNestedTemplInst(TYPE_METHOD(object->type)->theclass))) {
+ CTempl_ParseInstanceScopeFunction(object, inst, NULL);
+ } else {
+ memclrw(&di, sizeof(di));
+ if (action->u.inlinefunc.tclass) {
+ if ((inst = CInline_FindNestedTemplInst(action->u.inlinefunc.tclass))) {
+ CTempl_ParseInstanceScopeFunction(object, inst, action->u.inlinefunc.tclass);
+ } else {
+ CFunc_ParseFuncDef(object, &di, action->u.inlinefunc.tclass, 0, 0, NULL);
+ }
+ } else {
+ CFunc_ParseFuncDef(object, &di, NULL, 0, 0, NULL);
+ }
+ }
+
+ CPrep_StreamRemove(&action->u.inlinefunc.stream, &streamState);
+}
+
+Boolean CInline_CanFreeLHeap(void) {
+ CI_Action *action;
+
+ if (!anyerrors) {
+ for (action = cinline_actionlist; action; action = action->next) {
+ if (action->actiontype == CI_ActionInlineFunc)
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+Boolean CInline_GenerateDeferredFuncs(void) {
+ CI_Action *action;
+ CI_Export *export;
+
+ if (!anyerrors) {
+ if ((action = cinline_actionlist)) {
+ cinline_actionlist = action->next;
+ cinline_gendeps = 1;
+
+ switch (action->actiontype) {
+ case CI_ActionDefaultFunc:
+ CInline_GenerateDefaultFunc(action->obj);
+ break;
+ case CI_ActionInlineFunc:
+ if (!(action->obj->flags & OBJECT_DEFINED))
+ CInline_GenerateInlineFunc(action);
+ break;
+ case CI_ActionMemberFunc:
+ if (!(TYPE_FUNC(action->obj->type)->flags & FUNC_DEFINED))
+ CTempl_InstantiateMember(
+ action->u.memberfunc.templ, action->u.memberfunc.inst,
+ action->u.memberfunc.tmemb, action->obj, 0);
+ break;
+ case CI_ActionTemplateFunc:
+ if (!(TYPE_FUNC(action->obj->type)->flags & FUNC_DEFINED) && !action->u.templatefunc.inst->is_specialized)
+ CTempl_GenFuncInstance(action->u.templatefunc.func, action->u.templatefunc.inst, 0);
+ break;
+ default:
+ CError_FATAL(5001);
+ }
+
+ cinline_gendeps = 0;
+ return 1;
+ } else {
+ if ((export = cinline_exportlist) && !copts.defer_codegen) {
+ cinline_exportlist = export->next;
+ CInline_GenIFunctionCode(export->object, export->funcdata, export->xC);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static InitExpr *CInline_InitTemplateData(InitExpr *init) {
+ Statement *stmt;
+ CLabel *label;
+ Object *object;
+ Object *data;
+
+ object = init->object;
+
+ data = CParser_NewCompilerDefDataObject();
+ data->type = TYPE(&stsignedchar);
+ data->name = CParser_NameConcat("__init__", CMangler_GetLinkName(object)->name);
+ data->qual = Q_WEAK;
+ CInit_DeclareData(data, NULL, NULL, data->type->size);
+
+ stmt = CFunc_AppendStatement(ST_IFGOTO);
+ stmt->expr = create_objectnode(data);
+ label = newlabel();
+ stmt->label = label;
+
+ do {
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = CInline_CopyExpression(init->expr, CopyMode0);
+ init = init->next;
+ } while (init && init->object == object);
+
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = makediadicnode(create_objectnode(data), intconstnode(TYPE(&stsignedchar), 1), EASS);
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = label;
+ label->stmt = stmt;
+
+ return init;
+}
+
+void CInline_Finish(void) {
+ NameSpace *nspace;
+ Boolean saveDebugInfo;
+ Statement firstStmt;
+ Statement *stmt;
+ InitExpr *init;
+ Boolean doMore;
+
+ if (!init_expressions || anyerrors)
+ return;
+
+ cinline_freflist = NULL;
+
+ for (init = init_expressions; init; init = init->next)
+ CInline_AddFRefList_Expr(init->expr);
+
+ CInline_CheckDependencies(cinline_freflist);
+
+ do {
+ doMore = CInline_GenerateDeferredFuncs();
+ } while (doMore);
+
+ nspace = CFunc_FuncGenSetup(&firstStmt, NULL);
+ saveDebugInfo = copts.filesyminfo;
+ copts.filesyminfo = 0;
+
+ init = init_expressions;
+ while (init) {
+ if (init->object->nspace->theclass && (init->object->nspace->theclass->flags & CLASS_IS_TEMPL_INST)) {
+ init = CInline_InitTemplateData(init);
+ } else {
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = CInline_CopyExpression(init->expr, CopyMode0);
+ init = init->next;
+ }
+ }
+
+ CFunc_CodeCleanup(&firstStmt);
+
+ expanding_function = NULL;
+ recursive_inline = 0;
+ CInline_Expand(&firstStmt);
+
+ if (!anyerrors) {
+ if (copts.filesyminfo)
+ CPrep_SetSourceFile(&cparser_fileoffset);
+ CodeGen_Generator(&firstStmt, NULL, 0, 1);
+ }
+
+ cscope_current = nspace->parent;
+ copts.filesyminfo = saveDebugInfo;
+}
diff --git a/compiler_and_linker/FrontEnd/C/CMangler.c b/compiler_and_linker/FrontEnd/C/CMangler.c
new file mode 100644
index 0000000..615abf5
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CMangler.c
@@ -0,0 +1,713 @@
+#include "compiler/CMangler.h"
+#include "compiler/CError.h"
+#include "compiler/CInt64.h"
+#include "compiler/CFunc.h"
+#include "compiler/CParser.h"
+#include "compiler/CTemplateTools.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/enode.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/templates.h"
+#include "compiler/types.h"
+#include "cos.h"
+
+HashNameNode *constructor_name_node;
+HashNameNode *destructor_name_node;
+HashNameNode *asop_name_node;
+
+// forward decls
+static void CMangler_MangleClassName(TypeClass *tclass);
+static void CMangler_MangleTypeAppend(Type *type, UInt32 qual);
+static void CMangler_MangleArgs(FuncArg *args);
+
+void CMangler_Setup(void) {
+ constructor_name_node = GetHashNameNodeExport("__ct");
+ destructor_name_node = GetHashNameNodeExport("__dt");
+ asop_name_node = GetHashNameNodeExport("__as");
+}
+
+HashNameNode *CMangler_BasicDtorName(void) {
+ return GetHashNameNodeExport("__dtb");
+}
+
+HashNameNode *CMangler_VBaseDtorName(void) {
+ return GetHashNameNodeExport("__dtv");
+}
+
+HashNameNode *CMangler_ArrayDtorName(void) {
+ return GetHashNameNodeExport("__dta");
+}
+
+HashNameNode *CMangler_SDeleteDtorName(void) {
+ return GetHashNameNodeExport("__dts");
+}
+
+HashNameNode *CMangler_DeleteDtorName(void) {
+ return GetHashNameNodeExport("__dt");
+}
+
+char *CMangler_GetOperator(HashNameNode *name) {
+ char *str;
+
+ if (name == asop_name_node)
+ return "operator=";
+
+ str = name->name;
+ if (!strcmp(str, "__nw")) return "operator new";
+ if (!strcmp(str, "__dl")) return "operator delete";
+ if (!strcmp(str, "__nwa")) return "operator new[]";
+ if (!strcmp(str, "__dla")) return "operator delete[]";
+ if (!strcmp(str, "__pl")) return "operator+";
+ if (!strcmp(str, "__mi")) return "operator-";
+ if (!strcmp(str, "__ml")) return "operator*";
+ if (!strcmp(str, "__dv")) return "operator/";
+ if (!strcmp(str, "__md")) return "operator%";
+ if (!strcmp(str, "__er")) return "operator^";
+ if (!strcmp(str, "__ad")) return "operator&";
+ if (!strcmp(str, "__or")) return "operator|";
+ if (!strcmp(str, "__co")) return "operator~";
+ if (!strcmp(str, "__nt")) return "operator!";
+ if (!strcmp(str, "__lt")) return "operator<";
+ if (!strcmp(str, "__gt")) return "operator>";
+ if (!strcmp(str, "__apl")) return "operator+=";
+ if (!strcmp(str, "__ami")) return "operator-=";
+ if (!strcmp(str, "__amu")) return "operator*=";
+ if (!strcmp(str, "__adv")) return "operator/=";
+ if (!strcmp(str, "__amd")) return "operator%=";
+ if (!strcmp(str, "__aer")) return "operator^=";
+ if (!strcmp(str, "__aad")) return "operator&=";
+ if (!strcmp(str, "__aor")) return "operator|=";
+ if (!strcmp(str, "__ls")) return "operator<<";
+ if (!strcmp(str, "__rs")) return "operator>>";
+ if (!strcmp(str, "__als")) return "operator<<=";
+ if (!strcmp(str, "__ars")) return "operator>>=";
+ if (!strcmp(str, "__eq")) return "operator==";
+ if (!strcmp(str, "__ne")) return "operator!=";
+ if (!strcmp(str, "__le")) return "operator<=";
+ if (!strcmp(str, "__ge")) return "operator>=";
+ if (!strcmp(str, "__aa")) return "operator&&";
+ if (!strcmp(str, "__oo")) return "operator||";
+ if (!strcmp(str, "__pp")) return "operator++";
+ if (!strcmp(str, "__mm")) return "operator--";
+ if (!strcmp(str, "__cm")) return "operator,";
+ if (!strcmp(str, "__rm")) return "operator->*";
+ if (!strcmp(str, "__rf")) return "operator*";
+ if (!strcmp(str, "__cl")) return "operator()";
+ if (!strcmp(str, "__vc")) return "operator[]";
+ return NULL;
+}
+
+HashNameNode *CMangler_OperatorName(short token) {
+ switch (token) {
+ case TK_NEW: return GetHashNameNodeExport("__nw");
+ case TK_DELETE: return GetHashNameNodeExport("__dl");
+ case TK_NEW_ARRAY: return GetHashNameNodeExport("__nwa");
+ case TK_DELETE_ARRAY: return GetHashNameNodeExport("__dla");
+ case '+': return GetHashNameNodeExport("__pl");
+ case '-': return GetHashNameNodeExport("__mi");
+ case '*': return GetHashNameNodeExport("__ml");
+ case '/': return GetHashNameNodeExport("__dv");
+ case '%': return GetHashNameNodeExport("__md");
+ case '^': return GetHashNameNodeExport("__er");
+ case '&': return GetHashNameNodeExport("__ad");
+ case '|': return GetHashNameNodeExport("__or");
+ case '~': return GetHashNameNodeExport("__co");
+ case '!': return GetHashNameNodeExport("__nt");
+ case '=': return asop_name_node;
+ case '<': return GetHashNameNodeExport("__lt");
+ case '>': return GetHashNameNodeExport("__gt");
+ case TK_ADD_ASSIGN: return GetHashNameNodeExport("__apl");
+ case TK_SUB_ASSIGN: return GetHashNameNodeExport("__ami");
+ case TK_MULT_ASSIGN: return GetHashNameNodeExport("__amu");
+ case TK_DIV_ASSIGN: return GetHashNameNodeExport("__adv");
+ case TK_MOD_ASSIGN: return GetHashNameNodeExport("__amd");
+ case TK_XOR_ASSIGN: return GetHashNameNodeExport("__aer");
+ case TK_AND_ASSIGN: return GetHashNameNodeExport("__aad");
+ case TK_OR_ASSIGN: return GetHashNameNodeExport("__aor");
+ case TK_SHL: return GetHashNameNodeExport("__ls");
+ case TK_SHR: return GetHashNameNodeExport("__rs");
+ case TK_SHL_ASSIGN: return GetHashNameNodeExport("__als");
+ case TK_SHR_ASSIGN: return GetHashNameNodeExport("__ars");
+ case TK_LOGICAL_EQ: return GetHashNameNodeExport("__eq");
+ case TK_LOGICAL_NE: return GetHashNameNodeExport("__ne");
+ case TK_LESS_EQUAL: return GetHashNameNodeExport("__le");
+ case TK_GREATER_EQUAL: return GetHashNameNodeExport("__ge");
+ case TK_LOGICAL_AND: return GetHashNameNodeExport("__aa");
+ case TK_LOGICAL_OR: return GetHashNameNodeExport("__oo");
+ case TK_INCREMENT: return GetHashNameNodeExport("__pp");
+ case TK_DECREMENT: return GetHashNameNodeExport("__mm");
+ case ',': return GetHashNameNodeExport("__cm");
+ case TK_ARROW_STAR: return GetHashNameNodeExport("__rm");
+ case TK_ARROW: return GetHashNameNodeExport("__rf");
+ case '(': return GetHashNameNodeExport("__cl");
+ case '[': return GetHashNameNodeExport("__vc");
+ default: return NULL;
+ }
+}
+
+HashNameNode *CMangler_VTableName(TypeClass *theclass) {
+ HashNameNode *name;
+
+ name_mangle_list.size = 0;
+ AppendGListName(&name_mangle_list, "__vt__");
+ CMangler_MangleClassName(theclass);
+ AppendGListByte(&name_mangle_list, 0);
+ COS_LockHandle(name_mangle_list.data);
+ name = GetHashNameNodeExport(*name_mangle_list.data);
+ COS_UnlockHandle(name_mangle_list.data);
+ return name;
+}
+
+HashNameNode *CMangler_RTTIObjectName(Type *type, UInt32 qual) {
+ HashNameNode *name;
+
+ name_mangle_list.size = 0;
+ AppendGListName(&name_mangle_list, "__RTTI__");
+ CMangler_MangleTypeAppend(type, qual);
+ AppendGListByte(&name_mangle_list, 0);
+ COS_LockHandle(name_mangle_list.data);
+ name = GetHashNameNodeExport(*name_mangle_list.data);
+ COS_UnlockHandle(name_mangle_list.data);
+ return name;
+}
+
+HashNameNode *CMangler_ThunkName(Object *vfunc, SInt32 this_delta, SInt32 return_delta, SInt32 ctoroffset) {
+ HashNameNode *linkname;
+ HashNameNode *name;
+ char buf[64];
+
+ linkname = CMangler_GetLinkName(vfunc);
+ name_mangle_list.size = 0;
+ if (return_delta == 0) {
+ if (ctoroffset < 0)
+ sprintf(buf, "_@%" PRId32 "@", -this_delta);
+ else
+ sprintf(buf, "_@%" PRId32 "@%" PRId32 "@", -this_delta, ctoroffset);
+ } else {
+ sprintf(buf, "_@%" PRId32 "@%" PRId32 "@%" PRId32 "@", -this_delta, ctoroffset, return_delta);
+ }
+ AppendGListName(&name_mangle_list, buf);
+ AppendGListID(&name_mangle_list, linkname->name + 1);
+ COS_LockHandle(name_mangle_list.data);
+ name = GetHashNameNodeExport(*name_mangle_list.data);
+ COS_UnlockHandle(name_mangle_list.data);
+ return name;
+}
+
+static void CMangler_CheckTemplateArguments(TemplArg *arg) {
+ ENode *expr;
+
+ while (arg) {
+ if (arg->pid.type == TPT_NONTYPE) {
+ expr = arg->data.paramdecl.expr;
+ CError_ASSERT(360, expr);
+ if (expr->rtype->type != TYPETEMPLDEPEXPR) {
+ switch (expr->type) {
+ case EINTCONST:
+ break;
+ case EOBJREF:
+ CMangler_GetLinkName(expr->data.objref);
+ break;
+ default:
+ CError_FATAL(383);
+ }
+ }
+ }
+ arg = arg->next;
+ }
+}
+
+static void CMangler_AppendTemplateArgumentList(TemplArg *arg) {
+ ENode *expr;
+ char buf[32];
+
+ AppendGListByte(&name_mangle_list, '<');
+
+ while (arg) {
+ if (arg->pid.type == TPT_NONTYPE) {
+ expr = arg->data.paramdecl.expr;
+ CError_ASSERT(409, expr);
+ if (expr->rtype->type != TYPETEMPLDEPEXPR) {
+ switch (expr->type) {
+ case EINTCONST:
+ CInt64_PrintDec(buf, expr->data.intval);
+ AppendGListName(&name_mangle_list, buf);
+ break;
+ case EOBJREF:
+ AppendGListByte(&name_mangle_list, '&');
+ AppendGListName(&name_mangle_list, CMangler_GetLinkName(expr->data.objref)->name);
+ break;
+ default:
+ CError_FATAL(452);
+ }
+ } else {
+ AppendGListByte(&name_mangle_list, 'T');
+ }
+ } else if (arg->pid.type == TPT_TYPE) {
+ CMangler_MangleTypeAppend(arg->data.typeparam.type, arg->data.typeparam.qual);
+ } else {
+ CError_ASSERT(467, arg->pid.type == TPT_TEMPLATE);
+ CMangler_MangleTypeAppend(arg->data.ttargtype, 0);
+ }
+
+ if (arg->next)
+ AppendGListByte(&name_mangle_list, ',');
+ arg = arg->next;
+ }
+
+ AppendGListByte(&name_mangle_list, '>');
+}
+
+HashNameNode *CMangler_TemplateInstanceName(HashNameNode *basename, TemplArg *args) {
+ HashNameNode *name;
+
+ CMangler_CheckTemplateArguments(args);
+ name_mangle_list.size = 0;
+ AppendGListName(&name_mangle_list, basename->name);
+ CMangler_AppendTemplateArgumentList(args);
+ AppendGListByte(&name_mangle_list, 0);
+
+ COS_LockHandle(name_mangle_list.data);
+ name = GetHashNameNodeExport(*name_mangle_list.data);
+ COS_UnlockHandle(name_mangle_list.data);
+ return name;
+}
+
+static void CMangler_MangleTypeName(char *str) {
+ char buf[16];
+
+ sprintf(buf, "%d", strlen(str));
+ AppendGListName(&name_mangle_list, buf);
+ AppendGListName(&name_mangle_list, str);
+}
+
+static void CMangler_MangleNameSpaceName(NameSpace *nspace, char *str) {
+ char *stack[10];
+ int stackp;
+
+ stack[0] = str;
+ stackp = 1;
+ while (nspace) {
+ if (nspace->name) {
+ stack[stackp++] = nspace->name->name;
+ if (stackp >= 9)
+ break;
+ }
+ nspace = nspace->parent;
+ }
+
+ if (stackp > 1) {
+ AppendGListByte(&name_mangle_list, 'Q');
+ AppendGListByte(&name_mangle_list, '0' + stackp);
+ }
+
+ while (--stackp >= 0)
+ CMangler_MangleTypeName(stack[stackp]);
+}
+
+static void CMangler_MangleClassName(TypeClass *tclass) {
+ if (!tclass->classname)
+ CMangler_MangleNameSpaceName(tclass->nspace->parent, "class");
+ else
+ CMangler_MangleNameSpaceName(tclass->nspace->parent, tclass->nspace->name->name);
+}
+
+static void CMangler_MangleQualifier(UInt32 qual) {
+ if (qual & Q_CONST)
+ AppendGListByte(&name_mangle_list, 'C');
+ if (qual & Q_VOLATILE)
+ AppendGListByte(&name_mangle_list, 'V');
+}
+
+static void CMangler_MangleTypeAppend(Type *type, UInt32 qual) {
+ char buf[16];
+
+ switch (type->type) {
+ case TYPEVOID:
+ CMangler_MangleQualifier(qual);
+ AppendGListByte(&name_mangle_list, 'v');
+ break;
+ case TYPEINT:
+ case TYPEFLOAT:
+ CMangler_MangleQualifier(qual);
+ switch (TYPE_INTEGRAL(type)->integral) {
+ case IT_BOOL:
+ AppendGListByte(&name_mangle_list, 'b');
+ return;
+ case IT_CHAR:
+ AppendGListByte(&name_mangle_list, 'c');
+ return;
+ case IT_WCHAR_T:
+ AppendGListByte(&name_mangle_list, 'w');
+ return;
+ case IT_UCHAR:
+ AppendGListName(&name_mangle_list, "Uc");
+ return;
+ case IT_SCHAR:
+ AppendGListName(&name_mangle_list, "Sc");
+ return;
+ case IT_SHORT:
+ AppendGListByte(&name_mangle_list, 's');
+ return;
+ case IT_USHORT:
+ AppendGListName(&name_mangle_list, "Us");
+ return;
+ case IT_INT:
+ AppendGListByte(&name_mangle_list, 'i');
+ return;
+ case IT_UINT:
+ AppendGListName(&name_mangle_list, "Ui");
+ return;
+ case IT_LONG:
+ AppendGListByte(&name_mangle_list, 'l');
+ return;
+ case IT_ULONG:
+ AppendGListName(&name_mangle_list, "Ul");
+ return;
+ case IT_LONGLONG:
+ AppendGListByte(&name_mangle_list, 'x');
+ return;
+ case IT_ULONGLONG:
+ AppendGListName(&name_mangle_list, "Ux");
+ return;
+ case IT_FLOAT:
+ AppendGListByte(&name_mangle_list, 'f');
+ return;
+ case IT_SHORTDOUBLE:
+ AppendGListByte(&name_mangle_list, 'D');
+ return;
+ case IT_DOUBLE:
+ AppendGListByte(&name_mangle_list, 'd');
+ return;
+ case IT_LONGDOUBLE:
+ AppendGListByte(&name_mangle_list, 'r');
+ return;
+ default:
+ CError_FATAL(619);
+ }
+ case TYPEENUM:
+ CMangler_MangleQualifier(qual);
+ if (!TYPE_ENUM(type)->enumname)
+ CMangler_MangleNameSpaceName(TYPE_ENUM(type)->nspace, "enum");
+ else
+ CMangler_MangleNameSpaceName(TYPE_ENUM(type)->nspace, TYPE_ENUM(type)->enumname->name);
+ break;
+ case TYPEPOINTER:
+ CMangler_MangleQualifier(TYPE_POINTER(type)->qual);
+ if (TYPE_POINTER(type)->qual & Q_REFERENCE)
+ AppendGListByte(&name_mangle_list, 'R');
+ else
+ AppendGListByte(&name_mangle_list, 'P');
+ CMangler_MangleTypeAppend(TYPE_POINTER(type)->target, qual);
+ break;
+ case TYPEMEMBERPOINTER:
+ if (TYPE_MEMBER_POINTER(type)->ty2->type != TYPECLASS) {
+ AppendGListName(&name_mangle_list, "3<T>");
+ } else {
+ CMangler_MangleQualifier(TYPE_MEMBER_POINTER(type)->qual);
+ AppendGListByte(&name_mangle_list, 'M');
+ CMangler_MangleClassName(TYPE_CLASS(TYPE_MEMBER_POINTER(type)->ty2));
+ CMangler_MangleTypeAppend(TYPE_MEMBER_POINTER(type)->ty1, qual);
+ }
+ break;
+ case TYPEARRAY:
+ AppendGListByte(&name_mangle_list, 'A');
+ if (TYPE_POINTER(type)->target->size) {
+ sprintf(buf, "%" PRId32 "", type->size / TYPE_POINTER(type)->target->size);
+ AppendGListName(&name_mangle_list, buf);
+ } else {
+ AppendGListByte(&name_mangle_list, '0');
+ }
+ AppendGListByte(&name_mangle_list, '_');
+ CMangler_MangleTypeAppend(TYPE_POINTER(type)->target, qual);
+ break;
+ case TYPEFUNC:
+ CMangler_MangleQualifier(qual);
+ AppendGListByte(&name_mangle_list, 'F');
+ CMangler_MangleArgs(TYPE_FUNC(type)->args);
+ AppendGListByte(&name_mangle_list, '_');
+ CMangler_MangleTypeAppend(TYPE_FUNC(type)->functype, TYPE_FUNC(type)->qual);
+ break;
+ case TYPESTRUCT:
+ CMangler_MangleQualifier(qual);
+ switch (TYPE_STRUCT(type)->stype) {
+ case STRUCT_VECTOR_UCHAR:
+ AppendGListName(&name_mangle_list, "XUc");
+ return;
+ case STRUCT_VECTOR_SCHAR:
+ AppendGListName(&name_mangle_list, "Xc");
+ return;
+ case STRUCT_VECTOR_BCHAR:
+ AppendGListName(&name_mangle_list, "XC");
+ return;
+ case STRUCT_VECTOR_USHORT:
+ AppendGListName(&name_mangle_list, "XUs");
+ return;
+ case STRUCT_VECTOR_SSHORT:
+ AppendGListName(&name_mangle_list, "Xs");
+ return;
+ case STRUCT_VECTOR_BSHORT:
+ AppendGListName(&name_mangle_list, "XS");
+ return;
+ case STRUCT_VECTOR_UINT:
+ AppendGListName(&name_mangle_list, "XUi");
+ return;
+ case STRUCT_VECTOR_SINT:
+ AppendGListName(&name_mangle_list, "Xi");
+ return;
+ case STRUCT_VECTOR_BINT:
+ AppendGListName(&name_mangle_list, "XI");
+ return;
+ case STRUCT_VECTOR_FLOAT:
+ AppendGListName(&name_mangle_list, "Xf");
+ return;
+ case STRUCT_VECTOR_PIXEL:
+ AppendGListName(&name_mangle_list, "Xp");
+ return;
+ }
+
+ if (TYPE_STRUCT(type)->name && !IsTempName(TYPE_STRUCT(type)->name)) {
+ CMangler_MangleTypeName(TYPE_STRUCT(type)->name->name);
+ return;
+ }
+
+ switch (TYPE_STRUCT(type)->stype) {
+ case STRUCT_TYPE_STRUCT:
+ AppendGListName(&name_mangle_list, "struct");
+ break;
+ case STRUCT_TYPE_UNION:
+ AppendGListName(&name_mangle_list, "union");
+ break;
+ case STRUCT_TYPE_CLASS:
+ AppendGListName(&name_mangle_list, "class");
+ break;
+ default:
+ CError_FATAL(701);
+ }
+ break;
+
+ case TYPECLASS:
+ CMangler_MangleQualifier(qual);
+ CMangler_MangleClassName(TYPE_CLASS(type));
+ break;
+
+ case TYPETEMPLATE:
+ AppendGListName(&name_mangle_list, "1T");
+ break;
+
+ default:
+ CError_FATAL(716);
+ }
+}
+
+void CMangler_MangleType(Type *type, UInt32 qual) {
+ name_mangle_list.size = 0;
+ CMangler_MangleTypeAppend(type, qual);
+}
+
+static void CMangler_MangleArgs(FuncArg *args) {
+ TypePointer ptr;
+
+ if (args) {
+ if (args->type) {
+ while (args) {
+ if (args != &elipsis && args != &oldstyle) {
+ if (args->type->type == TYPEPOINTER) {
+ ptr = *TYPE_POINTER(args->type);
+ ptr.qual &= ~(Q_CONST | Q_VOLATILE);
+ CMangler_MangleTypeAppend(TYPE(&ptr), args->qual);
+ } else {
+ CMangler_MangleTypeAppend(args->type, 0);
+ }
+ } else {
+ AppendGListByte(&name_mangle_list, 'e');
+ }
+ args = args->next;
+ }
+ } else {
+ AppendGListByte(&name_mangle_list, 'e');
+ }
+ } else {
+ AppendGListByte(&name_mangle_list, 'v');
+ }
+}
+
+static void CMangler_MangleFunction(Object *obj, NameSpace *nspace) {
+ TypeFunc *tfunc = TYPE_FUNC(obj->type);
+ FuncArg *arg = tfunc->args;
+
+ AppendGListName(&name_mangle_list, obj->name->name);
+ if (obj->u.func.inst) {
+ if (tfunc->flags & FUNC_CONVERSION)
+ CMangler_MangleTypeAppend(tfunc->functype, tfunc->qual);
+ CMangler_AppendTemplateArgumentList(obj->u.func.inst->args);
+ }
+ AppendGListName(&name_mangle_list, "__");
+ while (nspace && nspace->name == NULL)
+ nspace = nspace->parent;
+
+ if (nspace) {
+ CMangler_MangleNameSpaceName(nspace->parent, nspace->name->name);
+ if (nspace->theclass) {
+ if (obj->name == destructor_name_node) {
+ AppendGListName(&name_mangle_list, "Fv");
+ return;
+ }
+ if (arg) {
+ if (obj->name == constructor_name_node) {
+ arg = arg->next;
+ if (arg && (nspace->theclass->flags & CLASS_HAS_VBASES))
+ arg = arg->next;
+ } else {
+ if ((tfunc->flags & FUNC_METHOD) && !TYPE_METHOD(tfunc)->is_static) {
+ CMangler_MangleQualifier(arg->qual);
+ arg = arg->next;
+ }
+ }
+ }
+ }
+ }
+
+ AppendGListByte(&name_mangle_list, 'F');
+ CMangler_MangleArgs(arg);
+ if (obj->u.func.inst && copts.new_mangler) {
+ AppendGListByte(&name_mangle_list, '_');
+ CMangler_MangleTypeAppend(tfunc->functype, tfunc->qual);
+ }
+}
+
+HashNameNode *CMangler_ConversionFuncName(Type *type, UInt32 qual) {
+ HashNameNode *name;
+
+ if (CTemplTool_IsTemplateArgumentDependentType(type))
+ return GetHashNameNodeExport("__op");
+
+ name_mangle_list.size = 0;
+ AppendGListName(&name_mangle_list, "__op");
+ CMangler_MangleTypeAppend(type, qual);
+ AppendGListByte(&name_mangle_list, 0);
+
+ COS_LockHandle(name_mangle_list.data);
+ name = GetHashNameNodeExport(*name_mangle_list.data);
+ COS_UnlockHandle(name_mangle_list.data);
+ return name;
+}
+
+static HashNameNode *CMangler_MangleNameToUpper(char *str) {
+ HashNameNode *name;
+
+ name_mangle_list.size = 0;
+ while (*str) {
+ AppendGListByte(&name_mangle_list, toupper(*(str++)));
+ }
+ AppendGListByte(&name_mangle_list, 0);
+
+ COS_LockHandle(name_mangle_list.data);
+ name = GetHashNameNodeExport(*name_mangle_list.data);
+ COS_UnlockHandle(name_mangle_list.data);
+ return name;
+}
+
+static HashNameNode *CMangler_FunctionLinkName(Object *obj) {
+ HashNameNode *name;
+ NameSpace *nspace;
+
+ if (obj->u.func.inst)
+ CMangler_CheckTemplateArguments(obj->u.func.inst->args);
+
+ for (nspace = obj->nspace; nspace; nspace = nspace->parent) {
+ if (nspace->name)
+ break;
+ }
+
+ name_mangle_list.size = 0;
+ if (is_pascal_object(obj) && (!nspace || !nspace->theclass)) {
+ AppendGListData(&name_mangle_list, "_", 1);
+ AppendGListID(&name_mangle_list, obj->name->name);
+ } else if ((obj->qual & Q_MANGLE_NAME) && (strcmp("main", obj->name->name) || (obj->nspace != cscope_root))) {
+ AppendGListData(&name_mangle_list, "_", 1);
+ CMangler_MangleFunction(obj, nspace);
+ AppendGListByte(&name_mangle_list, 0);
+ } else {
+ AppendGListData(&name_mangle_list, "_", 1);
+ AppendGListID(&name_mangle_list, obj->name->name);
+ }
+
+ COS_LockHandle(name_mangle_list.data);
+ name = GetHashNameNodeExport(*name_mangle_list.data);
+ COS_UnlockHandle(name_mangle_list.data);
+ return name;
+}
+
+HashNameNode *CMangler_GetCovariantFunctionName(Object *dobj, TypeClass *theclass) {
+ HashNameNode *name;
+
+ name = CMangler_GetLinkName(dobj);
+ name_mangle_list.size = 0;
+ AppendGListName(&name_mangle_list, name->name);
+ AppendGListName(&name_mangle_list, "@@");
+ CMangler_MangleTypeAppend(TYPE(theclass), 0);
+ AppendGListByte(&name_mangle_list, 0);
+
+ COS_LockHandle(name_mangle_list.data);
+ name = GetHashNameNodeExport(*name_mangle_list.data);
+ COS_UnlockHandle(name_mangle_list.data);
+ return name;
+}
+
+static HashNameNode *CMangler_DataLinkName(Object *obj) {
+ NameSpace *nspace;
+ HashNameNode *name;
+
+ nspace = obj->nspace;
+ while (nspace && nspace->name == NULL)
+ nspace = nspace->parent;
+
+ name_mangle_list.size = 0;
+ AppendGListData(&name_mangle_list, "_", 1);
+ AppendGListName(&name_mangle_list, obj->name->name);
+
+ while (nspace && nspace->name == NULL)
+ nspace = nspace->parent;
+ if (nspace && (obj->qual & Q_MANGLE_NAME)) {
+ AppendGListName(&name_mangle_list, "__");
+ CMangler_MangleNameSpaceName(nspace->parent, nspace->name->name);
+ }
+ AppendGListByte(&name_mangle_list, 0);
+
+ COS_LockHandle(name_mangle_list.data);
+ name = GetHashNameNodeExport(*name_mangle_list.data);
+ COS_UnlockHandle(name_mangle_list.data);
+ return name;
+}
+
+HashNameNode *CMangler_GetLinkName(Object *obj) {
+ while (obj->datatype == DALIAS)
+ obj = obj->u.alias.object;
+
+ switch (obj->datatype) {
+ case DFUNC:
+ case DVFUNC:
+ if (!obj->u.func.linkname)
+ obj->u.func.linkname = CMangler_FunctionLinkName(obj);
+ return obj->u.func.linkname;
+ case DDATA:
+ if (!obj->u.data.linkname)
+ obj->u.data.linkname = CMangler_DataLinkName(obj);
+ return obj->u.data.linkname;
+ case DINLINEFUNC:
+ return CMangler_FunctionLinkName(obj);
+ case DLOCAL:
+ case DABSOLUTE:
+ case DLABEL:
+ return obj->name;
+ case DNONLAZYPTR:
+ if (!obj->u.toc.linkname)
+ obj->u.toc.linkname = CMangler_DataLinkName(obj);
+ return obj->u.toc.linkname;
+ default:
+ CError_FATAL(1110);
+ return NULL;
+ }
+}
diff --git a/compiler_and_linker/FrontEnd/C/CParser.c b/compiler_and_linker/FrontEnd/C/CParser.c
new file mode 100644
index 0000000..b089e47
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CParser.c
@@ -0,0 +1,3477 @@
+#include "compiler/CParser.h"
+#include "compiler/CABI.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInit.h"
+#include "compiler/CInline.h"
+#include "compiler/CInt64.h"
+#include "compiler/CIRTransform.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CObjC.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CScope.h"
+#include "compiler/CSOM.h"
+#include "compiler/CTemplateNew.h"
+#include "compiler/CTemplateTools.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CompilerTools.h"
+#include "../Optimizer/IrOptimizer.h"
+#include "../Optimizer/IroPointerAnalysis.h"
+#include "compiler/ObjGenMachO.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/templates.h"
+#include "cos.h"
+
+FileOffsetInfo cparser_fileoffset;
+TStreamElement symdecltoken;
+ParserTryBlock *trychain;
+Boolean inassembler;
+Boolean dont_set_references;
+TypeStruct ptmstruct;
+TypeStruct catchinfostruct;
+Boolean in_assembler;
+Boolean illegalimplicitconversion;
+Boolean in_func_arglist;
+NameSpaceName *newp_fobj;
+NameSpaceName *newa_fobj;
+NameSpaceName *delp_fobj;
+NameSpaceName *dela_fobj;
+Object *newh_func;
+Object *delh_func;
+Object *copy_func;
+Object *clear_func;
+Object *Rgtid_func;
+Object *Rdync_func;
+Object *rt_ptmf_cast;
+Object *rt_ptmf_cmpr;
+Object *rt_ptmf_test;
+Object *rt_ptmf_call;
+Object *rt_ptmf_scall;
+Object *rt_ptmf_call4;
+Object *rt_ptmf_scall4;
+Object *rt_ptmf_null;
+Object *rt_som_new;
+Object *rt_som_newcheck;
+Object *rt_som_check;
+Object *rt_som_glue1;
+Object *rt_som_glue2;
+Object *rt_som_glue3;
+Object *carr_func;
+Object *cnar_func;
+Object *darr_func;
+Object *dnar_func;
+Object *dnar3_func;
+Object *Xgreg_func;
+Object *Xthrw_func;
+Object *Xicth_func;
+Object *Xecth_func;
+Object *Xunex_func;
+CompilerLinkerOptions copts;
+GList name_mangle_list;
+HashNameNode *no_name_node;
+HashNameNode *temp_argument_name;
+HashNameNode *this_name_node;
+HashNameNode *self_name_node;
+HashNameNode *vptr_name_node;
+CallbackAction *callbackactions;
+Boolean fatalerrors;
+Boolean anyerrors;
+jmp_buf errorreturn;
+static HashNameNode *uniquenamespacename;
+static SInt32 uniqueid;
+
+struct ClassAction {
+ struct ClassAction *next;
+ TypeClass *tclass;
+};
+static struct ClassAction *cparser_classactions;
+
+struct ParentCleanup {
+ struct ParentCleanup *next;
+ TypeClass *tclass;
+};
+static struct ParentCleanup *cparser_parentcleanup;
+
+struct SFuncList {
+ struct SFuncList *next;
+ Object *func;
+ Object *obj;
+ ENode *expr;
+};
+static struct SFuncList *cparser_sfunclist;
+
+char string[256];
+SInt32 compilererrornum;
+SInt32 compilererrfile;
+SInt32 compilererrline;
+
+Type sttemplexpr = {TYPETEMPLDEPEXPR, 0};
+Type stillegal = {TYPEILLEGAL, 1};
+Type stvoid = {TYPEVOID, 0};
+TypePointer void_ptr = {TYPEPOINTER, 0, &stvoid, 0};
+TypeFunc rt_func = {TYPEFUNC, 0, NULL, NULL, &stvoid, 0, 0};
+
+// forward declarations
+static void CParser_ParseDeclaration(DeclInfo *di);
+
+Object *CParser_NewRTFunc(Type *rettype, HashNameNode *name, Boolean flag, int argcount, ...) {
+ Object *obj;
+ FuncArg *args;
+ FuncArg *arg;
+ TypeFunc *tfunc;
+ va_list va;
+
+ args = NULL;
+ if (argcount) {
+ va_start(va, argcount);
+ while (--argcount >= 0) {
+ if (args) {
+ arg->next = CParser_NewFuncArg();
+ arg = arg->next;
+ } else {
+ arg = CParser_NewFuncArg();
+ args = arg;
+ }
+ arg->type = va_arg(va, Type *);
+ }
+ va_end(va);
+ }
+
+ obj = CParser_NewFunctionObject(NULL);
+
+ tfunc = galloc(sizeof(TypeFunc));
+ memclrw(tfunc, sizeof(TypeFunc));
+ tfunc->type = TYPEFUNC;
+ tfunc->functype = rettype;
+ tfunc->args = args;
+ CDecl_SetFuncFlags(tfunc, 0);
+
+ obj->name = name;
+ obj->type = TYPE(tfunc);
+ if (flag == 1)
+ obj->qual = Q_MANGLE_NAME;
+
+ return obj;
+}
+
+Boolean CParser_IsPublicRuntimeObject(Object *obj) {
+ if (newp_fobj->first.object == OBJ_BASE(obj) && !newp_fobj->first.next)
+ return 1;
+ if (newa_fobj->first.object == OBJ_BASE(obj) && !newa_fobj->first.next)
+ return 1;
+ if (delp_fobj->first.object == OBJ_BASE(obj) && !delp_fobj->first.next)
+ return 1;
+ if (dela_fobj->first.object == OBJ_BASE(obj) && !dela_fobj->first.next)
+ return 1;
+ return CodeGen_IsPublicRuntimeObject(obj);
+}
+
+Object *CParser_FindPublicRuntimeObject(HashNameNode *name) {
+ NameSpaceObjectList *list = CScope_FindName(cscope_root, name);
+ if (list && list->object->otype == OT_OBJECT && (!list->next || list->next->object->otype == OT_TYPETAG))
+ return OBJECT(list->object);
+ else
+ return NULL;
+}
+
+Boolean CParser_ReInitRuntimeObjects(Boolean is_precompiler) {
+ if (!(newp_fobj = CScope_FindNameSpaceName(cscope_root, CMangler_OperatorName(TK_NEW))))
+ return 0;
+ if (!(newa_fobj = CScope_FindNameSpaceName(cscope_root, CMangler_OperatorName(TK_NEW_ARRAY))))
+ return 0;
+ if (!(delp_fobj = CScope_FindNameSpaceName(cscope_root, CMangler_OperatorName(TK_DELETE))))
+ return 0;
+ if (!(dela_fobj = CScope_FindNameSpaceName(cscope_root, CMangler_OperatorName(TK_DELETE_ARRAY))))
+ return 0;
+
+ newh_func->name = GetHashNameNodeExport("__new_hdl");
+ delh_func->name = GetHashNameNodeExport("__del_hdl");
+ copy_func->name = GetHashNameNodeExport("__copy");
+ clear_func->name = GetHashNameNodeExport("__clear");
+ Rgtid_func->name = GetHashNameNodeExport("__get_typeid");
+ Rdync_func->name = GetHashNameNodeExport("__dynamic_cast");
+ rt_ptmf_cast->name = GetHashNameNodeExport("__ptmf_cast");
+ rt_ptmf_cmpr->name = GetHashNameNodeExport("__ptmf_cmpr");
+ rt_ptmf_test->name = GetHashNameNodeExport("__ptmf_test");
+ rt_ptmf_call->name = GetHashNameNodeExport("__ptmf_call");
+ rt_ptmf_scall->name = GetHashNameNodeExport("__ptmf_scall");
+ rt_ptmf_call4->name = GetHashNameNodeExport("__ptmf_call4");
+ rt_ptmf_scall4->name = GetHashNameNodeExport("__ptmf_scall4");
+ rt_ptmf_null->name = GetHashNameNodeExport("__ptmf_null");
+ rt_som_new->name = GetHashNameNodeExport("__som_new");
+ rt_som_newcheck->name = GetHashNameNodeExport("__som_check_new");
+ rt_som_check->name = GetHashNameNodeExport("__som_check_ev");
+ rt_som_glue1->name = GetHashNameNodeExport("_som_ptrgl4");
+ rt_som_glue2->name = GetHashNameNodeExport("_som_ptrgl5");
+ rt_som_glue3->name = GetHashNameNodeExport("_som_ptrgl_");
+ carr_func->name = GetHashNameNodeExport("__construct_array");
+ cnar_func->name = GetHashNameNodeExport("__construct_new_array");
+ darr_func->name = GetHashNameNodeExport("__destroy_arr");
+ dnar_func->name = GetHashNameNodeExport("__destroy_new_array");
+ dnar3_func->name = GetHashNameNodeExport("__destroy_new_array3");
+ Xgreg_func->name = GetHashNameNodeExport("__register_global_object");
+ Xthrw_func->name = GetHashNameNodeExport("__throw");
+ Xicth_func->name = GetHashNameNodeExport("__init__catch");
+ Xecth_func->name = GetHashNameNodeExport("__end__catch");
+ Xunex_func->name = GetHashNameNodeExport("__unexpected");
+
+ CMangler_Setup();
+
+ no_name_node = GetHashNameNodeExport("@no_name@");
+ temp_argument_name = GetHashNameNodeExport("@temp_ptr@");
+ this_name_node = GetHashNameNodeExport("this");
+ self_name_node = GetHashNameNodeExport("self");
+ vptr_name_node = GetHashNameNodeExport("__vptr$");
+
+ CSOM_Setup(is_precompiler);
+ return CodeGen_ReInitRuntimeObjects(is_precompiler);
+}
+
+static void CParser_SetupRuntimeObjects(void) {
+ ExceptSpecList *exspecs;
+ Type *sizet;
+ Object *func;
+
+ exspecs = galloc(sizeof(ExceptSpecList));
+ memclrw(exspecs, sizeof(ExceptSpecList));
+
+ sizet = CABI_GetSizeTType();
+
+ func = CParser_NewRTFunc(
+ TYPE(&void_ptr), CMangler_OperatorName(TK_NEW), 1,
+ 1, sizet);
+ CScope_AddGlobalObject(func);
+
+ func = CParser_NewRTFunc(
+ TYPE(&void_ptr), CMangler_OperatorName(TK_NEW_ARRAY), 1,
+ 1, sizet);
+ CScope_AddGlobalObject(func);
+
+ func = CParser_NewRTFunc(
+ TYPE(&stvoid), CMangler_OperatorName(TK_DELETE), 1,
+ 1, &void_ptr);
+ CError_ASSERT(379, IS_TYPE_FUNC(func->type));
+ TYPE_FUNC(func->type)->exspecs = exspecs;
+ CScope_AddGlobalObject(func);
+
+ func = CParser_NewRTFunc(
+ TYPE(&stvoid), CMangler_OperatorName(TK_DELETE_ARRAY), 1,
+ 1, &void_ptr);
+ CError_ASSERT(387, IS_TYPE_FUNC(func->type));
+ TYPE_FUNC(func->type)->exspecs = exspecs;
+ CScope_AddGlobalObject(func);
+
+ newh_func = CParser_NewRTFunc(
+ TYPE(&void_ptr), NULL, 0,
+ 1, sizet);
+ delh_func = CParser_NewRTFunc(
+ TYPE(&stvoid), NULL, 0,
+ 1, &void_ptr);
+
+ Rgtid_func = CParser_NewRTFunc(
+ TYPE(&void_ptr), NULL, 0,
+ 2, &void_ptr, &stsignedlong);
+ Rdync_func = CParser_NewRTFunc(
+ TYPE(&void_ptr), NULL, 0,
+ 5, &void_ptr, &stsignedlong, &void_ptr, &void_ptr, &stsignedshort);
+
+ copy_func = CParser_NewRTFunc(
+ TYPE(&void_ptr), NULL, 2,
+ 3, &void_ptr, &void_ptr, sizet);
+ clear_func = CParser_NewRTFunc(
+ TYPE(&void_ptr), NULL, 2,
+ 2, &void_ptr, sizet);
+
+ rt_ptmf_cast = CParser_NewRTFunc(
+ TYPE(&void_ptr), NULL, 2,
+ 3, &stsignedlong, &void_ptr, &void_ptr);
+ rt_ptmf_cmpr = CParser_NewRTFunc(
+ TYPE(&stsignedlong), NULL, 2,
+ 2, &void_ptr, &void_ptr);
+ rt_ptmf_test = CParser_NewRTFunc(
+ TYPE(&stsignedlong), NULL, 2,
+ 1, &void_ptr);
+
+ rt_ptmf_call = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
+ rt_ptmf_scall = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
+ rt_ptmf_call4 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
+ rt_ptmf_scall4 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
+
+ rt_ptmf_null = CParser_NewGlobalDataObject(NULL);
+ rt_ptmf_null->type = &stvoid;
+
+ rt_som_new = CParser_NewRTFunc(
+ TYPE(&void_ptr), NULL, 2,
+ 3, &void_ptr, &stsignedlong, &stsignedlong);
+ rt_som_newcheck = CParser_NewRTFunc(
+ TYPE(&stvoid), NULL, 0,
+ 1, &void_ptr);
+ rt_som_check = CParser_NewRTFunc(
+ TYPE(&stvoid), NULL, 0,
+ 1, &void_ptr);
+ rt_som_glue1 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
+ rt_som_glue2 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
+ rt_som_glue3 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0);
+
+ carr_func = CParser_NewRTFunc(
+ TYPE(&stvoid), NULL, 0,
+ 5, &void_ptr, &void_ptr, &void_ptr, sizet, sizet);
+ cnar_func = CParser_NewRTFunc(
+ TYPE(&void_ptr), NULL, 0,
+ 5, &void_ptr, &void_ptr, &void_ptr, sizet, sizet);
+ darr_func = CParser_NewRTFunc(
+ TYPE(&stvoid), NULL, 0,
+ 4, &void_ptr, &void_ptr, sizet, sizet);
+ dnar_func = CParser_NewRTFunc(
+ TYPE(&stvoid), NULL, 0,
+ 2, &void_ptr, &void_ptr);
+ dnar3_func = CParser_NewRTFunc(
+ TYPE(&stvoid), NULL, 0,
+ 4, &void_ptr, &void_ptr, &void_ptr, &stsignedshort);
+
+ Xgreg_func = CParser_NewRTFunc(
+ TYPE(&void_ptr), NULL, 0,
+ 3, &void_ptr, &void_ptr, &void_ptr);
+ Xthrw_func = CParser_NewRTFunc(
+ TYPE(&stvoid), NULL, 0,
+ 3, &void_ptr, &void_ptr, &void_ptr);
+ Xicth_func = CParser_NewRTFunc(
+ TYPE(&stvoid), NULL, 0,
+ 1, &void_ptr);
+ Xecth_func = CParser_NewRTFunc(
+ TYPE(&stvoid), NULL, 0,
+ 1, &void_ptr);
+ Xunex_func = CParser_NewRTFunc(
+ TYPE(&stvoid), NULL, 0,
+ 1, &void_ptr);
+
+ CodeGen_SetupRuntimeObjects();
+ CError_ASSERT(534, CParser_ReInitRuntimeObjects(0));
+}
+
+void CParser_Setup(void) {
+ CScope_Setup();
+
+ name_mangle_list.data = NULL;
+ if (InitGList(&name_mangle_list, 256))
+ CError_NoMem();
+
+ void_ptr.size = 4;
+ CError_Init();
+ CInit_Init();
+ CClass_Init();
+ CIRTrans_Setup();
+ CObjC_Setup();
+ CInline_Init();
+
+ in_assembler = 0;
+ in_func_arglist = 0;
+ CParser_SetUniqueID(1);
+ dont_set_references = 0;
+
+ copts.sideeffects = 1;
+ cparser_classactions = NULL;
+ name_obj_check = NULL;
+ callbackactions = NULL;
+ init_expressions = NULL;
+ cparser_sfunclist = NULL;
+ trychain = NULL;
+ cparser_parentcleanup = NULL;
+
+ memclrw(&cparser_fileoffset, sizeof(FileOffsetInfo));
+
+ memclrw(&catchinfostruct, sizeof(TypeStruct));
+ catchinfostruct.type = TYPESTRUCT;
+ catchinfostruct.size = 24;
+ catchinfostruct.stype = STRUCT_TYPE_STRUCT;
+ catchinfostruct.align = 4;
+
+ memclrw(&ptmstruct, sizeof(TypeStruct));
+ ptmstruct.type = TYPESTRUCT;
+ ptmstruct.size = 12;
+ ptmstruct.stype = STRUCT_TYPE_STRUCT;
+ ptmstruct.align = 4;
+
+ CMach_Configure();
+ CTempl_Setup();
+
+ uniquenamespacename = NULL;
+ disallowgreaterthan = 0;
+
+ CParser_SetupRuntimeObjects();
+}
+
+void CParser_Cleanup(void) {
+ CTempl_Cleanup();
+ CIRTrans_Cleanup();
+ CObjC_Cleanup();
+ CScope_Cleanup();
+ FreeGList(&name_mangle_list);
+}
+
+short GetPrec(short token) {
+ switch (token) {
+ case '%':
+ case '*':
+ case '/':
+ return 11;
+ case '+':
+ case '-':
+ return 10;
+ case TK_SHL:
+ case TK_SHR:
+ return 9;
+ case '<':
+ case '>':
+ case TK_LESS_EQUAL:
+ case TK_GREATER_EQUAL:
+ return 8;
+ case TK_LOGICAL_EQ:
+ case TK_LOGICAL_NE:
+ return 7;
+ case '&':
+ return 6;
+ case '^':
+ return 5;
+ case '|':
+ return 4;
+ case TK_LOGICAL_AND:
+ return 3;
+ case TK_LOGICAL_OR:
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+Boolean CParser_ParseOperatorName(short *token, Boolean flag1, Boolean flag2) {
+ HashNameNode *name;
+
+ switch ((tk = lex())) {
+ case TK_NEW:
+ case TK_DELETE:
+ if (lookahead() == '[') {
+ lex();
+ if (lex() != ']')
+ CError_Error(CErrorStr125);
+ //if (tk == TK_NEW)
+ // tk = TK_NEW_ARRAY;
+ //else
+ // tk = TK_DELETE_ARRAY;
+ tk = (tk == TK_NEW) ? TK_NEW_ARRAY : TK_DELETE_ARRAY;
+ }
+ break;
+ case '(':
+ if ((tk = lex()) != ')') {
+ CError_Error(CErrorStr204);
+ return 0;
+ }
+ tk = '(';
+ break;
+ case '[':
+ if ((tk = lex()) != ']') {
+ CError_Error(CErrorStr204);
+ return 0;
+ }
+ tk = '[';
+ break;
+ }
+
+ if ((name = CMangler_OperatorName(tk))) {
+ if (token)
+ *token = tk;
+ tk = lex();
+ tkidentifier = name;
+ return 1;
+ }
+
+ if (flag1) {
+ if (flag2) {
+ DeclInfo declinfo;
+ memclrw(&declinfo, sizeof(DeclInfo));
+ conversion_type_name(&declinfo);
+ tkidentifier = CMangler_ConversionFuncName(declinfo.thetype, declinfo.qual);
+ }
+ if (token)
+ *token = 0;
+ return 1;
+ } else {
+ CError_Error(CErrorStr204);
+ return 0;
+ }
+}
+
+SInt32 CParser_GetUniqueID(void) {
+ return uniqueid++;
+}
+
+void CParser_PrintUniqueID(char *buf) {
+ SInt32 id;
+ char mybuf[16];
+ char *ptr;
+
+ ptr = mybuf;
+ id = CParser_GetUniqueID();
+ while (id) {
+ *(ptr++) = '0' + (id - ((id / 10) * 10));
+ id = id / 10;
+ }
+
+ while (ptr > mybuf)
+ *(buf++) = *(--ptr);
+
+ *buf = 0;
+}
+
+void CParser_SetUniqueID(SInt32 id) {
+ uniqueid = id;
+}
+
+HashNameNode *CParser_GetUniqueName(void) {
+ char buf[20];
+ buf[0] = '@';
+ CParser_PrintUniqueID(buf + 1);
+ return GetHashNameNodeExport(buf);
+}
+
+HashNameNode *CParser_NameConcat(const char *a, const char *b) {
+ char mybuf[256];
+ char *buf;
+ char *dst;
+ int len;
+
+ len = strlen(a) + strlen(b);
+ if (len > (sizeof(mybuf) - 1)) {
+ buf = lalloc(len + 1);
+ dst = buf;
+ } else {
+ buf = mybuf;
+ dst = buf;
+ }
+
+ while (*a)
+ *(dst++) = *(a++);
+ while (*b)
+ *(dst++) = *(b++);
+ *dst = 0;
+
+ return GetHashNameNodeExport(buf);
+}
+
+HashNameNode *CParser_AppendUniqueName(char *prefix) {
+ char buf[256];
+ char *dst;
+ int i;
+
+ dst = buf;
+ for (i = 0; *prefix && i < 240; i++) {
+ *(dst++) = *(prefix++);
+ }
+ *(dst++) = '$';
+
+ CParser_PrintUniqueID(dst);
+ return GetHashNameNodeExport(buf);
+}
+
+HashNameNode *CParser_AppendUniqueNameFile(char *prefix) {
+ Str255 filename;
+ char buf[256];
+ char *src;
+ char *dst;
+ char c;
+ int i;
+ int j;
+ int len;
+
+ dst = buf;
+ for (i = 0; *prefix && i < 200; i++) {
+ *(dst++) = *(prefix++);
+ }
+ *(dst++) = '$';
+
+ CParser_PrintUniqueID(dst);
+
+ while (*dst) {
+ dst++;
+ i++;
+ }
+
+ COS_FileGetFSSpecInfo(&cparamblkptr->sourcefile, NULL, NULL, filename);
+ src = (char *) &filename[1];
+ len = filename[0];
+ for (j = 0; j < len && i < 255; j++, i++) {
+ c = *(src++);
+ if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9'))
+ c = '_';
+ *(dst++) = c;
+ }
+
+ dst[0] = 0;
+ return GetHashNameNodeExport(buf);
+}
+
+static HashNameNode *CParser_GetUnnamedNameSpaceName(void) {
+ Str255 filename;
+ char buf[256];
+ char *src;
+ char *dst;
+ char c;
+ int i;
+ int len;
+
+ if (!uniquenamespacename) {
+ strcpy(buf, "@unnamed@");
+ dst = buf + strlen(buf);
+
+ COS_FileGetFSSpecInfo(&cparamblkptr->sourcefile, NULL, NULL, filename);
+ src = (char *) &filename[1];
+ len = filename[0];
+ for (i = 0; i < len && dst < &buf[254]; i++) {
+ c = *(src++);
+ if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9'))
+ c = '_';
+ *(dst++) = c;
+ }
+
+ dst[0] = '@';
+ dst[1] = 0;
+ uniquenamespacename = GetHashNameNodeExport(buf);
+ }
+
+ return uniquenamespacename;
+}
+
+Boolean IsTempName(HashNameNode *name) {
+ return !name || (name->name[0] == '@') || (name->name[0] == '$');
+}
+
+static void CParser_SetCFMFlags(Object *object, DeclInfo *declinfo) {
+ if (declinfo && declinfo->exportflags)
+ object->flags |= declinfo->exportflags;
+
+ if (object->datatype == DDATA) {
+ if (copts.cfm_export)
+ object->flags = object->flags | OBJECT_EXPORT;
+ if (copts.cfm_internal)
+ object->flags = object->flags | OBJECT_INTERNAL;
+ } else if (copts.cfm_internal) {
+ object->flags = object->flags | OBJECT_INTERNAL;
+ } else {
+ if (copts.cfm_import)
+ object->flags = object->flags | OBJECT_IMPORT;
+ if (copts.cfm_export)
+ object->flags = object->flags | OBJECT_EXPORT;
+ if (copts.cfm_lib_export)
+ object->flags = object->flags | OBJECT_IMPORT | OBJECT_EXPORT;
+ }
+}
+
+void CParser_UpdateObject(Object *object, DeclInfo *declinfo) {
+ if (declinfo && declinfo->section)
+ object->section = declinfo->section;
+
+ CParser_SetCFMFlags(object, declinfo);
+ CodeGen_UpdateObject(object);
+}
+
+Object *CParser_NewObject(DeclInfo *declinfo) {
+ Object *object = galloc(sizeof(Object));
+ memclrw(object, sizeof(Object));
+ CParser_SetCFMFlags(object, declinfo);
+ object->otype = OT_OBJECT;
+ object->access = ACCESSPUBLIC;
+ object->section = SECT_DEFAULT;
+ return object;
+}
+
+Object *CParser_NewLocalDataObject(DeclInfo *declinfo, Boolean add_to_locals) {
+ Object *object = lalloc(sizeof(Object));
+ memclrw(object, sizeof(Object));
+ object->otype = OT_OBJECT;
+ object->access = ACCESSPUBLIC;
+ object->datatype = DLOCAL;
+
+ if (declinfo) {
+ object->type = declinfo->thetype;
+ object->name = declinfo->name;
+ object->qual = declinfo->qual;
+ object->sclass = declinfo->storageclass;
+ }
+
+ if (add_to_locals) {
+ ObjectList *list = lalloc(sizeof(ObjectList));
+ list->object = object;
+ list->next = locals;
+ locals = list;
+ }
+
+ return object;
+}
+
+Object *CParser_NewGlobalDataObject(DeclInfo *declinfo) {
+ Object *object = galloc(sizeof(Object));
+ memclrw(object, sizeof(Object));
+ object->otype = OT_OBJECT;
+ object->access = ACCESSPUBLIC;
+ object->section = SECT_DEFAULT;
+ object->datatype = DDATA;
+ object->nspace = cscope_current;
+
+ if (declinfo) {
+ object->type = declinfo->thetype;
+ object->name = declinfo->name;
+ object->qual = declinfo->qual;
+ object->sclass = declinfo->storageclass;
+ if (copts.cplusplus && !declinfo->is_extern_c)
+ object->qual |= Q_MANGLE_NAME;
+ }
+
+ CParser_UpdateObject(object, declinfo);
+ return object;
+}
+
+Object *CParser_NewCompilerDefDataObject(void) {
+ Object *object = galloc(sizeof(Object));
+ memclrw(object, sizeof(Object));
+ object->otype = OT_OBJECT;
+ object->access = ACCESSPUBLIC;
+ object->section = SECT_DEFAULT;
+ object->datatype = DDATA;
+ object->nspace = cscope_root;
+
+ return object;
+}
+
+Object *CParser_NewFunctionObject(DeclInfo *declinfo) {
+ Object *object = galloc(sizeof(Object));
+ memclrw(object, sizeof(Object));
+ object->otype = OT_OBJECT;
+ object->access = ACCESSPUBLIC;
+ object->section = SECT_DEFAULT;
+ object->datatype = DFUNC;
+ object->nspace = cscope_current;
+
+ if (declinfo) {
+ object->type = declinfo->thetype;
+ object->name = declinfo->name;
+ object->qual = declinfo->qual;
+ object->sclass = declinfo->storageclass;
+ if (copts.cplusplus && !declinfo->is_extern_c)
+ object->qual |= Q_MANGLE_NAME;
+ }
+
+ CParser_UpdateObject(object, declinfo);
+ return object;
+}
+
+Object *CParser_NewCompilerDefFunctionObject(void) {
+ Object *object = galloc(sizeof(Object));
+ memclrw(object, sizeof(Object));
+ object->otype = OT_OBJECT;
+ object->access = ACCESSPUBLIC;
+ object->section = SECT_DEFAULT;
+ object->datatype = DFUNC;
+ object->nspace = cscope_root;
+ return object;
+}
+
+Object *CParser_NewAliasObject(Object *object, SInt32 offset) {
+ Object *alias = galloc(sizeof(Object));
+ *alias = *object;
+ alias->datatype = DALIAS;
+ alias->u.alias.object = object;
+ alias->u.alias.member = NULL;
+ alias->u.alias.offset = offset;
+ CScope_AddObject(cscope_current, alias->name, OBJ_BASE(alias));
+ return alias;
+}
+
+FuncArg *CParser_NewFuncArg(void) {
+ FuncArg *arg = galloc(sizeof(FuncArg));
+ memclrw(arg, sizeof(FuncArg));
+ return arg;
+}
+
+Type *atomtype(void) {
+ switch (tksize) {
+ default:
+ CError_FATAL(1145);
+ case ATOM_VOID: return &stvoid;
+ case ATOM_CHAR: return TYPE(&stchar);
+ case ATOM_WCHAR: return TYPE(&stwchar);
+ case ATOM_UCHAR: return TYPE(&stunsignedchar);
+ case ATOM_SHORT: return TYPE(&stsignedshort);
+ case ATOM_USHORT: return TYPE(&stunsignedshort);
+ case ATOM_INT: return TYPE(&stsignedint);
+ case ATOM_UINT: return TYPE(&stunsignedint);
+ case ATOM_LONG: return TYPE(&stsignedlong);
+ case ATOM_ULONG: return TYPE(&stunsignedlong);
+ case ATOM_LONGLONG: return TYPE(&stsignedlonglong);
+ case ATOM_ULONGLONG: return TYPE(&stunsignedlonglong);
+ case ATOM_FLOAT: return TYPE(&stfloat);
+ case ATOM_SHORTDOUBLE: return TYPE(&stshortdouble);
+ case ATOM_DOUBLE: return TYPE(&stdouble);
+ case ATOM_LONGDOUBLE: return TYPE(&stlongdouble);
+ }
+}
+
+Object *CParser_FindDeallocationObject(Type *type, FuncArg *args, Boolean flag1, Boolean flag2, Boolean *outflag) {
+ NameSpaceObjectList *list;
+ NameSpaceObjectList *scan;
+ NameSpaceObjectList mylist;
+ NameResult pr;
+ Boolean first_time;
+ Boolean retry_flag;
+ Object *obj;
+ Type *sizet;
+
+ list = NULL;
+ *outflag = 0;
+ if (IS_TYPE_CLASS(type) && !flag2) {
+ HashNameNode *name;
+ name = (flag1 && copts.array_new_delete) ? dela_fobj->name : delp_fobj->name;
+ if (CScope_FindClassMemberObject(TYPE_CLASS(type), &pr, name)) {
+ if (pr.obj_10) {
+ mylist.next = NULL;
+ mylist.object = pr.obj_10;
+ list = &mylist;
+ } else {
+ CError_ASSERT(1202, pr.nsol_14);
+ list = pr.nsol_14;
+ }
+ } else if (TYPE_CLASS(type)->flags & CLASS_HANDLEOBJECT) {
+ CError_ASSERT(1210, !args && !flag1);
+ return delh_func;
+ }
+ }
+
+ first_time = 1;
+ retry_flag = flag1;
+ while (1) {
+ if (!args) {
+ for (scan = list; scan; scan = scan->next) {
+ obj = OBJECT(scan->object);
+ if (
+ obj->otype == OT_OBJECT &&
+ IS_TYPE_FUNC(obj->type) &&
+ TYPE_FUNC(obj->type)->args &&
+ !TYPE_FUNC(obj->type)->args->next &&
+ is_typesame(TYPE_FUNC(obj->type)->args->type, TYPE(&void_ptr))
+ )
+ return obj;
+ }
+
+ CError_ASSERT(1231, first_time);
+
+ sizet = CABI_GetSizeTType();
+ for (scan = list; scan; scan = scan->next) {
+ obj = OBJECT(scan->object);
+ if (
+ obj->otype == OT_OBJECT &&
+ IS_TYPE_FUNC(obj->type) &&
+ TYPE_FUNC(obj->type)->args &&
+ TYPE_FUNC(obj->type)->args->next &&
+ !TYPE_FUNC(obj->type)->args->next->next &&
+ is_typesame(TYPE_FUNC(obj->type)->args->type, TYPE(&void_ptr)) &&
+ TYPE_FUNC(obj->type)->args->next->type == sizet
+ ) {
+ *outflag = 1;
+ return obj;
+ }
+ }
+ } else {
+ for (scan = list; scan; scan = scan->next) {
+ obj = OBJECT(scan->object);
+ if (
+ obj->otype == OT_OBJECT &&
+ IS_TYPE_FUNC(obj->type) &&
+ TYPE_FUNC(obj->type)->args &&
+ TYPE_FUNC(obj->type)->args->next &&
+ is_arglistsame(TYPE_FUNC(obj->type)->args->next, args)
+ ) {
+ *outflag = 1;
+ return obj;
+ }
+ }
+
+ if (!first_time)
+ return NULL;
+ }
+
+ if (list)
+ CError_Warning(CErrorStr375, type, 0);
+
+ list = (retry_flag && copts.array_new_delete) ? &dela_fobj->first : &delp_fobj->first;
+ first_time = 0;
+ }
+}
+
+static Boolean oldstylecompatible(FuncArg *arg) {
+ if (copts.ignore_oldstyle)
+ return 1;
+
+ while (arg) {
+ if (arg == &elipsis)
+ return 0;
+ switch (arg->type->type) {
+ case TYPEINT:
+ if (TYPE_INTEGRAL(arg->type)->integral < IT_INT)
+ return 0;
+ break;
+ case TYPEFLOAT:
+ if (TYPE_INTEGRAL(arg->type)->integral < IT_DOUBLE)
+ return 0;
+ break;
+ }
+ arg = arg->next;
+ }
+
+ return 1;
+}
+
+static Boolean is_arglistequal(FuncArg *a, FuncArg *b) {
+ if (a == &oldstyle) {
+ if (b == &oldstyle)
+ return 1;
+ else
+ return oldstylecompatible(b);
+ } else {
+ if (b == &oldstyle)
+ return oldstylecompatible(a);
+ }
+
+ while (1) {
+ if (a == &elipsis || b == &elipsis)
+ return 1;
+
+ if (!a)
+ return !b;
+ if (!b)
+ return 0;
+
+ if (copts.mpwc_relax && !copts.cplusplus) {
+ if (!is_typeequal(a->type, b->type))
+ return 0;
+ } else {
+ if (!is_typesame(a->type, b->type))
+ return 0;
+ }
+
+ if (a->type->type == TYPEPOINTER && a->qual != b->qual)
+ return 0;
+
+ a = a->next;
+ b = b->next;
+ }
+}
+
+short is_memberpointerequal(Type *a, Type *b) {
+ FuncArg *arg_a;
+ FuncArg *arg_b;
+
+ if (a->type != b->type)
+ return 0;
+ if (!IS_TYPE_FUNC(a))
+ return is_typeequal(a, b);
+
+ if (!is_typesame(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype))
+ return 0;
+
+ if ((TYPE_FUNC(a)->flags & FUNC_CALL_CONV_MASK) != (TYPE_FUNC(b)->flags & FUNC_CALL_CONV_MASK))
+ return 0;
+
+ CError_ASSERT(1345, arg_a = TYPE_FUNC(a)->args);
+ CError_ASSERT(1346, arg_b = TYPE_FUNC(b)->args);
+
+ if (TYPE_FUNC(a)->flags & FUNC_FLAGS_80)
+ CError_ASSERT(1351, arg_a = arg_a->next);
+
+ if (TYPE_FUNC(b)->flags & FUNC_FLAGS_80)
+ CError_ASSERT(1355, arg_b = arg_b->next);
+
+ if (arg_a->qual != arg_b->qual)
+ return 0;
+
+ return is_arglistsame(arg_a->next, arg_b->next);
+}
+
+short is_typeequal(Type *a, Type *b) {
+restart:
+ if (a->type != b->type)
+ return 0;
+ switch (a->type) {
+ case TYPEVOID:
+ return 1;
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPECLASS:
+ return a == b;
+ case TYPESTRUCT:
+ return a == b;
+ case TYPEPOINTER:
+ if (TYPE_POINTER(a)->target == &stvoid || TYPE_POINTER(b)->target == &stvoid)
+ return 1;
+ a = TYPE_POINTER(a)->target;
+ b = TYPE_POINTER(b)->target;
+ if (copts.mpwc_relax && !copts.cplusplus)
+ return 1;
+ goto restart;
+ case TYPEMEMBERPOINTER:
+ if (TYPE_MEMBER_POINTER(a)->ty2 != TYPE_MEMBER_POINTER(b)->ty2)
+ return 0;
+ return is_memberpointerequal(TYPE_MEMBER_POINTER(a)->ty1, TYPE_MEMBER_POINTER(b)->ty1);
+ case TYPEARRAY:
+ if (a->size && b->size && a->size != b->size)
+ return 0;
+ a = TYPE_POINTER(a)->target;
+ b = TYPE_POINTER(b)->target;
+ goto restart;
+ case TYPEFUNC:
+ if (copts.cplusplus || !copts.cpp_extensions) {
+ if (copts.mpwc_relax && !copts.cplusplus) {
+ if (!is_typeequal(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype))
+ return 0;
+ } else {
+ if (!is_typesame(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype))
+ return 0;
+ }
+ if ((TYPE_FUNC(a)->flags & FUNC_CALL_CONV_MASK) != (TYPE_FUNC(b)->flags & FUNC_CALL_CONV_MASK))
+ return 0;
+ }
+ return is_arglistequal(TYPE_FUNC(a)->args, TYPE_FUNC(b)->args);
+ case TYPETEMPLATE:
+ return CTemplTool_TemplDepTypeCompare(TYPE_TEMPLATE(a), TYPE_TEMPLATE(b));
+ default:
+ CError_FATAL(1441);
+ return 0;
+ }
+}
+
+short iscpp_typeequal(Type *a, Type *b) {
+ restart:
+ if (a->type != b->type)
+ return 0;
+ switch (a->type) {
+ case TYPEVOID:
+ return 1;
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPECLASS:
+ return a == b;
+ case TYPESTRUCT:
+ return a == b;
+ case TYPEPOINTER:
+ if (TYPE_POINTER(b)->target == &stvoid) {
+ if (TYPE_POINTER(a)->target == &stvoid)
+ return 1;
+ else
+ return -1;
+ }
+ if (TYPE_POINTER(a)->target == &stvoid) {
+ illegalimplicitconversion = 1;
+ return 0;
+ }
+ a = TYPE_POINTER(a)->target;
+ b = TYPE_POINTER(b)->target;
+ goto restart;
+ case TYPEMEMBERPOINTER:
+ if (TYPE_MEMBER_POINTER(a)->ty2 != TYPE_MEMBER_POINTER(b)->ty2)
+ return 0;
+ return is_memberpointerequal(TYPE_MEMBER_POINTER(a)->ty1, TYPE_MEMBER_POINTER(b)->ty1);
+ case TYPEARRAY:
+ if (a->size && b->size && a->size != b->size)
+ return 0;
+ a = TYPE_POINTER(a)->target;
+ b = TYPE_POINTER(b)->target;
+ goto restart;
+ case TYPEFUNC:
+ if (!is_typesame(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype))
+ return 0;
+ if ((TYPE_FUNC(a)->flags & FUNC_CALL_CONV_MASK) != (TYPE_FUNC(b)->flags & FUNC_CALL_CONV_MASK))
+ return 0;
+ return is_arglistequal(TYPE_FUNC(a)->args, TYPE_FUNC(b)->args);
+ case TYPETEMPLATE:
+ return CTemplTool_TemplDepTypeCompare(TYPE_TEMPLATE(a), TYPE_TEMPLATE(b));
+ default:
+ CError_FATAL(1500);
+ return 0;
+ }
+}
+
+short CParser_CompareArgLists(FuncArg *a, FuncArg *b) {
+ Boolean r30;
+
+ r30 = 0;
+ if (a == &oldstyle) {
+ if (b == &oldstyle)
+ return 1;
+ else
+ return 2;
+ }
+ if (b == &oldstyle)
+ return 2;
+
+ while (1) {
+ if (a == &elipsis) {
+ if (b != &elipsis)
+ return 0;
+ break;
+ }
+ if (b == &elipsis)
+ return 0;
+
+ if (a == NULL) {
+ if (b)
+ return 0;
+ break;
+ }
+ if (b == NULL)
+ return 0;
+
+ if (a->type->type == TYPEPOINTER) {
+ if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(a->type))) {
+ if (IS_TYPE_REFERENCE(b->type)) {
+ if (!is_typesame(TYPE_POINTER(a->type)->target, TYPE_POINTER(b->type)->target))
+ return 0;
+ if ((a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE)))
+ return 0;
+ } else {
+ if (!copts.old_argmatch)
+ return 0;
+ if (!is_typesame(TYPE_POINTER(a->type)->target, b->type))
+ return 0;
+ if (b->type->type == TYPEPOINTER && (a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE)))
+ return 0;
+ r30 = 1;
+ }
+ } else {
+ if (b->type->type == TYPEPOINTER) {
+ if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(b->type))) {
+ if (!copts.old_argmatch)
+ return 0;
+ if (!is_typesame(a->type, TYPE_POINTER(b->type)->target))
+ return 0;
+ if (a->type->type == TYPEPOINTER && (a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE)))
+ return 0;
+ r30 = 1;
+ } else {
+ if (!is_typesame(TYPE_POINTER(a->type)->target, TYPE_POINTER(b->type)->target))
+ return 0;
+ if ((a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE)))
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+ } else {
+ if (b->type->type == TYPEPOINTER) {
+ if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(b->type))) {
+ if (!copts.old_argmatch)
+ return 0;
+ if (!is_typesame(a->type, TYPE_POINTER(b->type)->target))
+ return 0;
+ r30 = 1;
+ } else {
+ return 0;
+ }
+ } else {
+ if (!is_typesame(a->type, b->type))
+ return 0;
+ }
+ }
+
+ a = a->next;
+ b = b->next;
+ }
+
+ if (r30)
+ return 2;
+ return 1;
+}
+
+Boolean is_arglistsame(FuncArg *a, FuncArg *b) {
+ if (a == &oldstyle) {
+ if (b == &oldstyle)
+ return 1;
+ else
+ return oldstylecompatible(b);
+ } else {
+ if (b == &oldstyle)
+ return oldstylecompatible(a);
+ }
+
+ while (1) {
+ if (!a || !b || a == &elipsis || b == &elipsis)
+ return a == b;
+
+ if (a->type->type == TYPEPOINTER) {
+ if (b->type->type != TYPEPOINTER ||
+ (a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE)) ||
+ !is_typesame(TYPE_POINTER(a->type)->target, TYPE_POINTER(b->type)->target) ||
+ IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(a->type)) != IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(b->type)))
+ return 0;
+ } else {
+ if (!is_typesame(a->type, b->type))
+ return 0;
+ }
+
+ a = a->next;
+ b = b->next;
+ }
+}
+
+short is_typesame(Type *a, Type *b) {
+restart:
+ if (a->type != b->type) {
+ if (IS_TYPE_TEMPLATE(a) && IS_TYPE_CLASS(b) && (TYPE_CLASS(b)->flags & CLASS_IS_TEMPL))
+ return CTemplTool_IsSameTemplateType(b, a);
+ if (IS_TYPE_TEMPLATE(b) && IS_TYPE_CLASS(a) && (TYPE_CLASS(a)->flags & CLASS_IS_TEMPL))
+ return CTemplTool_IsSameTemplateType(a, b);
+ return 0;
+ }
+
+ switch (a->type) {
+ case TYPEVOID:
+ return 1;
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPECLASS:
+ return a == b;
+ case TYPETEMPLATE:
+ return CTemplTool_TemplDepTypeCompare(TYPE_TEMPLATE(a), TYPE_TEMPLATE(b));
+ case TYPESTRUCT:
+ return a == b;
+ case TYPEPOINTER:
+ if ((TYPE_POINTER(a)->qual & (Q_RESTRICT | Q_REFERENCE | Q_CONST | Q_VOLATILE)) != (TYPE_POINTER(b)->qual & (Q_RESTRICT | Q_REFERENCE | Q_CONST | Q_VOLATILE)))
+ return 0;
+ a = TYPE_POINTER(a)->target;
+ b = TYPE_POINTER(b)->target;
+ goto restart;
+ case TYPEMEMBERPOINTER:
+ if (!is_typesame(TYPE_MEMBER_POINTER(a)->ty2, TYPE_MEMBER_POINTER(b)->ty2))
+ return 0;
+ if ((TYPE_MEMBER_POINTER(a)->qual & (Q_RESTRICT | Q_REFERENCE | Q_CONST | Q_VOLATILE)) != (TYPE_MEMBER_POINTER(b)->qual & (Q_RESTRICT | Q_REFERENCE | Q_CONST | Q_VOLATILE)))
+ return 0;
+ return is_memberpointerequal(TYPE_MEMBER_POINTER(a)->ty1, TYPE_MEMBER_POINTER(b)->ty1);
+ case TYPEARRAY:
+ if (a->size != b->size)
+ return 0;
+ a = TYPE_POINTER(a)->target;
+ b = TYPE_POINTER(b)->target;
+ goto restart;
+ case TYPEFUNC:
+ if (!is_typesame(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype))
+ return 0;
+ if (TYPE_FUNC(a)->qual != TYPE_FUNC(b)->qual)
+ return 0;
+ if ((TYPE_FUNC(a)->flags & FUNC_CALL_CONV_MASK) != (TYPE_FUNC(b)->flags & FUNC_CALL_CONV_MASK))
+ return 0;
+ return is_arglistsame(TYPE_FUNC(a)->args, TYPE_FUNC(b)->args);
+ default:
+ CError_FATAL(1709);
+ return 0;
+ }
+}
+
+Type *CParser_GetBoolType(void) {
+ if (copts.cplusplus && copts.booltruefalse)
+ return TYPE(&stbool);
+ else
+ return TYPE(&stsignedint);
+}
+
+Type *CParser_GetWCharType(void) {
+ if (copts.cplusplus && copts.wchar_type)
+ return TYPE(&stwchar);
+ else
+ return TYPE(&stsignedint);
+}
+
+short CParser_GetOperator(ENodeType t) {
+ switch (t) {
+ default:
+ CError_FATAL(1748);
+ case EMONMIN: return '-';
+ case EBINNOT: return '~';
+ case ELOGNOT: return '!';
+ case EADD: return '+';
+ case ESUB: return '-';
+ case EMUL: return '*';
+ case EDIV: return '/';
+ case EMODULO: return '%';
+ case EAND: return '&';
+ case EXOR: return '^';
+ case EOR: return '|';
+ case ESHL: return TK_SHL;
+ case ESHR: return TK_SHR;
+ case ELESS: return '<';
+ case EGREATER: return '>';
+ case ELESSEQU: return TK_LESS_EQUAL;
+ case EGREATEREQU: return TK_GREATER_EQUAL;
+ case EEQU: return TK_LOGICAL_EQ;
+ case ENOTEQU: return TK_LOGICAL_NE;
+ }
+}
+
+Boolean CParser_IsMoreCVQualified(UInt32 a, UInt32 b) {
+ if ((a & Q_CONST) && !(b & Q_CONST)) {
+ return ((a & Q_VOLATILE) || !(b & Q_VOLATILE));
+ } else if ((a & Q_VOLATILE) && !(b & Q_VOLATILE)) {
+ return ((a & Q_CONST) || !(b & Q_CONST));
+ }
+ return 0;
+}
+
+Boolean CParser_IsSameOrMoreCVQualified(UInt32 a, UInt32 b) {
+ if ((a & (Q_CONST | Q_VOLATILE)) == (b & (Q_CONST | Q_VOLATILE)))
+ return 1;
+
+ if ((a & Q_CONST) && !(b & Q_CONST)) {
+ return ((a & Q_VOLATILE) || !(b & Q_VOLATILE));
+ } else if ((a & Q_VOLATILE) && !(b & Q_VOLATILE)) {
+ return ((a & Q_CONST) || !(b & Q_CONST));
+ }
+ return 0;
+}
+
+Boolean is_unsigned(Type *type) {
+ if (IS_TYPE_ENUM(type))
+ type = TYPE_ENUM(type)->enumtype;
+
+ if (
+ (type == TYPE(&stunsignedchar)) ||
+ (type == TYPE(&stunsignedshort)) ||
+ (type == TYPE(&stunsignedint)) ||
+ (type == TYPE(&stunsignedlong)) ||
+ (type == TYPE(&stunsignedlonglong)) ||
+ (type == TYPE(&stbool)) ||
+ (copts.unsigned_char && (type == TYPE(&stchar))) ||
+ (type->type == TYPEPOINTER))
+ return 1;
+
+ return 0;
+}
+
+StructMember *ismember(TypeStruct *tstruct, HashNameNode *name) {
+ StructMember *member;
+
+ for (member = tstruct->members; member; member = member->next) {
+ if (member->name == name)
+ return member;
+ }
+
+ return NULL;
+}
+
+void appendmember(TypeStruct *tstruct, StructMember *member) {
+ StructMember *last;
+
+ if (!tstruct->members) {
+ tstruct->members = member;
+ return;
+ }
+
+ for (last = tstruct->members; last->next; last = last->next) {}
+ last->next = member;
+}
+
+static void CParser_InsertTryBlock(ParserTryBlock *block) {
+ block->cscope_current = cscope_current;
+ block->cscope_currentclass = cscope_currentclass;
+ block->cscope_currentfunc = cscope_currentfunc;
+ block->ctempl_curinstance = ctempl_curinstance;
+ block->cerror_locktoken = cerror_locktoken;
+ block->cscope_is_member_func = cscope_is_member_func;
+ block->next = trychain;
+ trychain = block;
+}
+
+static void CParser_RemoveTryBlock(ParserTryBlock *block) {
+ cscope_current = block->cscope_current;
+ cscope_currentclass = block->cscope_currentclass;
+ cscope_currentfunc = block->cscope_currentfunc;
+ ctempl_curinstance = block->ctempl_curinstance;
+ cerror_locktoken = block->cerror_locktoken;
+ cscope_is_member_func = block->cscope_is_member_func;
+ trychain = block->next;
+}
+
+static Boolean TryIsDeclaration(Boolean flag1, Boolean flag2, Boolean flag3, short token) {
+ Boolean result;
+ DeclInfo declinfo;
+ struct ParserTryBlock tryblock;
+
+ switch (tk) {
+ case TK_IDENTIFIER:
+ case TK_COLON_COLON:
+ break;
+ case TK_VOID:
+ case TK_CHAR:
+ case TK_SHORT:
+ case TK_INT:
+ case TK_LONG:
+ case TK_FLOAT:
+ case TK_DOUBLE:
+ case TK_SIGNED:
+ case TK_UNSIGNED:
+ case TK_UNK_113:
+ case TK_UNK_114:
+ case TK_UNK_115:
+ case TK_UNK_116:
+ case TK_UNK_117:
+ case TK_UNK_118:
+ case TK_UNK_119:
+ case TK_UNK_11A:
+ case TK_BOOL:
+ case TK_WCHAR_T:
+ if (lookahead() != '(')
+ return 1;
+ break;
+ default:
+ return 1;
+ }
+
+ result = 0;
+ CParser_InsertTryBlock(&tryblock);
+ if (setjmp(tryblock.jmpbuf) == 0) {
+ memclrw(&declinfo, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(&declinfo, 0);
+ if (!(IS_TYPE_TEMPLATE(declinfo.thetype) && TYPE_TEMPLATE(declinfo.thetype)->dtype == TEMPLDEP_QUALNAME && !declinfo.x53 && !declinfo.x49)) {
+ if (flag1) {
+ declinfo.x46 = flag3;
+ scandeclarator(&declinfo);
+ if (!(flag2 && declinfo.name)) {
+ if (!token) {
+ if (tk == ';' || tk == ',' || tk == '=' || tk == '(' || tk == ')' || tk == '>')
+ result = 1;
+ } else {
+ result = (tk == token);
+ }
+ }
+ } else {
+ result = 1;
+ }
+ }
+ }
+
+ CParser_RemoveTryBlock(&tryblock);
+ return result;
+}
+
+Boolean isdeclaration(UInt8 flag1, UInt8 flag2, UInt8 flag3, short token) {
+ SInt32 state;
+
+ if (!(tk >= TK_AUTO && tk <= TK_BYREF) && tk != TK_COLON_COLON && !(tk == TK_IDENTIFIER && CScope_PossibleTypeName(tkidentifier))) {
+ if (!(tk == TK_IDENTIFIER && copts.altivec_model && !strcmp(tkidentifier->name, "vector")))
+ return 0;
+ } else {
+ if (!copts.cplusplus)
+ return 1;
+ }
+
+ CPrep_TokenStreamGetState(&state);
+ if (TryIsDeclaration(flag1, flag2, flag3, token)) {
+ CPrep_TokenStreamSetCurState(&state);
+ return 1;
+ } else {
+ CPrep_TokenStreamSetCurState(&state);
+ return 0;
+ }
+}
+
+Boolean islookaheaddeclaration(void) {
+ SInt32 state;
+
+ CPrep_TokenStreamGetState(&state);
+ tk = lex();
+ if (!(tk >= TK_AUTO && tk <= TK_BYREF) && tk != TK_COLON_COLON && !(tk == TK_IDENTIFIER && CScope_PossibleTypeName(tkidentifier))) {
+ if (!(tk == TK_IDENTIFIER && copts.altivec_model && !strcmp(tkidentifier->name, "vector"))) {
+ CPrep_TokenStreamSetCurState(&state);
+ return 0;
+ }
+ } else {
+ if (!copts.cplusplus) {
+ CPrep_TokenStreamSetCurState(&state);
+ return 1;
+ }
+ }
+
+ if (TryIsDeclaration(1, 1, 0, ')')) {
+ CPrep_TokenStreamSetCurState(&state);
+ return 1;
+ } else {
+ CPrep_TokenStreamSetCurState(&state);
+ return 0;
+ }
+}
+
+Type *CParser_ParseTypeID(UInt32 *qual, Boolean *flag) {
+ SInt32 state;
+ DeclInfo di;
+ struct ParserTryBlock tryblock;
+
+ memclrw(&di, sizeof(DeclInfo));
+ CPrep_TokenStreamGetState(&state);
+ CParser_InsertTryBlock(&tryblock);
+
+ if (setjmp(tryblock.jmpbuf) == 0) {
+ if (copts.cplusplus)
+ di.x55 = 1;
+
+ if (flag) {
+ di.x56 = 1;
+ *flag = 0;
+ }
+
+ CParser_GetDeclSpecs(&di, 0);
+ if (di.x57 && IS_TYPE_CLASS(di.thetype) && (TYPE_CLASS(di.thetype)->flags & CLASS_IS_TEMPL)) {
+ CParser_RemoveTryBlock(&tryblock);
+ *qual = di.qual;
+ *flag = 1;
+ return di.thetype;
+ }
+
+ if (flag && IS_TYPE_TEMPLATE(di.thetype) && TYPE_TEMPLATE(di.thetype)->dtype == TEMPLDEP_ARGUMENT &&
+ TYPE_TEMPLATE(di.thetype)->u.pid.type == TPT_TEMPLATE) {
+ CParser_RemoveTryBlock(&tryblock);
+ *qual = di.qual;
+ *flag = 1;
+ return di.thetype;
+ }
+
+ scandeclarator(&di);
+ if (!di.name) {
+ CParser_RemoveTryBlock(&tryblock);
+ *qual = di.qual;
+ return di.thetype;
+ }
+ }
+
+ CPrep_TokenStreamSetCurState(&state);
+ CParser_RemoveTryBlock(&tryblock);
+ return 0;
+}
+
+Boolean CParser_TryFuncDecl(void) {
+ Boolean result;
+ SInt32 state;
+ DeclInfo di;
+ struct ParserTryBlock tryblock;
+
+ result = 0;
+ CPrep_TokenStreamGetState(&state);
+ CParser_InsertTryBlock(&tryblock);
+
+ if (setjmp(tryblock.jmpbuf) == 0) {
+ memclrw(&di, sizeof(DeclInfo));
+ di.thetype = &stvoid;
+ scandeclarator(&di);
+
+ if (IS_TYPE_FUNC(di.thetype))
+ result = 1;
+ }
+
+ CParser_RemoveTryBlock(&tryblock);
+ CPrep_TokenStreamSetCurState(&state);
+ return result;
+}
+
+Boolean CParser_TryParamList(Boolean flag) {
+ Boolean result;
+ SInt32 state;
+ struct ParserTryBlock tryblock;
+
+ result = 0;
+ CPrep_TokenStreamGetState(&state);
+
+ switch ((tk = lex())) {
+ case ')':
+ case TK_ELLIPSIS:
+ result = 1;
+ break;
+ default:
+ CParser_InsertTryBlock(&tryblock);
+ if (setjmp(tryblock.jmpbuf) == 0) {
+ if (CFunc_ParseFakeArgList(flag) || tk == ')')
+ result = 1;
+ }
+ CParser_RemoveTryBlock(&tryblock);
+ break;
+ }
+
+ CPrep_TokenStreamSetCurState(&state);
+ return result;
+}
+
+Type *CParser_RemoveTopMostQualifiers(Type *type, UInt32 *qual) {
+ switch (type->type) {
+ case TYPEARRAY:
+ TYPE_POINTER(type)->target = CParser_RemoveTopMostQualifiers(TYPE_POINTER(type)->target, qual);
+ return type;
+ case TYPEPOINTER:
+ if (TYPE_POINTER(type)->qual & Q_CONST) {
+ TypePointer *newtype = galloc(sizeof(TypePointer));
+ *newtype = *TYPE_POINTER(type);
+ newtype->qual = 0;
+ return TYPE(newtype);
+ }
+ return type;
+ case TYPEMEMBERPOINTER:
+ if (TYPE_MEMBER_POINTER(type)->qual & Q_CONST) {
+ TypeMemberPointer *newtype = galloc(sizeof(TypeMemberPointer));
+ *newtype = *TYPE_MEMBER_POINTER(type);
+ newtype->qual = 0;
+ return TYPE(newtype);
+ }
+ return type;
+ default:
+ *qual = 0;
+ return type;
+ }
+}
+
+UInt32 CParser_GetTypeQualifiers(Type *type, UInt32 qual) {
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+
+ switch (type->type) {
+ case TYPEPOINTER:
+ qual = TYPE_POINTER(type)->qual;
+ break;
+ case TYPEMEMBERPOINTER:
+ qual = TYPE_MEMBER_POINTER(type)->qual;
+ break;
+ }
+
+ return qual;
+}
+
+UInt32 CParser_GetCVTypeQualifiers(Type *type, UInt32 qual) {
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+
+ switch (type->type) {
+ case TYPEPOINTER:
+ qual = TYPE_POINTER(type)->qual;
+ break;
+ case TYPEMEMBERPOINTER:
+ qual = TYPE_MEMBER_POINTER(type)->qual;
+ break;
+ }
+
+ return qual & (Q_CONST | Q_VOLATILE);
+}
+
+Boolean CParser_IsConst(Type *type, UInt32 qual) {
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+
+ switch (type->type) {
+ case TYPEPOINTER:
+ qual = TYPE_POINTER(type)->qual;
+ break;
+ case TYPEMEMBERPOINTER:
+ qual = TYPE_MEMBER_POINTER(type)->qual;
+ break;
+ }
+
+ return (qual & Q_CONST) != 0;
+}
+
+Boolean CParser_IsVolatile(Type *type, UInt32 qual) {
+ while (IS_TYPE_ARRAY(type))
+ type = TYPE_POINTER(type)->target;
+
+ switch (type->type) {
+ case TYPEPOINTER:
+ qual = TYPE_POINTER(type)->qual;
+ break;
+ case TYPEMEMBERPOINTER:
+ qual = TYPE_MEMBER_POINTER(type)->qual;
+ break;
+ }
+
+ return (qual & Q_VOLATILE) != 0;
+}
+
+Boolean is_const_object(Object *obj) {
+ return CParser_IsConst(obj->type, obj->qual);
+}
+
+Boolean is_volatile_object(Object *obj) {
+ return CParser_IsVolatile(obj->type, obj->qual);
+}
+
+Boolean CParserIsConstExpr(ENode *expr) {
+ return CParser_IsConst(expr->rtype, expr->flags & ENODE_FLAG_QUALS);
+}
+
+Boolean CParserIsVolatileExpr(ENode *expr) {
+ return CParser_IsVolatile(expr->rtype, expr->flags & ENODE_FLAG_QUALS);
+}
+
+Boolean CParser_HasInternalLinkage(const Object *obj) {
+ NameSpace *nspace;
+
+ for (nspace = obj->nspace; nspace; nspace = nspace->parent) {
+ if (nspace->is_unnamed)
+ return 1;
+ }
+
+ if (obj->datatype == DLOCAL)
+ return 1;
+ if (obj->qual & (Q_20000 | Q_WEAK))
+ return 0;
+ if (obj->sclass == TK_STATIC)
+ return 1;
+
+ // this feels *wrong* but it's the only way to match this function that I can see
+ if (obj->qual & Q_INLINE)
+ ((Object *) obj)->qual |= Q_20000;
+ return 0;
+}
+
+Boolean CParser_HasInternalLinkage2(const Object *obj) {
+ if (obj->datatype == DLOCAL)
+ return 1;
+ if (obj->qual & (Q_20000 | Q_WEAK))
+ return 0;
+ if (obj->sclass == TK_STATIC)
+ return 1;
+
+ // this feels *wrong* but it's the only way to match this function that I can see
+ if (obj->qual & Q_INLINE)
+ ((Object *) obj)->qual |= Q_20000;
+ return 0;
+}
+
+Boolean CParser_IsVirtualFunction(Object *obj, TypeClass **tclass, SInt32 *index) {
+ if (obj->datatype == DVFUNC) {
+ *tclass = TYPE_METHOD(obj->type)->theclass;
+ *index = TYPE_METHOD(obj->type)->vtbl_index;
+ return 1;
+ }
+
+ return 0;
+}
+
+Boolean is_pascal_object(Object *obj) {
+ return IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_PASCAL);
+}
+
+Boolean is_cfm_type(Type *type) {
+ return 0;
+}
+
+Boolean CParser_IsVTableObject(Object *obj) {
+ return
+ obj->datatype == DDATA &&
+ obj->nspace &&
+ obj->nspace->theclass &&
+ obj->nspace->theclass->vtable &&
+ obj->nspace->theclass->vtable->object == obj;
+}
+
+static Type *getthetype(short token, short size, short signedness) {
+ switch (token) {
+ case 0:
+ case TK_INT:
+ if (signedness == 1) {
+ switch (size) {
+ case 1: return TYPE(&stunsignedshort);
+ case 2: return TYPE(&stunsignedlong);
+ case 3: return TYPE(&stunsignedlonglong);
+ default: return TYPE(&stunsignedint);
+ }
+ } else {
+ switch (size) {
+ case 1: return TYPE(&stsignedshort);
+ case 2: return TYPE(&stsignedlong);
+ case 3: return TYPE(&stsignedlonglong);
+ default: return TYPE(&stsignedint);
+ }
+ }
+ case TK_BOOL:
+ return TYPE(&stbool);
+ case TK_WCHAR_T:
+ return TYPE(&stwchar);
+ case TK_CHAR:
+ switch (signedness) {
+ case 1: return TYPE(&stunsignedchar);
+ default: return TYPE(&stchar);
+ case -1: return TYPE(&stsignedchar);
+ }
+ case TK_DOUBLE:
+ switch (size) {
+ case 1: return TYPE(&stshortdouble);
+ case 2: return TYPE(&stlongdouble);
+ default: return TYPE(&stdouble);
+ }
+ case TK_FLOAT:
+ return TYPE(&stfloat);
+ case TK_VOID:
+ return TYPE(&stvoid);
+ default:
+ CError_Error(CErrorStr121);
+ return TYPE(&stvoid);
+ }
+}
+
+void TypedefDeclInfo(DeclInfo *declinfo, Type *type, UInt32 qual) {
+ if (type->type == TYPEPOINTER) {
+ if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(type))) {
+ declinfo->thetype = type;
+ declinfo->qual &= ~(Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST);
+ declinfo->qual |= qual;
+ return;
+ }
+
+ declinfo->thetype = galloc(sizeof(TypePointer));
+ *TYPE_POINTER(declinfo->thetype) = *TYPE_POINTER(type);
+ TYPE_POINTER(declinfo->thetype)->qual |= declinfo->qual & (Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST);
+ declinfo->qual &= ~(Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST);
+ declinfo->qual |= qual & (Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST);
+ } else if (type->type == TYPEMEMBERPOINTER) {
+ declinfo->thetype = galloc(sizeof(TypeMemberPointer));
+ *TYPE_MEMBER_POINTER(declinfo->thetype) = *TYPE_MEMBER_POINTER(type);
+ TYPE_MEMBER_POINTER(declinfo->thetype)->qual |= declinfo->qual & (Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST);
+ declinfo->qual &= ~(Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST);
+ declinfo->qual |= qual & (Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST);
+ } else {
+ declinfo->thetype = type;
+ declinfo->qual |= qual & (Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST);
+ if (IS_TYPE_ARRAY(declinfo->thetype) && !declinfo->thetype->size) {
+ declinfo->thetype = galloc(sizeof(TypePointer));
+ *TYPE_POINTER(declinfo->thetype) = *TYPE_POINTER(type);
+ }
+ }
+ declinfo->x49 = 1;
+}
+
+static void CParser_ParseAttributeFunctionSummary(DeclInfo *declinfo) {
+ Boolean flag;
+
+ if ((tk = lex()) != '(') {
+ CError_Error(CErrorStr114);
+ return;
+ }
+
+ flag = 1;
+ tk = lookahead();
+ while (tk == TK_IDENTIFIER) {
+ if (flag && !strcmp(tkidentifier->name, "entry_points_to")) {
+ PointerAnalysis_ParseEntryPointsToSpecifier(declinfo);
+ } else if (!strcmp(tkidentifier->name, "exit_points_to")) {
+ PointerAnalysis_ParseExitPointsToSpecifier(declinfo);
+ flag = 0;
+ } else if (!strcmp(tkidentifier->name, "function_modifies")) {
+ PointerAnalysis_ParseFunctionModifiesSpecifier(declinfo);
+ flag = 0;
+ } else {
+ lex();
+ CError_Error(CErrorStr121);
+ return;
+ }
+
+ tk = lookahead();
+ if (tk == ',') {
+ lex();
+ tk = lookahead();
+ }
+ }
+
+ lex();
+ if (tk != ')')
+ CError_Error(CErrorStr121);
+}
+
+void CParser_ParseAttribute(Type *type, DeclInfo *declinfo) {
+ CInt64 val64;
+ SInt32 val;
+
+ do {
+ if ((tk = lex()) != '(') {
+ CError_Error(CErrorStr121);
+ return;
+ }
+ if ((tk = lex()) != '(') {
+ CError_Error(CErrorStr121);
+ return;
+ }
+ if ((tk = lex()) != TK_IDENTIFIER && tk != TK_CONST) {
+ CError_Error(CErrorStr121);
+ return;
+ }
+
+ if (!strcmp(tkidentifier->name, "aligned") || !strcmp(tkidentifier->name, "__aligned__")) {
+ if ((tk = lex()) != '(') {
+ CError_Error(CErrorStr121);
+ return;
+ }
+
+ tk = lex();
+ val64 = CExpr_IntegralConstExpr();
+ switch ((val = CInt64_GetULong(&val64))) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 0x10:
+ case 0x20:
+ case 0x40:
+ case 0x80:
+ case 0x100:
+ case 0x200:
+ case 0x400:
+ case 0x800:
+ case 0x1000:
+ case 0x2000:
+ break;
+ default:
+ CError_Error(CErrorStr124);
+ return;
+ }
+ if (type) {
+ if (IS_TYPE_STRUCT(type)) {
+ if (val > TYPE_STRUCT(type)->align) {
+ TYPE_STRUCT(type)->align = val;
+ type->size += CABI_StructSizeAlignValue(type, type->size);
+ }
+ } else if (IS_TYPE_CLASS(type)) {
+ if (val > TYPE_CLASS(type)->align) {
+ TYPE_CLASS(type)->align = val;
+ type->size += CABI_StructSizeAlignValue(type, type->size);
+ }
+ } else {
+ CError_Error(CErrorStr149);
+ }
+ } else if (declinfo) {
+ declinfo->qual &= ~Q_ALIGNED_MASK;
+ switch (val) {
+ case 1:
+ declinfo->qual |= Q_ALIGNED_1;
+ break;
+ case 2:
+ declinfo->qual |= Q_ALIGNED_2;
+ break;
+ case 4:
+ declinfo->qual |= Q_ALIGNED_4;
+ break;
+ case 8:
+ declinfo->qual |= Q_ALIGNED_8;
+ break;
+ case 16:
+ declinfo->qual |= Q_ALIGNED_16;
+ break;
+ case 32:
+ declinfo->qual |= Q_ALIGNED_32;
+ break;
+ case 64:
+ declinfo->qual |= Q_ALIGNED_64;
+ break;
+ case 128:
+ declinfo->qual |= Q_ALIGNED_128;
+ break;
+ case 256:
+ declinfo->qual |= Q_ALIGNED_256;
+ break;
+ case 512:
+ declinfo->qual |= Q_ALIGNED_512;
+ break;
+ case 1024:
+ declinfo->qual |= Q_ALIGNED_1024;
+ break;
+ case 2048:
+ declinfo->qual |= Q_ALIGNED_2048;
+ break;
+ case 4096:
+ declinfo->qual |= Q_ALIGNED_4096;
+ break;
+ case 8192:
+ declinfo->qual |= Q_ALIGNED_8192;
+ break;
+ default:
+ CError_FATAL(2779);
+ break;
+ }
+ } else {
+ CError_Error(CErrorStr359);
+ }
+
+ if (tk != ')') {
+ CError_Error(CErrorStr121);
+ return;
+ }
+ } else if (!strcmp(tkidentifier->name, "nothrow") || !strcmp(tkidentifier->name, "__nothrow__")) {
+ if (declinfo && declinfo->thetype && IS_TYPE_FUNC(declinfo->thetype))
+ TYPE_FUNC(declinfo->thetype)->flags |= FUNC_NOTHROW;
+ else
+ CError_Error(CErrorStr359);
+ } else if (!strcmp("function_summary", tkidentifier->name)) {
+ CParser_ParseAttributeFunctionSummary(declinfo);
+ } else if (!strcmp(tkidentifier->name, "packed") || !strcmp(tkidentifier->name, "__packed__")) {
+ CError_Error(CErrorStr359);
+ } else if (!strcmp(tkidentifier->name, "unused") || !strcmp(tkidentifier->name, "__unused__")) {
+ } else if (!strcmp(tkidentifier->name, "noreturn") || !strcmp(tkidentifier->name, "__noreturn__")) {
+ } else if (tk == TK_CONST || !strcmp(tkidentifier->name, "__const__")) {
+ } else if (!strcmp(tkidentifier->name, "format") || !strcmp(tkidentifier->name, "__format__")) {
+ CError_Warning(CErrorStr359);
+ if ((tk = lex()) != '(') {
+ CError_Warning(CErrorStr114);
+ return;
+ }
+ tk = lex();
+ if ((tk = lex()) != ',') {
+ CError_Warning(CErrorStr116);
+ return;
+ }
+ tk = lex();
+ if ((tk = lex()) != ',') {
+ CError_Warning(CErrorStr116);
+ return;
+ }
+ tk = lex();
+ if ((tk = lex()) != ')') {
+ CError_Warning(CErrorStr115);
+ return;
+ }
+ } else if (!strcmp(tkidentifier->name, "mode") || !strcmp(tkidentifier->name, "__mode__")) {
+ CError_Warning(CErrorStr359);
+ if ((tk = lex()) != '(') {
+ CError_Warning(CErrorStr114);
+ return;
+ }
+ tk = lex();
+ if ((tk = lex()) != ')') {
+ CError_Warning(CErrorStr115);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr359);
+ }
+
+ if ((tk = lex()) != ')') {
+ CError_Error(CErrorStr121);
+ return;
+ }
+ if ((tk = lex()) != ')') {
+ CError_Error(CErrorStr121);
+ return;
+ }
+ tk = lex();
+ } while (tk == TK_UU_ATTRIBUTE_UU);
+}
+
+static void CParser_ParseTypeOf(DeclInfo *declinfo) {
+ DeclInfo subdi;
+ ENode *expr;
+
+ if ((tk = lex()) == '(' && islookaheaddeclaration()) {
+ tk = lex();
+
+ memclrw(&subdi, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(&subdi, 0);
+ scandeclarator(&subdi);
+ if (subdi.name)
+ CError_Error(CErrorStr121);
+
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+
+ TypedefDeclInfo(declinfo, subdi.thetype, subdi.qual);
+ } else {
+ expr = unary_expression();
+ if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EBITFIELD))
+ CError_Error(CErrorStr144);
+ TypedefDeclInfo(declinfo, expr->rtype, expr->flags & ENODE_FLAG_QUALS);
+ }
+}
+
+void CParser_ParseDeclSpec(DeclInfo *declinfo, Boolean flag) {
+ if ((tk = lex()) != TK_IDENTIFIER) {
+ if (tk != TK_EXPORT)
+ CError_Error(CErrorStr107);
+ else
+ declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_EXPORT;
+ } else if (!strcmp("internal", tkidentifier->name)) {
+ declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_INTERNAL;
+ } else if (!strcmp("import", tkidentifier->name) || !strcmp("dllimport", tkidentifier->name)) {
+ declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_IMPORT;
+ } else if (!strcmp("export", tkidentifier->name) || !strcmp("dllexport", tkidentifier->name)) {
+ declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_EXPORT;
+ } else if (!strcmp("lib_export", tkidentifier->name)) {
+ declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_IMPORT | EXPORT_FLAGS_EXPORT;
+ } else if (!strcmp("weak", tkidentifier->name)) {
+ declinfo->qual |= Q_WEAK;
+ } else {
+ CodeGen_ParseDeclSpec(tkidentifier, declinfo);
+ }
+}
+
+static int CParser_GetVectorDeclSpec(Type **type) {
+ tk = lex();
+ switch (tk) {
+ case TK_CHAR:
+ tk = lex();
+ switch (tk) {
+ case TK_BOOL:
+ *type = TYPE(&stvectorboolchar);
+ tk = lex();
+ return 1;
+ case TK_UNSIGNED:
+ *type = TYPE(&stvectorunsignedchar);
+ tk = lex();
+ return 1;
+ case TK_SIGNED:
+ *type = TYPE(&stvectorsignedchar);
+ tk = lex();
+ return 1;
+ case TK_IDENTIFIER:
+ if (tkidentifier == GetHashNameNode("bool")) {
+ *type = TYPE(&stvectorboolchar);
+ tk = lex();
+ return 1;
+ }
+ default:
+ CError_Error(CErrorStr121);
+ }
+ break;
+ case TK_SIGNED:
+ tk = lex();
+ switch (tk) {
+ case TK_CHAR:
+ *type = TYPE(&stvectorsignedchar);
+ tk = lex();
+ return 1;
+ case TK_SHORT:
+ *type = TYPE(&stvectorsignedshort);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_LONG:
+ *type = TYPE(&stvectorsignedlong);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_INT:
+ tk = lex();
+ switch (tk) {
+ case TK_SHORT:
+ *type = TYPE(&stvectorsignedshort);
+ tk = lex();
+ return 1;
+ case TK_LONG:
+ *type = TYPE(&stvectorsignedlong);
+ tk = lex();
+ return 1;
+ default:
+ *type = TYPE(&stvectorsignedlong);
+ return 1;
+ }
+ default:
+ CError_Error(CErrorStr121);
+ }
+ break;
+ case TK_UNSIGNED:
+ tk = lex();
+ switch (tk) {
+ case TK_CHAR:
+ *type = TYPE(&stvectorunsignedchar);
+ tk = lex();
+ return 1;
+ case TK_SHORT:
+ *type = TYPE(&stvectorunsignedshort);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_LONG:
+ *type = TYPE(&stvectorunsignedlong);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_INT:
+ tk = lex();
+ switch (tk) {
+ case TK_SHORT:
+ *type = TYPE(&stvectorunsignedshort);
+ tk = lex();
+ return 1;
+ case TK_LONG:
+ *type = TYPE(&stvectorunsignedlong);
+ tk = lex();
+ return 1;
+ default:
+ *type = TYPE(&stvectorunsignedlong);
+ return 1;
+ }
+ default:
+ CError_Error(CErrorStr121);
+ }
+ break;
+ case TK_BOOL:
+ tk = lex();
+ switch (tk) {
+ case TK_CHAR:
+ *type = TYPE(&stvectorboolchar);
+ tk = lex();
+ return 1;
+ case TK_SHORT:
+ *type = TYPE(&stvectorboolshort);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_LONG:
+ *type = TYPE(&stvectorboollong);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_INT:
+ tk = lex();
+ switch (tk) {
+ case TK_SHORT:
+ *type = TYPE(&stvectorboolshort);
+ tk = lex();
+ return 1;
+ case TK_LONG:
+ *type = TYPE(&stvectorboollong);
+ tk = lex();
+ return 1;
+ default:
+ *type = TYPE(&stvectorboollong);
+ return 1;
+ }
+ default:
+ CError_Error(CErrorStr121);
+ }
+ break;
+ case TK_SHORT:
+ tk = lex();
+ switch (tk) {
+ case TK_BOOL:
+ *type = TYPE(&stvectorboolshort);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_SIGNED:
+ *type = TYPE(&stvectorsignedshort);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_UNSIGNED:
+ *type = TYPE(&stvectorunsignedshort);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_INT:
+ tk = lex();
+ switch (tk) {
+ case TK_BOOL:
+ *type = TYPE(&stvectorboolshort);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_SIGNED:
+ *type = TYPE(&stvectorsignedshort);
+ tk = lex();
+ return 1;
+ case TK_UNSIGNED:
+ *type = TYPE(&stvectorunsignedshort);
+ tk = lex();
+ return 1;
+ case TK_IDENTIFIER:
+ if (tkidentifier == GetHashNameNode("bool")) {
+ *type = TYPE(&stvectorboolshort);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ }
+ default:
+ CError_Error(CErrorStr121);
+ }
+ break;
+ case TK_IDENTIFIER:
+ if (tkidentifier == GetHashNameNode("bool")) {
+ *type = TYPE(&stvectorboolshort);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ }
+ default:
+ CError_Error(CErrorStr121);
+ }
+ break;
+ case TK_LONG:
+ tk = lex();
+ switch (tk) {
+ case TK_BOOL:
+ *type = TYPE(&stvectorboollong);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_SIGNED:
+ *type = TYPE(&stvectorsignedlong);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_UNSIGNED:
+ *type = TYPE(&stvectorunsignedlong);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_INT:
+ tk = lex();
+ switch (tk) {
+ case TK_BOOL:
+ *type = TYPE(&stvectorboollong);
+ tk = lex();
+ return 1;
+ case TK_SIGNED:
+ *type = TYPE(&stvectorsignedlong);
+ tk = lex();
+ return 1;
+ case TK_UNSIGNED:
+ *type = TYPE(&stvectorunsignedlong);
+ tk = lex();
+ return 1;
+ case TK_IDENTIFIER:
+ if (tkidentifier == GetHashNameNode("bool")) {
+ *type = TYPE(&stvectorboollong);
+ tk = lex();
+ return 1;
+ }
+ default:
+ CError_Error(CErrorStr121);
+ }
+ break;
+ case TK_IDENTIFIER:
+ if (tkidentifier == GetHashNameNode("bool")) {
+ *type = TYPE(&stvectorboollong);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ }
+ default:
+ CError_Error(CErrorStr121);
+ }
+ break;
+ case TK_INT:
+ tk = lex();
+ switch (tk) {
+ case TK_BOOL:
+ tk = lex();
+ switch (tk) {
+ case TK_SHORT:
+ *type = TYPE(&stvectorboolshort);
+ tk = lex();
+ return 1;
+ case TK_LONG:
+ *type = TYPE(&stvectorboollong);
+ tk = lex();
+ return 1;
+ default:
+ *type = TYPE(&stvectorboollong);
+ return 1;
+ }
+ case TK_SIGNED:
+ tk = lex();
+ switch (tk) {
+ case TK_SHORT:
+ *type = TYPE(&stvectorsignedshort);
+ tk = lex();
+ return 1;
+ case TK_LONG:
+ *type = TYPE(&stvectorsignedlong);
+ tk = lex();
+ return 1;
+ default:
+ *type = TYPE(&stvectorsignedlong);
+ return 1;
+ }
+ case TK_UNSIGNED:
+ tk = lex();
+ switch (tk) {
+ case TK_SHORT:
+ *type = TYPE(&stvectorunsignedshort);
+ tk = lex();
+ return 1;
+ case TK_LONG:
+ *type = TYPE(&stvectorunsignedlong);
+ tk = lex();
+ return 1;
+ default:
+ *type = TYPE(&stvectorunsignedlong);
+ return 1;
+ }
+ case TK_SHORT:
+ tk = lex();
+ switch (tk) {
+ case TK_BOOL:
+ *type = TYPE(&stvectorboolshort);
+ tk = lex();
+ return 1;
+ case TK_SIGNED:
+ *type = TYPE(&stvectorsignedshort);
+ tk = lex();
+ return 1;
+ case TK_UNSIGNED:
+ *type = TYPE(&stvectorunsignedshort);
+ tk = lex();
+ return 1;
+ case TK_IDENTIFIER:
+ if (tkidentifier == GetHashNameNode("bool")) {
+ *type = TYPE(&stvectorboolshort);
+ tk = lex();
+ return 1;
+ }
+ default:
+ CError_Error(CErrorStr121);
+ }
+ break;
+ case TK_LONG:
+ tk = lex();
+ switch (tk) {
+ case TK_BOOL:
+ *type = TYPE(&stvectorboollong);
+ tk = lex();
+ return 1;
+ case TK_SIGNED:
+ *type = TYPE(&stvectorsignedlong);
+ tk = lex();
+ return 1;
+ case TK_UNSIGNED:
+ *type = TYPE(&stvectorunsignedlong);
+ tk = lex();
+ return 1;
+ case TK_IDENTIFIER:
+ if (tkidentifier == GetHashNameNode("bool")) {
+ *type = TYPE(&stvectorboollong);
+ tk = lex();
+ return 1;
+ }
+ }
+ case TK_IDENTIFIER:
+ if (tkidentifier == GetHashNameNode("bool")) {
+ tk = lex();
+ switch (tk) {
+ case TK_LONG:
+ *type = TYPE(&stvectorboollong);
+ tk = lex();
+ return 1;
+ case TK_SHORT:
+ *type = TYPE(&stvectorboolshort);
+ tk = lex();
+ return 1;
+ default:
+ *type = TYPE(&stvectorboolshort);
+ return 1;
+ }
+ }
+ default:
+ CError_Error(CErrorStr121);
+ }
+ break;
+ case TK_FLOAT:
+ *type = TYPE(&stvectorfloat);
+ tk = lex();
+ return 1;
+ case TK_IDENTIFIER:
+ if (tkidentifier == GetHashNameNode("pixel") || tkidentifier == GetHashNameNode("__pixel")) {
+ *type = TYPE(&stvectorpixel);
+ tk = lex();
+ return 1;
+ }
+ if (tkidentifier == GetHashNameNode("bool")) {
+ tk = lex();
+ switch (tk) {
+ case TK_CHAR:
+ *type = TYPE(&stvectorboolchar);
+ tk = lex();
+ return 1;
+ case TK_SHORT:
+ *type = TYPE(&stvectorboolshort);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_LONG:
+ *type = TYPE(&stvectorboollong);
+ tk = lex();
+ if (tk == TK_INT)
+ tk = lex();
+ return 1;
+ case TK_INT:
+ tk = lex();
+ switch (tk) {
+ case TK_SHORT:
+ *type = TYPE(&stvectorboolshort);
+ tk = lex();
+ return 1;
+ case TK_LONG:
+ *type = TYPE(&stvectorboollong);
+ tk = lex();
+ return 1;
+ default:
+ *type = TYPE(&stvectorboollong);
+ return 1;
+ }
+ }
+ }
+ default:
+ CError_Error(CErrorStr121);
+ }
+
+ return 0;
+}
+
+Boolean CParser_CheckTemplateClassUsage(TemplClass *tmclass, Boolean flag) {
+ NameSpace *nspace;
+
+ if (tmclass->templ__params) {
+ nspace = cscope_current;
+ while (1) {
+ if (!nspace) {
+ if (flag)
+ CError_Error(CErrorStr230);
+ return 0;
+ }
+ if (nspace->theclass == TYPE_CLASS(tmclass))
+ break;
+ nspace = nspace->parent;
+ }
+ }
+
+ return 1;
+}
+
+static Boolean CParser_IsAltiVecPrefix(void) {
+ HashNameNode *save = tkidentifier;
+
+ switch (lookahead()) {
+ case TK_CHAR:
+ case TK_SHORT:
+ case TK_INT:
+ case TK_LONG:
+ case TK_FLOAT:
+ case TK_SIGNED:
+ case TK_UNSIGNED:
+ case TK_BOOL:
+ return 1;
+ case TK_IDENTIFIER:
+ if (!strcmp(tkidentifier->name, "bool") || !strcmp(tkidentifier->name, "pixel") || !strcmp(tkidentifier->name, "__pixel"))
+ return 1;
+ }
+
+ tkidentifier = save;
+ return 0;
+}
+
+void CParser_GetDeclSpecs(DeclInfo *di, Boolean flag) {
+ short typesize;
+ short signedness;
+ short typetoken;
+ Boolean r24;
+ Boolean r23;
+ SInt32 state;
+ NameResult pr;
+
+ di->file = CPrep_BrowserCurrentFile();
+ CPrep_BrowserFilePosition(&di->file2, &di->sourceoffset);
+
+ r24 = 1;
+ r23 = copts.cplusplus;
+ typetoken = 0;
+ signedness = 0;
+ typesize = 0;
+
+restart:
+ switch (tk) {
+ case TK_AUTO:
+ case TK_REGISTER:
+ case TK_STATIC:
+ case TK_EXTERN:
+ case TK_TYPEDEF:
+ case TK_MUTABLE:
+ if (di->storageclass)
+ CError_Error(CErrorStr121);
+ di->storageclass = tk;
+ break;
+ case TK_CONST:
+ if (di->thetype) {
+ if (di->thetype->type == TYPEPOINTER) {
+ if (TYPE_POINTER(di->thetype)->qual & Q_CONST)
+ CError_QualifierCheck(Q_CONST);
+ TYPE_POINTER(di->thetype)->qual |= Q_CONST;
+ break;
+ } else if (di->thetype->type == TYPEMEMBERPOINTER) {
+ if (TYPE_MEMBER_POINTER(di->thetype)->qual & Q_CONST)
+ CError_QualifierCheck(Q_CONST);
+ TYPE_MEMBER_POINTER(di->thetype)->qual |= Q_CONST;
+ break;
+ }
+ }
+ if (di->qual & Q_CONST)
+ CError_QualifierCheck(Q_CONST);
+ di->qual |= Q_CONST;
+ break;
+ case TK_VOLATILE:
+ if (di->thetype) {
+ if (di->thetype->type == TYPEPOINTER) {
+ if (TYPE_POINTER(di->thetype)->qual & Q_VOLATILE)
+ CError_QualifierCheck(Q_VOLATILE);
+ TYPE_POINTER(di->thetype)->qual |= Q_VOLATILE;
+ break;
+ } else if (di->thetype->type == TYPEMEMBERPOINTER) {
+ if (TYPE_MEMBER_POINTER(di->thetype)->qual & Q_VOLATILE)
+ CError_QualifierCheck(Q_VOLATILE);
+ TYPE_MEMBER_POINTER(di->thetype)->qual |= Q_VOLATILE;
+ break;
+ }
+ }
+ if (di->qual & Q_VOLATILE)
+ CError_QualifierCheck(Q_VOLATILE);
+ di->qual |= Q_VOLATILE;
+ break;
+ case TK_PASCAL:
+ if (di->qual & Q_PASCAL)
+ CError_QualifierCheck(Q_PASCAL);
+ di->qual |= Q_PASCAL;
+ break;
+ case TK_EXPLICIT:
+ CError_QualifierCheck(di->qual & Q_EXPLICIT);
+ di->qual |= Q_EXPLICIT;
+ break;
+ case TK_VIRTUAL:
+ CError_QualifierCheck(di->qual & Q_VIRTUAL);
+ di->qual |= Q_VIRTUAL;
+ break;
+ case TK_IN:
+ CError_QualifierCheck(di->qual & Q_IN);
+ di->qual |= Q_IN;
+ break;
+ case TK_OUT:
+ CError_QualifierCheck(di->qual & Q_OUT);
+ di->qual |= Q_OUT;
+ break;
+ case TK_INOUT:
+ CError_QualifierCheck(di->qual & Q_INOUT);
+ di->qual |= Q_INOUT;
+ break;
+ case TK_BYCOPY:
+ CError_QualifierCheck(di->qual & Q_BYCOPY);
+ di->qual |= Q_BYCOPY;
+ break;
+ case TK_BYREF:
+ CError_QualifierCheck(di->qual & Q_BYREF);
+ di->qual |= Q_BYREF;
+ break;
+ case TK_ONEWAY:
+ CError_QualifierCheck(di->qual & Q_ONEWAY);
+ di->qual |= Q_ONEWAY;
+ break;
+ case TK_UU_DECLSPEC:
+ if ((tk = lex()) != '(')
+ CError_Error(CErrorStr114);
+ CParser_ParseDeclSpec(di, 0);
+ if ((tk = lex()) != ')')
+ CError_Error(CErrorStr115);
+ break;
+ case TK_ASM:
+ if (di->qual & Q_ASM)
+ CError_QualifierCheck(Q_ASM);
+ di->qual |= Q_ASM;
+ break;
+ case TK_INLINE:
+ if (di->qual & Q_INLINE)
+ CError_QualifierCheck(Q_INLINE);
+ di->qual |= Q_INLINE;
+ break;
+ case TK_SHORT:
+ if (typesize || (typetoken && typetoken != TK_INT && typetoken != TK_DOUBLE))
+ CError_Error(CErrorStr121);
+ typesize = 1;
+ break;
+ case TK_LONG:
+ if (copts.longlong) {
+ if (typetoken && typetoken != TK_INT && typetoken != TK_DOUBLE)
+ CError_Error(CErrorStr121);
+ if (typesize) {
+ if (typesize != 2 || typetoken == TK_DOUBLE)
+ CError_Error(CErrorStr121);
+ typesize = 3;
+ } else {
+ typesize = 2;
+ }
+ } else {
+ if (typesize || (typetoken && typetoken != TK_INT && typetoken != TK_DOUBLE))
+ CError_Error(CErrorStr121);
+ typesize = 2;
+ }
+ break;
+ case TK_SIGNED:
+ if (signedness || (typetoken && typetoken != TK_INT && typetoken != TK_CHAR))
+ CError_Error(CErrorStr121);
+ signedness = -1;
+ break;
+ case TK_UNSIGNED:
+ if (signedness || (typetoken && typetoken != TK_INT && typetoken != TK_CHAR))
+ CError_Error(CErrorStr121);
+ signedness = 1;
+ break;
+ case TK_VOID:
+ if (typetoken || typesize || signedness)
+ CError_Error(CErrorStr121);
+ typetoken = TK_VOID;
+ break;
+ case TK_FLOAT:
+ if (typetoken || typesize || signedness)
+ CError_Error(CErrorStr121);
+ typetoken = TK_FLOAT;
+ break;
+ case TK_BOOL:
+ if (typetoken || typesize)
+ CError_Error(CErrorStr121);
+ typetoken = TK_BOOL;
+ break;
+ case TK_CHAR:
+ if (typetoken || typesize)
+ CError_Error(CErrorStr121);
+ typetoken = TK_CHAR;
+ break;
+ case TK_WCHAR_T:
+ if (typetoken || typesize || signedness)
+ CError_Error(CErrorStr121);
+ typetoken = TK_WCHAR_T;
+ break;
+ case TK_INT:
+ if (typetoken)
+ CError_Error(CErrorStr121);
+ typetoken = TK_INT;
+ break;
+ case TK_DOUBLE:
+ if (typetoken || signedness)
+ CError_Error(CErrorStr121);
+ typetoken = TK_DOUBLE;
+ break;
+ case TK_STRUCT:
+ if (typetoken || signedness || typesize)
+ CError_Error(CErrorStr121);
+ tk = lex();
+ scanstruct(di, STRUCT_TYPE_STRUCT);
+ if (tk == TK_UU_ATTRIBUTE_UU)
+ CParser_ParseAttribute(di->thetype, NULL);
+ if (!(tk != TK_CONST && tk != TK_VOLATILE && tk != TK_UU_FAR && tk != TK_UU_DECLSPEC)) {
+ typetoken = -1;
+ goto restart;
+ }
+ return;
+ case TK_CLASS:
+ if (typetoken || signedness || typesize)
+ CError_Error(CErrorStr121);
+ tk = lex();
+ CDecl_ParseClass(di, CLASS_MODE_CLASS, 1, 0);
+ if (tk == TK_UU_ATTRIBUTE_UU)
+ CParser_ParseAttribute(di->thetype, NULL);
+ if (!(tk != TK_CONST && tk != TK_VOLATILE && tk != TK_UU_FAR && tk != TK_UU_DECLSPEC)) {
+ typetoken = -1;
+ goto restart;
+ }
+ return;
+ case TK_UNION:
+ if (typetoken || signedness || typesize)
+ CError_Error(CErrorStr121);
+ tk = lex();
+ scanstruct(di, STRUCT_TYPE_UNION);
+ if (tk == TK_UU_ATTRIBUTE_UU)
+ CParser_ParseAttribute(di->thetype, NULL);
+ if (!(tk != TK_CONST && tk != TK_VOLATILE && tk != TK_UU_FAR && tk != TK_UU_DECLSPEC)) {
+ typetoken = -1;
+ goto restart;
+ }
+ return;
+ case TK_ENUM:
+ if (typetoken || signedness || typesize)
+ CError_Error(CErrorStr121);
+ tk = lex();
+ scanenum(di);
+ if (tk == TK_UU_ATTRIBUTE_UU)
+ CParser_ParseAttribute(di->thetype, NULL);
+ if (!(tk != TK_CONST && tk != TK_VOLATILE && tk != TK_UU_FAR && tk != TK_UU_DECLSPEC)) {
+ typetoken = -1;
+ goto restart;
+ }
+ return;
+ case TK_TYPENAME:
+ if (typetoken || signedness || typesize || di->x53)
+ CError_Error(CErrorStr121);
+ di->x53 = 1;
+ tk = lex();
+ if (tk != TK_COLON_COLON && tk != TK_IDENTIFIER) {
+ CError_Error(CErrorStr121);
+ break;
+ }
+ goto some_shared_label;
+ case TK_COLON_COLON:
+ if (typetoken || signedness || typesize)
+ goto switchDefault;
+ goto some_shared_label;
+ case TK_UU_VECTOR:
+ if (typetoken || signedness || typesize)
+ CError_Error(CErrorStr121);
+ handle_vector:
+ if (CParser_GetVectorDeclSpec(&di->thetype)) {
+ if (tk == TK_CONST) {
+ if (di->qual == 0) {
+ di->qual |= Q_CONST;
+ tk = lex();
+ } else {
+ CError_Error(CErrorStr121);
+ }
+ }
+ if (tk == TK_VOLATILE) {
+ if (di->qual == 0) {
+ di->qual |= Q_VOLATILE;
+ tk = lex();
+ } else {
+ CError_Error(CErrorStr121);
+ }
+ }
+ return;
+ }
+ break;
+ case TK_UU_TYPEOF_UU:
+ if (typetoken || signedness || typesize)
+ CError_Error(CErrorStr121);
+ CParser_ParseTypeOf(di);
+ typetoken = -1;
+ goto bailOut;
+ case TK_IDENTIFIER:
+ if (copts.altivec_model && !typetoken && !signedness && !typesize && !strcmp(tkidentifier->name, "vector")) {
+ if (CParser_IsAltiVecPrefix())
+ goto handle_vector;
+ }
+ if (!typetoken && !signedness && !typesize) {
+ if (copts.objective_c && !strcmp(tkidentifier->name, "id")) {
+ di->thetype = CObjC_ParseID();
+ typetoken = -1;
+ goto bailOut;
+ }
+ some_shared_label:
+ CPrep_TokenStreamGetState(&state);
+ if (CScope_ParseDeclName(&pr)) {
+ if (pr.type) {
+ if (IS_TYPE_TEMPLATE(pr.type)) {
+ switch (TYPE_TEMPLATE(pr.type)->dtype) {
+ case TEMPLDEP_ARGUMENT:
+ switch (TYPE_TEMPLATE(pr.type)->u.pid.type) {
+ case TPT_TYPE:
+ break;
+ case TPT_NONTYPE:
+ CError_Error(CErrorStr348);
+ pr.type = TYPE(&stsignedint);
+ break;
+ case TPT_TEMPLATE:
+ CError_Error(CErrorStr230);
+ pr.type = TYPE(&stsignedint);
+ break;
+ default:
+ CError_FATAL(4109);
+ }
+ break;
+ case TEMPLDEP_QUALNAME:
+ if (!di->x53 && !pr.x20 && di->x55)
+ CError_Error(CErrorStr355);
+ break;
+ case TEMPLDEP_TEMPLATE:
+ case TEMPLDEP_ARRAY:
+ case TEMPLDEP_QUALTEMPL:
+ case TEMPLDEP_BITFIELD:
+ break;
+ default:
+ CError_FATAL(4136);
+ }
+ }
+
+ if (IS_TYPE_CLASS(pr.type) && (TYPE_CLASS(pr.type)->flags & CLASS_IS_TEMPL)) {
+ if (!CParser_CheckTemplateClassUsage(TEMPL_CLASS(pr.type), 0)) {
+ if (di->x56) {
+ if (di->qual)
+ CError_Error(CErrorStr121);
+ di->thetype = pr.type;
+ di->x57 = 1;
+ tk = lex();
+ return;
+ } else {
+ CError_Error(CErrorStr230);
+ pr.type = TYPE(&stsignedint);
+ }
+ }
+ }
+
+ TypedefDeclInfo(di, pr.type, pr.qual);
+ di->x49 = pr.x20;
+ typetoken = -1;
+ tk = lex();
+ if (tk == '<' && copts.objective_c && IS_TYPE_CLASS(di->thetype) && TYPE_CLASS(di->thetype)->objcinfo)
+ di->thetype = CObjC_ParseTypeProtocol(TYPE_CLASS(di->thetype));
+ goto bailOut;
+ } else if (pr.nsol_14) {
+ if (pr.x1D) {
+ if (flag && (OBJECT(pr.nsol_14->object)->nspace == pr.nspace_0 || di->in_friend_decl)) {
+ di->x14 = pr.nsol_14;
+ if (IS_TYPE_FUNC(OBJECT(di->x14->object)->type) && ((TYPE_FUNC(OBJECT(di->x14->object)->type)->flags & FUNC_IS_CTOR) | FUNC_IS_DTOR))
+ r23 = 0;
+ } else {
+ CError_Error(CErrorStr121);
+ }
+ }
+ } else if (pr.obj_10) {
+ switch (pr.obj_10->otype) {
+ case OT_OBJECT:
+ if (pr.x1D) {
+ if (flag && (OBJECT(pr.obj_10)->nspace == pr.nspace_0 || di->in_friend_decl)) {
+ di->x10 = OBJECT(pr.obj_10);
+ if (IS_TYPE_FUNC(di->x10->type) && ((TYPE_FUNC(di->x10->type)->flags & FUNC_IS_CTOR) | FUNC_IS_DTOR))
+ r23 = 0;
+ } else {
+ CError_Error(CErrorStr121);
+ }
+ }
+ break;
+ case OT_ENUMCONST:
+ case OT_MEMBERVAR:
+ CError_Error(CErrorStr121);
+ break;
+ default:
+ CError_FATAL(4217);
+ }
+ } else if (pr.name_4) {
+ if (copts.cplusplus)
+ CError_Error(CErrorStr121);
+ } else if (pr.x21) {
+ CPrep_TokenStreamSetState(&state);
+ CPrep_UnLex();
+ tk = lex();
+ r23 = 0;
+ } else {
+ CError_FATAL(4234);
+ }
+ }
+ }
+ default:
+ switchDefault:
+ if (!typetoken && !signedness && !typesize) {
+ di->x4A = 1;
+ if (r23) {
+ if (!di->storageclass && !di->qual && !di->exportflags)
+ CError_Error(CErrorStr121);
+ else
+ CError_Warning(CErrorStr349);
+ }
+ }
+ if (typetoken >= 0)
+ di->thetype = getthetype(typetoken, typesize, signedness);
+ if (r24)
+ di->x48 = 1;
+ if (tk == TK_UU_ATTRIBUTE_UU)
+ CParser_ParseAttribute(NULL, di);
+ return;
+ case ';':
+ if (!typetoken && !signedness && !typesize && copts.warn_emptydecl)
+ CError_Warning(CErrorStr216);
+ if (typetoken >= 0)
+ di->thetype = getthetype(typetoken, typesize, signedness);
+ return;
+ }
+
+ tk = lex();
+bailOut:
+ r24 = 0;
+ goto restart;
+}
+
+void CParser_RegisterNonGlobalClass(TypeClass *tclass) {
+ struct ParentCleanup *p = lalloc(sizeof(struct ParentCleanup));
+ p->next = cparser_parentcleanup;
+ p->tclass = tclass;
+ cparser_parentcleanup = p;
+}
+
+void CParser_RegisterSingleExprFunction(Object *func, ENode *expr) {
+ struct SFuncList *p = lalloc(sizeof(struct SFuncList));
+ p->next = cparser_sfunclist;
+ p->func = func;
+ p->obj = NULL;
+ p->expr = expr;
+ cparser_sfunclist = p;
+}
+
+void CParser_RegisterDummyCtorFunction(Object *func, Object *obj) {
+ struct SFuncList *p = lalloc(sizeof(struct SFuncList));
+ p->next = cparser_sfunclist;
+ p->func = func;
+ p->obj = obj;
+ p->expr = NULL;
+ cparser_sfunclist = p;
+}
+
+static void CParser_FreeLocalHeap(void) {
+ struct SFuncList *s;
+ struct ParentCleanup *p;
+
+ while ((s = cparser_sfunclist)) {
+ cparser_sfunclist = s->next;
+ if (s->expr)
+ CFunc_GenerateSingleExprFunc(s->func, s->expr);
+ else
+ CFunc_GenerateDummyCtorFunc(s->func, s->obj);
+ }
+
+ if (cparser_parentcleanup) {
+ if (!CInline_CanFreeLHeap())
+ return;
+
+ for (p = cparser_parentcleanup; p; p = p->next) {
+ while (!p->tclass->nspace->parent->is_global)
+ p->tclass->nspace->parent = p->tclass->nspace->parent->parent;
+ }
+
+ cparser_parentcleanup = NULL;
+ }
+
+ freelheap();
+}
+
+static void CParser_GlobalCleanup(Boolean flag) {
+ Boolean working;
+
+ do {
+ CParser_FreeLocalHeap();
+ working = 0;
+
+ if (flag) {
+ if (cparser_classactions) {
+ CClass_ClassAction(cparser_classactions->tclass);
+ cparser_classactions = cparser_classactions->next;
+ working = 1;
+ } else if (CTempl_Instantiate()) {
+ working = 1;
+ }
+ }
+
+ while (CInline_GenerateDeferredFuncs()) {
+ CParser_FreeLocalHeap();
+ working = 1;
+ }
+ } while (working);
+}
+
+Boolean CParser_IsAnonymousUnion(DeclInfo *di, Boolean flag) {
+ return IS_TYPE_CLASS(di->thetype) &&
+ ((TYPE_CLASS(di->thetype)->mode == CLASS_MODE_UNION || (flag && copts.cpp_extensions))) &&
+ IsTempName(TYPE_CLASS(di->thetype)->classname);
+}
+
+void CParser_CheckAnonymousUnion(DeclInfo *di, Boolean flag) {
+ ObjMemberVar *ivar;
+ Object *obj;
+ Object *ivar_obj;
+
+ if (!CParser_IsAnonymousUnion(di, 0)) {
+ if (copts.warn_emptydecl) {
+ switch (di->thetype->type) {
+ case TYPEENUM:
+ case TYPESTRUCT:
+ case TYPECLASS:
+ if (!di->storageclass && !di->qual)
+ return;
+ }
+ CError_Warning(CErrorStr216);
+ }
+ return;
+ }
+
+ if (!flag && di->storageclass != TK_STATIC)
+ CError_Error(CErrorStr177);
+
+ if (flag && di->storageclass != TK_STATIC) {
+ obj = CParser_NewLocalDataObject(di, 1);
+ obj->name = CParser_GetUniqueName();
+ CFunc_SetupLocalVarInfo(obj);
+ obj->u.var.info->noregister = 1;
+ } else {
+ obj = CParser_NewGlobalDataObject(di);
+ obj->name = CParser_GetUniqueName();
+ obj->nspace = cscope_root;
+ obj->sclass = TK_STATIC;
+ CInit_DeclareData(obj, NULL, NULL, obj->type->size);
+ }
+
+ for (ivar = TYPE_CLASS(di->thetype)->ivars; ivar; ivar = ivar->next) {
+ ivar_obj = galloc(sizeof(Object));
+ *ivar_obj = *obj;
+ ivar_obj->name = ivar->name;
+ ivar_obj->type = ivar->type;
+ ivar_obj->qual = ivar->qual;
+ ivar_obj->datatype = DALIAS;
+ ivar_obj->u.alias.object = obj;
+ ivar_obj->u.alias.offset = ivar->offset;
+ ivar_obj->u.alias.member = NULL;
+ CScope_AddObject(cscope_current, ivar_obj->name, OBJ_BASE(ivar_obj));
+ }
+}
+
+void CParser_NewCallBackAction(Object *obj, TypeClass *tclass) {
+ CallbackAction *act = galloc(sizeof(CallbackAction));
+ act->next = callbackactions;
+ act->obj = obj;
+ act->tclass = tclass;
+ callbackactions = act;
+ obj->flags = obj->flags | OBJECT_LAZY;
+}
+
+void CParser_NewClassAction(TypeClass *tclass) {
+ struct ClassAction *act = galloc(sizeof(struct ClassAction));
+ act->next = cparser_classactions;
+ act->tclass = tclass;
+ cparser_classactions = act;
+}
+
+void CParser_CallBackAction(Object *obj) {
+ CallbackAction *act;
+
+ for (act = callbackactions; act; act = act->next) {
+ if (act->obj == obj) {
+ CParser_NewClassAction(act->tclass);
+ return;
+ }
+ }
+
+ CError_FATAL(4551);
+}
+
+static Object *CParser_FindOverloadFunc(NameSpaceObjectList *list, TypeFunc *tfunc) {
+ while (list) {
+ if (list->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(list->object)->type))
+ if (CParser_CompareArgLists(tfunc->args, TYPE_FUNC(OBJECT(list->object)->type)->args) == 1)
+ return OBJECT(list->object);
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+Object *CParser_ParseObject(void) {
+ DeclInfo di;
+ NameResult pr;
+ NameSpaceObjectList *list;
+ Object *obj;
+
+ memclrw(&di, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(&di, 1);
+ scandeclarator(&di);
+
+ if (di.name && (list = CScope_FindObjectList(&pr, di.name))) {
+ if (list->object->otype == OT_OBJECT) {
+ if (IS_TYPE_FUNC(di.thetype))
+ return CParser_FindOverloadFunc(list, TYPE_FUNC(di.thetype));
+
+ if (is_typesame(di.thetype, OBJECT(list->object)->type) && OBJECT(list->object)->qual == di.qual)
+ return OBJECT(list->object);
+
+ obj = OBJECT(list->object);
+ CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, di.thetype, di.qual);
+ }
+ }
+
+ return NULL;
+}
+
+void CParser_ParseGlobalDeclaration(void) {
+ DeclInfo di;
+
+ if (tk) {
+ CPrep_NewFileOffsetInfo(&cparser_fileoffset, NULL);
+ symdecloffset = cparser_fileoffset.tokenline;
+ symdecltoken = *CPrep_CurStreamElement();
+
+ memclrw(&di, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(&di, 1);
+ if (di.storageclass == TK_REGISTER || di.storageclass == TK_AUTO) {
+ CError_Error(CErrorStr177);
+ di.storageclass = 0;
+ }
+
+ if (tk != ';')
+ scandeclaratorlist(&di);
+ else
+ CParser_CheckAnonymousUnion(&di, 0);
+
+ tk = lex();
+ } else {
+ CError_Error(CErrorStr102);
+ }
+}
+
+static void CParser_ParseLinkageSpecification(DeclInfo *di) {
+ UInt32 qual;
+ UInt8 r28;
+
+ if (!strcmp(tkstring, "C") || !strcmp(tkstring, "Objective C")) {
+ qual = 0;
+ r28 = 1;
+ } else if (!strcmp(tkstring, "C++")) {
+ qual = 0;
+ r28 = 0;
+ } else if (!strcmp(tkstring, "Pascal")) {
+ qual = Q_PASCAL;
+ r28 = 1;
+ } else {
+ CError_Error(CErrorStr121);
+ qual = 0;
+ r28 = 1;
+ }
+
+ if ((tk = lex()) == '{') {
+ while (1) {
+ if ((tk = lex()) == 0) {
+ CError_Error(CErrorStr130);
+ return;
+ }
+
+ if (tk == '}')
+ break;
+
+ CPrep_NewFileOffsetInfo(&cparser_fileoffset, NULL);
+ symdecloffset = cparser_fileoffset.tokenline;
+ symdecltoken = *CPrep_CurStreamElement();
+
+ memclrw(di, sizeof(DeclInfo));
+ di->is_extern_c = r28;
+ di->qual = qual;
+ CParser_ParseDeclaration(di);
+ }
+ } else if (tk == TK_EXTERN && copts.cpp_extensions && lookahead() == TK_STRING) {
+ tk = lex();
+ CParser_ParseLinkageSpecification(di);
+ } else {
+ memclrw(di, sizeof(DeclInfo));
+ di->is_extern_c = r28;
+ di->qual = qual;
+ CParser_GetDeclSpecs(di, 1);
+
+ if (di->storageclass != TK_TYPEDEF) {
+ if (di->storageclass && copts.pedantic)
+ CError_Warning(CErrorStr177);
+ if (!di->storageclass)
+ di->storageclass = TK_EXTERN;
+ }
+ if (copts.cpp_extensions)
+ di->x48 = 0;
+ if (tk != ';')
+ scandeclaratorlist(di);
+ }
+}
+
+static void CParser_ParseNameSpace(DeclInfo *di) {
+ NameSpace *nspace;
+ ObjNameSpace *objns;
+ HashNameNode *name;
+ Boolean flag;
+ CScopeSave save;
+ NameSpaceObjectList *list;
+ NameSpaceList *nsl;
+
+ if ((tk = lex()) == TK_IDENTIFIER) {
+ name = tkidentifier;
+ flag = 0;
+ if ((tk = lex()) == '=') {
+ CScope_ParseNameSpaceAlias(name);
+ return;
+ }
+ } else {
+ if (tk != '{') {
+ CError_Error(CErrorStr107);
+ return;
+ }
+ name = CParser_GetUnnamedNameSpaceName();
+ flag = 1;
+ }
+
+ nspace = cscope_current;
+ if (!(list = CScope_FindName(nspace, name))) {
+ objns = galloc(sizeof(ObjNameSpace));
+ memclrw(objns, sizeof(ObjNameSpace));
+ objns->otype = OT_NAMESPACE;
+ objns->access = ACCESSPUBLIC;
+ if (flag) {
+ nspace = CScope_NewListNameSpace(name, 1);
+ nspace->is_unnamed = 1;
+ nsl = galloc(sizeof(NameSpaceList));
+ nsl->next = cscope_current->usings;
+ nsl->nspace = nspace;
+ cscope_current->usings = nsl;
+ } else {
+ nspace = CScope_NewHashNameSpace(name);
+ if (cscope_current->is_unnamed)
+ nspace->is_unnamed = 1;
+ }
+
+ nspace->parent = cscope_current;
+ objns->nspace = nspace;
+ CScope_AddObject(cscope_current, name, OBJ_BASE(objns));
+ } else {
+ if (list->object->otype != OT_NAMESPACE)
+ CError_Error(CErrorStr320);
+ else
+ nspace = OBJ_NAMESPACE(list->object)->nspace;
+ }
+
+ if (tk != '{') {
+ CError_Error(CErrorStr135);
+ return;
+ }
+
+ CScope_SetNameSpaceScope(nspace, &save);
+ while (1) {
+ if ((tk = lex()) == 0) {
+ CError_Error(CErrorStr130);
+ break;
+ }
+
+ if (tk == '}')
+ break;
+
+ CPrep_NewFileOffsetInfo(&cparser_fileoffset, NULL);
+ symdecloffset = cparser_fileoffset.tokenline;
+ symdecltoken = *CPrep_CurStreamElement();
+
+ memclrw(di, sizeof(DeclInfo));
+ CParser_ParseDeclaration(di);
+ }
+ CScope_RestoreScope(&save);
+}
+
+static void CParser_ParseDeclaration(DeclInfo *di) {
+ switch (tk) {
+ case TK_AT_INTERFACE:
+ CObjC_ParseInterface();
+ break;
+ case TK_AT_IMPLEMENTATION:
+ CObjC_ParseImplementation();
+ break;
+ case TK_AT_PROTOCOL:
+ CObjC_ParseProtocol();
+ break;
+ case TK_AT_CLASS:
+ CObjC_ParseClassDeclaration();
+ break;
+ case TK_NAMESPACE:
+ CParser_ParseNameSpace(di);
+ break;
+ case TK_EXPORT:
+ CError_Error(CErrorStr190);
+ if ((tk = lex()) != TK_TEMPLATE) {
+ CError_Error(CErrorStr121);
+ return;
+ }
+ case TK_TEMPLATE:
+ CTempl_Parse(NULL, 0);
+ break;
+ case TK_USING:
+ if ((tk = lex()) == TK_NAMESPACE) {
+ tk = lex();
+ CScope_ParseUsingDirective(cscope_current);
+ } else {
+ CScope_ParseUsingDeclaration(cscope_current, 0, 0);
+ }
+ break;
+ case TK_EXTERN:
+ if (copts.cplusplus) {
+ di->storageclass = TK_EXTERN;
+ if ((tk = lex()) == TK_STRING) {
+ CParser_ParseLinkageSpecification(di);
+ break;
+ }
+ }
+ default:
+ CParser_GetDeclSpecs(di, 1);
+ if ((di->storageclass == TK_REGISTER || di->storageclass == TK_AUTO) != 0) {
+ CError_Error(CErrorStr177);
+ di->storageclass = 0;
+ }
+ if (tk != ';')
+ scandeclaratorlist(di);
+ else
+ CParser_CheckAnonymousUnion(di, 0);
+ CParser_GlobalCleanup(0);
+ }
+}
+
+void cparser(void) {
+ DeclInfo di;
+
+ if (copts.crippled && copts.optimizationlevel > 1) {
+ CError_Warning(CErrorStr385);
+ copts.optimizationlevel = 1;
+ CodeGen_UpdateOptimizerOptions();
+ CodeGen_UpdateBackEndOptions();
+ }
+
+ if ((tk = lex())) {
+ do {
+ CPrep_NewFileOffsetInfo(&cparser_fileoffset, NULL);
+ symdecloffset = cparser_fileoffset.tokenline;
+ symdecltoken = *CPrep_CurStreamElement();
+
+ memclrw(&di, sizeof(DeclInfo));
+ CParser_ParseDeclaration(&di);
+ } while (tk && (tk = lex()));
+ } else {
+ if (!copts.cplusplus && copts.ANSIstrict)
+ CError_Error(CErrorStr102);
+ }
+
+ CInit_DefineTentativeData();
+ copts.defer_codegen = 0;
+ CParser_GlobalCleanup(1);
+
+ if (cparamblkptr->precompile != 1) {
+ CInline_Finish();
+ CParser_GlobalCleanup(1);
+ }
+
+ CClass_GenThunks();
+ if (cparamblkptr->precompile != 1)
+ CObjC_GenerateModule();
+
+ CSOM_Cleanup();
+ CInit_DefineTentativeData();
+}
diff --git a/compiler_and_linker/FrontEnd/C/CPrec.c b/compiler_and_linker/FrontEnd/C/CPrec.c
new file mode 100644
index 0000000..e61b96e
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CPrec.c
@@ -0,0 +1,3482 @@
+#include "compiler/CPrec.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInit.h"
+#include "compiler/CInline.h"
+#include "compiler/CMachine.h"
+#include "compiler/CObjC.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CScope.h"
+#include "compiler/CSOM.h"
+#include "compiler/CTemplateNew.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/Exceptions.h"
+#include "compiler/enode.h"
+#include "compiler/objc.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/som.h"
+#include "compiler/templates.h"
+#include "compiler/types.h"
+#include "cos.h"
+#include "compiler/CCompiler.h"
+#include "compiler/InlineAsm.h"
+
+#define RESOLVE_BUFFER(offset) ((void *) (((char *) cprec_buffer) + ((uintptr_t) (offset))))
+#define RESOLVE_RAW_BUFFER(offset) ((void *) (((char *) cprec_rawbuffer) + ((uintptr_t) (offset))))
+#define RESOLVE_SAFE(offset) (!(offset) ? NULL : ((void *) (((char *) cprec_rawbuffer) + ((uintptr_t) (offset)))))
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct StaticData {
+ struct StaticData *next;
+ Object *object;
+ void *buffer;
+ OLinkList *links;
+ SInt32 size;
+} StaticData;
+
+typedef struct Header {
+ UInt32 magic;
+ UInt16 version;
+ UInt16 x6;
+ char target;
+ Boolean check_header_flags;
+ Boolean cplusplus;
+ UInt32 xC;
+ UInt32 x10;
+ UInt32 x14;
+ UInt32 x18;
+ UInt32 x1C;
+ UInt32 x20;
+ UInt32 x24;
+ UInt32 x28;
+ UInt32 x2C;
+ UInt32 x30;
+ UInt32 compressedPatchCount;
+ UInt32 compressedPatchSize;
+ UInt32 compressedPatchOffset;
+ UInt32 builtinPatchSize;
+ UInt32 builtinPatchOffset;
+ UInt32 tokenStreamPatchSize;
+ UInt32 tokenStreamPatchOffset;
+ UInt32 root_names;
+ NameSpaceList *usings;
+ TemplClass *ctempl_templates;
+ CSOMStub *csom_stubs;
+ StaticData *cprec_staticdata;
+ UInt32 uniqueID;
+ CallbackAction *callbackactions;
+ Type *cobjc_type_class;
+ Type *cobjc_type_id;
+ Type *cobjc_type_sel;
+ ObjCSelector **cobjc_selhashtable;
+ BClassList *cobjc_classdefs;
+ ObjCProtocol *cobjc_protocols;
+ UInt32 cobjc_selrefcount;
+ UInt32 cobjc_classrefcount;
+ UInt32 cobjc_stringcount;
+ InitExpr *init_expressions;
+ CI_Action *cinline_tactionlist;
+ TemplateFunction *ctempl_templatefuncs;
+ UInt32 x9C;
+ UInt32 xA0;
+ UInt32 xA4;
+ UInt32 xA8;
+ UInt32 xAC;
+ UInt32 xB0;
+ UInt32 xB4;
+ UInt32 xB8;
+ UInt32 xBC;
+ UInt32 xC0;
+ UInt32 xC4;
+ UInt32 xC8;
+ UInt32 xCC;
+ UInt32 xD0;
+ UInt32 xD4;
+ UInt32 xD8;
+ UInt32 xDC;
+ UInt32 xE0;
+ UInt32 xE4;
+ HashNameNode *nametable[0x800];
+ Macro *macrotable[0x800];
+ NameSpaceName *root_nametable[0x400];
+} Header;
+
+typedef struct Patch {
+ struct Patch *next;
+ SInt32 offset;
+} Patch;
+
+typedef struct AddrPatch {
+ struct AddrPatch *next;
+ void *addr;
+ void *value;
+} AddrPatch;
+
+typedef struct BuiltIn {
+ void *target;
+ SInt32 idx;
+ Patch *patches;
+} BuiltIn;
+
+static Boolean cprec_exportargnames;
+static Boolean cprec_dowrite;
+static OSErr cprec_ioerror;
+static void *cprec_rawbuffer;
+static void *cprec_buffer;
+static SInt32 cprec_zero_offset;
+static SInt32 cprec_offset;
+static int cprec_builtins;
+static void **cprec_builtin_array;
+
+typedef struct TokenPatch {
+ struct TokenPatch *next;
+ TStreamElement *tokens;
+ SInt32 count;
+} TokenPatch;
+static TokenPatch *cprec_tokenpatches;
+static StaticData *cprec_staticdata;
+
+typedef struct PointerHash {
+ struct PointerHash *next;
+ TypePointer *tptr;
+ TypePointer *prec_tptr;
+} PointerHash;
+static PointerHash **cprec_pointerhash;
+
+static BuiltIn *cprec_builtin;
+static Patch *cprec_patch_list;
+static AddrPatch **cprec_addrhash;
+static Header *cprec_header;
+static GList cprec_glist;
+static short cprec_refnum;
+char *precomp_target_str;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+// Assorted forward declarations
+static NameSpace *CPrec_GetNameSpacePatch(NameSpace *nspace);
+static ObjEnumConst *CPrec_GetObjEnumConstPatch(ObjEnumConst *obj);
+static Object *CPrec_GetObjectPatch(Object *obj);
+static ObjBase *CPrec_GetObjBasePatch(ObjBase *obj);
+static ObjMemberVar *CPrec_GetObjMemberVarPatch(ObjMemberVar *ivar);
+static Type *CPrec_GetTypePatch(Type *type);
+static ENode *CPrec_GetExpressionPatch(ENode *expr);
+static ObjCMethod *CPrec_GetObjCMethodPatch(ObjCMethod *meth);
+static ObjCProtocolList *CPrec_GetObjCProtocolListPatch(ObjCProtocolList *lst);
+static TemplArg *CPrec_GetTemplateArgPatch(TemplArg *arg);
+static NameSpaceObjectList *CPrec_GetNameSpaceObjectListPatch(NameSpaceObjectList *nsol);
+static OSErr CPrec_FlushBufferCheck(void);
+
+void SetupPrecompiler(Boolean isPrecompiling) {
+ cprec_refnum = 0;
+ cprec_glist.data = NULL;
+ cprec_header = NULL;
+ cprec_staticdata = NULL;
+ cprec_ioerror = noErr;
+}
+
+void CleanupPrecompiler(void) {
+ if (cprec_refnum) {
+ COS_FileClose(cprec_refnum);
+ cprec_refnum = 0;
+ }
+
+ if (cprec_glist.data)
+ FreeGList(&cprec_glist);
+}
+
+static OLinkList *CPrec_OLinkListCopy(OLinkList *list) {
+ OLinkList *copy;
+
+ if (!list)
+ return NULL;
+
+ copy = galloc(sizeof(OLinkList));
+ *copy = *list;
+ copy->next = CPrec_OLinkListCopy(copy->next);
+ return copy;
+}
+
+void PreComp_StaticData(Object *obj, const void *data, OLinkList *links, SInt32 size) {
+ StaticData *entry;
+
+ if (obj->sclass != TK_STATIC && !(obj->qual & (Q_20000 | Q_WEAK)))
+ CError_Error(CErrorStr180);
+
+ entry = galloc(sizeof(StaticData));
+ entry->object = obj;
+ entry->size = size;
+
+ entry->next = cprec_staticdata;
+ cprec_staticdata = entry;
+
+ if (data) {
+ entry->buffer = galloc(obj->type->size);
+ memcpy(entry->buffer, data, obj->type->size);
+ } else {
+ entry->buffer = NULL;
+ }
+
+ entry->links = CPrec_OLinkListCopy(links);
+}
+
+static void CPrec_InitAddressHashTable(void) {
+ cprec_addrhash = lalloc(0x4000 * sizeof(AddrPatch *));
+ memclrw(cprec_addrhash, 0x4000 * sizeof(AddrPatch *));
+}
+
+static void CPrec_InitPointerHashTable(void) {
+ cprec_pointerhash = lalloc(0x400 * sizeof(PointerHash *));
+ memclrw(cprec_pointerhash, 0x400 * sizeof(PointerHash *));
+}
+
+static int CPrec_AddressHashVal(void *addr) {
+ UInt32 v = (UInt32) addr;
+ return (
+ v +
+ ((unsigned char *) &v)[0] +
+ ((unsigned char *) &v)[1] +
+ ((unsigned char *) &v)[2] +
+ ((unsigned char *) &v)[3]
+ ) & 0x3FFF;
+}
+
+static AddrPatch *CPrec_FindAddrPatch(void *addr) {
+ AddrPatch *scan;
+
+ for (scan = cprec_addrhash[CPrec_AddressHashVal(addr)]; scan; scan = scan->next) {
+ if (scan->addr == addr)
+ return scan;
+ }
+
+ return NULL;
+}
+
+static AddrPatch *CPrec_NewAddrPatch(void *addr, void *value) {
+ AddrPatch **loc;
+ AddrPatch *patch;
+
+ loc = cprec_addrhash + CPrec_AddressHashVal(addr);
+ patch = lalloc(sizeof(AddrPatch));
+ patch->addr = addr;
+ patch->value = value;
+ patch->next = *loc;
+ *loc = patch;
+ return patch;
+}
+
+static void CPrec_SetupBuiltInArray(void) {
+ int count1, count2;
+ Boolean flag;
+ void **array;
+
+#define REG_BUILTIN(a) \
+ if (!flag) { array[count2++] = (a); } else { count1++; }
+
+ for (count2 = count1 = 0, flag = 1; ;) {
+ REG_BUILTIN(cscope_root);
+ REG_BUILTIN(&stvoid);
+ REG_BUILTIN(&stbool);
+ REG_BUILTIN(&stchar);
+ REG_BUILTIN(&stsignedchar);
+ REG_BUILTIN(&stunsignedchar);
+ REG_BUILTIN(&stwchar);
+ REG_BUILTIN(&stsignedshort);
+ REG_BUILTIN(&stunsignedshort);
+ REG_BUILTIN(&stsignedint);
+ REG_BUILTIN(&stunsignedint);
+ REG_BUILTIN(&stsignedlong);
+ REG_BUILTIN(&stunsignedlong);
+ REG_BUILTIN(&stsignedlonglong);
+ REG_BUILTIN(&stunsignedlonglong);
+ REG_BUILTIN(&stfloat);
+ REG_BUILTIN(&stshortdouble);
+ REG_BUILTIN(&stdouble);
+ REG_BUILTIN(&stlongdouble);
+ REG_BUILTIN(&elipsis);
+ REG_BUILTIN(&oldstyle);
+ REG_BUILTIN(&stillegal);
+ REG_BUILTIN(&sttemplexpr);
+ REG_BUILTIN(&stvoid);
+ REG_BUILTIN(&void_ptr);
+ REG_BUILTIN(&rt_func);
+ REG_BUILTIN(&catchinfostruct);
+ REG_BUILTIN(newh_func);
+ REG_BUILTIN(delh_func);
+ REG_BUILTIN(copy_func);
+ REG_BUILTIN(clear_func);
+ REG_BUILTIN(Rgtid_func);
+ REG_BUILTIN(Rdync_func);
+ REG_BUILTIN(rt_ptmf_cast);
+ REG_BUILTIN(rt_ptmf_cmpr);
+ REG_BUILTIN(rt_ptmf_test);
+ REG_BUILTIN(rt_ptmf_call);
+ REG_BUILTIN(rt_ptmf_scall);
+ REG_BUILTIN(rt_ptmf_null);
+ REG_BUILTIN(rt_som_glue1);
+ REG_BUILTIN(rt_som_glue2);
+ REG_BUILTIN(rt_som_glue3);
+ REG_BUILTIN(rt_som_check);
+ REG_BUILTIN(rt_som_new);
+ REG_BUILTIN(rt_som_newcheck);
+ REG_BUILTIN(rt_ptmf_call4);
+ REG_BUILTIN(rt_ptmf_scall4);
+ REG_BUILTIN(carr_func);
+ REG_BUILTIN(cnar_func);
+ REG_BUILTIN(darr_func);
+ REG_BUILTIN(dnar_func);
+ REG_BUILTIN(dnar3_func);
+ REG_BUILTIN(Xgreg_func);
+ REG_BUILTIN(Xthrw_func);
+ REG_BUILTIN(Xicth_func);
+ REG_BUILTIN(Xecth_func);
+ REG_BUILTIN(Xunex_func);
+ REG_BUILTIN(&stvectorunsignedchar);
+ REG_BUILTIN(&stvectorsignedchar);
+ REG_BUILTIN(&stvectorboolchar);
+ REG_BUILTIN(&stvectorunsignedshort);
+ REG_BUILTIN(&stvectorsignedshort);
+ REG_BUILTIN(&stvectorboolshort);
+ REG_BUILTIN(&stvectorunsignedlong);
+ REG_BUILTIN(&stvectorsignedlong);
+ REG_BUILTIN(&stvectorboollong);
+ REG_BUILTIN(&stvectorfloat);
+ REG_BUILTIN(&stvectorpixel);
+
+ if (flag) {
+ array = lalloc(sizeof(void *) * count1);
+ cprec_builtin_array = array;
+ cprec_builtins = count1;
+ flag = 0;
+ } else {
+ return;
+ }
+ }
+}
+
+static void CPrec_SetupBuiltIn(void) {
+ int x;
+
+ CPrec_SetupBuiltInArray();
+ cprec_builtin = lalloc(sizeof(BuiltIn) * cprec_builtins);
+ memclrw(cprec_builtin, sizeof(BuiltIn) * cprec_builtins);
+
+ for (x = 0; x < cprec_builtins; x++) {
+ cprec_builtin[x].target = cprec_builtin_array[x];
+ cprec_builtin[x].idx = ~x;
+ CPrec_NewAddrPatch(cprec_builtin[x].target, (void *) cprec_builtin[x].idx);
+ }
+}
+
+static void CPrec_NewPointerPatch(void *src, void *ptr) {
+ if (cprec_dowrite) {
+ Patch *patch = lalloc(sizeof(Patch));
+ patch->offset = (SInt32) src;
+ CError_ASSERT(507, (patch->offset & 0x80000001) == 0);
+
+ if ((SInt32) ptr < 0) {
+ ptr = (void *) ~((SInt32) ptr);
+ CError_ASSERT(513, (SInt32) ptr < cprec_builtins);
+
+ patch->next = cprec_builtin[(SInt32) ptr].patches;
+ cprec_builtin[(SInt32) ptr].patches = patch;
+ ptr = NULL;
+ } else {
+ patch->next = cprec_patch_list;
+ cprec_patch_list = patch;
+ }
+
+ src = (void *)((char *) src - cprec_zero_offset);
+ CError_ASSERT(525, (SInt32) src >= 0 && (SInt32) src <= cprec_glist.size);
+ *((void **) (*cprec_glist.data + (SInt32) src)) = ptr;
+ }
+}
+
+static void CPrec_ExistingPointerPatch(void *src, void *ptr) {
+ if (cprec_dowrite) {
+ AddrPatch *addrPatch;
+ Patch *patch;
+
+ CError_ASSERT(543, addrPatch = CPrec_FindAddrPatch(ptr));
+
+ patch = lalloc(sizeof(Patch));
+ patch->offset = (SInt32) src;
+ patch->next = cprec_patch_list;
+ cprec_patch_list = patch;
+
+ CError_ASSERT(548, (patch->offset & 0x80000001) == 0);
+
+ src = (void *)((char *) src - cprec_zero_offset);
+ CError_ASSERT(552, (SInt32) src >= 0 && (SInt32) src <= cprec_glist.size);
+ *((void **) (*cprec_glist.data + (SInt32) src)) = addrPatch->value;
+ }
+}
+
+static void CPrec_NamePatch(void *src, HashNameNode *name) {
+ name->id = 1;
+ CPrec_ExistingPointerPatch(src, name);
+}
+
+static void *CPrec_AppendAlign(void) {
+ if (cprec_dowrite) {
+ while (cprec_offset & 3) {
+ AppendGListByte(&cprec_glist, 0);
+ ++cprec_offset;
+ }
+ }
+
+ return (void *) cprec_offset;
+}
+
+static UInt32 CPrec_AppendByte(UInt8 v) {
+ if (cprec_dowrite)
+ AppendGListByte(&cprec_glist, v);
+ return cprec_offset++;
+}
+
+static UInt32 CPrec_AppendWord16(UInt16 v) {
+ UInt32 offset;
+ if (cprec_dowrite)
+ AppendGListWord(&cprec_glist, v);
+ offset = cprec_offset;
+ cprec_offset += 2;
+ return offset;
+}
+
+static UInt32 CPrec_AppendWord32(UInt32 v) {
+ UInt32 offset;
+ if (cprec_dowrite)
+ AppendGListLong(&cprec_glist, v);
+ offset = cprec_offset;
+ cprec_offset += 4;
+ return offset;
+}
+
+static UInt32 CPrec_AppendPointer(void *v) {
+ UInt32 offset;
+ if (cprec_dowrite)
+ AppendGListLong(&cprec_glist, (SInt32) v);
+ offset = cprec_offset;
+ cprec_offset += 4;
+ return offset;
+}
+
+static UInt32 CPrec_AppendPointerPatch(void *v) {
+ AddrPatch *addrPatch;
+
+ if (v) {
+ CError_ASSERT(644, addrPatch = CPrec_FindAddrPatch(v));
+
+ if (cprec_dowrite) {
+ Patch *patch = lalloc(sizeof(Patch));
+ patch->offset = cprec_offset;
+ patch->next = cprec_patch_list;
+ cprec_patch_list = patch;
+ CError_ASSERT(651, (patch->offset & 0x80000001) == 0);
+ }
+
+ return CPrec_AppendPointer(addrPatch->value);
+ } else {
+ return CPrec_AppendPointer(NULL);
+ }
+}
+
+static void CPrec_AppendNamePatch(HashNameNode *name) {
+ if (name) {
+ CPrec_AppendPointerPatch(name);
+ name->id = 1;
+ }
+}
+
+static void CPrec_AppendString(const char *str) {
+ int len = strlen(str) + 1;
+ if (cprec_dowrite)
+ AppendGListData(&cprec_glist, str, len);
+ cprec_offset += len;
+}
+
+static void CPrec_AppendData(const void *data, int len) {
+ if (cprec_dowrite)
+ AppendGListData(&cprec_glist, data, len);
+ cprec_offset += len;
+}
+
+static void CPrec_RawMemPatch(void *source, const void *data, int len) {
+ void *ptr = CPrec_AppendAlign();
+ CPrec_AppendData(data, len);
+ CPrec_NewPointerPatch(source, ptr);
+}
+
+static void CPrec_DumpNameTable(void) {
+ HashNameNode *name;
+ int i;
+ HashNameNode *p;
+ HashNameNode *next;
+
+ if (cprec_dowrite) {
+ i = 0;
+ do {
+ name = name_hash_nodes[i];
+ while (name && name->id == 0)
+ name = name->next;
+
+ if (name) {
+ p = CPrec_AppendAlign();
+ cprec_header->nametable[i] = p;
+
+ while (1) {
+ CPrec_NewAddrPatch(name, p);
+ CPrec_AppendPointer(NULL);
+ CPrec_AppendWord32(0);
+ CPrec_AppendWord16(name->hashval);
+ CPrec_AppendString(name->name);
+
+ name = name->next;
+ while (name && name->id == 0)
+ name = name->next;
+
+ if (!name)
+ break;
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&p->next, next);
+ p = next;
+ }
+ }
+ } while (++i < 0x800);
+ } else {
+ i = 0;
+ do {
+ if ((name = name_hash_nodes[i])) {
+ p = CPrec_AppendAlign();
+ while (1) {
+ CPrec_NewAddrPatch(name, p);
+ CPrec_AppendPointer(NULL);
+ CPrec_AppendWord32(0);
+ CPrec_AppendWord16(name->hashval);
+ CPrec_AppendString(name->name);
+
+ name = name->next;
+ if (!name)
+ break;
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&p->next, next);
+ p = next;
+ }
+ }
+ } while (++i < 0x800);
+ }
+}
+
+static void CPrec_DumpMacroTable(void) {
+ Macro *macro;
+ int i;
+ int j;
+ Macro *p;
+ Macro *next;
+
+ i = 0;
+ do {
+ for (macro = macrohashtable[i]; macro; macro = macro->next) {
+ if (macro->c) {
+ CPrec_NewAddrPatch(macro->c, (void *) cprec_offset);
+ CPrec_AppendString(macro->c);
+ }
+ }
+ } while (++i < 0x800);
+
+ i = 0;
+ do {
+ macro = macrohashtable[i];
+
+ if (macro) {
+ p = CPrec_AppendAlign();
+ if (cprec_dowrite)
+ cprec_header->macrotable[i] = p;
+
+ while (1) {
+ CPrec_AppendPointer(NULL);
+ CPrec_AppendNamePatch(macro->name);
+ CPrec_AppendPointerPatch(macro->c);
+ CPrec_AppendWord16(macro->xC);
+ CPrec_AppendByte(macro->is_special);
+ CPrec_AppendByte(macro->xF);
+
+ for (j = 1; j < (macro->xC & 0x7FFF); j++)
+ CPrec_AppendNamePatch(macro->names[j - 1]);
+
+ macro = macro->next;
+ if (!macro)
+ break;
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&p->next, next);
+ p = next;
+ }
+ }
+ } while (++i < 0x800);
+}
+
+static BClassList *CPrec_GetClassAccessPatch(BClassList *path) {
+ AddrPatch *addrPatch;
+ BClassList *first, *current, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(path)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(path, first);
+
+ while (1) {
+ CPrec_AppendData(path, sizeof(BClassList));
+ CPrec_NewPointerPatch(&current->type, CPrec_GetTypePatch(path->type));
+ if (!path->next)
+ break;
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ path = path->next;
+ }
+
+ return first;
+}
+
+static int CPrec_PointerHash(TypePointer *type) {
+ Type *target;
+ int work;
+ FuncArg *arg;
+
+ work = type->qual;
+ target = type->target;
+
+restart:
+ switch (target->type) {
+ case TYPECLASS:
+ if (TYPE_CLASS(target)->classname)
+ work += TYPE_CLASS(target)->classname->hashval;
+ break;
+ case TYPEENUM:
+ if (TYPE_ENUM(target)->enumname)
+ work += TYPE_ENUM(target)->enumname->hashval;
+ target = TYPE_ENUM(target)->enumtype;
+ work += 3;
+ case TYPEINT:
+ case TYPEFLOAT:
+ work += TYPE_INTEGRAL(target)->integral;
+ break;
+ case TYPEPOINTER:
+ work += TYPE_POINTER(target)->qual;
+ target = TYPE_POINTER(target)->target;
+ goto restart;
+ case TYPEARRAY:
+ work += target->size;
+ target = TYPE_POINTER(target)->target;
+ goto restart;
+ case TYPEFUNC:
+ work += TYPE_FUNC(target)->functype->type;
+ work += TYPE_FUNC(target)->functype->size;
+ for (arg = TYPE_FUNC(target)->args; arg; arg = arg->next) {
+ if (arg->type) {
+ work += arg->type->type;
+ work += arg->type->size;
+ }
+ }
+ break;
+ }
+
+ work += target->type + target->size;
+ return (work + (work >> 24) + (work >> 16) + (work >> 8)) & 0x3FF;
+}
+
+static TypePointer *CPrec_GetTypePointerPatch(TypePointer *tptr) {
+ TypePointer *p;
+ int hash;
+ PointerHash *phash;
+ TypePointer *scan1;
+ TypePointer *scan2;
+
+ if (tptr->qual & Q_IS_OBJC_ID) {
+ p = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(tptr, p);
+ CPrec_AppendData(tptr, sizeof(TypeObjCID));
+ if (TYPE_OBJC_ID(tptr)->protocols)
+ CPrec_NewPointerPatch(&TYPE_OBJC_ID(p)->protocols, CPrec_GetObjCProtocolListPatch(TYPE_OBJC_ID(tptr)->protocols));
+ } else {
+ if (!copts.faster_pch_gen && cprec_dowrite && tptr->size > 0) {
+ hash = CPrec_PointerHash(tptr);
+ for (phash = cprec_pointerhash[hash]; phash; phash = phash->next) {
+ scan1 = tptr;
+ scan2 = phash->tptr;
+ check_again:
+ if (scan1->type == scan2->type && scan1->size == scan2->size && scan1->qual == scan2->qual) {
+ scan1 = TYPE_POINTER(TPTR_TARGET(scan1));
+ scan2 = TYPE_POINTER(TPTR_TARGET(scan2));
+ if (scan1->type == TYPEPOINTER && scan1->type == TYPEARRAY)
+ goto check_again;
+ if (scan1 == scan2)
+ return phash->prec_tptr;
+ }
+ }
+
+ p = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(tptr, p);
+
+ phash = lalloc(sizeof(PointerHash));
+ phash->tptr = tptr;
+ phash->prec_tptr = p;
+ phash->next = cprec_pointerhash[hash];
+ cprec_pointerhash[hash] = phash;
+ } else {
+ p = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(tptr, p);
+ }
+
+ CPrec_AppendData(tptr, sizeof(TypePointer));
+ }
+
+ CPrec_NewPointerPatch(&p->target, CPrec_GetTypePatch(tptr->target));
+ return p;
+}
+
+static TypeEnum *CPrec_GetTypeEnumPatch(TypeEnum *type) {
+ TypeEnum *p = CPrec_AppendAlign();
+
+ CPrec_NewAddrPatch(type, p);
+ CPrec_AppendData(type, sizeof(TypeEnum));
+
+ if (type->nspace)
+ CPrec_NewPointerPatch(&p->nspace, CPrec_GetNameSpacePatch(type->nspace));
+ if (type->enumlist)
+ CPrec_NewPointerPatch(&p->enumlist, CPrec_GetObjEnumConstPatch(type->enumlist));
+
+ CPrec_NewPointerPatch(&p->enumtype, CPrec_GetTypePatch(type->enumtype));
+ if (type->enumname)
+ CPrec_NamePatch(&p->enumname, type->enumname);
+
+ return p;
+}
+
+static TypeBitfield *CPrec_GetTypeBitfieldPatch(TypeBitfield *type) {
+ TypeBitfield *p = CPrec_AppendAlign();
+
+ CPrec_NewAddrPatch(type, p);
+ CPrec_AppendData(type, sizeof(TypeBitfield));
+ CPrec_NewPointerPatch(&p->bitfieldtype, CPrec_GetTypePatch(type->bitfieldtype));
+
+ return p;
+}
+
+static TypeStruct *CPrec_GetTypeStructPatch(TypeStruct *tstruct) {
+ StructMember *member;
+ TypeStruct *p;
+ StructMember *current, *next;
+
+ p = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(tstruct, p);
+ CPrec_AppendData(tstruct, sizeof(TypeStruct));
+
+ if (tstruct->name)
+ CPrec_NamePatch(&p->name, tstruct->name);
+
+ if ((member = tstruct->members)) {
+ current = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&p->members, current);
+
+ while (1) {
+ CPrec_AppendData(member, sizeof(StructMember));
+ CPrec_NewPointerPatch(&current->type, CPrec_GetTypePatch(member->type));
+ CPrec_NamePatch(&current->name, member->name);
+
+ if (!member->next)
+ break;
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+
+ member = member->next;
+ }
+ }
+
+ return p;
+}
+
+static ExceptSpecList *CPrec_GetExceptSpecPatch(ExceptSpecList *exspec) {
+ ExceptSpecList *first, *current, *next;
+
+ first = current = CPrec_AppendAlign();
+ while (exspec) {
+ CPrec_AppendData(exspec, sizeof(ExceptSpecList));
+ if (exspec->type)
+ CPrec_NewPointerPatch(&current->type, CPrec_GetTypePatch(exspec->type));
+
+ if (!exspec->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ exspec = exspec->next;
+ }
+
+ return first;
+}
+
+static FuncArg *CPrec_GetArgListPatch(FuncArg *lst, Boolean includeNames) {
+ FuncArg *first, *current, *next;
+ AddrPatch *addrPatch;
+
+ if ((addrPatch = CPrec_FindAddrPatch(lst)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ while (1) {
+ if (!includeNames)
+ lst->name = NULL;
+ CPrec_AppendData(lst, sizeof(FuncArg));
+ if (includeNames && lst->name)
+ CPrec_NamePatch(&current->name, lst->name);
+
+ if (lst->dexpr)
+ CPrec_NewPointerPatch(&current->dexpr, CPrec_GetExpressionPatch(lst->dexpr));
+ if (lst->type)
+ CPrec_NewPointerPatch(&current->type, CPrec_GetTypePatch(lst->type));
+ else
+ CError_FATAL(1167);
+
+ if (!lst->next)
+ break;
+
+ if ((addrPatch = CPrec_FindAddrPatch(lst->next))) {
+ CPrec_NewPointerPatch(&current->next, addrPatch->value);
+ break;
+ }
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ lst = lst->next;
+ CPrec_NewAddrPatch(lst, next);
+ }
+
+ return first;
+}
+
+static TypeFunc *CPrec_GetTypeFuncPatch(TypeFunc *type) {
+ TypeFunc *p = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(type, p);
+
+ CPrec_AppendData(type, (type->flags & FUNC_METHOD) ? sizeof(TypeMemberFunc) : sizeof(TypeFunc));
+
+ CPrec_NewPointerPatch(&p->functype, CPrec_GetTypePatch(type->functype));
+ if (type->args)
+ CPrec_NewPointerPatch(&p->args, CPrec_GetArgListPatch(type->args, (type->flags & FUNC_IS_TEMPL_ANY) != 0));
+ if (type->exspecs)
+ CPrec_NewPointerPatch(&p->exspecs, CPrec_GetExceptSpecPatch(type->exspecs));
+ if (type->flags & FUNC_METHOD)
+ CPrec_NewPointerPatch(&TYPE_METHOD(p)->theclass, CPrec_GetTypePatch((Type *) TYPE_METHOD(type)->theclass));
+
+ return p;
+}
+
+static TypeMemberPointer *CPrec_GetTypeMemberPointerPatch(TypeMemberPointer *type) {
+ TypeMemberPointer *p = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(type, p);
+
+ CPrec_AppendData(type, sizeof(TypeMemberPointer));
+
+ CPrec_NewPointerPatch(&p->ty1, CPrec_GetTypePatch(type->ty1));
+ CPrec_NewPointerPatch(&p->ty2, CPrec_GetTypePatch(type->ty2));
+
+ return p;
+}
+
+static TypeTemplDep *CPrec_GetTypeTemplDepPatch(TypeTemplDep *type) {
+ TypeTemplDep *p = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(type, p);
+
+ CPrec_AppendData(type, sizeof(TypeTemplDep));
+
+ switch (type->dtype) {
+ case TEMPLDEP_ARGUMENT:
+ break;
+ case TEMPLDEP_QUALNAME:
+ CPrec_NewPointerPatch(&p->u.qual.type, CPrec_GetTypeTemplDepPatch(type->u.qual.type));
+ CPrec_NamePatch(&p->u.qual.name, type->u.qual.name);
+ break;
+ case TEMPLDEP_TEMPLATE:
+ CPrec_NewPointerPatch(&p->u.templ.templ, CPrec_GetTypePatch((Type *) type->u.templ.templ));
+ CPrec_NewPointerPatch(&p->u.templ.args, CPrec_GetTemplateArgPatch(type->u.templ.args));
+ break;
+ case TEMPLDEP_ARRAY:
+ CPrec_NewPointerPatch(&p->u.array.type, CPrec_GetTypePatch(type->u.array.type));
+ CPrec_NewPointerPatch(&p->u.array.index, CPrec_GetExpressionPatch(type->u.array.index));
+ break;
+ case TEMPLDEP_QUALTEMPL:
+ CPrec_NewPointerPatch(&p->u.qualtempl.type, CPrec_GetTypeTemplDepPatch(type->u.qualtempl.type));
+ CPrec_NewPointerPatch(&p->u.qualtempl.args, CPrec_GetTemplateArgPatch(type->u.qualtempl.args));
+ break;
+ case TEMPLDEP_BITFIELD:
+ CPrec_NewPointerPatch(&p->u.bitfield.type, CPrec_GetTypePatch(type->u.bitfield.type));
+ CPrec_NewPointerPatch(&p->u.bitfield.size, CPrec_GetExpressionPatch(type->u.bitfield.size));
+ break;
+ default:
+ CError_FATAL(1295);
+ }
+
+ return p;
+}
+
+static ClassList *CPrec_GetClassListPatch(ClassList *cl) {
+ AddrPatch *addrPatch;
+ ClassList *first, *current, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(cl)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(cl, first);
+
+ do {
+ CPrec_AppendData(cl, sizeof(ClassList));
+ CPrec_NewPointerPatch(&current->base, CPrec_GetTypePatch((Type *) cl->base));
+
+ if (!cl->next)
+ break;
+
+ if ((addrPatch = CPrec_FindAddrPatch(cl->next))) {
+ CPrec_NewPointerPatch(&current->next, addrPatch->value);
+ break;
+ } else {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ cl = cl->next;
+ }
+ } while (1);
+
+ return first;
+}
+
+static VClassList *CPrec_GetVClassListPatch(VClassList *vcl) {
+ VClassList *first, *current, *next;
+ first = current = CPrec_AppendAlign();
+
+ do {
+ CPrec_AppendData(vcl, sizeof(VClassList));
+ CPrec_NewPointerPatch(&current->base, CPrec_GetTypePatch((Type *) vcl->base));
+
+ if (!vcl->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ vcl = vcl->next;
+ } while (1);
+
+ return first;
+}
+
+static ClassFriend *CPrec_GetClassFriendPatch(ClassFriend *cf) {
+ ClassFriend *first, *current, *next;
+ first = current = CPrec_AppendAlign();
+
+ do {
+ CPrec_AppendData(cf, sizeof(ClassFriend));
+ if (cf->isclass)
+ CPrec_NewPointerPatch(&current->u.theclass, CPrec_GetTypePatch((Type *) cf->u.theclass));
+ else
+ CPrec_NewPointerPatch(&current->u.theclass, CPrec_GetObjectPatch(cf->u.obj));
+
+ if (!cf->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ cf = cf->next;
+ } while (1);
+
+ return first;
+}
+
+static BClassList *CPrec_GetBClassListPatch(BClassList *bcl) {
+ BClassList *first, *current, *next;
+ first = current = CPrec_AppendAlign();
+
+ do {
+ CPrec_AppendData(bcl, sizeof(BClassList));
+ CPrec_NewPointerPatch(&current->type, CPrec_GetTypePatch((Type *) bcl->type));
+
+ if (!bcl->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ bcl = bcl->next;
+ } while (1);
+
+ return first;
+}
+
+static VTable *CPrec_GetVTablePatch(VTable *vtbl) {
+ VTable *p = CPrec_AppendAlign();
+ CPrec_AppendData(vtbl, sizeof(VTable));
+
+ if (vtbl->object)
+ CPrec_NewPointerPatch(&p->object, CPrec_GetObjectPatch(vtbl->object));
+ if (vtbl->owner)
+ CPrec_NewPointerPatch(&p->owner, CPrec_GetTypePatch((Type *) vtbl->owner));
+
+ return p;
+}
+
+static SOMReleaseOrder *CPrec_GetSOMReleaseOrderPatch(SOMReleaseOrder *sro) {
+ SOMReleaseOrder *first, *current, *next;
+ first = current = CPrec_AppendAlign();
+
+ do {
+ CPrec_AppendData(sro, sizeof(SOMReleaseOrder));
+ CPrec_NamePatch(&current->name, sro->name);
+ if (!sro->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ sro = sro->next;
+ } while (1);
+
+ return first;
+}
+
+static SOMInfo *CPrec_GetSOMInfoPatch(SOMInfo *som) {
+ SOMInfo *p = CPrec_AppendAlign();
+ CPrec_AppendData(som, sizeof(SOMInfo));
+
+ if (som->metaclass)
+ CPrec_NewPointerPatch(&p->metaclass, CPrec_GetTypePatch((Type *) som->metaclass));
+ if (som->classdataobject)
+ CPrec_NewPointerPatch(&p->classdataobject, CPrec_GetObjectPatch(som->classdataobject));
+ if (som->order)
+ CPrec_NewPointerPatch(&p->order, CPrec_GetSOMReleaseOrderPatch(som->order));
+
+ return p;
+}
+
+static ObjCMethodArg *CPrec_GetObjCMethodArgPatch(ObjCMethodArg *arg) {
+ ObjCMethodArg *first, *current, *next;
+ first = current = CPrec_AppendAlign();
+
+ do {
+ CPrec_AppendData(arg, sizeof(ObjCMethod));
+ if (arg->selector)
+ CPrec_NamePatch(&current->selector, arg->selector);
+ if (arg->name)
+ CPrec_NamePatch(&current->name, arg->name);
+ if (arg->type)
+ CPrec_NewPointerPatch(&current->type, CPrec_GetTypePatch(arg->type));
+
+ if (!arg->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ arg = arg->next;
+ } while (1);
+
+ return first;
+}
+
+static ObjCMethodList *CPrec_GetObjCMethodListPatch(ObjCMethodList *lst) {
+ AddrPatch *addrPatch;
+ ObjCMethodList *first, *current, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(lst)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(lst, first);
+
+ do {
+ CPrec_AppendData(lst, sizeof(ObjCMethodList));
+ if (lst->method)
+ CPrec_NewPointerPatch(&current->method, CPrec_GetObjCMethodPatch(lst->method));
+
+ if (!lst->next)
+ break;
+
+ if ((addrPatch = CPrec_FindAddrPatch(lst->next))) {
+ CPrec_NewPointerPatch(&current->next, addrPatch->value);
+ break;
+ } else {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ lst = lst->next;
+ CPrec_NewAddrPatch(lst, next);
+ }
+ } while (1);
+
+ return first;
+}
+
+static ObjCSelector *CPrec_GetObjCSelectorPatch(ObjCSelector *sel) {
+ AddrPatch *addrPatch;
+ ObjCSelector *current, *first, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(sel)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(sel, first);
+
+ do {
+ CPrec_AppendData(sel, sizeof(ObjCSelector));
+ if (sel->selobject)
+ CPrec_NewPointerPatch(&current->selobject, CPrec_GetObjectPatch(sel->selobject));
+ CPrec_NamePatch(&current->name, sel->name);
+ if (sel->methods)
+ CPrec_NewPointerPatch(&current->methods, CPrec_GetObjCMethodListPatch(sel->methods));
+
+ if (!sel->next)
+ break;
+
+ if ((addrPatch = CPrec_FindAddrPatch(sel->next))) {
+ CPrec_NewPointerPatch(&current->next, addrPatch->value);
+ break;
+ } else {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ sel = sel->next;
+ CPrec_NewAddrPatch(sel, next);
+ }
+ } while (1);
+
+ return first;
+}
+
+static ObjCMethod *CPrec_GetObjCMethodPatch(ObjCMethod *meth) {
+ // does not match - affected by weirdness where the arg goes into r31 instead of r28
+ AddrPatch *addrPatch;
+ ObjCMethod *current, *first, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(meth)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(meth, first);
+
+ do {
+ CPrec_AppendData(meth, sizeof(ObjCMethod));
+ if (meth->object)
+ CPrec_NewPointerPatch(&current->object, CPrec_GetObjectPatch(meth->object));
+ if (meth->functype)
+ CPrec_NewPointerPatch(&current->functype, CPrec_GetTypePatch((Type *) meth->functype));
+ if (meth->selector)
+ CPrec_NewPointerPatch(&current->selector, CPrec_GetObjCSelectorPatch(meth->selector));
+ if (meth->return_type)
+ CPrec_NewPointerPatch(&current->return_type, CPrec_GetTypePatch(meth->return_type));
+ if (meth->selector_args)
+ CPrec_NewPointerPatch(&current->selector_args, CPrec_GetObjCMethodArgPatch(meth->selector_args));
+
+ if (!meth->next)
+ break;
+
+ if ((addrPatch = CPrec_FindAddrPatch(meth->next))) {
+ CPrec_NewPointerPatch(&current->next, addrPatch->value);
+ break;
+ } else {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ meth = meth->next;
+ CPrec_NewAddrPatch(meth, next);
+ }
+ } while (1);
+
+ return first;
+}
+
+static ObjCProtocol *CPrec_GetObjCProtocolPatch(ObjCProtocol *prot) {
+ AddrPatch *addrPatch;
+ ObjCProtocol *current, *first, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(prot)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(prot, first);
+
+ do {
+ CPrec_AppendData(prot, sizeof(ObjCProtocol));
+ CPrec_NamePatch(&current->name, prot->name);
+ if (prot->protocols)
+ CPrec_NewPointerPatch(&current->protocols, CPrec_GetObjCProtocolListPatch(prot->protocols));
+ if (prot->methods)
+ CPrec_NewPointerPatch(&current->methods, CPrec_GetObjCMethodPatch(prot->methods));
+ if (prot->object)
+ CPrec_NewPointerPatch(&current->object, CPrec_GetObjectPatch(prot->object));
+
+ if (!prot->next)
+ break;
+
+ if ((addrPatch = CPrec_FindAddrPatch(prot->next))) {
+ CPrec_NewPointerPatch(&current->next, addrPatch->value);
+ break;
+ } else {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ prot = prot->next;
+ CPrec_NewAddrPatch(prot, next);
+ }
+ } while (1);
+
+ return first;
+}
+
+static ObjCProtocolList *CPrec_GetObjCProtocolListPatch(ObjCProtocolList *lst) {
+ AddrPatch *addrPatch;
+ ObjCProtocolList *first, *current, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(lst)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(lst, first);
+
+ do {
+ CPrec_AppendData(lst, sizeof(ObjCProtocolList));
+ CPrec_NewPointerPatch(&current->protocol, CPrec_GetObjCProtocolPatch(lst->protocol));
+
+ if (!lst->next)
+ break;
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ lst = lst->next;
+ } while (1);
+
+ return first;
+}
+
+static ObjCCategory *CPrec_GetObjCCategoryPatch(ObjCCategory *cat) {
+ AddrPatch *addrPatch;
+ ObjCCategory *current, *first, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(cat)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(cat, first);
+
+ do {
+ CPrec_AppendData(cat, sizeof(ObjCCategory));
+ CPrec_NamePatch(&current->name, cat->name);
+ if (cat->protocols)
+ CPrec_NewPointerPatch(&current->protocols, CPrec_GetObjCProtocolListPatch(cat->protocols));
+ if (cat->methods)
+ CPrec_NewPointerPatch(&current->methods, CPrec_GetObjCMethodPatch(cat->methods));
+
+ if (!cat->next)
+ break;
+
+ if ((addrPatch = CPrec_FindAddrPatch(cat->next))) {
+ CPrec_NewPointerPatch(&current->next, addrPatch->value);
+ break;
+ } else {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ cat = cat->next;
+ CPrec_NewAddrPatch(cat, next);
+ }
+ } while (1);
+
+ return first;
+}
+
+static ObjCInfo *CPrec_GetObjCInfoPatch(ObjCInfo *info) {
+ ObjCInfo *p = CPrec_AppendAlign();
+ CPrec_AppendData(info, sizeof(ObjCInfo));
+
+ if (info->classobject)
+ CPrec_NewPointerPatch(&p->classobject, CPrec_GetObjectPatch(info->classobject));
+ if (info->metaobject)
+ CPrec_NewPointerPatch(&p->metaobject, CPrec_GetObjectPatch(info->metaobject));
+ if (info->classrefobj)
+ CPrec_NewPointerPatch(&p->classrefobj, CPrec_GetObjectPatch(info->classrefobj));
+ if (info->methods)
+ CPrec_NewPointerPatch(&p->methods, CPrec_GetObjCMethodPatch(info->methods));
+ if (info->protocols)
+ CPrec_NewPointerPatch(&p->protocols, CPrec_GetObjCProtocolListPatch(info->protocols));
+ if (info->categories)
+ CPrec_NewPointerPatch(&p->categories, CPrec_GetObjCCategoryPatch(info->categories));
+
+ return p;
+}
+
+static TemplArg *CPrec_GetTemplateArgPatch(TemplArg *arg) {
+ TemplArg *first, *current, *next;
+ first = current = CPrec_AppendAlign();
+
+ do {
+ CPrec_AppendData(arg, sizeof(TemplArg));
+ switch (arg->pid.type) {
+ case TPT_TYPE:
+ if (arg->data.typeparam.type)
+ CPrec_NewPointerPatch(&current->data.typeparam.type, CPrec_GetTypePatch(arg->data.typeparam.type));
+ break;
+ case TPT_NONTYPE:
+ if (arg->data.paramdecl.expr)
+ CPrec_NewPointerPatch(&current->data.paramdecl.expr, CPrec_GetExpressionPatch(arg->data.paramdecl.expr));
+ break;
+ case TPT_TEMPLATE:
+ if (arg->data.ttargtype)
+ CPrec_NewPointerPatch(&current->data.ttargtype, CPrec_GetTypePatch(arg->data.ttargtype));
+ break;
+ default:
+ CError_FATAL(1879);
+ }
+
+ if (!arg->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ arg = arg->next;
+ } while (1);
+
+ return first;
+}
+
+static TemplParam *CPrec_GetTemplateParamPatch(TemplParam *param) {
+ // register swap issues
+ TemplParam *first, *current, *next;
+ first = current = CPrec_AppendAlign();
+
+ do {
+ CPrec_AppendData(param, sizeof(TemplParam));
+ if (param->name)
+ CPrec_NamePatch(&current->name, param->name);
+
+ switch (param->pid.type) {
+ case TPT_TYPE:
+ if (param->data.typeparam.type)
+ CPrec_NewPointerPatch(&current->data.typeparam.type, CPrec_GetTypePatch(param->data.typeparam.type));
+ break;
+ case TPT_NONTYPE:
+ CPrec_NewPointerPatch(&current->data.paramdecl.type, CPrec_GetTypePatch(param->data.paramdecl.type));
+ if (param->data.paramdecl.defaultarg)
+ CPrec_NewPointerPatch(&current->data.paramdecl.defaultarg, CPrec_GetExpressionPatch(param->data.paramdecl.defaultarg));
+ break;
+ case TPT_TEMPLATE:
+ if (param->data.templparam.plist)
+ CPrec_NewPointerPatch(&current->data.templparam.plist, CPrec_GetTemplateParamPatch(param->data.templparam.plist));
+ CError_ASSERT(1953, !param->data.templparam.defaultarg);
+ break;
+ default:
+ CError_FATAL(1958);
+ }
+
+ if (!param->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ param = param->next;
+ } while (1);
+
+ return first;
+}
+
+static TStreamElement *CPrec_GetTStreamPatch(TStreamElement *tokens, SInt32 count) {
+ TStreamElement elem;
+ TStreamElement *first, *current, *scan;
+ SInt32 x;
+
+ scan = tokens;
+ x = 0;
+ while (x < count) {
+ elem = *scan;
+ memclrw(scan, sizeof(TStreamElement));
+
+ scan->tokentype = elem.tokentype;
+ switch (elem.tokentype) {
+ case TK_IDENTIFIER:
+ scan->data.tkidentifier = elem.data.tkidentifier;
+ break;
+ case TK_INTCONST:
+ scan->subtype = elem.subtype;
+ scan->data.tkintconst = elem.data.tkintconst;
+ break;
+ case TK_FLOATCONST:
+ scan->subtype = elem.subtype;
+ scan->data.tkfloatconst = elem.data.tkfloatconst;
+ break;
+ case TK_STRING:
+ case TK_STRING_WIDE:
+ scan->subtype = elem.subtype;
+ scan->data.tkstring = elem.data.tkstring;
+ break;
+ }
+ x++;
+ scan++;
+ }
+
+ first = current = CPrec_AppendAlign();
+ CPrec_AppendData(tokens, count * sizeof(TStreamElement));
+
+ if (cprec_dowrite) {
+ TokenPatch *tp = lalloc(sizeof(TokenPatch));
+ tp->tokens = current;
+ tp->count = count;
+ tp->next = cprec_tokenpatches;
+ cprec_tokenpatches = tp;
+ }
+
+ x = 0;
+ while (x < count) {
+ switch (tokens->tokentype) {
+ case TK_IDENTIFIER:
+ CPrec_NamePatch(&current->data.tkidentifier, tokens->data.tkidentifier);
+ break;
+ case TK_INTCONST:
+ case TK_FLOATCONST:
+ break;
+ case TK_STRING:
+ case TK_STRING_WIDE:
+ CPrec_RawMemPatch(&current->data.tkstring.data, tokens->data.tkstring.data, tokens->data.tkstring.size);
+ break;
+ case TK_EOL:
+ break;
+ default:
+ if (tokens->tokentype < 0)
+ CError_FATAL(2063);
+ }
+ x++;
+ tokens++;
+ current++;
+ }
+
+ return first;
+}
+
+static TemplFuncInstance *CPrec_GetTemplFuncInstancePatch(TemplFuncInstance *inst) {
+ AddrPatch *addrPatch;
+ TemplFuncInstance *first, *current, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(inst)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(inst, first);
+
+ do {
+ CPrec_AppendData(inst, sizeof(TemplFuncInstance));
+ CPrec_NewPointerPatch(&current->object, CPrec_GetObjectPatch(inst->object));
+ CPrec_NewPointerPatch(&current->args, CPrec_GetTemplateArgPatch(inst->args));
+
+ if (!inst->next)
+ break;
+
+ if ((addrPatch = CPrec_FindAddrPatch(inst->next))) {
+ CPrec_NewPointerPatch(&current->next, addrPatch->value);
+ break;
+ } else {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ inst = inst->next;
+ CPrec_NewAddrPatch(inst, next);
+ }
+ } while (1);
+
+ return first;
+}
+
+static TemplateMember *CPrec_GetTemplateMemberPatch(TemplateMember *memb) {
+ TemplateMember *current, *first, *next;
+ first = current = CPrec_AppendAlign();
+
+ do {
+ memclrw(&memb->fileoffset, sizeof(FileOffsetInfo));
+ memb->srcfile = NULL;
+ memb->startoffset = 0;
+ memb->endoffset = 0;
+
+ CPrec_AppendData(memb, sizeof(TemplateMember));
+ if (memb->params)
+ CPrec_NewPointerPatch(&current->params, CPrec_GetTemplateParamPatch(memb->params));
+ CPrec_NewPointerPatch(&current->object, CPrec_GetObjectPatch(memb->object));
+ if (memb->stream.firsttoken)
+ CPrec_NewPointerPatch(&current->stream.firsttoken, CPrec_GetTStreamPatch(memb->stream.firsttoken, memb->stream.tokens));
+
+ if (!memb->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ memb = memb->next;
+ } while (1);
+
+ return first;
+}
+
+static TemplPartialSpec *CPrec_GetTemplPartialSpecPatch(TemplPartialSpec *pspec) {
+ TemplPartialSpec *first, *current, *next;
+ first = current = CPrec_AppendAlign();
+
+ do {
+ CPrec_AppendData(pspec, sizeof(TemplPartialSpec));
+ if (pspec->templ)
+ CPrec_NewPointerPatch(&current->templ, CPrec_GetTypePatch((Type *) pspec->templ));
+ if (pspec->args)
+ CPrec_NewPointerPatch(&current->args, CPrec_GetTemplateArgPatch(pspec->args));
+
+ if (!pspec->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ pspec = pspec->next;
+ } while (1);
+
+ return first;
+}
+
+static TemplateFriend *CPrec_GetTemplateFriendPatch(TemplateFriend *frnd) {
+ TemplateFriend *p;
+
+ memclrw(&frnd->fileoffset, sizeof(FileOffsetInfo));
+ p = CPrec_AppendAlign();
+ CPrec_AppendData(frnd, sizeof(TemplateFriend));
+
+ if (frnd->decl.thetype)
+ CPrec_NewPointerPatch(&p->decl.thetype, CPrec_GetTypePatch(frnd->decl.thetype));
+ if (frnd->decl.nspace)
+ CPrec_NewPointerPatch(&p->decl.nspace, CPrec_GetNameSpacePatch(frnd->decl.nspace));
+ if (frnd->decl.name)
+ CPrec_NamePatch(&p->decl.name, frnd->decl.name);
+ if (frnd->decl.expltargs)
+ CPrec_NewPointerPatch(&p->decl.expltargs, CPrec_GetTemplateArgPatch(frnd->decl.expltargs));
+ if (frnd->stream.firsttoken)
+ CPrec_NewPointerPatch(&p->stream.firsttoken, CPrec_GetTStreamPatch(frnd->stream.firsttoken, frnd->stream.tokens));
+
+ return p;
+}
+
+static TemplateAction *CPrec_GetTemplateActionPatch(TemplateAction *act) {
+ // register swap issue
+ TemplateAction *current, *first, *next;
+ first = current = CPrec_AppendAlign();
+
+ do {
+ memclrw(&act->source_ref, sizeof(TStreamElement));
+ CPrec_AppendData(act, sizeof(TemplateAction));
+
+ switch (act->type) {
+ case TAT_NESTEDCLASS:
+ CPrec_NewPointerPatch(&current->u.tclasstype, CPrec_GetTypePatch((Type *) act->u.tclasstype));
+ break;
+ case TAT_ENUMTYPE:
+ CPrec_NewPointerPatch(&current->u.enumtype, CPrec_GetTypePatch((Type *) act->u.enumtype));
+ break;
+ case TAT_FRIEND:
+ CPrec_NewPointerPatch(&current->u.tfriend, CPrec_GetTemplateFriendPatch(act->u.tfriend));
+ break;
+ case TAT_ENUMERATOR:
+ CPrec_NewPointerPatch(&current->u.enumerator.objenumconst, CPrec_GetObjEnumConstPatch(act->u.enumerator.objenumconst));
+ if (act->u.enumerator.initexpr)
+ CPrec_NewPointerPatch(&current->u.enumerator.initexpr, CPrec_GetExpressionPatch(act->u.enumerator.initexpr));
+ break;
+ case TAT_BASE:
+ CPrec_NewPointerPatch(&current->u.base.type, CPrec_GetTypePatch(act->u.base.type));
+ if (act->u.base.insert_after)
+ CPrec_NewPointerPatch(&current->u.base.insert_after, CPrec_GetClassListPatch(act->u.base.insert_after));
+ break;
+ case TAT_OBJECTINIT:
+ CPrec_NewPointerPatch(&current->u.objectinit.object, CPrec_GetObjectPatch(act->u.objectinit.object));
+ CPrec_NewPointerPatch(&current->u.objectinit.initexpr, CPrec_GetExpressionPatch(act->u.objectinit.initexpr));
+ break;
+ case TAT_USINGDECL:
+ CPrec_NewPointerPatch(&current->u.usingdecl.type, CPrec_GetTypeTemplDepPatch(act->u.usingdecl.type));
+ break;
+ case TAT_OBJECTDEF:
+ CPrec_NewPointerPatch(&current->u.refobj, CPrec_GetObjBasePatch(act->u.refobj));
+ break;
+ default:
+ CError_FATAL(2410);
+ }
+
+ if (!act->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ act = act->next;
+ } while (1);
+
+ return first;
+}
+
+static TemplateFunction *CPrec_GetTemplateFunctionPatch(TemplateFunction *tf) {
+ // the same cursed register swaps
+ AddrPatch *addrPatch;
+ TemplateFunction *first, *current, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(tf)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(tf, first);
+
+ do {
+ memclrw(&tf->deftoken, sizeof(TStreamElement));
+ tf->srcfile = NULL;
+ tf->startoffset = 0;
+ tf->endoffset = 0;
+
+ CPrec_AppendData(tf, sizeof(TemplateFunction));
+ if (tf->unk4)
+ CPrec_NewPointerPatch(&current->unk4, CPrec_GetTemplateFunctionPatch(tf->unk4));
+ CPrec_NamePatch(&current->name, tf->name);
+ if (tf->params)
+ CPrec_NewPointerPatch(&current->params, CPrec_GetTemplateParamPatch(tf->params));
+ if (tf->stream.firsttoken)
+ CPrec_NewPointerPatch(&current->stream.firsttoken, CPrec_GetTStreamPatch(tf->stream.firsttoken, tf->stream.tokens));
+ CPrec_NewPointerPatch(&current->tfunc, CPrec_GetObjectPatch(tf->tfunc));
+ if (tf->instances)
+ CPrec_NewPointerPatch(&current->instances, CPrec_GetTemplFuncInstancePatch(tf->instances));
+
+ if (!tf->next)
+ break;
+
+ if ((addrPatch = CPrec_FindAddrPatch(tf->next))) {
+ CPrec_NewPointerPatch(&current->next, addrPatch->value);
+ break;
+ } else {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ tf = tf->next;
+ CPrec_NewAddrPatch(tf, next);
+ }
+ } while (1);
+
+ return first;
+}
+
+static TypeClass *CPrec_GetTypeClassPatch(TypeClass *tclass) {
+ TypeClass *first, *current, *next;
+ Boolean hasNextTempl, hasNextTemplInst;
+ first = current = CPrec_AppendAlign();
+
+ do_over:
+ hasNextTempl = hasNextTemplInst = 0;
+ CPrec_NewAddrPatch(tclass, current);
+
+ if (tclass->flags & CLASS_IS_TEMPL) {
+ // template class
+ CPrec_AppendData(tclass, sizeof(TemplClass));
+ if (TEMPL_CLASS(tclass)->next)
+ hasNextTempl = 1;
+ if (TEMPL_CLASS(tclass)->templ_parent)
+ CPrec_NewPointerPatch(&TEMPL_CLASS(current)->templ_parent, CPrec_GetTypePatch((Type *) TEMPL_CLASS(tclass)->templ_parent));
+ if (TEMPL_CLASS(tclass)->inst_parent)
+ CPrec_NewPointerPatch(&TEMPL_CLASS(current)->inst_parent, CPrec_GetTypePatch((Type *) TEMPL_CLASS(tclass)->inst_parent));
+ if (TEMPL_CLASS(tclass)->templ__params)
+ CPrec_NewPointerPatch(&TEMPL_CLASS(current)->templ__params, CPrec_GetTemplateParamPatch(TEMPL_CLASS(tclass)->templ__params));
+ if (TEMPL_CLASS(tclass)->members)
+ CPrec_NewPointerPatch(&TEMPL_CLASS(current)->members, CPrec_GetTemplateMemberPatch(TEMPL_CLASS(tclass)->members));
+ if (TEMPL_CLASS(tclass)->instances)
+ CPrec_NewPointerPatch(&TEMPL_CLASS(current)->instances, CPrec_GetTypePatch((Type *) TEMPL_CLASS(tclass)->instances));
+ if (TEMPL_CLASS(tclass)->pspec_owner)
+ CPrec_NewPointerPatch(&TEMPL_CLASS(current)->pspec_owner, CPrec_GetTypePatch((Type *) TEMPL_CLASS(tclass)->pspec_owner));
+ if (TEMPL_CLASS(tclass)->pspecs)
+ CPrec_NewPointerPatch(&TEMPL_CLASS(current)->pspecs, CPrec_GetTemplPartialSpecPatch(TEMPL_CLASS(tclass)->pspecs));
+ if (TEMPL_CLASS(tclass)->actions)
+ CPrec_NewPointerPatch(&TEMPL_CLASS(current)->actions, CPrec_GetTemplateActionPatch(TEMPL_CLASS(tclass)->actions));
+ } else if (tclass->flags & CLASS_IS_TEMPL_INST) {
+ // template class instance
+ CPrec_AppendData(tclass, sizeof(TemplClassInst));
+ if (TEMPL_CLASS_INST(tclass)->next)
+ hasNextTemplInst = 1;
+ if (TEMPL_CLASS_INST(tclass)->parent)
+ CPrec_NewPointerPatch(&TEMPL_CLASS_INST(current)->parent, CPrec_GetTypePatch((Type *) TEMPL_CLASS_INST(tclass)->parent));
+ if (TEMPL_CLASS_INST(tclass)->templ)
+ CPrec_NewPointerPatch(&TEMPL_CLASS_INST(current)->templ, CPrec_GetTypePatch((Type *) TEMPL_CLASS_INST(tclass)->templ));
+ if (TEMPL_CLASS_INST(tclass)->inst_args)
+ CPrec_NewPointerPatch(&TEMPL_CLASS_INST(current)->inst_args, CPrec_GetTemplateArgPatch(TEMPL_CLASS_INST(tclass)->inst_args));
+ if (TEMPL_CLASS_INST(tclass)->oargs)
+ CPrec_NewPointerPatch(&TEMPL_CLASS_INST(current)->oargs, CPrec_GetTemplateArgPatch(TEMPL_CLASS_INST(tclass)->oargs));
+ } else {
+ // base
+ CPrec_AppendData(tclass, sizeof(TypeClass));
+ }
+
+ if (tclass->nspace)
+ CPrec_NewPointerPatch(&current->nspace, CPrec_GetNameSpacePatch(tclass->nspace));
+ if (tclass->classname)
+ CPrec_NamePatch(&current->classname, tclass->classname);
+ if (tclass->bases)
+ CPrec_NewPointerPatch(&current->bases, CPrec_GetClassListPatch(tclass->bases));
+ if (tclass->vbases)
+ CPrec_NewPointerPatch(&current->vbases, CPrec_GetVClassListPatch(tclass->vbases));
+ if (tclass->ivars)
+ CPrec_NewPointerPatch(&current->ivars, CPrec_GetObjMemberVarPatch(tclass->ivars));
+ if (tclass->friends)
+ CPrec_NewPointerPatch(&current->friends, CPrec_GetClassFriendPatch(tclass->friends));
+ if (tclass->vtable)
+ CPrec_NewPointerPatch(&current->vtable, CPrec_GetVTablePatch(tclass->vtable));
+ if (tclass->sominfo)
+ CPrec_NewPointerPatch(&current->sominfo, CPrec_GetSOMInfoPatch(tclass->sominfo));
+ if (tclass->objcinfo)
+ CPrec_NewPointerPatch(&current->objcinfo, CPrec_GetObjCInfoPatch(tclass->objcinfo));
+
+ if (hasNextTempl) {
+ AddrPatch *addrPatch = CPrec_FindAddrPatch(TEMPL_CLASS(tclass)->next);
+ if (!addrPatch) {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&TEMPL_CLASS(current)->next, next);
+ current = next;
+ tclass = (TypeClass *) TEMPL_CLASS(tclass)->next;
+ goto do_over;
+ } else {
+ CPrec_NewPointerPatch(&TEMPL_CLASS(current)->next, addrPatch->value);
+ }
+ }
+
+ if (hasNextTemplInst) {
+ AddrPatch *addrPatch = CPrec_FindAddrPatch(TEMPL_CLASS_INST(tclass)->next);
+ if (!addrPatch) {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&TEMPL_CLASS_INST(current)->next, next);
+ current = next;
+ tclass = (TypeClass *) TEMPL_CLASS_INST(tclass)->next;
+ goto do_over;
+ } else {
+ CPrec_NewPointerPatch(&TEMPL_CLASS_INST(current)->next, addrPatch->value);
+ }
+ }
+
+ return first;
+}
+
+static Type *CPrec_GetTypePatch(Type *type) {
+ AddrPatch *addrPatch = CPrec_FindAddrPatch(type);
+ if (addrPatch)
+ return addrPatch->value;
+
+ switch (type->type) {
+ case TYPEPOINTER:
+ case TYPEARRAY:
+ return (Type *) CPrec_GetTypePointerPatch(TYPE_POINTER(type));
+ case TYPEENUM:
+ return (Type *) CPrec_GetTypeEnumPatch(TYPE_ENUM(type));
+ case TYPEBITFIELD:
+ return (Type *) CPrec_GetTypeBitfieldPatch(TYPE_BITFIELD(type));
+ case TYPESTRUCT:
+ return (Type *) CPrec_GetTypeStructPatch(TYPE_STRUCT(type));
+ case TYPEFUNC:
+ return (Type *) CPrec_GetTypeFuncPatch(TYPE_FUNC(type));
+ case TYPEMEMBERPOINTER:
+ return (Type *) CPrec_GetTypeMemberPointerPatch(TYPE_MEMBER_POINTER(type));
+ case TYPETEMPLATE:
+ return (Type *) CPrec_GetTypeTemplDepPatch(TYPE_TEMPLATE(type));
+ case TYPECLASS:
+ return (Type *) CPrec_GetTypeClassPatch(TYPE_CLASS(type));
+ case TYPEVOID:
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPELABEL:
+ case TYPEOBJCID:
+ case TYPETEMPLDEPEXPR:
+ default:
+ CError_FATAL(2796);
+ return NULL;
+ }
+}
+
+static ExceptionAction *CPrec_GetExceptionPatch(ExceptionAction *exc) {
+ ExceptionAction *first, *current, *next;
+
+ first = current = CPrec_AppendAlign();
+repeat:
+ CPrec_AppendData(exc, sizeof(ExceptionAction));
+ switch (exc->type) {
+ case EAT_DESTROYLOCAL:
+ CPrec_NewPointerPatch(&current->data.destroy_local.dtor, CPrec_GetObjectPatch(exc->data.destroy_local.dtor));
+ break;
+ case EAT_DESTROYLOCALCOND:
+ CPrec_NewPointerPatch(&current->data.destroy_local_cond.dtor, CPrec_GetObjectPatch(exc->data.destroy_local_cond.dtor));
+ break;
+ case EAT_DESTROYLOCALOFFSET:
+ CPrec_NewPointerPatch(&current->data.destroy_local_offset.dtor, CPrec_GetObjectPatch(exc->data.destroy_local_offset.dtor));
+ break;
+ case EAT_DESTROYLOCALPOINTER:
+ CPrec_NewPointerPatch(&current->data.destroy_local_pointer.dtor, CPrec_GetObjectPatch(exc->data.destroy_local_pointer.dtor));
+ break;
+ case EAT_DESTROYLOCALARRAY:
+ CPrec_NewPointerPatch(&current->data.destroy_local_array.dtor, CPrec_GetObjectPatch(exc->data.destroy_local_array.dtor));
+ break;
+ case EAT_DESTROYPARTIALARRAY:
+ break;
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYBASE:
+ CPrec_NewPointerPatch(&current->data.destroy_member.dtor, CPrec_GetObjectPatch(exc->data.destroy_member.dtor));
+ break;
+ case EAT_DESTROYMEMBERCOND:
+ CPrec_NewPointerPatch(&current->data.destroy_member_cond.dtor, CPrec_GetObjectPatch(exc->data.destroy_member_cond.dtor));
+ break;
+ case EAT_DESTROYMEMBERARRAY:
+ CPrec_NewPointerPatch(&current->data.destroy_member_array.dtor, CPrec_GetObjectPatch(exc->data.destroy_member_array.dtor));
+ break;
+ case EAT_DELETEPOINTER:
+ case EAT_DELETELOCALPOINTER:
+ CPrec_NewPointerPatch(&current->data.delete_pointer.deletefunc, CPrec_GetObjectPatch(exc->data.delete_pointer.deletefunc));
+ break;
+ case EAT_DELETEPOINTERCOND:
+ CPrec_NewPointerPatch(&current->data.delete_pointer_cond.deletefunc, CPrec_GetObjectPatch(exc->data.delete_pointer_cond.deletefunc));
+ break;
+ case EAT_CATCHBLOCK:
+ if (exc->data.catch_block.catch_typeid) {
+ CPrec_NewPointerPatch(&current->data.catch_block.catch_typeid, CPrec_GetObjectPatch(exc->data.catch_block.catch_typeid));
+ CPrec_NewPointerPatch(&current->data.catch_block.catch_type, CPrec_GetTypePatch(exc->data.catch_block.catch_type));
+ }
+ break;
+ case EAT_ACTIVECATCHBLOCK:
+ break;
+ case EAT_SPECIFICATION:
+ if (exc->data.specification.unexp_id) {
+ int x;
+ char *ptrs;
+ ptrs = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->data.specification.unexp_id, ptrs);
+ CPrec_AppendData(exc->data.specification.unexp_id, sizeof(Object *) * exc->data.specification.unexp_ids);
+ for (x = 0; x < exc->data.specification.unexp_ids; x++) {
+ CPrec_NewPointerPatch(ptrs + x * sizeof(Object *), CPrec_GetObjectPatch(exc->data.specification.unexp_id[x]));
+ }
+ }
+ break;
+ case EAT_TERMINATE:
+ break;
+ default:
+ CError_FATAL(2905);
+ }
+
+ if (exc->prev) {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->prev, next);
+ current = next;
+ exc = exc->prev;
+ goto repeat;
+ }
+ return first;
+}
+
+static ENodeList *CPrec_GetExpressionListPatch(ENodeList *lst) {
+ ENodeList *first, *current, *next;
+ first = current = CPrec_AppendAlign();
+
+ do {
+ CPrec_AppendData(lst, sizeof(ENodeList));
+ CPrec_NewPointerPatch(&current->node, CPrec_GetExpressionPatch(lst->node));
+
+ if (!lst->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ lst = lst->next;
+ } while (1);
+
+ return first;
+}
+
+static EMemberInfo *CPrec_GetEMemberInfoPatch(EMemberInfo *emember) {
+ EMemberInfo *p;
+
+ CError_FATAL(2953);
+
+ p = CPrec_AppendAlign();
+ CPrec_AppendData(emember, sizeof(EMemberInfo));
+
+ if (emember->path)
+ CPrec_NewPointerPatch(&p->path, CPrec_GetClassAccessPatch(emember->path));
+ if (emember->expr)
+ CPrec_NewPointerPatch(&p->expr, CPrec_GetExpressionPatch(emember->expr));
+ CError_ASSERT(2968, !emember->templargs);
+ CPrec_NewPointerPatch(&p->list, CPrec_GetNameSpaceObjectListPatch(emember->list));
+
+ return p;
+}
+
+static ENode *CPrec_GetExpressionPatch(ENode *expr) {
+ ENode *p;
+
+ if (ENODE_IS(expr, ETEMPLDEP) && expr->data.templdep.subtype == TDE_SOURCEREF)
+ expr->data.templdep.u.sourceref.token = NULL;
+
+ p = CPrec_AppendAlign();
+ CPrec_AppendData(expr, sizeof(ENode));
+
+ CPrec_NewPointerPatch(&p->rtype, CPrec_GetTypePatch(expr->rtype));
+
+ switch (expr->type) {
+ ENODE_CASE_MONADIC:
+ CPrec_NewPointerPatch(&p->data.monadic, CPrec_GetExpressionPatch(expr->data.monadic));
+ break;
+ ENODE_CASE_DIADIC_ALL:
+ CPrec_NewPointerPatch(&p->data.diadic.left, CPrec_GetExpressionPatch(expr->data.diadic.left));
+ CPrec_NewPointerPatch(&p->data.diadic.right, CPrec_GetExpressionPatch(expr->data.diadic.right));
+ break;
+ case ECOND:
+ CPrec_NewPointerPatch(&p->data.cond.cond, CPrec_GetExpressionPatch(expr->data.cond.cond));
+ CPrec_NewPointerPatch(&p->data.cond.expr1, CPrec_GetExpressionPatch(expr->data.cond.expr1));
+ CPrec_NewPointerPatch(&p->data.cond.expr2, CPrec_GetExpressionPatch(expr->data.cond.expr2));
+ break;
+ case ESTRINGCONST:
+ CPrec_RawMemPatch(&p->data.string.data, expr->data.string.data, expr->data.string.size);
+ break;
+ case EOBJREF:
+ CPrec_NewPointerPatch(&p->data.objref, CPrec_GetObjectPatch(expr->data.objref));
+ break;
+ case EOBJLIST:
+ CPrec_NewPointerPatch(&p->data.objlist.list, CPrec_GetNameSpaceObjectListPatch(expr->data.objlist.list));
+ CError_ASSERT(3043, !expr->data.objlist.templargs);
+ if (expr->data.objlist.name)
+ CPrec_NamePatch(&p->data.objlist.name, expr->data.objlist.name);
+ break;
+ case EMFPOINTER:
+ CPrec_NewPointerPatch(&p->data.mfpointer.accessnode, CPrec_GetExpressionPatch(expr->data.mfpointer.accessnode));
+ CPrec_NewPointerPatch(&p->data.mfpointer.mfpointer, CPrec_GetExpressionPatch(expr->data.mfpointer.mfpointer));
+ break;
+ case ENULLCHECK:
+ CPrec_NewPointerPatch(&p->data.nullcheck.nullcheckexpr, CPrec_GetExpressionPatch(expr->data.nullcheck.nullcheckexpr));
+ CPrec_NewPointerPatch(&p->data.nullcheck.condexpr, CPrec_GetExpressionPatch(expr->data.nullcheck.condexpr));
+ break;
+ case ETEMP:
+ CPrec_NewPointerPatch(&p->data.temp.type, CPrec_GetTypePatch(expr->data.temp.type));
+ break;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ CPrec_NewPointerPatch(&p->data.funccall.funcref, CPrec_GetExpressionPatch(expr->data.funccall.funcref));
+ CPrec_NewPointerPatch(&p->data.funccall.functype, CPrec_GetTypePatch(TYPE(expr->data.funccall.functype)));
+ if (expr->data.funccall.args)
+ CPrec_NewPointerPatch(&p->data.funccall.args, CPrec_GetExpressionListPatch(expr->data.funccall.args));
+ break;
+ case EMEMBER:
+ CPrec_NewPointerPatch(&p->data.emember, CPrec_GetEMemberInfoPatch(expr->data.emember));
+ break;
+ case ETEMPLDEP:
+ switch (expr->data.templdep.subtype) {
+ case TDE_PARAM:
+ break;
+ case TDE_SIZEOF:
+ case TDE_ALIGNOF:
+ CPrec_NewPointerPatch(&p->data.templdep.u.typeexpr.type, CPrec_GetTypePatch(expr->data.templdep.u.typeexpr.type));
+ break;
+ case TDE_CAST:
+ if (expr->data.templdep.u.cast.args)
+ CPrec_NewPointerPatch(&p->data.templdep.u.cast.args, CPrec_GetExpressionListPatch(expr->data.templdep.u.cast.args));
+ CPrec_NewPointerPatch(&p->data.templdep.u.cast.type, CPrec_GetTypePatch(expr->data.templdep.u.cast.type));
+ break;
+ case TDE_QUALNAME:
+ CPrec_NamePatch(&p->data.templdep.u.qual.name, expr->data.templdep.u.qual.name);
+ CPrec_NewPointerPatch(&p->data.templdep.u.qual.type, CPrec_GetTypePatch(TYPE(expr->data.templdep.u.qual.type)));
+ break;
+ case TDE_OBJ:
+ CPrec_NewPointerPatch(&p->data.templdep.u.obj, CPrec_GetObjectPatch(expr->data.templdep.u.obj));
+ break;
+ case TDE_SOURCEREF:
+ CPrec_NewPointerPatch(&p->data.templdep.u.sourceref.expr, CPrec_GetExpressionPatch(expr->data.templdep.u.sourceref.expr));
+ break;
+ case TDE_ADDRESS_OF:
+ CPrec_NewPointerPatch(&p->data.templdep.u.monadic, CPrec_GetExpressionPatch(expr->data.templdep.u.monadic));
+ break;
+ default:
+ CError_FATAL(3136);
+ }
+ break;
+ case EINTCONST:
+ case EFLOATCONST:
+ case EPRECOMP:
+ case EARGOBJ:
+ case ELOCOBJ:
+ case ELABEL:
+ case EINSTRUCTION:
+ case EVECTOR128CONST:
+ break;
+ default:
+ CError_FATAL(3142);
+ }
+
+ return p;
+}
+
+static CI_Switch *CPrec_GetSwitchInfoPatch(CI_Switch *si) {
+ CI_Switch *p = CPrec_AppendAlign();
+ CPrec_AppendData(si, sizeof(CI_Switch) + sizeof(CI_SwitchCase) * (si->numcases - 1));
+
+ CPrec_NewPointerPatch(&p->expr, CPrec_GetExpressionPatch(si->expr));
+ CPrec_NewPointerPatch(&p->unkSwitch8, CPrec_GetTypePatch(si->unkSwitch8));
+ return p;
+}
+
+static InlineAsm *CPrec_GetInlineAsmPatch(InlineAsm *ia, SInt32 size) {
+ InlineAsm *p;
+ SInt32 index;
+ SInt32 offset;
+ Object *object;
+
+ p = CPrec_AppendAlign();
+ CPrec_AppendData(ia, size);
+
+ index = 0;
+ while (1) {
+ object = InlineAsm_GetObjectOffset(ia, index, &offset);
+ if (!object)
+ break;
+
+ object = CPrec_GetObjectPatch(object);
+ CPrec_NewPointerPatch((char *) p + offset, object);
+ index++;
+ }
+
+ return p;
+}
+
+static CI_Statement *CPrec_GetStatementPatch(CI_Statement *stmt, short count) {
+ short i;
+ CI_Statement *first, *current;
+
+ for (i = 0; i < count; i++) {
+ stmt[i].sourcefilepath = NULL;
+ stmt[i].sourceoffset = -1;
+ }
+
+ first = current = CPrec_AppendAlign();
+ CPrec_AppendData(stmt, sizeof(CI_Statement) * count);
+
+ for (i = 0; i < count; i++) {
+ if (stmt->dobjstack)
+ CPrec_NewPointerPatch(&current->dobjstack, CPrec_GetExceptionPatch(stmt->dobjstack));
+
+ switch (stmt->type) {
+ case ST_EXPRESSION:
+ case ST_RETURN:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ if (stmt->u.expr)
+ CPrec_NewPointerPatch(&current->u.expr, CPrec_GetExpressionPatch(stmt->u.expr));
+ break;
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ CPrec_NewPointerPatch(&current->u.ifgoto.expr, CPrec_GetExpressionPatch(stmt->u.ifgoto.expr));
+ break;
+ case ST_SWITCH:
+ CPrec_NewPointerPatch(&current->u.switchdata, CPrec_GetSwitchInfoPatch(stmt->u.switchdata));
+ break;
+ case ST_ASM:
+ CPrec_NewPointerPatch(&current->u.asmdata.data, CPrec_GetInlineAsmPatch(stmt->u.asmdata.data, stmt->u.asmdata.size));
+ break;
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_GOTO:
+ break;
+ default:
+ CError_FATAL(3261);
+ }
+
+ current++;
+ stmt++;
+ }
+
+ return first;
+}
+
+static CI_Var *CPrec_GetLocObjectPatch(CI_Var *obj, short count) {
+ CI_Var *first, *current;
+ short i;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_AppendData(obj, sizeof(CI_Var) * count);
+
+ for (i = 0; i < count; i++) {
+ CPrec_NamePatch(&current->name, obj->name);
+ CPrec_NewPointerPatch(&current->type, CPrec_GetTypePatch(obj->type));
+ current++;
+ obj++;
+ }
+
+ return first;
+}
+
+static CI_FuncData *CPrec_GetInlineFuncPatch(CI_FuncData *ifunc) {
+ CI_FuncData *p;
+
+ memclrw(&ifunc->fileoffset, sizeof(FileOffsetInfo));
+ ifunc->symdecloffset = 0;
+ ifunc->functionbodyoffset = 0;
+ ifunc->functionbodypath = NULL;
+ ifunc->symdeclend = 0;
+
+ p = CPrec_AppendAlign();
+ CPrec_AppendData(ifunc, sizeof(CI_FuncData));
+
+ if (ifunc->numarguments)
+ CPrec_NewPointerPatch(&p->arguments, CPrec_GetLocObjectPatch(ifunc->arguments, ifunc->numarguments));
+ if (ifunc->numlocals)
+ CPrec_NewPointerPatch(&p->locals, CPrec_GetLocObjectPatch(ifunc->locals, ifunc->numlocals));
+ if (ifunc->numstatements)
+ CPrec_NewPointerPatch(&p->statements, CPrec_GetStatementPatch(ifunc->statements, ifunc->numstatements));
+
+ return p;
+}
+
+static ObjEnumConst *CPrec_GetObjEnumConstPatch(ObjEnumConst *obj) {
+ AddrPatch *addrPatch;
+ ObjEnumConst *first, *current, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(obj)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(obj, first);
+
+ do {
+ CPrec_AppendData(obj, sizeof(ObjEnumConst));
+ if (cprec_dowrite) {
+ CError_ASSERT(3349, obj->access != 255);
+ obj->access = 255;
+ }
+ CPrec_NamePatch(&current->name, obj->name);
+ CPrec_NewPointerPatch(&current->type, CPrec_GetTypePatch( obj->type));
+
+ if (!obj->next)
+ break;
+
+ if ((addrPatch = CPrec_FindAddrPatch(obj->next))) {
+ CPrec_NewPointerPatch(&current->next, addrPatch->value);
+ break;
+ } else {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ obj = obj->next;
+ CPrec_NewAddrPatch(obj, next);
+ }
+ } while (1);
+
+ return first;
+}
+
+static ObjType *CPrec_GetObjTypePatch(ObjType *obj) {
+ AddrPatch *addrPatch;
+ ObjType *p;
+
+ if ((addrPatch = CPrec_FindAddrPatch(obj)))
+ return addrPatch->value;
+
+ p = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(obj, p);
+ CPrec_AppendData(obj, sizeof(ObjType));
+ CPrec_NewPointerPatch(&p->type, CPrec_GetTypePatch(obj->type));
+ return p;
+}
+
+static ObjTypeTag *CPrec_GetObjTypeTagPatch(ObjTypeTag *obj) {
+ AddrPatch *addrPatch;
+ ObjTypeTag *p;
+
+ if ((addrPatch = CPrec_FindAddrPatch(obj)))
+ return addrPatch->value;
+
+ p = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(obj, p);
+ CPrec_AppendData(obj, sizeof(ObjTypeTag));
+ CPrec_NewPointerPatch(&p->type, CPrec_GetTypePatch(obj->type));
+ return p;
+}
+
+static ObjNameSpace *CPrec_GetObjNameSpacePatch(ObjNameSpace *obj) {
+ AddrPatch *addrPatch;
+ ObjNameSpace *p;
+
+ if ((addrPatch = CPrec_FindAddrPatch(obj)))
+ return addrPatch->value;
+
+ p = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(obj, p);
+ CPrec_AppendData(obj, sizeof(ObjNameSpace));
+ CPrec_NewPointerPatch(&p->nspace, CPrec_GetNameSpacePatch(obj->nspace));
+ return p;
+}
+
+static ObjMemberVar *CPrec_GetObjMemberVarPatch(ObjMemberVar *ivar) {
+ AddrPatch *addrPatch;
+ ObjMemberVar *first, *current, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(ivar)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(ivar, first);
+
+ while (1) {
+ if (ivar->has_path) {
+ CPrec_AppendData(ivar, sizeof(ObjMemberVarPath));
+ if (OBJ_MEMBER_VAR_PATH(ivar)->path)
+ CPrec_NewPointerPatch(
+ &OBJ_MEMBER_VAR_PATH(current)->path,
+ CPrec_GetClassAccessPatch(OBJ_MEMBER_VAR_PATH(ivar)->path));
+ } else {
+ CPrec_AppendData(ivar, sizeof(ObjMemberVar));
+ }
+
+ if (ivar->name)
+ CPrec_NamePatch(&current->name, ivar->name);
+ CPrec_NewPointerPatch(&current->type, CPrec_GetTypePatch(ivar->type));
+
+ if (!ivar->next)
+ break;
+
+ if ((addrPatch = CPrec_FindAddrPatch(ivar->next))) {
+ CPrec_NewPointerPatch(&current->next, addrPatch->value);
+ break;
+ }
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+
+ current = next;
+ ivar = ivar->next;
+ CPrec_NewAddrPatch(ivar, current);
+ }
+
+ return first;
+}
+
+static DefArgCtorInfo *CPrec_GetDefArgCtorInfoPatch(DefArgCtorInfo *dac) {
+ DefArgCtorInfo *p = CPrec_AppendAlign();
+ CPrec_AppendData(dac, sizeof(DefArgCtorInfo));
+ CPrec_NewPointerPatch(&p->default_func, CPrec_GetObjectPatch(dac->default_func));
+ CPrec_NewPointerPatch(&p->default_arg, CPrec_GetExpressionPatch(dac->default_arg));
+ return p;
+}
+
+static InlineXRef *CPrec_GetInlineXRefPatch(InlineXRef *ix) {
+ InlineXRef *first, *current, *next;
+ first = current = CPrec_AppendAlign();
+
+ do {
+ CPrec_AppendData(ix, sizeof(InlineXRef) + sizeof(XRefOffset) * (ix->numxrefs - 1));
+ CPrec_NewPointerPatch(&current->object, CPrec_GetObjectPatch(ix->object));
+
+ if (!ix->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ ix = ix->next;
+ } while (1);
+
+ return first;
+}
+
+static Object *CPrec_GetObjectPatch(Object *obj) {
+ AddrPatch *addrPatch;
+ Object *p;
+
+ if (CWUserBreak(cparams.context) != cwNoErr)
+ CError_UserBreak();
+
+ if ((addrPatch = CPrec_FindAddrPatch(obj)))
+ return addrPatch->value;
+
+ p = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(obj, p);
+
+ obj->toc = NULL;
+
+ if ((obj->qual & Q_IS_TEMPLATED) && obj->datatype != DALIAS) {
+ CPrec_AppendData(obj, sizeof(ObjectTemplated));
+ CPrec_NewPointerPatch(&OBJECT_TEMPL(p)->parent, CPrec_GetObjectPatch(OBJECT_TEMPL(obj)->parent));
+ } else {
+ CPrec_AppendData(obj, sizeof(Object));
+ }
+
+ if (obj->nspace)
+ CPrec_NewPointerPatch(&p->nspace, CPrec_GetNameSpacePatch(obj->nspace));
+ if (obj->name)
+ CPrec_NamePatch(&p->name, obj->name);
+ CPrec_NewPointerPatch(&p->type, CPrec_GetTypePatch(obj->type));
+
+ switch (obj->datatype) {
+ case DABSOLUTE:
+ break;
+
+ case DLOCAL:
+ CError_FATAL(3580);
+ break;
+
+ case DFUNC:
+ case DVFUNC:
+ if (IS_TEMPL_FUNC(obj->type))
+ CPrec_NewPointerPatch(&p->u.func.u.templ, CPrec_GetTemplateFunctionPatch(obj->u.func.u.templ));
+ else if ((obj->qual & Q_INLINE) && obj->u.func.u.ifuncdata)
+ CPrec_NewPointerPatch(&p->u.func.u.ifuncdata, CPrec_GetInlineFuncPatch(obj->u.func.u.ifuncdata));
+
+ if (obj->u.func.defargdata)
+ CPrec_NewPointerPatch(&p->u.func.defargdata, CPrec_GetDefArgCtorInfoPatch(obj->u.func.defargdata));
+ if (obj->u.func.linkname)
+ CPrec_NamePatch(&p->u.func.linkname, obj->u.func.linkname);
+ if (obj->u.func.inst)
+ CPrec_NewPointerPatch(&p->u.func.inst, CPrec_GetTemplFuncInstancePatch(obj->u.func.inst));
+ break;
+
+ case DDATA:
+ CError_ASSERT(3622, !obj->u.data.info);
+ if (obj->qual & Q_INLINE_DATA) {
+ switch (obj->type->type) {
+ case TYPEINT:
+ case TYPEENUM:
+ case TYPEPOINTER:
+ break;
+ case TYPEFLOAT:
+ CPrec_RawMemPatch(&p->u.data.u.floatconst, obj->u.data.u.floatconst, sizeof(Float));
+ break;
+ default:
+ CError_FATAL(3638);
+ }
+ }
+ if (obj->u.data.linkname)
+ CPrec_NamePatch(&p->u.data.linkname, obj->u.data.linkname);
+ break;
+
+ case DINLINEFUNC:
+ CPrec_RawMemPatch(&p->u.ifunc.data, obj->u.ifunc.data, obj->u.ifunc.size);
+ if (obj->u.ifunc.xrefs)
+ CPrec_NewPointerPatch(&p->u.ifunc.xrefs, CPrec_GetInlineXRefPatch(obj->u.ifunc.xrefs));
+ break;
+
+ case DALIAS:
+ CPrec_NewPointerPatch(&p->u.alias.object, CPrec_GetObjectPatch(obj->u.alias.object));
+ if (obj->u.alias.member)
+ CPrec_NewPointerPatch(&p->u.alias.member, CPrec_GetClassAccessPatch(obj->u.alias.member));
+ break;
+
+ default:
+ CError_FATAL(3677);
+ }
+
+ if (cprec_dowrite)
+ obj->datatype = -1;
+
+ return p;
+}
+
+static ObjBase *CPrec_GetObjBasePatch(ObjBase *obj) {
+ switch (obj->otype) {
+ default:
+ CError_FATAL(3694);
+ case OT_ENUMCONST:
+ return (ObjBase *) CPrec_GetObjEnumConstPatch((ObjEnumConst *) obj);
+ case OT_TYPE:
+ return (ObjBase *) CPrec_GetObjTypePatch((ObjType *) obj);
+ case OT_TYPETAG:
+ return (ObjBase *) CPrec_GetObjTypeTagPatch((ObjTypeTag *) obj);
+ case OT_NAMESPACE:
+ return (ObjBase *) CPrec_GetObjNameSpacePatch((ObjNameSpace *) obj);
+ case OT_MEMBERVAR:
+ return (ObjBase *) CPrec_GetObjMemberVarPatch((ObjMemberVar *) obj);
+ case OT_OBJECT:
+ return (ObjBase *) CPrec_GetObjectPatch((Object *) obj);
+ }
+}
+
+static ObjectList *CPrec_GetObjectListPatch(ObjectList *ol) {
+ AddrPatch *addrPatch;
+ ObjectList *first, *current, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(ol)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(ol, first);
+restart:
+ CPrec_AppendData(ol, sizeof(ObjectList));
+ CPrec_NewPointerPatch(&current->object, CPrec_GetObjectPatch(ol->object));
+ if (ol->next) {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ ol = ol->next;
+ goto restart;
+ }
+
+ return first;
+}
+
+static NameSpaceObjectList *CPrec_GetNameSpaceObjectListPatch(NameSpaceObjectList *nsol) {
+ AddrPatch *addrPatch;
+ NameSpaceObjectList *first, *current, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(nsol)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(nsol, first);
+
+ do {
+ CPrec_AppendData(nsol, sizeof(NameSpaceObjectList));
+ CPrec_NewPointerPatch(&current->object, CPrec_GetObjBasePatch(nsol->object));
+
+ if (!nsol->next)
+ break;
+
+ if ((addrPatch = CPrec_FindAddrPatch(nsol->next))) {
+ CPrec_NewPointerPatch(&current->next, addrPatch->value);
+ break;
+ } else {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ nsol = nsol->next;
+ CPrec_NewAddrPatch(nsol, next);
+ }
+ } while (1);
+
+ return first;
+}
+
+static NameSpaceName *CPrec_GetNameSpaceNamePatch(NameSpaceName *nsn, Boolean flag) {
+ AddrPatch *addrPatch;
+ NameSpaceName *first, *current, *next;
+
+ if ((addrPatch = CPrec_FindAddrPatch(nsn)))
+ return addrPatch->value;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(nsn, first);
+
+ do {
+ CPrec_AppendData(nsn, sizeof(NameSpaceName));
+ CPrec_NamePatch(&current->name, nsn->name);
+ CPrec_NewPointerPatch(&current->first.object, CPrec_GetObjBasePatch(nsn->first.object));
+ if (nsn->first.next)
+ CPrec_NewPointerPatch(&current->first.next, CPrec_GetNameSpaceObjectListPatch(nsn->first.next));
+
+ if (!nsn->next)
+ break;
+
+ if ((addrPatch = CPrec_FindAddrPatch(nsn->next))) {
+ CPrec_NewPointerPatch(&current->next, addrPatch->value);
+ break;
+ } else {
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ nsn = nsn->next;
+ CPrec_NewAddrPatch(nsn, next);
+ }
+ } while (!flag || !cprec_dowrite || CPrec_FlushBufferCheck() == noErr);
+
+ return first;
+}
+
+static NameSpaceList *CPrec_GetNameSpaceListPatch(NameSpaceList *nsl) {
+ NameSpaceList *first, *current, *next;
+ first = current = CPrec_AppendAlign();
+
+ do {
+ CPrec_AppendData(nsl, sizeof(NameSpaceList));
+ CPrec_NewPointerPatch(&current->nspace, CPrec_GetNameSpacePatch(nsl->nspace));
+
+ if (!nsl->next)
+ break;
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ nsl = nsl->next;
+ } while (1);
+
+ return first;
+}
+
+static NameSpace *CPrec_GetNameSpacePatch(NameSpace *nspace) {
+ NameSpace *p;
+ AddrPatch *addrPatch;
+
+ if ((addrPatch = CPrec_FindAddrPatch(nspace)))
+ return addrPatch->value;
+
+ p = CPrec_AppendAlign();
+ CPrec_NewAddrPatch(nspace, p);
+ CPrec_AppendData(nspace, sizeof(NameSpace));
+
+ if (nspace->parent)
+ CPrec_NewPointerPatch(&p->parent, CPrec_GetNameSpacePatch(nspace->parent));
+ if (nspace->name)
+ CPrec_NamePatch(&p->name, nspace->name);
+ if (nspace->usings)
+ CPrec_NewPointerPatch(&p->usings, CPrec_GetNameSpaceListPatch(nspace->usings));
+ if (nspace->theclass)
+ CPrec_NewPointerPatch(&p->theclass, CPrec_GetTypePatch((Type *) nspace->theclass));
+
+ if (nspace->is_hash) {
+ char *hash;
+ int i;
+ hash = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&p->data.hash, hash);
+ CPrec_AppendData(nspace->data.hash, sizeof(NameSpaceName *) * 1024);
+ for (i = 0; i < 1024; i++) {
+ if (nspace->data.hash[i])
+ CPrec_NewPointerPatch(hash + (i * sizeof(NameSpaceName *)), CPrec_GetNameSpaceNamePatch(nspace->data.hash[i], 0));
+ }
+ } else if (nspace->data.list) {
+ CPrec_NewPointerPatch(&p->data.list, CPrec_GetNameSpaceNamePatch(nspace->data.list, 0));
+ }
+
+ return p;
+}
+
+static void CPrec_DumpRootNameSpace(void) {
+ NameSpaceList *nslist;
+ NameSpaceName *nsname;
+ int i;
+
+ CError_ASSERT(3905, cscope_root->is_hash);
+
+ if (cscope_root->usings) {
+ nslist = CPrec_GetNameSpaceListPatch(cscope_root->usings);
+ if (cprec_dowrite)
+ cprec_header->usings = nslist;
+ }
+
+ if (cprec_dowrite)
+ cprec_header->root_names = cscope_root->names;
+
+ i = 0;
+ do {
+ if (cscope_root->data.hash[i]) {
+ nsname = CPrec_GetNameSpaceNamePatch(cscope_root->data.hash[i], 1);
+ if (cprec_dowrite) {
+ if (cprec_ioerror != noErr)
+ break;
+ cprec_header->root_nametable[i] = nsname;
+ }
+ }
+ } while (++i < 0x400);
+}
+
+static CSOMStub *CPrec_GetSOMPatch(CSOMStub *stub) {
+ CSOMStub *first, *current, *next;
+
+ first = current = CPrec_AppendAlign();
+ while (1) {
+ CPrec_AppendData(stub, sizeof(CSOMStub));
+
+ CPrec_NewPointerPatch(&current->object, CPrec_GetObjectPatch(stub->object));
+ CPrec_NewPointerPatch(&current->tclass, CPrec_GetTypePatch(TYPE(stub->tclass)));
+
+ if (!stub->next)
+ break;
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ stub = stub->next;
+ }
+
+ return first;
+}
+
+static OLinkList *CPrec_GetOLinkPatch(OLinkList *olink) {
+ OLinkList *first, *current, *next;
+
+ first = current = CPrec_AppendAlign();
+ while (1) {
+ CPrec_AppendData(olink, sizeof(OLinkList));
+
+ CPrec_NewPointerPatch(&current->obj, CPrec_GetObjectPatch(olink->obj));
+
+ if (!olink->next)
+ break;
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ olink = olink->next;
+ }
+
+ return first;
+}
+
+static StaticData *CPrec_GetStaticDataPatch(StaticData *sd) {
+ StaticData *current, *first, *next;
+
+ first = current = CPrec_AppendAlign();
+ while (1) {
+ CPrec_AppendData(sd, sizeof(StaticData));
+
+ CPrec_NewPointerPatch(&current->object, CPrec_GetObjectPatch(sd->object));
+ if (sd->buffer)
+ CPrec_RawMemPatch(&current->buffer, sd->buffer, sd->object->type->size);
+ if (sd->links)
+ CPrec_NewPointerPatch(&current->links, CPrec_GetOLinkPatch(sd->links));
+
+ if (!sd->next)
+ break;
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ sd = sd->next;
+ }
+
+ return first;
+}
+
+static CallbackAction *CPrec_GetCallbackPatch(CallbackAction *ca) {
+ CallbackAction *first, *current, *next;
+
+ first = current = CPrec_AppendAlign();
+ while (1) {
+ CPrec_AppendData(ca, sizeof(CallbackAction));
+
+ CPrec_NewPointerPatch(&current->obj, CPrec_GetObjectPatch(ca->obj));
+ CPrec_NewPointerPatch(&current->tclass, CPrec_GetTypePatch(TYPE(ca->tclass)));
+
+ if (!ca->next)
+ break;
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ ca = ca->next;
+ }
+
+ return first;
+}
+
+static ObjCSelector **CPrec_GetSelHashTablePatch(ObjCSelector **table) {
+ ObjCSelector **first, **current;
+ int i;
+
+ first = current = CPrec_AppendAlign();
+ CPrec_AppendData(table, sizeof(ObjCSelector *) * 0x400);
+
+ for (i = 0; i < 0x400; i++) {
+ if (*table)
+ CPrec_NewPointerPatch(current, CPrec_GetObjCSelectorPatch(*table));
+ table++;
+ current++;
+ }
+
+ return first;
+}
+
+static InitExpr *CPrec_GetIExpressionPatch(InitExpr *initexpr) {
+ InitExpr *first, *current, *next;
+
+ first = current = CPrec_AppendAlign();
+ while (1) {
+ CPrec_AppendData(initexpr, sizeof(InitExpr));
+
+ CPrec_NewPointerPatch(&current->object, CPrec_GetObjectPatch(initexpr->object));
+ CPrec_NewPointerPatch(&current->expr, CPrec_GetExpressionPatch(initexpr->expr));
+
+ if (!initexpr->next)
+ break;
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ initexpr = initexpr->next;
+ }
+
+ return first;
+}
+
+static CI_Action *CPrec_GetInlineActionPatch(CI_Action *act) {
+ CI_Action *current, *first, *next;
+
+ first = current = CPrec_AppendAlign();
+ while (1) {
+ if (act->actiontype == CI_ActionInlineFunc)
+ memclrw(&act->u.inlinefunc.fileoffset, sizeof(FileOffsetInfo));
+
+ CPrec_AppendData(act, sizeof(CI_Action));
+
+ CPrec_NewPointerPatch(&current->obj, CPrec_GetObjectPatch(act->obj));
+
+ switch (act->actiontype) {
+ case CI_ActionInlineFunc:
+ if (act->u.inlinefunc.stream.firsttoken)
+ CPrec_NewPointerPatch(
+ &current->u.inlinefunc.stream.firsttoken,
+ CPrec_GetTStreamPatch(act->u.inlinefunc.stream.firsttoken, act->u.inlinefunc.stream.tokens));
+ if (act->u.inlinefunc.tclass)
+ CPrec_NewPointerPatch(&current->u.inlinefunc.tclass, CPrec_GetTypePatch(TYPE(act->u.inlinefunc.tclass)));
+ break;
+
+ case CI_ActionMemberFunc:
+ CPrec_NewPointerPatch(&current->u.memberfunc.templ, CPrec_GetTypePatch(TYPE(act->u.memberfunc.templ)));
+ CPrec_NewPointerPatch(&current->u.memberfunc.inst, CPrec_GetTypePatch(TYPE(act->u.memberfunc.inst)));
+ CPrec_NewPointerPatch(&current->u.memberfunc.tmemb, CPrec_GetTemplateMemberPatch(act->u.memberfunc.tmemb));
+ break;
+
+ case CI_ActionTemplateFunc:
+ CPrec_NewPointerPatch(&current->u.templatefunc.func, CPrec_GetTemplateFunctionPatch(act->u.templatefunc.func));
+ CPrec_NewPointerPatch(&current->u.templatefunc.inst, CPrec_GetTemplFuncInstancePatch(act->u.templatefunc.inst));
+ break;
+
+ case CI_ActionDefaultFunc:
+ break;
+
+ default:
+ CError_FATAL(4177);
+ }
+
+ if (!act->next)
+ break;
+
+ next = CPrec_AppendAlign();
+ CPrec_NewPointerPatch(&current->next, next);
+ current = next;
+ act = act->next;
+ }
+
+ return first;
+}
+
+static void CPrec_GenerateBuiltinPatches(void) {
+ int x;
+ int y;
+ Patch *scan;
+
+ for (x = 0; x < cprec_builtins; x++) {
+ y = 0;
+ for (scan = cprec_builtin[x].patches; scan; scan = scan->next)
+ ++y;
+
+ if (y) {
+ CPrec_AppendWord32(y);
+ CPrec_AppendWord32(x);
+ for (scan = cprec_builtin[x].patches; scan; scan = scan->next)
+ CPrec_AppendWord32(scan->offset);
+ }
+ }
+
+ CPrec_AppendWord32(0);
+}
+
+static void CPrec_GenerateTokenStreamPatches(void) {
+ TokenPatch *scan;
+
+ for (scan = cprec_tokenpatches; scan; scan = scan->next) {
+ CPrec_AppendWord32((UInt32) scan->tokens);
+ CPrec_AppendWord32((UInt32) scan->count);
+ }
+ CPrec_AppendWord32(0);
+}
+
+static OSErr CPrec_CompressWrite(const char *data, SInt32 size) {
+ char buf[2048 + 256];
+ OSErr err;
+ int bufpos = 0;
+ int blockstart;
+ int c;
+ const char *p = data;
+ const char *end = data + size;
+
+ for (;;) {
+ if (p < end) {
+ if (!*p) {
+ c = 224;
+ while (!*p && p < end && c < 256) {
+ c++;
+ p++;
+ }
+ buf[bufpos++] = c - 1;
+ } else {
+ blockstart = bufpos++;
+ c = 0;
+ while (p < end && c < 224) {
+ if (!p[0] && !p[1]) {
+ break;
+ } else {
+ buf[bufpos++] = *(p++);
+ c++;
+ }
+ }
+ buf[blockstart] = c - 1;
+ }
+ }
+
+ if (p >= end || bufpos > 2048) {
+ if ((err = COS_FileWrite(cprec_refnum, buf, bufpos)))
+ return err;
+
+ if (p >= end)
+ break;
+ else
+ bufpos = 0;
+ }
+ }
+
+ return noErr;
+}
+
+static OSErr CPrec_FlushRawBuffer(void) {
+ OSErr err;
+
+ if (cprec_dowrite) {
+ CPrec_AppendAlign();
+ cprec_zero_offset += cprec_glist.size;
+ COS_LockHandle(cprec_glist.data);
+ err = CPrec_CompressWrite(*cprec_glist.data, cprec_glist.size);
+ COS_UnlockHandle(cprec_glist.data);
+ cprec_glist.size = 0;
+
+ return err;
+ } else {
+ return noErr;
+ }
+}
+
+static OSErr CPrec_FlushBufferCheck(void) {
+ static SInt32 flushmax;
+ OSErr err;
+
+ if (cprec_glist.size > flushmax)
+ flushmax = cprec_glist.size;
+
+ if (cprec_glist.size > 10000) {
+ err = CPrec_FlushRawBuffer();
+ if (err) {
+ cprec_ioerror = err;
+ return err;
+ }
+ }
+
+ return noErr;
+}
+
+static int CPrec_CompressPatches(void) {
+ Patch *scan;
+ int count;
+ SInt32 last;
+
+ cprec_glist.size = 0;
+
+ scan = cprec_patch_list;
+ last = 0;
+ count = 0;
+ while (scan) {
+ CError_ASSERT(4339, (scan->offset & 0x80000001) == 0);
+
+ if ((scan->offset - last) >= -128 && (scan->offset - last) <= 126)
+ CPrec_AppendByte(((scan->offset - last) >> 1) | 0x80);
+ else
+ CPrec_AppendWord32(scan->offset);
+
+ last = scan->offset;
+ scan = scan->next;
+ count++;
+ }
+
+ return count;
+}
+
+static OSErr CPrec_DumpColorSymbolTable(Boolean doWrite) {
+ OSErr err;
+
+ freelheap();
+
+ CPrec_InitAddressHashTable();
+ CPrec_InitPointerHashTable();
+
+ cprec_patch_list = NULL;
+ cprec_tokenpatches = NULL;
+ cprec_offset = 0;
+ cprec_zero_offset = 0;
+ cprec_dowrite = doWrite;
+ cprec_ioerror = noErr;
+
+ CPrec_SetupBuiltIn();
+ CPrec_AppendWord32(0);
+
+ CPrec_DumpNameTable();
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+
+ CPrec_DumpMacroTable();
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+
+ CPrec_DumpRootNameSpace();
+ if (doWrite) {
+ if (cprec_ioerror != noErr)
+ return cprec_ioerror;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ if (ctempl_templates) {
+ TemplClass *p = TEMPL_CLASS(CPrec_GetTypePatch(TYPE(ctempl_templates)));
+ if (doWrite)
+ cprec_header->ctempl_templates = p;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ if (ctempl_templatefuncs) {
+ TemplateFunction *p = CPrec_GetTemplateFunctionPatch(ctempl_templatefuncs);
+ if (doWrite)
+ cprec_header->ctempl_templatefuncs = p;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ if (csom_stubs) {
+ CSOMStub *p = CPrec_GetSOMPatch(csom_stubs);
+ if (doWrite)
+ cprec_header->csom_stubs = p;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ if (cprec_staticdata) {
+ StaticData *p = CPrec_GetStaticDataPatch(cprec_staticdata);
+ if (doWrite)
+ cprec_header->cprec_staticdata = p;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ if (callbackactions) {
+ CallbackAction *p = CPrec_GetCallbackPatch(callbackactions);
+ if (doWrite)
+ cprec_header->callbackactions = p;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ if (cobjc_type_class) {
+ Type *p = CPrec_GetTypePatch(cobjc_type_class);
+ if (doWrite)
+ cprec_header->cobjc_type_class = p;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ if (cobjc_type_id) {
+ Type *p = CPrec_GetTypePatch(cobjc_type_id);
+ if (doWrite)
+ cprec_header->cobjc_type_id = p;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ if (cobjc_type_sel) {
+ Type *p = CPrec_GetTypePatch(cobjc_type_sel);
+ if (doWrite)
+ cprec_header->cobjc_type_sel = p;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ if (cobjc_selhashtable) {
+ ObjCSelector **p = CPrec_GetSelHashTablePatch(cobjc_selhashtable);
+ if (doWrite)
+ cprec_header->cobjc_selhashtable = p;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ if (cobjc_classdefs) {
+ BClassList *p = CPrec_GetBClassListPatch(cobjc_classdefs);
+ if (doWrite)
+ cprec_header->cobjc_classdefs = p;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ if (cobjc_protocols) {
+ ObjCProtocol *p = CPrec_GetObjCProtocolPatch(cobjc_protocols);
+ if (doWrite)
+ cprec_header->cobjc_protocols = p;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ if (init_expressions) {
+ InitExpr *p = CPrec_GetIExpressionPatch(init_expressions);
+ if (doWrite)
+ cprec_header->init_expressions = p;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ if (cinline_tactionlist) {
+ CI_Action *p = CPrec_GetInlineActionPatch(cinline_tactionlist);
+ if (doWrite)
+ cprec_header->cinline_tactionlist = p;
+ if ((err = CPrec_FlushRawBuffer()) != noErr)
+ return err;
+ }
+
+ return noErr;
+}
+
+static OSErr CPrec_FileAlign(short refnum, SInt32 *len) {
+ OSErr err;
+ SInt32 n;
+ char buf[8];
+
+ n = *len;
+ if ((n & 7) == 0)
+ return noErr;
+
+ memclrw(buf, 8);
+ err = COS_FileWrite(refnum, buf, n = 8 - (n & 7));
+ *len += n;
+
+ return err;
+}
+
+static OSErr CPrec_WriteFile(void) {
+ char str[128];
+ int i;
+ HashNameNode *name;
+ OSErr err;
+ SInt32 offset;
+
+ if (InitGList(&cprec_glist, 0x40000))
+ CError_NoMem();
+
+ CompilerGetCString(10, str);
+ CWShowStatus(cparams.context, str, "");
+ CPrep_RemoveSpecialMacros();
+
+ for (i = 0; i < 0x800; i++) {
+ for (name = name_hash_nodes[i]; name; name = name->next)
+ name->id = 0;
+ }
+
+ if ((err = CPrec_DumpColorSymbolTable(0)) != noErr)
+ return err;
+
+ CompilerGetCString(11, str);
+ CWShowStatus(cparams.context, str, "");
+
+ cprec_header = galloc(sizeof(Header));
+ memclrw(cprec_header, sizeof(Header));
+
+ cprec_header->magic = 0xBEEFFACE;
+ cprec_header->version = 1047;
+ cprec_header->target = 2;
+ cprec_header->check_header_flags = copts.checkprecompflags;
+ cprec_header->cplusplus = copts.cplusplus;
+ cprec_header->uniqueID = CParser_GetUniqueID();
+ cprec_header->cobjc_selrefcount = cobjc_selrefcount;
+ cprec_header->cobjc_classrefcount = cobjc_classrefcount;
+ cprec_header->cobjc_stringcount = cobjc_stringcount;
+
+ if ((err = COS_FileWrite(cprec_refnum, cprec_header, sizeof(Header))) != noErr)
+ return err;
+
+ offset = sizeof(Header);
+
+ if ((err = CPrec_DumpColorSymbolTable(1)) != noErr)
+ return err;
+
+ cprec_header->x28 = cprec_offset;
+ cprec_header->x30 = offset;
+
+ if ((err = COS_FileGetPos(cprec_refnum, &offset)) != noErr)
+ return err;
+
+ cprec_header->x2C = offset - cprec_header->x30;
+
+ cprec_header->compressedPatchCount = CPrec_CompressPatches();
+ cprec_header->compressedPatchSize = cprec_glist.size;
+ cprec_header->compressedPatchOffset = offset;
+
+ if (cprec_header->compressedPatchCount) {
+ if ((err = COS_FileWrite(cprec_refnum, *cprec_glist.data, cprec_glist.size)) != noErr)
+ return err;
+ offset += cprec_glist.size;
+ }
+
+ if ((err = CPrec_FileAlign(cprec_refnum, &offset)) != noErr)
+ return err;
+
+ cprec_glist.size = 0;
+ CPrec_GenerateBuiltinPatches();
+ cprec_header->builtinPatchSize = cprec_glist.size;
+ cprec_header->builtinPatchOffset = offset;
+
+ if ((err = COS_FileWrite(cprec_refnum, *cprec_glist.data, cprec_glist.size)) != noErr)
+ return err;
+ offset += cprec_glist.size;
+
+ if (cprec_tokenpatches) {
+ cprec_glist.size = 0;
+ CPrec_GenerateTokenStreamPatches();
+ cprec_header->tokenStreamPatchSize = cprec_glist.size;
+ cprec_header->tokenStreamPatchOffset = offset;
+
+ if ((err = COS_FileWrite(cprec_refnum, *cprec_glist.data, cprec_glist.size)) != noErr)
+ return err;
+ offset += cprec_glist.size;
+ }
+
+ if ((err = COS_FileSetPos(cprec_refnum, 0)) != noErr)
+ return err;
+
+ if ((err = COS_FileWrite(cprec_refnum, cprec_header, sizeof(Header))) != noErr)
+ return err;
+
+ return noErr;
+}
+
+void PrecompilerWrite(void) {
+ OSErr err;
+ short strindex;
+ char str[128];
+ FSSpec spec;
+
+ spec = cparamblkptr->sourcefile;
+ if (CWGetPrecompiledHeaderSpec(cparamblkptr->context, &spec, precomp_target_str) == cwNoErr) {
+ strindex = 3;
+ err = COS_FileNew(&spec, &cprec_refnum, copts.appltype, copts.headtype);
+ if (err == noErr) {
+ strindex = 4;
+ err = CPrec_WriteFile();
+ }
+ CleanupPrecompiler();
+
+ if (err != noErr) {
+ CompilerGetCString(strindex, str);
+ sprintf(string, str, err);
+ CWReportMessage(cparamblkptr->context, NULL, string, NULL, messagetypeError, 0);
+ } else {
+ CWFileTime time = 0;
+ CWSetModDate(cparamblkptr->context, &spec, &time, 1);
+ }
+ }
+}
+
+static void CPrec_ReadData(SInt32 offset, void *buffer, SInt32 size) {
+ if (
+ COS_FileSetPos(cprec_refnum, offset) != noErr ||
+ COS_FileRead(cprec_refnum, buffer, size) != noErr
+ )
+ CError_ErrorTerm(CErrorStr181);
+}
+
+static void CPrec_ReadRawBuffer(void) {
+ UInt8 *buffer;
+ UInt8 *work;
+ UInt8 *end;
+ UInt32 size;
+ int ch;
+
+ if (!cprec_buffer) {
+ size = cprec_header->x28 + (cprec_header->x28 >> 7) + 64;
+ buffer = galloc(size);
+ cprec_rawbuffer = buffer;
+
+ work = buffer + size - cprec_header->x2C;
+ CPrec_ReadData(cprec_header->x30, work, cprec_header->x2C);
+ } else {
+ buffer = galloc(cprec_header->x28);
+ cprec_rawbuffer = buffer;
+ work = (UInt8 *) cprec_buffer + cprec_header->x30;
+ }
+
+ end = work + cprec_header->x2C;
+
+ while (work < end) {
+ if ((ch = *(work++)) >= 0xE0) {
+ ch -= 0xE0;
+ do {
+ *(buffer++) = 0;
+ } while (--ch >= 0);
+ } else {
+ do {
+ *(buffer++) = *(work++);
+ } while (--ch >= 0);
+ }
+ }
+
+ if (work != end || buffer != RESOLVE_RAW_BUFFER(cprec_header->x28))
+ CError_ErrorTerm(CErrorStr181);
+}
+
+static void CPrec_RelocateRawBuffer(void) {
+ UInt8 *patches;
+ UInt32 offset;
+ UInt8 *dest;
+ SInt32 count;
+ UInt8 *patch;
+ UInt32 var;
+
+ if ((count = cprec_header->compressedPatchCount)) {
+ if (!cprec_buffer) {
+ patches = lalloc(cprec_header->compressedPatchSize);
+ CPrec_ReadData(cprec_header->compressedPatchOffset, patches, cprec_header->compressedPatchSize);
+ } else {
+ patches = RESOLVE_BUFFER(cprec_header->compressedPatchOffset);
+ }
+
+ offset = 0;
+ patch = patches;
+ dest = cprec_rawbuffer;
+ do {
+ if (!(*patch & 0x80)) {
+ ((UInt8 *) &var)[0] = *(patch++);
+ ((UInt8 *) &var)[1] = *(patch++);
+ ((UInt8 *) &var)[2] = *(patch++);
+ ((UInt8 *) &var)[3] = *(patch++);
+ offset = var;
+ } else {
+ offset += (char) (*(patch++) * 2);
+ }
+ *((uintptr_t *) (dest + offset)) += (uintptr_t) dest;
+ } while (--count > 0);
+
+ freelheap();
+
+ if (patch != (patches + cprec_header->compressedPatchSize))
+ CError_ErrorTerm(CErrorStr181);
+ }
+}
+
+static void CPrec_RelocateBuiltins(void) {
+ UInt32 *patches;
+ void *builtin;
+ UInt32 count;
+ UInt8 *buffer;
+
+ if (cprec_header->builtinPatchSize) {
+ CPrec_SetupBuiltInArray();
+ if (!cprec_buffer) {
+ patches = lalloc(cprec_header->builtinPatchSize);
+ CPrec_ReadData(cprec_header->builtinPatchOffset, patches, cprec_header->builtinPatchSize);
+ } else {
+ patches = RESOLVE_BUFFER(cprec_header->builtinPatchOffset);
+ }
+
+ buffer = cprec_rawbuffer;
+ while (1) {
+ if (!(count = *(patches++)))
+ break;
+
+ builtin = cprec_builtin_array[*(patches++)];
+ do {
+ *((void **) (buffer + *(patches++))) = builtin;
+ } while (--count);
+ }
+ }
+}
+
+static void CPrec_RelocateTokenStreams(void) {
+ UInt32 *patches;
+ UInt32 count;
+ TStreamElement *tokens;
+ UInt8 *buffer;
+ CPrepFileInfo *file;
+ SInt32 pos;
+
+ if (cprec_header->tokenStreamPatchSize) {
+ CPrep_GetPrepPos(&file, &pos);
+
+ if (!cprec_buffer) {
+ patches = lalloc(cprec_header->tokenStreamPatchSize);
+ CPrec_ReadData(cprec_header->tokenStreamPatchOffset, patches, cprec_header->tokenStreamPatchSize);
+ } else {
+ patches = RESOLVE_BUFFER(cprec_header->tokenStreamPatchOffset);
+ }
+
+ buffer = cprec_rawbuffer;
+ while (1) {
+ if (!*patches)
+ break;
+
+ tokens = (TStreamElement *) (buffer + *(patches++));
+ count = *(patches++);
+
+ while (count--) {
+ tokens->tokenfile = file;
+ tokens->tokenoffset = pos;
+ tokens++;
+ }
+ }
+ }
+}
+
+static void CPrec_RelocateMacroTable(void) {
+ int i;
+ int j;
+ int count;
+ UInt8 *buffer;
+ Macro **prec_table;
+ Macro **table;
+ Macro *macro;
+ uintptr_t offset;
+
+ buffer = cprec_rawbuffer;
+ prec_table = cprec_header->macrotable;
+ table = macrohashtable;
+
+ i = 0;
+ do {
+ for (macro = *table; macro; macro = macro->next) {
+ macro->name = GetHashNameNodeExport(macro->name->name);
+ count = macro->xC & 0x7FFF;
+ for (j = 1; j < count; j++)
+ macro->names[j - 1] = GetHashNameNodeExport(macro->names[j - 1]->name);
+ }
+
+ if ((offset = (uintptr_t) *prec_table)) {
+ if (*table) {
+ macro = (Macro *) (buffer + offset);
+ while (macro->next)
+ macro = macro->next;
+ macro->next = *table;
+ }
+ *table = (Macro *) (buffer + offset);
+ }
+
+ prec_table++;
+ table++;
+ } while (++i < 0x800);
+}
+
+static void CPrec_RelocateTable(void **table, int size, void **dest) {
+ int i;
+ void *buffer = cprec_rawbuffer;
+
+ for (i = 0; i < size; i++) {
+ if (*table)
+ *dest = (char *) buffer + (uintptr_t) *table;
+ else
+ *dest = NULL;
+ table++;
+ dest++;
+ }
+}
+
+static void CPrec_RelocateRootNameSpace(void) {
+ CError_ASSERT(4981, cscope_root->is_hash);
+
+ cscope_root->names = cprec_header->root_names;
+ CPrec_RelocateTable(
+ (void **) cprec_header->root_nametable,
+ 0x400,
+ (void **) cscope_root->data.hash);
+}
+
+static void CPrec_FixNameIds(void) {
+ int i;
+ HashNameNode *node;
+
+ for (i = 0; i < 2048; i++) {
+ for (node = name_hash_nodes[i]; node; node = node->next)
+ node->id = -1;
+ }
+}
+
+static void CPrec_DefineStaticData(void) {
+ StaticData *sd = cprec_staticdata;
+ cprec_staticdata = NULL;
+
+ while (sd) {
+ CInit_DeclareData(sd->object, sd->buffer, sd->links, sd->size);
+ sd = sd->next;
+ }
+}
+
+void PrecompilerRead(short refnum, void *buffer) {
+ cprec_refnum = refnum;
+ cprec_buffer = buffer;
+
+ CPrep_RemoveSpecialMacros();
+
+ if (!CScope_IsEmptySymTable())
+ CError_ErrorTerm(CErrorStr180);
+
+ if (!cprec_buffer) {
+ cprec_header = galloc(sizeof(Header));
+ CPrec_ReadData(0, cprec_header, sizeof(Header));
+ } else {
+ cprec_header = cprec_buffer;
+ }
+
+ if (cprec_header->magic != 0xBEEFFACE)
+ CError_ErrorTerm(CErrorStr181);
+ if (cprec_header->version != 1047)
+ CError_ErrorTerm(CErrorStr222);
+ if (cprec_header->target != 2)
+ CError_ErrorTerm(CErrorStr223);
+
+ copts.checkprecompflags = cprec_header->check_header_flags;
+
+ CPrec_ReadRawBuffer();
+ CPrec_RelocateRawBuffer();
+ CPrec_RelocateBuiltins();
+ CPrec_RelocateTable((void **) cprec_header->nametable, 0x800, (void **) name_hash_nodes);
+ CPrec_FixNameIds();
+ CPrec_RelocateMacroTable();
+ CPrec_RelocateTokenStreams();
+ CPrec_RelocateRootNameSpace();
+
+ if (!cprec_header->usings)
+ cscope_root->usings = NULL;
+ else
+ cscope_root->usings = RESOLVE_RAW_BUFFER(cprec_header->usings);
+
+ ctempl_templates = RESOLVE_SAFE(cprec_header->ctempl_templates);
+ ctempl_templatefuncs = RESOLVE_SAFE(cprec_header->ctempl_templatefuncs);
+ csom_stubs = RESOLVE_SAFE(cprec_header->csom_stubs);
+ cprec_staticdata = RESOLVE_SAFE(cprec_header->cprec_staticdata);
+ callbackactions = RESOLVE_SAFE(cprec_header->callbackactions);
+ cobjc_type_class = RESOLVE_SAFE(cprec_header->cobjc_type_class);
+ cobjc_type_id = RESOLVE_SAFE(cprec_header->cobjc_type_id);
+ cobjc_type_sel = RESOLVE_SAFE(cprec_header->cobjc_type_sel);
+ cobjc_selhashtable = RESOLVE_SAFE(cprec_header->cobjc_selhashtable);
+ cobjc_classdefs = RESOLVE_SAFE(cprec_header->cobjc_classdefs);
+ cobjc_protocols = RESOLVE_SAFE(cprec_header->cobjc_protocols);
+ init_expressions = RESOLVE_SAFE(cprec_header->init_expressions);
+ cinline_tactionlist = RESOLVE_SAFE(cprec_header->cinline_tactionlist);
+ CParser_SetUniqueID(cprec_header->uniqueID);
+ cobjc_selrefcount = cprec_header->cobjc_selrefcount;
+ cobjc_classrefcount = cprec_header->cobjc_classrefcount;
+ cobjc_stringcount = cprec_header->cobjc_stringcount;
+
+ cprec_refnum = 0;
+
+ CleanupPrecompiler();
+ cscope_current = cscope_root;
+
+ if (!CParser_ReInitRuntimeObjects(1))
+ CError_ErrorTerm(CErrorStr181);
+
+ CPrep_InsertSpecialMacros();
+
+ if (cparamblkptr->precompile != 1)
+ CPrec_DefineStaticData();
+}
diff --git a/compiler_and_linker/FrontEnd/C/CPrep.c b/compiler_and_linker/FrontEnd/C/CPrep.c
index a2ac9e2..904e72a 100644
--- a/compiler_and_linker/FrontEnd/C/CPrep.c
+++ b/compiler_and_linker/FrontEnd/C/CPrep.c
@@ -14,7 +14,7 @@
#include "compiler/CodeGen.h"
#include "compiler/CompilerTools.h"
#include "compiler/FuncLevelAsmPPC.h"
-#include "compiler/IroPointerAnalysis.h"
+#include "../Optimizer/IroPointerAnalysis.h"
#include "compiler/ObjGenMachO.h"
#include "compiler/objects.h"
#include "compiler/scopes.h"
diff --git a/compiler_and_linker/FrontEnd/C/CPreprocess.c b/compiler_and_linker/FrontEnd/C/CPreprocess.c
new file mode 100644
index 0000000..4e6b3c0
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CPreprocess.c
@@ -0,0 +1,676 @@
+#include "compiler/CPreprocess.h"
+#include "compiler/CError.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CompilerTools.h"
+#include "cos.h"
+
+void CPrep_PreprocessDumpNewLine(void) {
+ if (copts.line_prepdump && pplist.data && filesp >= 0)
+ AppendGListData(&pplist, "\r", 1);
+}
+
+void CPrep_PreprocessDumpFileInfo(Boolean flag) {
+ char linebuf[512];
+ int size;
+ SInt16 tmp16;
+ SInt32 tmp32;
+ Str255 filename;
+
+ if (pplist.data && filesp >= 0) {
+ if (nlflag && flag && pplist.size > 0)
+ AppendGListName(&pplist, "\r");
+
+ if (copts.line_prepdump)
+ size = sprintf(linebuf, "#line % " PRId32 "\t\"", linenumber);
+ else
+ size = sprintf(linebuf, "/* #line % " PRId32 "\t\"", linenumber);
+ AppendGListData(&pplist, linebuf, size);
+
+ if (copts.fullpath_prepdump) {
+ if (prep_file->nameNode) {
+ AppendGListData(&pplist, prep_file->nameNode->name, strlen(prep_file->nameNode->name));
+ } else {
+ COS_FileGetPathName(linebuf, &prep_file->textfile, &tmp32);
+ AppendGListData(&pplist, linebuf, strlen(linebuf));
+ }
+ } else {
+ if (prep_file->nameNode) {
+ char *work = prep_file->nameNode->name + strlen(prep_file->nameNode->name);
+ while (work > prep_file->nameNode->name && !strchr("/\\:", work[-1]))
+ work--;
+
+ AppendGListData(&pplist, work, strlen(work));
+ } else {
+ COS_FileGetFSSpecInfo(&prep_file->textfile, &tmp16, &tmp32, filename);
+ AppendGListData(&pplist, &filename[1], filename[0]);
+ }
+ }
+
+ size = sprintf(linebuf, "\"\t/* stack depth % " PRId32 " */", filesp);
+ AppendGListData(&pplist, linebuf, size);
+
+ if (copts.line_prepdump && flag)
+ CPrep_PreprocessDumpNewLine();
+
+ nlflag = 1;
+ }
+}
+
+static void CPrep_DumpWString(UInt16 *str, short len) {
+ int divisor;
+ int i;
+
+ while (len--) {
+ if (*str < 32) {
+ AppendGListByte(&pplist, '\\');
+ switch (*str) {
+ case 7:
+ AppendGListByte(&pplist, 'a');
+ break;
+ case 8:
+ AppendGListByte(&pplist, 'b');
+ break;
+ case 27:
+ AppendGListByte(&pplist, 'e');
+ break;
+ case 12:
+ AppendGListByte(&pplist, 'f');
+ break;
+ case 10:
+ AppendGListByte(&pplist, 'n');
+ break;
+ case 13:
+ AppendGListByte(&pplist, 'r');
+ break;
+ case 9:
+ AppendGListByte(&pplist, 't');
+ break;
+ case 11:
+ AppendGListByte(&pplist, 'v');
+ break;
+ default:
+ if (*str >= 8)
+ AppendGListByte(&pplist, '0' + (*str / 8));
+ AppendGListByte(&pplist, '0' + (*str % 8));
+ }
+ } else if (*str > 255) {
+ AppendGListByte(&pplist, '\\');
+ AppendGListByte(&pplist, 'x');
+
+ divisor = 0x1000;
+ for (i = 0; i < 4; i++) {
+ AppendGListByte(&pplist, "0123456789ABCDEF"[(*str / divisor) % 16]);
+ divisor /= 16;
+ }
+ } else {
+ switch (*str) {
+ case '"':
+ case '\\':
+ AppendGListByte(&pplist, '\\');
+ default:
+ AppendGListByte(&pplist, *str);
+ }
+ }
+ str++;
+ }
+}
+
+static void CPrep_DumpString(UInt8 *str, short len) {
+ while (len--) {
+ if (*str < 32) {
+ AppendGListByte(&pplist, '\\');
+ switch (*str) {
+ case 7:
+ AppendGListByte(&pplist, 'a');
+ break;
+ case 8:
+ AppendGListByte(&pplist, 'b');
+ break;
+ case 12:
+ AppendGListByte(&pplist, 'f');
+ break;
+ case 10:
+ AppendGListByte(&pplist, 'n');
+ break;
+ case 13:
+ AppendGListByte(&pplist, 'r');
+ break;
+ case 9:
+ AppendGListByte(&pplist, 't');
+ break;
+ case 11:
+ AppendGListByte(&pplist, 'v');
+ break;
+ default:
+ if (*str >= 8)
+ AppendGListByte(&pplist, '0' + (*str / 8));
+ AppendGListByte(&pplist, '0' + (*str % 8));
+ }
+ } else {
+ switch (*str) {
+ case '"':
+ case '\\':
+ AppendGListByte(&pplist, '\\');
+ default:
+ AppendGListByte(&pplist, *str);
+ }
+ }
+ str++;
+ }
+}
+
+void CPrep_Preprocess(void) {
+ short innertoken;
+ short token;
+ char startToken;
+ char endToken;
+ int depth;
+ Boolean save_asmpoundcomment; // r16
+ Boolean save_cplusplus; // r15
+ char *p;
+
+ startToken = 0;
+ depth = 0;
+
+ if (InitGList(&pplist, 10000))
+ CError_NoMem();
+
+ nlflag = 0;
+ spaceskip = 0;
+
+ if ((token = lex())) {
+ do {
+ if (nlflag) {
+ if (!copts.line_prepdump)
+ AppendGListData(&pplist, "\r", 1);
+ } else {
+ if (spaceskip)
+ AppendGListByte(&pplist, ' ');
+ }
+
+ while (1) {
+ switch ((innertoken = token)) {
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ AppendGListByte(&pplist, token);
+ if (cprep_nostring) {
+ if (innertoken == startToken) {
+ depth++;
+ } else if (innertoken == endToken) {
+ if (--depth == 0) {
+ cprep_nostring = 0;
+ in_assembler = 0;
+ copts.cplusplus = save_cplusplus;
+ copts.asmpoundcomment = save_asmpoundcomment;
+ }
+ }
+ }
+ break;
+
+ case TK_INTCONST:
+ case TK_FLOATCONST:
+ if (tokenstacklevel > 0)
+ p = macropos;
+ else
+ p = prep_file_start + ts_current[-1].tokenoffset;
+ AppendGListData(&pplist, p, pos - p);
+ break;
+
+ case TK_IDENTIFIER:
+ AppendGListData(&pplist, tkidentifier->name, strlen(tkidentifier->name));
+ break;
+
+ case TK_AUTO:
+ AppendGListData(&pplist, "auto", 4);
+ break;
+ case TK_REGISTER:
+ AppendGListData(&pplist, "register", 8);
+ break;
+ case TK_STATIC:
+ AppendGListData(&pplist, "static", 6);
+ break;
+ case TK_EXTERN:
+ AppendGListData(&pplist, "extern", 6);
+ break;
+ case TK_TYPEDEF:
+ AppendGListData(&pplist, "typedef", 7);
+ break;
+ case TK_INLINE:
+ AppendGListData(&pplist, "inline", 6);
+ break;
+ case TK_VOID:
+ AppendGListData(&pplist, "void", 4);
+ break;
+ case TK_CHAR:
+ AppendGListData(&pplist, "char", 4);
+ break;
+ case TK_SHORT:
+ AppendGListData(&pplist, "short", 5);
+ break;
+ case TK_INT:
+ AppendGListData(&pplist, "int", 3);
+ break;
+ case TK_LONG:
+ AppendGListData(&pplist, "long", 4);
+ break;
+ case TK_FLOAT:
+ AppendGListData(&pplist, "float", 5);
+ break;
+ case TK_DOUBLE:
+ AppendGListData(&pplist, "double", 6);
+ break;
+ case TK_SIGNED:
+ AppendGListData(&pplist, "signed", 6);
+ break;
+ case TK_UNSIGNED:
+ AppendGListData(&pplist, "unsigned", 8);
+ break;
+ case TK_STRUCT:
+ AppendGListData(&pplist, "struct", 6);
+ break;
+ case TK_UNION:
+ AppendGListData(&pplist, "union", 5);
+ break;
+ case TK_ENUM:
+ AppendGListData(&pplist, "enum", 4);
+ break;
+ case TK_CLASS:
+ AppendGListData(&pplist, "class", 5);
+ break;
+ case TK_CONST:
+ AppendGListData(&pplist, "const", 5);
+ break;
+ case TK_VOLATILE:
+ AppendGListData(&pplist, "volatile", 8);
+ break;
+ case TK_PASCAL:
+ AppendGListData(&pplist, "pascal", 6);
+ break;
+ case TK_UU_FAR:
+ AppendGListData(&pplist, "__far", 5);
+ break;
+ case TK_ONEWAY:
+ AppendGListData(&pplist, "oneway", 6);
+ break;
+ case TK_IN:
+ AppendGListData(&pplist, "in", 2);
+ break;
+ case TK_OUT:
+ AppendGListData(&pplist, "out", 3);
+ break;
+ case TK_INOUT:
+ AppendGListData(&pplist, "inout", 5);
+ break;
+ case TK_BYCOPY:
+ AppendGListData(&pplist, "bycopy", 6);
+ break;
+ case TK_BYREF:
+ AppendGListData(&pplist, "byref", 5);
+ break;
+ case TK_ASM:
+ AppendGListData(&pplist, "asm", 3);
+ endToken = 0;
+ startToken = 0;
+ AppendGListByte(&pplist, ' ');
+ token = lex();
+ if (token == TK_VOLATILE || (token == TK_IDENTIFIER && !strcmp(tkidentifier->name, "__volatile__"))) {
+ AppendGListData(&pplist, "volatile", 8);
+ token = lex();
+ }
+ if (token) {
+ if (token < ' ' || token > 255)
+ continue;
+ AppendGListByte(&pplist, token);
+
+ if (token == '(') {
+ startToken = '(';
+ endToken = ')';
+ } else if (token == '{') {
+ startToken = '{';
+ endToken = '}';
+ } else {
+ continue;
+ }
+
+ cprep_nostring = 1;
+ in_assembler = 1;
+ depth = 1;
+ save_asmpoundcomment = copts.asmpoundcomment;
+ save_cplusplus = copts.cplusplus;
+
+ token = lex();
+ if (token == '"') {
+ AppendGListByte(&pplist, token);
+ copts.cplusplus = 0;
+ copts.asmpoundcomment = 1;
+ break;
+ } else if (token == 0) {
+ break;
+ }
+ continue;
+ }
+ break;
+
+ case TK_CASE:
+ AppendGListData(&pplist, "case", 4);
+ break;
+ case TK_DEFAULT:
+ AppendGListData(&pplist, "default", 7);
+ break;
+ case TK_IF:
+ AppendGListData(&pplist, "if", 2);
+ break;
+ case TK_ELSE:
+ AppendGListData(&pplist, "else", 4);
+ break;
+ case TK_SWITCH:
+ AppendGListData(&pplist, "switch", 6);
+ break;
+ case TK_WHILE:
+ AppendGListData(&pplist, "while", 5);
+ break;
+ case TK_DO:
+ AppendGListData(&pplist, "do", 2);
+ break;
+ case TK_FOR:
+ AppendGListData(&pplist, "for", 3);
+ break;
+ case TK_GOTO:
+ AppendGListData(&pplist, "goto", 4);
+ break;
+ case TK_CONTINUE:
+ AppendGListData(&pplist, "continue", 8);
+ break;
+ case TK_BREAK:
+ AppendGListData(&pplist, "break", 5);
+ break;
+ case TK_RETURN:
+ AppendGListData(&pplist, "return", 6);
+ break;
+ case TK_SIZEOF:
+ AppendGListData(&pplist, "sizeof", 6);
+ break;
+ case TK_CATCH:
+ AppendGListData(&pplist, "catch", 5);
+ break;
+ case TK_DELETE:
+ AppendGListData(&pplist, "delete", 6);
+ break;
+ case TK_FRIEND:
+ AppendGListData(&pplist, "friend", 6);
+ break;
+ case TK_NEW:
+ AppendGListData(&pplist, "new", 3);
+ break;
+ case TK_OPERATOR:
+ AppendGListData(&pplist, "operator", 8);
+ break;
+ case TK_PRIVATE:
+ AppendGListData(&pplist, "private", 7);
+ break;
+ case TK_PROTECTED:
+ AppendGListData(&pplist, "protected", 9);
+ break;
+ case TK_PUBLIC:
+ AppendGListData(&pplist, "public", 6);
+ break;
+ case TK_TEMPLATE:
+ AppendGListData(&pplist, "template", 8);
+ break;
+ case TK_THIS:
+ AppendGListData(&pplist, "this", 4);
+ break;
+ case TK_THROW:
+ AppendGListData(&pplist, "throw", 5);
+ break;
+ case TK_TRY:
+ AppendGListData(&pplist, "try", 3);
+ break;
+ case TK_VIRTUAL:
+ AppendGListData(&pplist, "virtual", 7);
+ break;
+ case TK_INHERITED:
+ AppendGListData(&pplist, "inherited", 9);
+ break;
+ case TK_CONST_CAST:
+ AppendGListData(&pplist, "const_cast", 10);
+ break;
+ case TK_DYNAMIC_CAST:
+ AppendGListData(&pplist, "dynamic_cast", 12);
+ break;
+ case TK_EXPLICIT:
+ AppendGListData(&pplist, "explicit", 8);
+ break;
+ case TK_MUTABLE:
+ AppendGListData(&pplist, "mutable", 7);
+ break;
+ case TK_NAMESPACE:
+ AppendGListData(&pplist, "namespace", 9);
+ break;
+ case TK_REINTERPRET_CAST:
+ AppendGListData(&pplist, "reinterpret_cast", 16);
+ break;
+ case TK_STATIC_CAST:
+ AppendGListData(&pplist, "static_cast", 11);
+ break;
+ case TK_USING:
+ AppendGListData(&pplist, "using", 5);
+ break;
+ case TK_WCHAR_T:
+ AppendGListData(&pplist, "wchar_t", 7);
+ break;
+ case TK_TYPENAME:
+ AppendGListData(&pplist, "typename", 8);
+ break;
+ case TK_TRUE:
+ AppendGListData(&pplist, "true", 4);
+ break;
+ case TK_FALSE:
+ AppendGListData(&pplist, "false", 5);
+ break;
+ case TK_TYPEID:
+ AppendGListData(&pplist, "typeid", 6);
+ break;
+ case TK_EXPORT:
+ AppendGListData(&pplist, "export", 6);
+ break;
+ case TK_UU_STDCALL:
+ AppendGListData(&pplist, "__stdcall", 9);
+ break;
+ case TK_UU_CDECL:
+ AppendGListData(&pplist, "__cdecl", 7);
+ break;
+ case TK_UU_FASTCALL:
+ AppendGListData(&pplist, "__fastcall", 10);
+ break;
+ case TK_UU_DECLSPEC:
+ AppendGListData(&pplist, "__declspec", 10);
+ break;
+ case TK_MULT_ASSIGN:
+ AppendGListData(&pplist, "*=", 2);
+ break;
+ case TK_DIV_ASSIGN:
+ AppendGListData(&pplist, "/=", 2);
+ break;
+ case TK_MOD_ASSIGN:
+ AppendGListData(&pplist, "%=", 2);
+ break;
+ case TK_ADD_ASSIGN:
+ AppendGListData(&pplist, "+=", 2);
+ break;
+ case TK_SUB_ASSIGN:
+ AppendGListData(&pplist, "-=", 2);
+ break;
+ case TK_SHL_ASSIGN:
+ AppendGListData(&pplist, "<<=", 3);
+ break;
+ case TK_SHR_ASSIGN:
+ AppendGListData(&pplist, ">>=", 3);
+ break;
+ case TK_AND_ASSIGN:
+ AppendGListData(&pplist, "&=", 2);
+ break;
+ case TK_XOR_ASSIGN:
+ AppendGListData(&pplist, "^=", 2);
+ break;
+ case TK_OR_ASSIGN:
+ AppendGListData(&pplist, "|=", 2);
+ break;
+ case TK_LOGICAL_OR:
+ AppendGListData(&pplist, "||", 2);
+ break;
+ case TK_LOGICAL_AND:
+ AppendGListData(&pplist, "&&", 2);
+ break;
+ case TK_LOGICAL_EQ:
+ AppendGListData(&pplist, "==", 2);
+ break;
+ case TK_LOGICAL_NE:
+ AppendGListData(&pplist, "!=", 2);
+ break;
+ case TK_LESS_EQUAL:
+ AppendGListData(&pplist, "<=", 2);
+ break;
+ case TK_GREATER_EQUAL:
+ AppendGListData(&pplist, ">=", 2);
+ break;
+ case TK_SHL:
+ AppendGListData(&pplist, "<<", 2);
+ break;
+ case TK_SHR:
+ AppendGListData(&pplist, ">>", 2);
+ break;
+ case TK_INCREMENT:
+ AppendGListData(&pplist, "++", 2);
+ break;
+ case TK_DECREMENT:
+ AppendGListData(&pplist, "--", 2);
+ break;
+ case TK_ARROW:
+ AppendGListData(&pplist, "->", 2);
+ break;
+ case TK_ELLIPSIS:
+ AppendGListData(&pplist, "...", 3);
+ break;
+ case TK_DOT_STAR:
+ AppendGListData(&pplist, ".*", 2);
+ break;
+ case TK_ARROW_STAR:
+ AppendGListData(&pplist, "->*", 3);
+ break;
+ case TK_COLON_COLON:
+ AppendGListData(&pplist, "::", 2);
+ break;
+ case TK_AT_INTERFACE:
+ AppendGListData(&pplist, "@interface", 10);
+ break;
+ case TK_AT_IMPLEMENTATION:
+ AppendGListData(&pplist, "@implementation", 15);
+ break;
+ case TK_AT_PROTOCOL:
+ AppendGListData(&pplist, "@protocol", 9);
+ break;
+ case TK_AT_END:
+ AppendGListData(&pplist, "@end", 4);
+ break;
+ case TK_AT_PRIVATE:
+ AppendGListData(&pplist, "@private", 8);
+ break;
+ case TK_AT_PROTECTED:
+ AppendGListData(&pplist, "@protected", 10);
+ break;
+ case TK_AT_PUBLIC:
+ AppendGListData(&pplist, "@public", 7);
+ break;
+ case TK_AT_CLASS:
+ AppendGListData(&pplist, "@class", 6);
+ break;
+ case TK_AT_SELECTOR:
+ AppendGListData(&pplist, "@selector", 9);
+ break;
+ case TK_AT_ENCODE:
+ AppendGListData(&pplist, "@encode", 7);
+ break;
+ case TK_AT_DEFS:
+ AppendGListData(&pplist, "@defs", 5);
+ break;
+ case TK_SELF:
+ AppendGListData(&pplist, "self", 4);
+ break;
+ case TK_SUPER:
+ AppendGListData(&pplist, "super", 5);
+ break;
+ case TK_BOOL:
+ if (!copts.cplusplus && copts.c9x)
+ AppendGListData(&pplist, "_Bool", 5);
+ else
+ AppendGListData(&pplist, "bool", 4);
+ break;
+ case TK_RESTRICT:
+ if (copts.c9x)
+ AppendGListData(&pplist, "restrict", 8);
+ else
+ AppendGListData(&pplist, "__restrict", 10);
+ break;
+ case TK_UU_VECTOR:
+ AppendGListData(&pplist, "__vector", 8);
+ break;
+ case TK_UU_TYPEOF_UU:
+ AppendGListData(&pplist, "__typeof__", 10);
+ break;
+ case TK_UU_ATTRIBUTE_UU:
+ AppendGListData(&pplist, "__attribute__", 13);
+ break;
+ case TK_UU_ALIGNOF_UU:
+ AppendGListData(&pplist, "__alignof__", 11);
+ break;
+ case TK_UU_UUIDOF:
+ AppendGListData(&pplist, "__uuidof", 8);
+ break;
+ case TK_U_COMPLEX:
+ AppendGListData(&pplist, "_Complex", 8);
+ break;
+ case TK_U_IMAGINARY:
+ AppendGListData(&pplist, "_Imaginary", 10);
+ break;
+
+ case TK_STRING:
+ if (ispascalstring) {
+ AppendGListData(&pplist, "\"\\p", 3);
+ CPrep_DumpString((UInt8 *) tkstring + 1, tksize - 1);
+ } else {
+ AppendGListByte(&pplist, '"');
+ CPrep_DumpString((UInt8 *) tkstring, tksize - 1);
+ }
+ AppendGListByte(&pplist, '"');
+ break;
+
+ case TK_STRING_WIDE:
+ AppendGListData(&pplist, "L\"", 2);
+ CPrep_DumpWString((UInt16 *) tkstring, (tksize / stwchar.size) - 1);
+ AppendGListByte(&pplist, '"');
+ break;
+
+ default:
+ if (token >= 32 && token <= 255)
+ AppendGListByte(&pplist, token);
+ else
+ CError_FATAL(563);
+ }
+ break;
+ }
+
+ CPrep_TokenStreamFlush();
+ nlflag = 0;
+ spaceskip = 0;
+ } while ((token = lex()));
+ }
+
+ AppendGListByte(&pplist, 0);
+ COS_ResizeHandle(pplist.data, pplist.size);
+}
diff --git a/compiler_and_linker/FrontEnd/C/CRTTI.c b/compiler_and_linker/FrontEnd/C/CRTTI.c
new file mode 100644
index 0000000..3881153
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CRTTI.c
@@ -0,0 +1,940 @@
+#include "compiler/CRTTI.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CInit.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CScope.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/types.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CPrep.h"
+
+typedef struct Offset {
+ struct Offset *next;
+ SInt32 offset;
+} Offset;
+
+static Offset *crtti_offsets;
+static OLinkList *crtti_olinks;
+
+// forward decls
+static Object *CRTTI_ConstructTypeInfoObject(Type *type, UInt32 qual);
+
+typedef struct RTTISubClassList {
+ struct RTTISubClassList *next;
+ TypeClass *base;
+ SInt32 voffset;
+} RTTISubClassList;
+
+typedef struct RTTIBaseList {
+ struct RTTIBaseList *next;
+ TypeClass *base;
+ RTTISubClassList *subclasses;
+ SInt32 voffset;
+ short numsubclasses;
+ Boolean x12;
+ Boolean x13;
+} RTTIBaseList;
+
+static RTTIBaseList *CRTTI_CreateBaseList(TypeClass *tclass, TypeClass *tclassbase, RTTIBaseList *list, SInt32 voffset, Boolean flag) {
+ RTTIBaseList *scan;
+ ClassList *base;
+ Boolean flag27;
+ SInt32 newvoffset;
+
+ if (tclass != tclassbase) {
+ flag27 = 0;
+
+ for (scan = list; scan; scan = scan->next) {
+ if (scan->base == tclassbase) {
+ if (scan->voffset == voffset) {
+ if (!flag)
+ scan->x12 = 0;
+ flag27 = 0;
+ } else {
+ scan->x13 = 1;
+ flag27 = 1;
+ }
+ break;
+ }
+ }
+
+ if (!scan || flag27) {
+ scan = lalloc(sizeof(RTTIBaseList));
+ memclrw(scan, sizeof(RTTIBaseList));
+
+ scan->next = list;
+ list = scan;
+ scan->base = tclassbase;
+ scan->voffset = voffset;
+ scan->x12 = flag;
+ scan->x13 = flag27;
+ }
+ }
+
+ for (base = tclassbase->bases; base; base = base->next) {
+ if (base->is_virtual)
+ newvoffset = CClass_VirtualBaseOffset(tclass, base->base);
+ else
+ newvoffset = voffset + base->offset;
+
+ list = CRTTI_CreateBaseList(tclass, base->base, list, newvoffset, flag || base->access == ACCESSPRIVATE);
+ }
+
+ return list;
+}
+
+static void CRTTI_CreateSubClassList(TypeClass *tclass, RTTIBaseList *baselist, TypeClass *tclassbase, SInt32 voffset, Boolean flag) {
+ ClassList *base;
+ RTTISubClassList *scan;
+ SInt32 newvoffset;
+
+ if (baselist->base != tclassbase) {
+ for (scan = baselist->subclasses; scan; scan = scan->next) {
+ if (scan->base == tclassbase && scan->voffset == voffset)
+ break;
+ }
+
+ if (!scan) {
+ scan = lalloc(sizeof(RTTISubClassList));
+ scan->next = baselist->subclasses;
+ baselist->subclasses = scan;
+
+ scan->base = tclassbase;
+ scan->voffset = voffset;
+ baselist->numsubclasses++;
+ }
+ }
+
+ for (base = tclassbase->bases; base; base = base->next) {
+ if (base->access == ACCESSPUBLIC) {
+ if (base->is_virtual) {
+ if (!flag)
+ continue;
+ newvoffset = CClass_VirtualBaseOffset(tclass, base->base);
+ } else {
+ newvoffset = voffset + base->offset;
+ }
+
+ CRTTI_CreateSubClassList(tclass, baselist, base->base, newvoffset, flag);
+ }
+ }
+}
+
+static Object *CRTTI_CreateBaseListObject(TypeClass *tclass) {
+ RTTIBaseList *baselist;
+ OLinkList *refs;
+ Object *object;
+ SInt32 *buf;
+ SInt32 size;
+ short count1;
+ short count2;
+ short total;
+ OLinkList *ref;
+ RTTIBaseList *scan;
+ RTTISubClassList *subclass;
+ SInt32 *work;
+ SInt32 *work2;
+
+ baselist = CRTTI_CreateBaseList(tclass, tclass, NULL, 0, 0);
+ if (!baselist)
+ return NULL;
+
+ count1 = 0;
+ count2 = 0;
+ total = 0;
+
+ for (scan = baselist; scan; scan = scan->next) {
+ if (scan->x13 || scan->x12) {
+ CRTTI_CreateSubClassList(tclass, scan, scan->base, scan->voffset, scan->x13 == 0);
+ if (scan->numsubclasses) {
+ total += scan->numsubclasses;
+ count2++;
+ }
+ } else {
+ count1++;
+ }
+ }
+
+ if (!count1 && !count2)
+ return NULL;
+
+ size = (count1 + total) * 8 + count2 * 12 + 4;
+ buf = lalloc(size);
+ memclrw(buf, size);
+
+ object = CParser_NewCompilerDefDataObject();
+ object->name = CParser_GetUniqueName();
+ object->type = CDecl_NewStructType(size, 4);
+ object->qual = Q_CONST;
+ object->sclass = TK_STATIC;
+ refs = NULL;
+
+ work = buf;
+
+ if (count1) {
+ for (scan = baselist; scan; scan = scan->next) {
+ if (!scan->x12 && !scan->x13) {
+ ref = lalloc(sizeof(OLinkList));
+ ref->next = refs;
+ refs = ref;
+
+ ref->obj = CRTTI_ConstructTypeInfoObject(TYPE(scan->base), 0);
+ ref->offset = ((char *) work) - ((char *) buf);
+ ref->somevalue = 0;
+
+ work[1] = CTool_EndianConvertWord32(scan->voffset);
+ work += 2;
+ }
+ }
+ }
+
+ if (count2) {
+ for (scan = baselist; scan; scan = scan->next) {
+ if (scan->numsubclasses) {
+ ref = lalloc(sizeof(OLinkList));
+ ref->next = refs;
+ refs = ref;
+
+ ref->obj = CRTTI_ConstructTypeInfoObject(TYPE(scan->base), 0);
+ ref->offset = ((char *) work) - ((char *) buf);
+ ref->somevalue = 0;
+
+ work[1] = CTool_EndianConvertWord32(scan->voffset | 0x80000000);
+ work[2] = CTool_EndianConvertWord32(scan->numsubclasses);
+ work2 = work + 3;
+
+ for (subclass = scan->subclasses; subclass; subclass = subclass->next) {
+ ref = lalloc(sizeof(OLinkList));
+ ref->next = refs;
+ refs = ref;
+
+ ref->obj = CRTTI_ConstructTypeInfoObject(TYPE(subclass->base), 0);
+ ref->offset = ((char *) work2) - ((char *) buf);
+ ref->somevalue = 0;
+
+ work2[1] = CTool_EndianConvertWord32(subclass->voffset);
+ work2 += 2;
+ }
+
+ work = work2;
+ }
+ }
+ }
+
+ CInit_DeclareData(object, buf, refs, object->type->size);
+ return object;
+}
+
+static Object *CRTTI_ConstructTypeInfoObject(Type *type, UInt32 qual) {
+ Object *baselistobj;
+ Object *nameobj;
+ HashNameNode *rttiname;
+ OLinkList *refs;
+ char *namestr;
+ int namelen;
+ Object *object;
+ NameSpaceObjectList *list;
+ TypePointer tptr_copy;
+ TypeMemberPointer tmemptr_copy;
+ UInt32 data[2];
+
+ switch (type->type) {
+ case TYPEPOINTER:
+ if (TPTR_QUAL(type) & (Q_CONST | Q_VOLATILE)) {
+ tptr_copy = *TYPE_POINTER(type);
+ tptr_copy.qual &= ~(Q_CONST | Q_VOLATILE);
+ type = TYPE(&tptr_copy);
+ }
+ break;
+ case TYPEMEMBERPOINTER:
+ if (TYPE_MEMBER_POINTER(type)->qual & (Q_CONST | Q_VOLATILE)) {
+ tmemptr_copy = *TYPE_MEMBER_POINTER(type);
+ tmemptr_copy.qual &= ~(Q_CONST | Q_VOLATILE);
+ type = TYPE(&tmemptr_copy);
+ }
+ break;
+ default:
+ qual = 0;
+ }
+
+ if (IS_TYPE_CLASS(type) && type->size == 0) {
+ CDecl_CompleteType(type);
+ if (!(TYPE_CLASS(type)->flags & CLASS_COMPLETED))
+ CError_Error(CErrorStr136, type, 0);
+ }
+
+ rttiname = CMangler_RTTIObjectName(type, qual);
+ list = CScope_FindName(cscope_root, rttiname);
+
+ if (!list || (object = OBJECT(list->object))->otype != OT_OBJECT || object->datatype != DDATA) {
+ namestr = CError_GetTypeName(type, qual, 0);
+ namelen = strlen(namestr) + 1;
+ nameobj = CInit_DeclareString(namestr, namelen, 0, 0);
+
+ baselistobj = NULL;
+ if (IS_TYPE_CLASS(type))
+ baselistobj = CRTTI_CreateBaseListObject(TYPE_CLASS(type));
+
+ memclrw(data, sizeof(data));
+
+ object = CParser_NewCompilerDefDataObject();
+ object->name = rttiname;
+ object->type = CDecl_NewStructType(sizeof(data), 4);
+ object->qual = Q_CONST;
+ object->sclass = TK_STATIC;
+
+ refs = lalloc(sizeof(OLinkList));
+ refs->next = NULL;
+ refs->obj = nameobj;
+ refs->offset = 0;
+ refs->somevalue = 0;
+
+ if (baselistobj) {
+ refs->next = lalloc(sizeof(OLinkList));
+ refs->next->next = NULL;
+ refs->next->obj = baselistobj;
+ refs->next->offset = 4;
+ refs->next->somevalue = 0;
+ }
+
+ CScope_AddGlobalObject(object);
+ CInit_DeclareData(object, data, refs, object->type->size);
+ }
+
+ return object;
+}
+
+static void CRTTI_ConstructVTableHeader(TypeClass *tclass1, TypeClass *tclass2, Object *typeinfoObj, char *data, SInt32 offset, SInt32 voffset) {
+ ClassList *base;
+ Offset *o;
+ OLinkList *olink;
+ SInt32 tmp;
+ SInt32 newoffset;
+ SInt32 newvoffset;
+
+ if (tclass2->vtable->owner == tclass2) {
+ for (o = crtti_offsets; o; o = o->next) {
+ if (o->offset == voffset)
+ break;
+ }
+
+ if (!o) {
+ o = lalloc(sizeof(Offset));
+ o->next = crtti_offsets;
+ o->offset = voffset;
+ crtti_offsets = o;
+
+ olink = lalloc(sizeof(OLinkList));
+ olink->next = crtti_olinks;
+ olink->obj = typeinfoObj;
+ olink->offset = voffset;
+ olink->somevalue = 0;
+ crtti_olinks = olink;
+
+ *((SInt32 *) (data + voffset + 4)) = CTool_EndianConvertWord32(-offset);
+ } else {
+ tmp = *((SInt32 *) (data + voffset + 4));
+ CError_ASSERT(404, tmp == CTool_EndianConvertWord32(-offset));
+ }
+ }
+
+ for (base = tclass2->bases; base; base = base->next) {
+ if (base->base->vtable) {
+ if (base->is_virtual) {
+ newoffset = CClass_VirtualBaseOffset(tclass1, base->base);
+ newvoffset = CClass_VirtualBaseVTableOffset(tclass1, base->base);
+ } else {
+ newoffset = offset + base->offset;
+ newvoffset = voffset + base->voffset;
+ }
+
+ CRTTI_ConstructVTableHeader(tclass1, base->base, typeinfoObj, data, newoffset, newvoffset);
+ }
+ }
+}
+
+OLinkList *CRTTI_ConstructVTableHeaders(TypeClass *tclass, void *data, OLinkList *links) {
+ crtti_offsets = NULL;
+ crtti_olinks = links;
+
+ CRTTI_ConstructVTableHeader(
+ tclass, tclass,
+ CRTTI_ConstructTypeInfoObject(TYPE(tclass), 0),
+ data, 0, 0);
+
+ return crtti_olinks;
+}
+
+static Type *CRTTI_FindTypeInfoType(void) {
+ NameSpace *nspace;
+ NameSpaceObjectList *list;
+ Type *type;
+
+ if ((list = CScope_FindName(cscope_root, GetHashNameNodeExport("std"))) && list->object->otype == OT_NAMESPACE)
+ nspace = OBJ_NAMESPACE(list->object)->nspace;
+ else
+ nspace = cscope_root;
+
+ type = CScope_GetLocalTagType(nspace, GetHashNameNodeExport("type_info"));
+ if (type && IS_TYPE_CLASS(type) && type->size)
+ return type;
+
+ CError_Error(CErrorStr140, "::std::type_info");
+ return TYPE(&stchar);
+}
+
+ENode *CRTTI_ParseTypeID(void) {
+ ENode *expr;
+ Type *type;
+ Type *typeinfoType;
+ UInt32 qual;
+
+ if (!copts.RTTI)
+ CError_Warning(CErrorStr257);
+
+ typeinfoType = CRTTI_FindTypeInfoType();
+
+ if (lex() != '(') {
+ CError_Error(CErrorStr114);
+ return nullnode();
+ }
+
+ tk = lex();
+ if ((type = CParser_ParseTypeID(&qual, NULL))) {
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+
+ if (IS_TYPE_REFERENCE(type))
+ type = TPTR_TARGET(type);
+ } else {
+ expr = s_expression();
+
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+
+ type = expr->rtype;
+ qual = ENODE_QUALS(expr);
+
+ if (IS_TYPE_REFERENCE(type))
+ type = TPTR_TARGET(type);
+
+ if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->vtable) {
+ expr = funccallexpr(
+ Rgtid_func,
+ getnodeaddress(expr, 0),
+ intconstnode(TYPE(&stsignedlong), TYPE_CLASS(type)->vtable->offset),
+ NULL,
+ NULL);
+ expr->rtype = CDecl_NewPointerType(typeinfoType);
+
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = typeinfoType;
+ expr->flags = ENODE_FLAG_CONST;
+ return expr;
+ }
+ }
+
+ expr = create_objectrefnode(CRTTI_ConstructTypeInfoObject(type, qual));
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = typeinfoType;
+ expr->flags = ENODE_FLAG_CONST;
+ return expr;
+}
+
+static void CRTTI_ConstCastQualCheck(UInt32 qual1, UInt32 qual2) {
+ if (
+ ((qual1 & Q_CONST) && !(qual2 & Q_CONST)) ||
+ ((qual1 & Q_VOLATILE) && !(qual2 & Q_VOLATILE))
+ )
+ CError_Error(CErrorStr258);
+}
+
+static void CRTTI_ConstCastCheck(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2) {
+ Boolean flag = 1;
+ if (IS_TYPE_REFERENCE(type2)) {
+ type2 = TPTR_TARGET(type2);
+ flag = 0;
+ }
+
+ while (1) {
+ if (type1->type != type2->type)
+ break;
+
+ switch (type1->type) {
+ case TYPEPOINTER:
+ if (!flag)
+ CRTTI_ConstCastQualCheck(TPTR_QUAL(type1), TPTR_QUAL(type2));
+ type1 = TPTR_TARGET(type1);
+ type2 = TPTR_TARGET(type2);
+ flag = 0;
+ continue;
+
+ case TYPEMEMBERPOINTER:
+ if (!flag)
+ CRTTI_ConstCastQualCheck(TYPE_MEMBER_POINTER(type1)->qual, TYPE_MEMBER_POINTER(type2)->qual);
+ type1 = TYPE_MEMBER_POINTER(type1)->ty1;
+ type2 = TYPE_MEMBER_POINTER(type2)->ty1;
+ flag = 0;
+ continue;
+ }
+
+ break;
+ }
+
+ if (!flag && !IS_TYPE_FUNC(type1) && !IS_TYPE_FUNC(type2))
+ CRTTI_ConstCastQualCheck(CParser_GetCVTypeQualifiers(type1, qual1), CParser_GetCVTypeQualifiers(type2, qual2));
+}
+
+static ENode *CRTTI_ParseCast(DeclInfo *di) {
+ ENode *expr;
+
+ if (lex() != '<') {
+ CError_Error(CErrorStr230);
+ return NULL;
+ }
+
+ tk = lex();
+
+ memclrw(di, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(di, 0);
+ scandeclarator(di);
+
+ if (di->name)
+ CError_Error(CErrorStr164);
+
+ if (tk != '>') {
+ CError_Error(CErrorStr231);
+ return NULL;
+ }
+
+ if (lex() != '(') {
+ CError_Error(CErrorStr114);
+ return NULL;
+ }
+
+ tk = lex();
+ expr = s_expression();
+ if (!IS_TYPE_REFERENCE(di->thetype))
+ expr = pointer_generation(expr);
+
+ if (tk != ')') {
+ CError_Error(CErrorStr115);
+ return NULL;
+ }
+
+ tk = lex();
+ return expr;
+}
+
+static void CRTTI_IncompleteCheck(Type *type) {
+ if (IS_TYPE_POINTER_ONLY(type))
+ type = TPTR_TARGET(type);
+
+ if (IS_TYPE_CLASS(type) && type->size == 0) {
+ CDecl_CompleteType(type);
+ if (!(TYPE_CLASS(type)->flags & CLASS_COMPLETED))
+ CError_Error(CErrorStr136, type, 0);
+ }
+}
+
+static Boolean CRTTI_IsSameType(Type *a, Type *b) {
+ while (1) {
+ if (a->type != b->type)
+ return 0;
+
+ switch (a->type) {
+ case TYPEVOID:
+ return 1;
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPESTRUCT:
+ return a == b;
+ case TYPEPOINTER:
+ a = TPTR_TARGET(a);
+ b = TPTR_TARGET(b);
+ continue;
+ default:
+ return is_typesame(a, b);
+ }
+ }
+}
+
+static ENode *CRTTI_UniversalCast(ENode *expr, Type *type, UInt32 qual, UInt8 mode) {
+ // type/qual are the target type
+ Boolean isSimpleCast;
+ Boolean needsTypcon;
+ Boolean failed;
+
+ if (ENODE_IS(expr, EOBJLIST))
+ return CExpr_AssignmentPromotion(expr, type, qual & (Q_CONST | Q_VOLATILE), 1);
+
+ isSimpleCast = needsTypcon = failed = 0;
+
+ switch (type->type) {
+ case TYPEINT:
+ case TYPEENUM:
+ if (mode == 2 && IS_TYPE_POINTER_ONLY(expr->rtype) && type != TYPE(&stbool))
+ failed = 1;
+ break;
+
+ case TYPEPOINTER:
+ if (TPTR_QUAL(type) & Q_REFERENCE) {
+ if (
+ !CRTTI_IsSameType(TPTR_TARGET(type), expr->rtype) &&
+ mode == 2 &&
+ !(
+ IS_TYPE_CLASS(TPTR_TARGET(type)) &&
+ IS_TYPE_CLASS(expr->rtype) &&
+ (
+ CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(type)), TYPE_CLASS(expr->rtype), NULL, 0, 1) ||
+ CClass_IsBaseClass(TYPE_CLASS(expr->rtype), TYPE_CLASS(TPTR_TARGET(type)), NULL, 0, 1)
+ )
+ )
+ )
+ {
+ failed = 1;
+ }
+ } else if (IS_TYPE_POINTER_ONLY(expr->rtype)) {
+ if (
+ mode == 3 ||
+ CRTTI_IsSameType(type, expr->rtype) ||
+ IS_TYPE_VOID(TPTR_TARGET(type)) ||
+ IS_TYPE_VOID(TPTR_TARGET(expr->rtype))
+ )
+ {
+ isSimpleCast = needsTypcon = 1;
+ }
+ else if (
+ mode == 2 &&
+ !(
+ IS_TYPE_CLASS(TPTR_TARGET(type)) &&
+ IS_TYPE_CLASS(TPTR_TARGET(expr->rtype)) &&
+ (
+ CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(type)), TYPE_CLASS(TPTR_TARGET(expr->rtype)), NULL, 0, 1) ||
+ CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(expr->rtype)), TYPE_CLASS(TPTR_TARGET(type)), NULL, 0, 1)
+ )
+ )
+ )
+ {
+ failed = 1;
+ }
+ } else {
+ if (IS_TYPE_ENUM(expr->rtype))
+ expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
+
+ if (IS_TYPE_INT(expr->rtype)) {
+ if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval)) {
+ isSimpleCast = 1;
+ break;
+ }
+
+ if (mode != 2)
+ break;
+ }
+
+ if (IS_TYPE_CLASS(expr->rtype)) {
+ if (mode == 2)
+ break;
+ }
+
+ failed = 1;
+ }
+ break;
+ }
+
+ if (failed) {
+ CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual);
+ return expr;
+ }
+
+ if (isSimpleCast) {
+ if (needsTypcon && ENODE_IS(expr, EINDIRECT) && (copts.pointercast_lvalue || !copts.ANSIstrict))
+ expr = makemonadicnode(expr, ETYPCON);
+
+ expr->rtype = type;
+ expr->flags = qual & ENODE_FLAG_QUALS;
+ return expr;
+ }
+
+ if (copts.old_argmatch)
+ return do_typecast(expr, type, qual);
+
+ return CExpr_Convert(expr, type, qual, 1, 1);
+}
+
+ENode *CRTTI_Parse_dynamic_cast(void) {
+ Boolean isRef;
+ ENode *expr;
+ TypeClass *srcclass;
+ TypeClass *destclass;
+ ENode *typeinfo;
+ DeclInfo di;
+
+ expr = CRTTI_ParseCast(&di);
+ if (!expr)
+ return nullnode();
+
+ if (!copts.RTTI)
+ CError_Warning(CErrorStr257);
+
+ CRTTI_ConstCastCheck(expr->rtype, expr->flags, di.thetype, di.qual);
+ if (!IS_TYPE_POINTER_ONLY(di.thetype)) {
+ CError_Error(CErrorStr164);
+ return expr;
+ }
+
+ isRef = (TPTR_QUAL(di.thetype) & Q_REFERENCE) != 0;
+
+ if (IS_TYPE_CLASS(TPTR_TARGET(di.thetype))) {
+ destclass = TYPE_CLASS(TPTR_TARGET(di.thetype));
+ CDecl_CompleteType(TYPE(destclass));
+ if (!(destclass->flags & CLASS_COMPLETED)) {
+ CError_Error(CErrorStr136, destclass, 0);
+ return expr;
+ }
+ } else if (!IS_TYPE_VOID(TPTR_TARGET(di.thetype))) {
+ CError_Error(CErrorStr164);
+ return expr;
+ } else {
+ destclass = NULL;
+ }
+
+ if (isRef) {
+ if (!IS_TYPE_CLASS(expr->rtype)) {
+ CError_Error(CErrorStr164);
+ return expr;
+ }
+
+ srcclass = TYPE_CLASS(expr->rtype);
+ if (destclass) {
+ if (srcclass == destclass || CClass_IsBaseClass(srcclass, destclass, NULL, 0, 1))
+ return do_typecast(expr, di.thetype, di.qual);
+ }
+
+ expr = getnodeaddress(expr, 1);
+ } else {
+ if (!IS_TYPE_POINTER_ONLY(expr->rtype) || !IS_TYPE_CLASS(TPTR_TARGET(expr->rtype))) {
+ CError_Error(CErrorStr164);
+ return expr;
+ }
+
+ srcclass = TYPE_CLASS(TPTR_TARGET(expr->rtype));
+ if (destclass) {
+ if (srcclass == destclass || CClass_IsBaseClass(srcclass, destclass, NULL, 0, 1))
+ return do_typecast(expr, di.thetype, di.qual);
+ }
+ }
+
+ if (!(srcclass->flags & CLASS_COMPLETED)) {
+ CError_Error(CErrorStr136, srcclass, 0);
+ return expr;
+ }
+
+ if (!srcclass->vtable) {
+ CError_Error(CErrorStr164);
+ return expr;
+ }
+
+ if (srcclass->sominfo) {
+ CError_Error(CErrorStr164);
+ return expr;
+ }
+
+ if (destclass) {
+ typeinfo = create_objectrefnode(CRTTI_ConstructTypeInfoObject(TYPE(destclass), 0));
+ if (destclass->sominfo) {
+ CError_Error(CErrorStr164);
+ return expr;
+ }
+ } else {
+ typeinfo = nullnode();
+ }
+
+ expr = CExpr_FuncCallSix(
+ Rdync_func,
+ expr,
+ intconstnode(TYPE(&stsignedlong), srcclass->vtable->offset),
+ typeinfo,
+ create_objectrefnode(CRTTI_ConstructTypeInfoObject(TYPE(srcclass), 0)),
+ intconstnode(TYPE(&stsignedshort), isRef),
+ NULL
+ );
+
+ if (isRef) {
+ expr->rtype = CDecl_NewPointerType(TYPE(destclass));
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TYPE(destclass);
+ } else {
+ expr->rtype = di.thetype;
+ }
+ expr->flags = di.qual & ENODE_FLAG_QUALS;
+ return expr;
+}
+
+ENode *CRTTI_Parse_static_cast(void) {
+ ENode *expr;
+ DeclInfo di;
+
+ expr = CRTTI_ParseCast(&di);
+ if (!expr)
+ return nullnode();
+
+ CRTTI_ConstCastCheck(expr->rtype, expr->flags, di.thetype, di.qual);
+
+ if (IS_TYPE_REFERENCE(di.thetype)) {
+ if (IS_TYPE_CLASS(expr->rtype) && CExpr_CanImplicitlyConvert(expr, di.thetype, di.qual)) {
+ expr = CExpr_Convert(expr, di.thetype, di.qual, 0, 1);
+ CError_ASSERT(959, IS_TYPE_POINTER_ONLY(expr->rtype));
+
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TPTR_TARGET(di.thetype);
+ expr->flags = di.qual & ENODE_FLAG_QUALS;
+ return expr;
+ }
+ } else {
+ if (CExpr_CanImplicitlyConvert(expr, di.thetype, di.qual))
+ return CExpr_Convert(expr, di.thetype, di.qual, 1, 1);
+ }
+
+ if (!IS_TYPE_VOID(di.thetype) && !(IS_TYPE_POINTER_ONLY(expr->rtype) && IS_TYPE_VOID(TPTR_TARGET(expr->rtype)))) {
+ CRTTI_IncompleteCheck(di.thetype);
+ CRTTI_IncompleteCheck(expr->rtype);
+ }
+
+ return CRTTI_UniversalCast(expr, di.thetype, di.qual, 2);
+}
+
+ENode *CRTTI_Parse_reinterpret_cast(void) {
+ ENode *expr;
+ Type *origtype;
+ ENode *lvalue;
+ DeclInfo di;
+
+ expr = CRTTI_ParseCast(&di);
+ if (!expr)
+ return nullnode();
+
+ CRTTI_ConstCastCheck(expr->rtype, expr->flags, di.thetype, di.qual);
+
+ if (IS_TYPE_REFERENCE(di.thetype)) {
+ lvalue = CExpr_LValue(expr, 0, 1);
+ if (!ENODE_IS(lvalue, EINDIRECT))
+ return lvalue;
+
+ lvalue->data.monadic->rtype = CDecl_NewPointerType(lvalue->rtype);
+ expr = lvalue->data.monadic;
+ origtype = di.thetype;
+ di.thetype = CDecl_NewPointerType(TPTR_TARGET(di.thetype));
+ } else {
+ origtype = NULL;
+ }
+
+ switch (di.thetype->type) {
+ case TYPEINT:
+ switch (expr->rtype->type) {
+ case TYPEMEMBERPOINTER:
+ case TYPEPOINTER:
+ expr = do_typecast(expr, di.thetype, di.qual);
+ break;
+ default:
+ CError_Error(CErrorStr164);
+ }
+ break;
+ case TYPEPOINTER:
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ case TYPEENUM:
+ if (origtype)
+ di.thetype = origtype;
+ expr = do_typecast(expr, di.thetype, di.qual);
+ break;
+ case TYPEPOINTER:
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = di.thetype;
+ expr->flags = di.qual & ENODE_FLAG_QUALS;
+ break;
+ default:
+ CError_Error(CErrorStr164);
+ }
+ break;
+ case TYPEMEMBERPOINTER:
+ if (IS_TYPE_MEMBERPOINTER(expr->rtype)) {
+ if (IS_TYPE_FUNC(TYPE_MEMBER_POINTER(di.thetype)->ty1)) {
+ if (IS_TYPE_FUNC(TYPE_MEMBER_POINTER(expr->rtype)->ty1)) {
+ expr->rtype = di.thetype;
+ expr->flags = di.qual & ENODE_FLAG_QUALS;
+ break;
+ }
+ } else {
+ if (!IS_TYPE_FUNC(TYPE_MEMBER_POINTER(expr->rtype)->ty1)) {
+ expr->rtype = di.thetype;
+ expr->flags = di.qual & ENODE_FLAG_QUALS;
+ break;
+ }
+ }
+ }
+ expr = do_typecast(expr, di.thetype, di.qual);
+ break;
+ default:
+ CError_Error(CErrorStr164);
+ }
+
+ if (origtype && IS_TYPE_POINTER_ONLY(expr->rtype)) {
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TPTR_TARGET(di.thetype);
+ }
+
+ return expr;
+}
+
+ENode *CRTTI_Parse_const_cast(void) {
+ DeclInfo di;
+ ENode *expr;
+
+ if (!(expr = CRTTI_ParseCast(&di)))
+ return nullnode();
+
+ if (IS_TYPE_POINTER_ONLY(di.thetype)) {
+ if (TPTR_QUAL(di.thetype) & Q_REFERENCE) {
+ if (!iscpp_typeequal(TPTR_TARGET(di.thetype), expr->rtype))
+ CError_Error(CErrorStr164);
+
+ if (ENODE_IS(expr, EINDIRECT)) {
+ expr->rtype = TPTR_TARGET(di.thetype);
+ expr->flags = di.qual & ENODE_FLAG_QUALS;
+ } else {
+ CError_Error(CErrorStr142);
+ }
+ } else {
+ if (!iscpp_typeequal(di.thetype, expr->rtype))
+ CError_Error(CErrorStr164);
+
+ expr = do_typecast(expr, di.thetype, di.qual);
+ }
+ } else if (IS_TYPE_MEMBERPOINTER(di.thetype)) {
+ if (!iscpp_typeequal(di.thetype, expr->rtype))
+ CError_Error(CErrorStr164);
+
+ expr = do_typecast(expr, di.thetype, di.qual);
+ } else {
+ if (!is_typesame(di.thetype, expr->rtype))
+ CError_Error(CErrorStr164);
+ else
+ expr = do_typecast(expr, di.thetype, di.qual);
+ }
+
+ return expr;
+}
diff --git a/compiler_and_linker/FrontEnd/C/CSOM.c b/compiler_and_linker/FrontEnd/C/CSOM.c
new file mode 100644
index 0000000..7e80e32
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CSOM.c
@@ -0,0 +1,2068 @@
+#include "compiler/CSOM.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CException.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInit.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CScope.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/types.h"
+#include "cos.h"
+
+// all pointers have been converted to UInt32 for the sake of maintaining 32-bit compat
+
+typedef struct {
+ SInt32 zero;
+ /* struct somStaticClassInfo * */ UInt32 sci;
+ /* void * */ UInt32 instanceDataToken;
+ SInt32 reserved[3];
+ /* void * */ UInt32 tokens[1];
+} somClassDataStructure;
+
+enum {
+ mtVirtualMethod = 0,
+ mtProcedure = 1,
+ mtNonStatic = 2,
+ mtEmpty = 3,
+ mtDToken = 4
+};
+
+enum {
+ pdUByte = 0,
+ pdSByte = 1,
+ pdUHalf = 2,
+ pdSHalf = 3,
+ pdULong = 4,
+ pdSLong = 5,
+ pdVLong = 6,
+ pdVoid = 7,
+ pdSFlt = 8,
+ pdDFlt = 9,
+ pdLFlt = 10,
+ pdVSAgg = 11,
+ pdNPtr = 12,
+ pdLPtr = 13,
+ pdSAgg = 14,
+ pdLAgg = 15
+};
+
+enum {
+ fgShortOrChars = 1,
+ fgShortFloats = 2,
+ fgAnyFloats = 4,
+ fgAnyNon4Bytes = 8
+};
+
+enum {
+ cfSharedStrings = 1,
+ cfTempClass = 2,
+ cfProxyClass = 4,
+ cfClassAllocate = 0x100,
+ cfClassDeallocate = 0x200,
+ cfClassInit = 0x400,
+ cfClassUninit = 0x800
+};
+
+typedef struct {
+ UInt32 majorVersion;
+ UInt32 minorVersion;
+ UInt32 flags;
+ UInt16 dataAlignment;
+ UInt16 classTokenCount;
+ UInt16 numDirectParents;
+ UInt16 numMetaClasses;
+ UInt16 numOverriddenAncestors;
+ UInt16 numMigratedMethods;
+ UInt16 numSelectInherited;
+ UInt16 numUnused;
+ UInt16 dummy2a[4];
+} somStaticClassCounts;
+
+typedef UInt8 somSlotUsage;
+typedef UInt8 somSignatureInfo;
+typedef UInt16 somOverrideData;
+typedef UInt16 somMigratedMethods;
+typedef UInt16 somSelectedInherited;
+typedef UInt32 somParentVersions;
+
+typedef struct {
+ /* const char * */ UInt32 className;
+ UInt32 instanceDataSize;
+ /* const somParentVersions * */ UInt32 parentVersions;
+ /* const somSlotUsage * */ UInt32 ttSlotUsage;
+ /* const somSignatureInfo * */ UInt32 signatureInfo;
+ /* const char * */ UInt32 methodNames;
+ /* const somOverrideData * */ UInt32 overrideData;
+ /* const somMigratedMethods * */ UInt32 migratedMethods;
+ /* const somSelectedInherited * */ UInt32 selectedInherited;
+ /* const void * */ UInt32 unused;
+ /* const void * */ UInt32 dummy4b[4];
+} somStaticClassDescription;
+
+typedef struct somStaticClassInfo {
+ UInt32 layoutVersion;
+ /* somClassDataStructure * */ UInt32 tokenTable;
+ /* somMethodPtr * */ UInt32 overrideMethods;
+ /* somClassDataStructure ** */ UInt32 specifiedAncestry;
+ /* somOpaque */ UInt32 DLLDesignator;
+ /* somMethodPtr * */ UInt32 specialProcs;
+ /* somRuntimeClassInfo * */ UInt32 runtimeClassInfo;
+ SInt32 interesting;
+ /* somClassDataStructure ** */ UInt32 actualAncestry;
+ /* void * */ UInt32 extra[4];
+ /* const somStaticClassCounts * */ UInt32 classCounts;
+ somStaticClassDescription classDescription;
+} somStaticClassInfo;
+
+CSOMStub *csom_stubs;
+static HashNameNode *csom_initname;
+static HashNameNode *csom_uninitname;
+static HashNameNode *csom_envname;
+static HashNameNode *csom_selfname;
+
+static FuncArg SOMIDT_arg1 = {
+ NULL,
+ NULL,
+ NULL,
+ TYPE(&void_ptr),
+ 0,
+ 0,
+ 0
+};
+
+static TypeFunc SOMIDT_type = {
+ TYPEFUNC,
+ 0,
+ &SOMIDT_arg1,
+ NULL,
+ TYPE(&void_ptr),
+ 0,
+ 0
+};
+
+void CSOM_Setup(Boolean flag) {
+ if (!flag)
+ csom_stubs = NULL;
+
+ csom_initname = GetHashNameNodeExport("somInit");
+ csom_uninitname = GetHashNameNodeExport("somUninit");
+ csom_envname = GetHashNameNodeExport("Environment");
+ csom_selfname = GetHashNameNodeExport("__somself");
+}
+
+void CSOM_Cleanup(void) {
+ CSOMStub *stub;
+
+ if (cparamblkptr->precompile != 1) {
+ for (stub = csom_stubs; stub; stub = stub->next) {
+ switch (stub->x10) {
+ case 0:
+ CodeGen_SOMStub(stub->object, rt_som_glue1, stub->tclass->sominfo->classdataobject, stub->offset);
+ break;
+ case 1:
+ CodeGen_SOMStub(stub->object, rt_som_glue2, stub->tclass->sominfo->classdataobject, stub->offset);
+ break;
+ case 2:
+ CodeGen_SOMStub(stub->object, rt_som_glue3, stub->tclass->sominfo->classdataobject, stub->offset);
+ break;
+ default:
+ CError_FATAL(132);
+ }
+ }
+ }
+}
+
+static HashNameNode *CSOM_NameTranslate(HashNameNode *name) {
+ if (name == constructor_name_node)
+ name = csom_initname;
+ else if (name == destructor_name_node)
+ name = csom_uninitname;
+ return name;
+}
+
+static Type *CSOM_FindClassType(HashNameNode *name) {
+ Type *type;
+
+ type = CScope_GetTagType(cscope_current, name);
+ if (!type) {
+ CPrep_ErrorName(CErrorStr281, name->name);
+ type = &stvoid;
+ }
+
+ return type;
+}
+
+CW_INLINE UInt16 CSOM_GetTokenTableIndex(const Object *object) {
+ CError_ASSERT(173, IS_TYPE_METHOD(object->type));
+ return TYPE_METHOD(object->type)->vtbl_index;
+}
+
+static SInt32 CSOM_GetTokenOffset(Object *object) {
+ return 24 + 4 * CSOM_GetTokenTableIndex(object);
+}
+
+typedef struct TypeSig {
+ UInt8 x0;
+ UInt8 x1;
+ UInt8 x2;
+} TypeSig;
+
+static int CSOM_GetTypeSig(TypeSig *sig, Type *type, Boolean flag) {
+ if (type->size > 4)
+ sig->x1 |= fgAnyNon4Bytes;
+
+ switch (type->type) {
+ case TYPEVOID:
+ if (flag)
+ return pdVoid;
+ break;
+ case TYPEINT:
+ case TYPEENUM:
+ if (is_unsigned(type)) {
+ switch (type->size) {
+ case 1:
+ sig->x1 |= fgShortOrChars;
+ return pdUByte;
+ case 2:
+ sig->x1 |= fgShortOrChars;
+ return pdUHalf;
+ case 4:
+ return pdULong;
+ case 8:
+ return pdVLong;
+ }
+ } else {
+ switch (type->size) {
+ case 1:
+ sig->x1 |= fgShortOrChars;
+ return pdSByte;
+ case 2:
+ sig->x1 |= fgShortOrChars;
+ return pdSHalf;
+ case 4:
+ return pdSLong;
+ case 8:
+ return pdVLong;
+ }
+ }
+ break;
+ case TYPEFLOAT:
+ sig->x1 |= fgAnyFloats;
+ switch (type->size) {
+ case 4:
+ sig->x1 |= fgShortFloats;
+ return pdSFlt;
+ case 8:
+ return pdDFlt;
+ case 12:
+ case 16:
+ return pdLFlt;
+ }
+ break;
+ case TYPEPOINTER:
+ return pdNPtr;
+ case TYPESTRUCT:
+ case TYPECLASS:
+ if (flag) {
+ if (type->size <= 2) {
+ sig->x1 |= fgShortOrChars;
+ return pdVSAgg;
+ } else if (type->size <= 4) {
+ return pdSAgg;
+ } else {
+ return pdLAgg;
+ }
+ }
+ break;
+ }
+
+ CError_Error(CErrorStr273);
+ return 5;
+}
+
+static void CSOM_GetFuncSig(TypeFunc *tfunc, Boolean flag) {
+ FuncArg *arg;
+ Boolean pendingData;
+ UInt8 work;
+ TypeSig sig;
+
+ sig.x2 = CSOM_GetTypeSig(&sig, tfunc->functype, 1);
+ sig.x1 = 0;
+ sig.x0 = 0;
+
+ for (arg = tfunc->args; arg; arg = arg->next) {
+ if (arg == &elipsis || arg == &oldstyle || (++sig.x0 == 0)) {
+ CError_Error(CErrorStr273);
+ break;
+ }
+
+ CSOM_GetTypeSig(&sig, arg->type, 0);
+ }
+
+ if (flag) {
+ if ((arg = tfunc->args)) {
+ if (TYPE_METHOD(tfunc)->is_static == 0)
+ arg = arg->next;
+ if (arg && CMach_GetFunctionResultClass(tfunc) != 0)
+ arg = arg->next;
+ }
+
+ AppendGListByte(&name_mangle_list, sig.x0);
+ AppendGListByte(&name_mangle_list, (sig.x1 << 4) | sig.x2);
+ if (sig.x1) {
+ pendingData = 0;
+ work = 0;
+ while (arg) {
+ work = (work << 4) | CSOM_GetTypeSig(&sig, arg->type, 0);
+ if (pendingData) {
+ AppendGListByte(&name_mangle_list, work);
+ pendingData = 0;
+ work = 0;
+ } else {
+ pendingData = 1;
+ }
+ arg = arg->next;
+ }
+
+ if (pendingData)
+ AppendGListByte(&name_mangle_list, work << 4);
+ }
+ }
+}
+
+void CSOM_CheckFuncType(TypeFunc *tfunc) {
+ CSOM_GetFuncSig(tfunc, 0);
+}
+
+static Object *CSOM_MakeObject(char *name1, char *name2, SInt32 size) {
+ Object *object = CParser_NewCompilerDefDataObject();
+ object->name = CParser_NameConcat(name1, name2);
+ object->type = CDecl_NewStructType(size, 4);
+ CScope_AddObject(object->nspace, object->name, OBJ_BASE(object));
+ return object;
+}
+
+void CSOM_MakeSOMClass(TypeClass *tclass) {
+ ClassList *base;
+
+ for (base = tclass->bases; base; base = base->next) {
+ if (!base->base->sominfo) {
+ CError_Error(CErrorStr267);
+ break;
+ }
+ }
+
+ if (!tclass->sominfo) {
+ SOMInfo *info = galloc(sizeof(SOMInfo));
+ memclrw(info, sizeof(SOMInfo));
+ tclass->sominfo = info;
+
+ info->classdataobject = CSOM_MakeObject(tclass->classname->name, "ClassData", 28);
+ info->classdataobject->flags = info->classdataobject->flags | OBJECT_EXPORT;
+ }
+}
+
+static Boolean CSOM_IsTokenListFunc(Object *object) {
+ Type *type = object->type;
+ if (
+ IS_TYPE_FUNC(type) &&
+ !(TYPE_FUNC(type)->flags & FUNC_FLAGS_20) &&
+ !TYPE_METHOD(type)->is_static &&
+ (!(object->qual & Q_INLINE) || object->datatype == DVFUNC)
+ )
+ return 1;
+
+ return 0;
+}
+
+static Object **CSOM_GetLexicalOrderMethodArray(TypeClass *tclass, int *resultCount) {
+ Object *object;
+ int count;
+ Object **array;
+ CScopeObjectIterator iter;
+
+ count = 0;
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (IS_TYPE_METHOD(object->type)) {
+ if (CSOM_IsTokenListFunc(object)) {
+ if (TYPE_METHOD(object->type)->vtbl_index > count)
+ count = TYPE_METHOD(object->type)->vtbl_index;
+ } else {
+ TYPE_METHOD(object->type)->vtbl_index = 0;
+ }
+ }
+ }
+
+ *resultCount = ++count;
+
+ array = lalloc(sizeof(Object *) * count);
+ memclrw(array, sizeof(Object *) * count);
+
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (CSOM_IsTokenListFunc(object))
+ array[TYPE_METHOD(object->type)->vtbl_index] = object;
+ }
+
+ return array;
+}
+
+void CSOM_ClassComplete(TypeClass *tclass) {
+ Object *object;
+ CScopeObjectIterator iter;
+ SInt32 counter;
+ SOMReleaseOrder *order;
+
+ if (tclass->sominfo->order) {
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (CSOM_IsTokenListFunc(object)) {
+ HashNameNode *name;
+
+ name = CSOM_NameTranslate(object->name);
+ for (order = tclass->sominfo->order, counter = 0; order; order = order->next, counter++) {
+ if (order->name == name) {
+ order->state = SOMMS_Method;
+ TYPE_METHOD(object->type)->vtbl_index = counter;
+ break;
+ }
+ }
+
+ if (!order)
+ CError_Error(CErrorStr278, object);
+ }
+ }
+
+ for (order = tclass->sominfo->order; order; order = order->next) {
+ if (order->state == SOMMS_Deleted) {
+ SOMReleaseOrder *order2;
+ VClassList *vbase;
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ for (order2 = vbase->base->sominfo->order; order2; order2 = order2->next) {
+ if (order->name == order2->name && order2->state == SOMMS_Method) {
+ order->state = SOMMS_Migrated;
+ break;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ Object **array;
+ int arrayCount;
+ SInt32 i;
+
+ array = CSOM_GetLexicalOrderMethodArray(tclass, &arrayCount);
+ for (i = counter = 0; i < arrayCount; i++) {
+ object = array[i];
+ if (object) {
+ if (counter == 0 && copts.pedantic)
+ CError_Warning(CErrorStr291);
+ TYPE_METHOD(object->type)->vtbl_index = counter++;
+ }
+ }
+ }
+
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ NameSpaceObjectList *nsol;
+ if (!(nsol = CScope_NextObjectIteratorObjectList(&iter)))
+ break;
+
+ if (nsol->object->otype == OT_OBJECT && nsol->next && nsol->next->object->otype == OT_OBJECT) {
+ while (nsol) {
+ if (
+ nsol->object->otype == OT_OBJECT &&
+ (!(OBJECT(nsol->object)->qual & Q_INLINE) || OBJECT(nsol->object)->datatype == DVFUNC)
+ )
+ CError_Error(CErrorStr270, nsol->object);
+ nsol = nsol->next;
+ }
+ }
+ }
+
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (!(object->qual & Q_INLINE)) {
+ CError_ASSERT(529, IS_TYPE_FUNC(object->type));
+
+ TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_4;
+ tclass->action = CLASS_ACTION_1;
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (IS_TYPE_FUNC(object->type))
+ TYPE_FUNC(object->type)->flags &= ~FUNC_FLAGS_4;
+ }
+ break;
+ }
+ }
+
+ if (tclass->sominfo->oidl_callstyle == 0) {
+ Type *envType;
+ envType = CSOM_FindClassType(csom_envname);
+
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (
+ IS_TYPE_FUNC(object->type) &&
+ TYPE_METHOD(object->type)->is_static == 0 &&
+ !(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_20) &&
+ !(
+ TYPE_FUNC(object->type)->args &&
+ TYPE_FUNC(object->type)->args->next &&
+ IS_TYPE_POINTER_ONLY(TYPE_FUNC(object->type)->args->next->type) &&
+ TPTR_TARGET(TYPE_FUNC(object->type)->args->next->type) == envType
+ )
+ )
+ {
+ CError_Error(CErrorStr282, object);
+ }
+ }
+ }
+
+ if (tclass->action == CLASS_ACTION_0)
+ CError_Error(CErrorStr280);
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct SOMOverride {
+ struct SOMOverride *next;
+ Object *a;
+ Object *b;
+} SOMOverride;
+
+typedef struct SOMAncestor {
+ struct SOMAncestor *next;
+ TypeClass *tclass;
+ SOMOverride *overrides;
+ Boolean xC;
+ Boolean xD;
+} SOMAncestor;
+
+typedef struct SOMMethod {
+ struct SOMMethod *next;
+ HashNameNode *name;
+ union {
+ Object *object;
+ struct {
+ UInt16 a;
+ UInt16 b;
+ } pair;
+ } u;
+ SOMMethodState state;
+} SOMMethod;
+
+typedef struct SOMGenerator {
+ SOMMethod *methods;
+ SOMAncestor *ancestors;
+ Object *sciObj;
+ Object *classAncestorsObj;
+ Object *overrideProcsObj;
+ Object *dlldFunc;
+ Object *specialProcsObj;
+ somStaticClassCounts counts;
+ int overrideProcsCount;
+ Boolean hasNew;
+ Boolean hasDelete;
+} SOMGenerator;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static SOMAncestor *CSOM_FindAddAncestor(SOMGenerator *gen, TypeClass *tclass, TypeClass *ancestorClass, UInt16 *resultIndex) {
+ SOMAncestor *ancestor;
+ SOMAncestor *scan;
+ UInt16 index;
+
+ ancestor = gen->ancestors;
+ for (scan = ancestor, index = 0; scan; scan = scan->next, index++) {
+ if (scan->tclass == ancestorClass) {
+ if (resultIndex)
+ *resultIndex = index;
+ return scan;
+ }
+ }
+
+ if (ancestor) {
+ index = 1;
+ while (ancestor->next) {
+ index++;
+ ancestor = ancestor->next;
+ }
+
+ ancestor->next = lalloc(sizeof(SOMAncestor));
+ memclrw(ancestor->next, sizeof(SOMAncestor));
+ ancestor = ancestor->next;
+ } else {
+ index = 0;
+ ancestor = lalloc(sizeof(SOMAncestor));
+ memclrw(ancestor, sizeof(SOMAncestor));
+ gen->ancestors = ancestor;
+ }
+
+ ancestor->tclass = ancestorClass;
+ if (resultIndex)
+ *resultIndex = index;
+ return ancestor;
+}
+
+static void CSOM_GenerateOverrideIntroLists(SOMGenerator *gen, TypeClass *tclass) {
+ Object *object;
+ VClassList *vbase;
+ ClassList *base;
+ SOMMethod *method;
+ SOMMethod **ptr;
+ CScopeObjectIterator iter;
+
+ for (base = tclass->bases; base; base = base->next) {
+ SOMAncestor *ancestor = CSOM_FindAddAncestor(gen, tclass, base->base, NULL);
+ ancestor->xD = 1;
+ gen->counts.numDirectParents++;
+ }
+
+ if (tclass->sominfo->metaclass && tclass->sominfo->metaclass->sominfo) {
+ SOMAncestor *ancestor = CSOM_FindAddAncestor(gen, tclass, tclass->sominfo->metaclass, NULL);
+ ancestor->xC = 1;
+ gen->counts.numMetaClasses++;
+ }
+
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (IS_TYPE_FUNC(object->type) && (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_20)) {
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ Object *object2;
+ CScopeObjectIterator iter2;
+ CScope_InitObjectIterator(&iter2, vbase->base->nspace);
+ while (1) {
+ if (!(object2 = OBJECT(CScope_NextObjectIteratorObject(&iter2))))
+ break;
+
+ if (
+ IS_TYPE_FUNC(object2->type) &&
+ object->name == object2->name &&
+ object2->datatype == DVFUNC &&
+ !(TYPE_FUNC(object2->type)->flags & FUNC_FLAGS_20) &&
+ CClass_GetOverrideKind(TYPE_FUNC(object->type), TYPE_FUNC(object2->type), 0) != 0
+ )
+ {
+ SOMAncestor *ancestor;
+ SOMOverride *override;
+ ancestor = CSOM_FindAddAncestor(gen, tclass, vbase->base, NULL);
+ if (ancestor->overrides) {
+ override = lalloc(sizeof(SOMOverride));
+ memclrw(override, sizeof(SOMOverride));
+ override->next = ancestor->overrides;
+ ancestor->overrides = override;
+ } else {
+ override = lalloc(sizeof(SOMOverride));
+ memclrw(override, sizeof(SOMOverride));
+ ancestor->overrides = override;
+ gen->counts.numOverriddenAncestors++;
+ }
+ override->a = object;
+ override->b = object2;
+ break;
+ }
+ }
+ }
+ gen->overrideProcsCount++;
+ }
+ }
+
+ ptr = &gen->methods;
+ if (tclass->sominfo->order) {
+ SOMReleaseOrder *order;
+ SOMReleaseOrder *order2;
+ SInt32 index;
+ UInt16 index2;
+
+ for (order = tclass->sominfo->order, index = 0; order; order = order->next, index++) {
+ method = lalloc(sizeof(SOMMethod));
+ memclrw(method, sizeof(SOMMethod));
+ *ptr = method;
+ ptr = &method->next;
+
+ method->name = order->name;
+ method->state = order->state;
+ switch (order->state) {
+ case SOMMS_Migrated:
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ for (order2 = vbase->base->sominfo->order, index2 = 0; order2; order2 = order2->next, index2++) {
+ if (order->name == order2->name && order2->state == SOMMS_Method) {
+ CSOM_FindAddAncestor(gen, tclass, vbase->base, &method->u.pair.a);
+ method->u.pair.b = index2;
+ break;
+ }
+ }
+
+ if (order2)
+ break;
+ }
+ gen->counts.numMigratedMethods++;
+ break;
+
+ case SOMMS_Method:
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (
+ IS_TYPE_FUNC(object->type) &&
+ CSOM_NameTranslate(object->name) == order->name
+ )
+ {
+ CError_ASSERT(733, TYPE_METHOD(object->type)->vtbl_index == index);
+ method->u.object = object;
+ break;
+ }
+ }
+
+ CError_ASSERT(737, object != NULL);
+ break;
+ }
+
+ gen->counts.classTokenCount++;
+ }
+ } else {
+ Object **array;
+ int arrayCount;
+ SInt32 i;
+
+ array = CSOM_GetLexicalOrderMethodArray(tclass, &arrayCount);
+ for (i = 0; i < arrayCount; i++) {
+ object = array[i];
+ if (object) {
+ method = lalloc(sizeof(SOMMethod));
+ memclrw(method, sizeof(SOMMethod));
+ *ptr = method;
+ ptr = &method->next;
+
+ method->u.object = object;
+ method->name = object->name;
+ method->state = SOMMS_Method;
+ gen->counts.classTokenCount++;
+ }
+ }
+ }
+}
+
+static void CSOM_GenerateClassAncestors(SOMGenerator *gen, TypeClass *tclass) {
+ SOMAncestor *ancestor;
+ Object *object;
+ OLinkList *relocs;
+ SInt32 size;
+ char *buf;
+
+ if (gen->ancestors) {
+ object = CSOM_MakeObject(tclass->classname->name, "ClassAncestors", 4);
+ object->sclass = TK_STATIC;
+
+ relocs = NULL;
+ size = 0;
+ for (ancestor = gen->ancestors; ancestor; ancestor = ancestor->next) {
+ OLinkList *reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = ancestor->tclass->sominfo->classdataobject;
+ reloc->offset = size;
+ reloc->somevalue = 0;
+ size += 4;
+ }
+
+ buf = lalloc(size);
+ memclrw(buf, size);
+ object->type->size = size;
+ CInit_DeclareData(object, buf, relocs, object->type->size);
+ gen->classAncestorsObj = object;
+ }
+}
+
+static void CSOM_GenerateOverrideProcs(SOMGenerator *gen, TypeClass *tclass) {
+ SOMOverride *override;
+ SOMAncestor *ancestor;
+ Object *object;
+ OLinkList *relocs;
+ SInt32 size;
+ SInt32 offset;
+ char *buf;
+
+ if (gen->overrideProcsCount) {
+ size = gen->overrideProcsCount * 4;
+ object = CSOM_MakeObject(tclass->classname->name, "OverrideProcs", size);
+ object->sclass = TK_STATIC;
+
+ relocs = NULL;
+ offset = 0;
+ for (ancestor = gen->ancestors; ancestor; ancestor = ancestor->next) {
+ if (ancestor->overrides) {
+ for (override = ancestor->overrides; override; override = override->next) {
+ OLinkList *reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = override->a;
+ reloc->offset = offset;
+ reloc->somevalue = 0;
+ offset += 4;
+ }
+ }
+ }
+
+ buf = lalloc(size);
+ memclrw(buf, size);
+ CInit_DeclareData(object, buf, relocs, object->type->size);
+ gen->overrideProcsObj = object;
+ }
+}
+
+static Object *CSOM_GenerateOverrideData(SOMGenerator *gen) {
+ SOMAncestor *ancestor;
+ Object *object;
+ short ancestorIndex;
+
+ name_mangle_list.size = 0;
+ for (ancestor = gen->ancestors, ancestorIndex = 0; ancestor; ancestor = ancestor->next, ancestorIndex++) {
+ if (ancestor->overrides) {
+ SOMOverride *override;
+ short overrideCount;
+
+ AppendGListWord(&name_mangle_list, CTool_EndianConvertWord16(ancestorIndex));
+
+ override = ancestor->overrides;
+ overrideCount = 0;
+ while (override) {
+ overrideCount++;
+ override = override->next;
+ }
+ AppendGListWord(&name_mangle_list, CTool_EndianConvertWord16(overrideCount));
+
+ for (override = ancestor->overrides; override; override = override->next) {
+ AppendGListWord(&name_mangle_list, CTool_EndianConvertWord16(CSOM_GetTokenTableIndex(override->b)));
+ }
+ }
+ }
+
+ COS_LockHandle(name_mangle_list.data);
+ object = CInit_DeclareString(*name_mangle_list.data, name_mangle_list.size, 0, 0);
+ COS_UnlockHandle(name_mangle_list.data);
+ return object;
+}
+
+static Object *CSOM_GenerateMigrateData(SOMGenerator *gen) {
+ SOMMethod *method;
+ Object *object;
+ int index;
+
+ name_mangle_list.size = 0;
+ for (method = gen->methods, index = 0; method; method = method->next, index++) {
+ if (method->state == SOMMS_Migrated) {
+ AppendGListWord(&name_mangle_list, CTool_EndianConvertWord16(method->u.pair.a));
+ AppendGListWord(&name_mangle_list, CTool_EndianConvertWord16(method->u.pair.b));
+ AppendGListWord(&name_mangle_list, CTool_EndianConvertWord16(index));
+ }
+ }
+
+ COS_LockHandle(name_mangle_list.data);
+ object = CInit_DeclareString(*name_mangle_list.data, name_mangle_list.size, 0, 0);
+ COS_UnlockHandle(name_mangle_list.data);
+ return object;
+}
+
+static void CSOM_GenerateDLLDFunc(SOMGenerator *gen, TypeClass *tclass) {
+ TypeFunc *tfunc;
+ Object *object;
+
+ tfunc = galloc(sizeof(TypeFunc));
+ memclrw(tfunc, sizeof(TypeFunc));
+ tfunc->type = TYPEFUNC;
+ tfunc->functype = &stvoid;
+
+ object = CParser_NewCompilerDefFunctionObject();
+ object->type = TYPE(tfunc);
+ object->sclass = TK_STATIC;
+ object->name = CParser_NameConcat(tclass->classname->name, "DLLD");
+
+ if (CScope_GetLocalObject(cscope_root, object->name))
+ CError_Error(CErrorStr333, object);
+
+ gen->dlldFunc = object;
+ CFunc_GenerateDummyFunction(object);
+}
+
+static void CSOM_GenerateSpecialProcs(SOMGenerator *gen, TypeClass *tclass) {
+ Object *newFunc;
+ Object *deleteFunc;
+ Object *object;
+ OLinkList *relocs;
+ SInt32 size;
+ CScopeObjectIterator iter;
+ char buf[16];
+
+ newFunc = deleteFunc = NULL;
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (IS_TYPE_FUNC(object->type)) {
+ if (object->name == CMangler_OperatorName(TK_NEW)) {
+ newFunc = object;
+ gen->hasNew = 1;
+ } else if (object->name == CMangler_OperatorName(TK_DELETE)) {
+ deleteFunc = object;
+ gen->hasDelete = 1;
+ }
+ }
+ }
+
+ if (newFunc || deleteFunc) {
+ object = CSOM_MakeObject(tclass->classname->name, "SpecialProcs", 4);
+ object->sclass = TK_STATIC;
+
+ relocs = NULL;
+ size = 0;
+
+ if (newFunc) {
+ OLinkList *reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = newFunc;
+ reloc->offset = size;
+ reloc->somevalue = 0;
+ size += 4;
+ }
+
+ if (deleteFunc) {
+ OLinkList *reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = deleteFunc;
+ reloc->offset = size;
+ reloc->somevalue = 0;
+ size += 4;
+ }
+
+ memclrw(buf, sizeof(buf));
+ object->type->size = size;
+ CInit_DeclareData(object, buf, relocs, object->type->size);
+ gen->specialProcsObj = object;
+ }
+}
+
+static Object *CSOM_GenerateParentVersion(SOMGenerator *gen) {
+ SInt32 size;
+ UInt32 *buf;
+ SOMAncestor *ancestor;
+ SInt32 offset;
+
+ size = 8 * (gen->counts.numDirectParents + gen->counts.numMetaClasses);
+ buf = lalloc(size);
+
+ for (ancestor = gen->ancestors, offset = 0; ancestor; ancestor = ancestor->next) {
+ if (ancestor->xC || ancestor->xD) {
+ buf[offset++] = CTool_EndianConvertWord32(ancestor->tclass->sominfo->majorversion);
+ buf[offset++] = CTool_EndianConvertWord32(ancestor->tclass->sominfo->minorversion);
+ }
+ }
+
+ return CInit_DeclareString((char *) buf, size, 0, 0);
+}
+
+static void CSOM_SetNibble(char *buf, int offset, UInt8 value) {
+ int i = offset >> 1;
+ if (offset & 1) {
+ int left = buf[i] & 0xF0;
+ int right = value & 0xF;
+ buf[i] = left | right;
+ } else {
+ int left = value << 4;
+ int right = buf[i] & 0xF;
+ buf[i] = left | right;
+ }
+}
+
+static Object *CSOM_GenerateSlotUsage(SOMGenerator *gen) {
+ SInt32 size;
+ SOMMethod *method;
+ char *buf;
+ int offset;
+
+ size = (gen->counts.classTokenCount + 1) / 2;
+ buf = lalloc(size);
+ memclrw(buf, size);
+
+ for (method = gen->methods, offset = 0; method; method = method->next, offset++) {
+ switch (method->state) {
+ case SOMMS_Deleted:
+ case SOMMS_Migrated:
+ CSOM_SetNibble(buf, offset, mtEmpty);
+ break;
+ case SOMMS_Method:
+ CSOM_SetNibble(buf, offset, mtVirtualMethod);
+ break;
+ default:
+ CError_FATAL(1048);
+ }
+ }
+
+ return CInit_DeclareString(buf, size, 0, 0);
+}
+
+static Object *CSOM_GenerateSignature(SOMGenerator *gen) {
+ Object *object;
+ SOMMethod *method;
+
+ name_mangle_list.size = 0;
+
+ for (method = gen->methods; method; method = method->next) {
+ if (method->state == SOMMS_Method)
+ CSOM_GetFuncSig(TYPE_FUNC(method->u.object->type), 1);
+ }
+
+ COS_LockHandle(name_mangle_list.data);
+ object = CInit_DeclareString(*name_mangle_list.data, name_mangle_list.size, 0, 0);
+ COS_UnlockHandle(name_mangle_list.data);
+ return object;
+}
+
+static Object *CSOM_GenerateMethodNames(SOMGenerator *gen) {
+ Object *object;
+ SOMMethod *method;
+ HashNameNode *name;
+
+ name_mangle_list.size = 0;
+
+ for (method = gen->methods; method; method = method->next) {
+ if (method->name) {
+ name = CSOM_NameTranslate(method->name);
+ AppendGListID(&name_mangle_list, name->name);
+ }
+ }
+
+ COS_LockHandle(name_mangle_list.data);
+ object = CInit_DeclareString(*name_mangle_list.data, name_mangle_list.size, 0, 0);
+ COS_UnlockHandle(name_mangle_list.data);
+ return object;
+}
+
+static void CSOM_SetupClassCounts(SOMGenerator *gen, TypeClass *tclass, somStaticClassCounts *counts) {
+ gen->counts.majorVersion = tclass->sominfo->majorversion;
+ gen->counts.minorVersion = tclass->sominfo->minorversion;
+ gen->counts.flags = cfSharedStrings;
+ if (gen->hasNew)
+ gen->counts.flags |= cfClassAllocate;
+ if (gen->hasDelete)
+ gen->counts.flags |= cfClassDeallocate;
+
+ switch (tclass->align) {
+ case 1:
+ gen->counts.dataAlignment = 0;
+ break;
+ case 2:
+ gen->counts.dataAlignment = 1;
+ break;
+ case 4:
+ gen->counts.dataAlignment = 2;
+ break;
+ case 8:
+ gen->counts.dataAlignment = 3;
+ break;
+ default:
+ gen->counts.dataAlignment = 4;
+ break;
+ }
+
+ gen->counts.numSelectInherited = 0;
+
+ memclrw(counts, sizeof(somStaticClassCounts));
+ counts->majorVersion = CTool_EndianConvertWord32(gen->counts.majorVersion);
+ counts->minorVersion = CTool_EndianConvertWord32(gen->counts.minorVersion);
+ counts->flags = CTool_EndianConvertWord32(gen->counts.flags);
+ counts->dataAlignment = CTool_EndianConvertWord16(gen->counts.dataAlignment);
+ counts->classTokenCount = CTool_EndianConvertWord16(gen->counts.classTokenCount);
+ counts->numDirectParents = CTool_EndianConvertWord16(gen->counts.numDirectParents);
+ counts->numMetaClasses = CTool_EndianConvertWord16(gen->counts.numMetaClasses);
+ counts->numOverriddenAncestors = CTool_EndianConvertWord16(gen->counts.numOverriddenAncestors);
+ counts->numMigratedMethods = CTool_EndianConvertWord16(gen->counts.numMigratedMethods);
+ counts->numSelectInherited = CTool_EndianConvertWord16(gen->counts.numSelectInherited);
+}
+
+static void CSOM_GenerateSCIObject(SOMGenerator *gen, TypeClass *tclass) {
+ Object *object;
+ OLinkList *relocs;
+ OLinkList *reloc;
+ somStaticClassInfo sci;
+ somStaticClassCounts classCounts;
+
+ object = CSOM_MakeObject(tclass->classname->name, "SCI", sizeof(sci));
+ object->sclass = TK_STATIC;
+
+ memclrw(&sci, sizeof(sci));
+ sci.layoutVersion = CTool_EndianConvertWord32(70);
+
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = NULL;
+ relocs = reloc;
+ reloc->obj = tclass->sominfo->classdataobject;
+ reloc->offset = 4;
+ reloc->somevalue = 0;
+
+ if (gen->overrideProcsObj) {
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = gen->overrideProcsObj;
+ reloc->offset = 8;
+ reloc->somevalue = 0;
+ }
+
+ if (gen->classAncestorsObj) {
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = gen->classAncestorsObj;
+ reloc->offset = 12;
+ reloc->somevalue = 0;
+ }
+
+ if (gen->dlldFunc) {
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = gen->dlldFunc;
+ reloc->offset = 16;
+ reloc->somevalue = 0;
+ }
+
+ if (gen->specialProcsObj) {
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = gen->specialProcsObj;
+ reloc->offset = 20;
+ reloc->somevalue = 0;
+ }
+
+ CSOM_SetupClassCounts(gen, tclass, &classCounts);
+
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = CInit_DeclareString((char *) &classCounts, sizeof(classCounts), 0, 0);
+ reloc->offset = 52;
+ reloc->somevalue = 0;
+
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = CInit_DeclareString(tclass->classname->name, strlen(tclass->classname->name) + 1, 0, 0);
+ reloc->offset = 56;
+ reloc->somevalue = 0;
+
+ sci.classDescription.instanceDataSize = CTool_EndianConvertWord32(tclass->size);
+
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = CSOM_GenerateParentVersion(gen);
+ reloc->offset = 64;
+ reloc->somevalue = 0;
+
+ if (gen->methods) {
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = CSOM_GenerateSlotUsage(gen);
+ reloc->offset = 68;
+ reloc->somevalue = 0;
+
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = CSOM_GenerateSignature(gen);
+ reloc->offset = 72;
+ reloc->somevalue = 0;
+
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = CSOM_GenerateMethodNames(gen);
+ reloc->offset = 76;
+ reloc->somevalue = 0;
+ }
+
+ if (gen->overrideProcsObj) {
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = CSOM_GenerateOverrideData(gen);
+ reloc->offset = 80;
+ reloc->somevalue = 0;
+ }
+
+ if (gen->counts.numMigratedMethods) {
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = CSOM_GenerateMigrateData(gen);
+ reloc->offset = 84;
+ reloc->somevalue = 0;
+ }
+
+ sci.classDescription.selectedInherited = 0;
+
+ CInit_DeclareData(object, &sci, relocs, object->type->size);
+ gen->sciObj = object;
+}
+
+static void CSOM_GenerateClassDataObject(SOMGenerator *gen, TypeClass *tclass) {
+ void *buf;
+ OLinkList *relocs;
+ OLinkList *reloc;
+ SInt32 size;
+ SOMMethod *method;
+
+ relocs = NULL;
+ for (size = 24, method = gen->methods; method; method = method->next) {
+ if (method->state == SOMMS_Method) {
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = method->u.object;
+ reloc->offset = size;
+ reloc->somevalue = 0;
+ }
+ size += 4;
+ }
+
+ buf = lalloc(size);
+ memclrw(buf, size);
+
+ reloc = lalloc(sizeof(OLinkList));
+ reloc->next = relocs;
+ relocs = reloc;
+ reloc->obj = gen->sciObj;
+ reloc->offset = 4;
+ reloc->somevalue = 0;
+
+ tclass->sominfo->classdataobject->type->size = size;
+ CInit_DeclareData(tclass->sominfo->classdataobject, buf, relocs, tclass->sominfo->classdataobject->type->size);
+}
+
+void CSOM_GenerateClassStructures(TypeClass *tclass) {
+ SOMGenerator gen;
+
+ memclrw(&gen, sizeof(gen));
+ CSOM_GenerateOverrideIntroLists(&gen, tclass);
+ CSOM_GenerateClassAncestors(&gen, tclass);
+ CSOM_GenerateOverrideProcs(&gen, tclass);
+ CSOM_GenerateDLLDFunc(&gen, tclass);
+ CSOM_GenerateSpecialProcs(&gen, tclass);
+ CSOM_GenerateSCIObject(&gen, tclass);
+ CSOM_GenerateClassDataObject(&gen, tclass);
+}
+
+static TypeClass *CSOM_GetCurrentSOMClass(void) {
+ if (cscope_current->theclass && cscope_current->theclass->sominfo)
+ return cscope_current->theclass;
+
+ CError_Error(CErrorStr277);
+ return NULL;
+}
+
+void CSOM_PragmaReleaseOrder(void) {
+ TypeClass *tclass;
+ SOMReleaseOrder *firstOrder;
+ SOMReleaseOrder *order;
+ SOMReleaseOrder **ptr;
+ Boolean flag;
+ short token;
+
+ if (!(tclass = CSOM_GetCurrentSOMClass()))
+ return;
+
+ token = CPrep_PragmaLex(0);
+ if (token != '(') {
+ if (token != TK_IDENTIFIER) {
+ CPrep_Error(CErrorStr114);
+ return;
+ }
+
+ if (!strcmp(tkidentifier->name, "list")) {
+ token = CPrep_PragmaLex(0);
+ if (token != TK_IDENTIFIER) {
+ CPrep_Error(CErrorStr107);
+ return;
+ }
+ }
+
+ flag = 1;
+ } else {
+ flag = 0;
+ token = CPrep_PragmaLex(0);
+ }
+
+ firstOrder = NULL;
+ if (flag || token != ')') {
+ ptr = &firstOrder;
+ while (1) {
+ if (token != TK_IDENTIFIER) {
+ CPrep_Error(CErrorStr107);
+ return;
+ }
+
+ for (order = firstOrder; order; order = order->next) {
+ if (order->name == tkidentifier) {
+ CError_Error(CErrorStr122, tkidentifier->name);
+ return;
+ }
+ }
+
+ order = galloc(sizeof(SOMReleaseOrder));
+ *ptr = order;
+ ptr = &order->next;
+
+ order->next = NULL;
+ order->name = tkidentifier;
+ order->state = SOMMS_Deleted;
+
+ if (flag) {
+ token = CPrep_PragmaLex(1);
+ if (!token)
+ break;
+ } else {
+ token = CPrep_PragmaLex(0);
+ if (token == ')')
+ break;
+ }
+
+ if (token != ',') {
+ CPrep_Error(CErrorStr116);
+ return;
+ }
+
+ token = CPrep_PragmaLex(flag);
+ }
+ }
+
+ tclass->sominfo->order = firstOrder;
+}
+
+void CSOM_PragmaClassVersion(void) {
+ Type *type;
+
+ if (CPrep_PragmaLex(0) != '(') {
+ CPrep_Error(CErrorStr114);
+ return;
+ }
+
+ if (CPrep_PragmaLex(0) != TK_IDENTIFIER) {
+ CPrep_Error(CErrorStr107);
+ return;
+ }
+
+ type = CScope_GetTagType(cscope_current, tkidentifier);
+ if (!(type && IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo)) {
+ CPrep_ErrorName(CErrorStr276, tkidentifier->name);
+ return;
+ }
+
+ if (CPrep_PragmaLex(0) != ',') {
+ CPrep_Error(CErrorStr116);
+ return;
+ }
+
+ if (CPrep_PragmaLex(0) != TK_INTCONST) {
+ CPrep_Error(CErrorStr186);
+ return;
+ }
+
+ TYPE_CLASS(type)->sominfo->majorversion = CInt64_GetULong(&tkintconst);
+
+ if (CPrep_PragmaLex(0) != ',') {
+ CPrep_Error(CErrorStr116);
+ return;
+ }
+
+ if (CPrep_PragmaLex(0) != TK_INTCONST) {
+ CPrep_Error(CErrorStr186);
+ return;
+ }
+
+ TYPE_CLASS(type)->sominfo->minorversion = CInt64_GetULong(&tkintconst);
+
+ if (CPrep_PragmaLex(0) != ')') {
+ CPrep_Error(CErrorStr115);
+ return;
+ }
+}
+
+void CSOM_PragmaMetaClass(void) {
+ Type *type;
+ Type *type2;
+
+ if (CPrep_PragmaLex(0) != '(') {
+ CPrep_Error(CErrorStr114);
+ return;
+ }
+
+ if (CPrep_PragmaLex(0) != TK_IDENTIFIER) {
+ CPrep_Error(CErrorStr107);
+ return;
+ }
+
+ type = CScope_GetTagType(cscope_current, tkidentifier);
+ if (!(type && IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo)) {
+ CPrep_ErrorName(CErrorStr276, tkidentifier->name);
+ return;
+ }
+
+ if (CPrep_PragmaLex(0) != ',') {
+ CPrep_Error(CErrorStr116);
+ return;
+ }
+
+ if (CPrep_PragmaLex(0) != TK_IDENTIFIER) {
+ CPrep_Error(CErrorStr107);
+ return;
+ }
+
+ type2 = CScope_GetTagType(cscope_current, tkidentifier);
+ if (!(type2 && IS_TYPE_CLASS(type2) && TYPE_CLASS(type2)->sominfo)) {
+ CPrep_ErrorName(CErrorStr276, tkidentifier->name);
+ return;
+ }
+
+ TYPE_CLASS(type)->sominfo->metaclass = TYPE_CLASS(type2);
+
+ if (CPrep_PragmaLex(0) != ')') {
+ CPrep_Error(CErrorStr115);
+ return;
+ }
+}
+
+void CSOM_PragmaCallStyle(void) {
+ TypeClass *tclass;
+
+ if (!(tclass = CSOM_GetCurrentSOMClass()))
+ return;
+
+ if (CPrep_PragmaLex(0) != TK_IDENTIFIER) {
+ CPrep_Error(CErrorStr107);
+ return;
+ }
+
+ if (!strcmp(tkidentifier->name, "IDL")) {
+ tclass->sominfo->oidl_callstyle = 0;
+ return;
+ }
+
+ if (!strcmp(tkidentifier->name, "OIDL")) {
+ tclass->sominfo->oidl_callstyle = 1;
+ return;
+ }
+
+ CPrep_Error(CErrorStr186);
+}
+
+void CSOM_FixNewDeleteFunctype(TypeFunc *tfunc) {
+ FuncArg *arg = CParser_NewFuncArg();
+ arg->name = GetHashNameNodeExport("__theclass");
+ arg->type = CDecl_NewPointerType(CSOM_FindClassType(GetHashNameNodeExport("SOMClass")));
+ arg->next = tfunc->args;
+ tfunc->args = arg;
+}
+
+static Object *CSOM_FindRTFunc(char *namestr, char *sig) {
+ NameSpaceObjectList *nsol;
+ Object *object;
+ FuncArg *arg;
+
+ if (
+ (nsol = CScope_GetLocalObject(cscope_root, GetHashNameNodeExport(namestr))) &&
+ nsol->object->otype == OT_OBJECT
+ )
+ {
+ object = OBJECT(nsol->object);
+ if (
+ IS_TYPE_FUNC(object->type) &&
+ *(sig++) == 'p' &&
+ IS_TYPE_POINTER_ONLY(TYPE_FUNC(object->type)->functype)
+ )
+ {
+ for (arg = TYPE_FUNC(object->type)->args; arg; arg = arg->next) {
+ switch (*(sig++)) {
+ case 'p':
+ if (IS_TYPE_POINTER_ONLY(arg->type))
+ continue;
+ break;
+ case 'i':
+ if (arg->type == TYPE(&stsignedint))
+ continue;
+ break;
+ case 'I':
+ if (arg->type == TYPE(&stunsignedint))
+ continue;
+ break;
+ case 'l':
+ if (arg->type == TYPE(&stsignedlong))
+ continue;
+ break;
+ case 'L':
+ if (arg->type == TYPE(&stunsignedlong))
+ continue;
+ break;
+ }
+ break;
+ }
+
+ if (arg == NULL && *sig == 0)
+ return object;
+ }
+
+ CError_Error(CErrorStr275, namestr);
+ } else {
+ CError_Error(CErrorStr274, namestr);
+ }
+
+ return NULL;
+}
+
+static ENode *CSOM_MakeTempCondition(ENode *left, ENode *cond, ENode *expr1, ENode *right) {
+ ENode *expr;
+
+ expr = lalloc(sizeof(ENode));
+ expr->type = ECOND;
+ expr->cost = 0;
+ expr->flags = 0;
+ expr->rtype = &stvoid;
+ expr->data.cond.cond = cond;
+ expr->data.cond.expr1 = expr1;
+ expr->data.cond.expr2 = nullnode();
+ expr->data.cond.expr2->rtype = &stvoid;
+
+ if (left)
+ expr = makediadicnode(left, expr, ECOMMA);
+
+ if (right) {
+ expr = makediadicnode(expr, right, ECOMMA);
+ expr->rtype = right->rtype;
+ }
+
+ return expr;
+}
+
+ENode *CSOM_New(TypeClass *tclass) {
+ Object *newFunc;
+ ENode *expr;
+
+ if (tk == '(') {
+ if ((tk = lex()) == ')') {
+ tk = lex();
+ } else {
+ CError_Error(CErrorStr272);
+ }
+ }
+
+ if (!copts.som_env_check || !copts.som_call_optimize) {
+ newFunc = CSOM_FindRTFunc("somNewObjectInstance", "ppll");
+ if (!newFunc)
+ return nullnode();
+ } else {
+ newFunc = rt_som_new;
+ }
+
+ expr = funccallexpr(
+ newFunc,
+ create_objectrefnode(tclass->sominfo->classdataobject),
+ intconstnode(TYPE(&stunsignedlong), tclass->sominfo->majorversion),
+ intconstnode(TYPE(&stunsignedlong), tclass->sominfo->minorversion),
+ NULL
+ );
+ expr->rtype = CDecl_NewPointerType(TYPE(tclass));
+
+ if (copts.som_env_check && !copts.som_call_optimize) {
+ ENode *tempExpr;
+ ENode *checkExpr;
+ ENode *notExpr;
+ tempExpr = CExpr_GetETEMPCopy(expr);
+ checkExpr = funccallexpr(rt_som_newcheck, nullnode(), NULL, NULL, NULL);
+ notExpr = makemonadicnode(tempExpr, ELOGNOT);
+ notExpr->rtype = CParser_GetBoolType();
+ expr = CSOM_MakeTempCondition(NULL, notExpr, checkExpr, tempExpr);
+ }
+
+ return expr;
+}
+
+ENode *CSOM_Delete(TypeClass *tclass, ENode *objExpr) {
+ Object *func;
+
+ if ((func = CSOM_FindRTFunc("somReleaseObjectReference", "pp")))
+ return funccallexpr(func, objExpr, NULL, NULL, NULL);
+
+ return nullnode();
+}
+
+void CSOM_InitAutoClass(Object *object) {
+ Type *type;
+ Statement *stmt;
+ Object *func;
+
+ if ((func = CSOM_FindRTFunc("somReleaseObjectReference", "pp"))) {
+ type = object->type;
+ object->type = CDecl_NewPointerType(type);
+ TPTR_QUAL(object->type) = Q_REFERENCE;
+
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = makediadicnode(create_objectnode2(object), CSOM_New(TYPE_CLASS(type)), EASS);
+ CExcept_RegisterDeleteObject(stmt, object, func);
+ }
+}
+
+static void CSOM_FindIntroClassOffset(TypeClass *tclass, Object *func, TypeClass **resultClass, SInt32 *resultOffset) {
+ Object *scan;
+ VClassList *vbase;
+ CScopeObjectIterator iter;
+
+ if (!(TYPE_FUNC(func->type)->flags & FUNC_FLAGS_20)) {
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ while (1) {
+ if (!(scan = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (scan == func) {
+ *resultClass = tclass;
+ *resultOffset = CSOM_GetTokenOffset(scan);
+ return;
+ }
+ }
+
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ CScope_InitObjectIterator(&iter, vbase->base->nspace);
+ while (1) {
+ if (!(scan = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (scan == func) {
+ *resultClass = vbase->base;
+ *resultOffset = CSOM_GetTokenOffset(scan);
+ return;
+ }
+ }
+ }
+ } else {
+ for (vbase = tclass->vbases; vbase; vbase = vbase->next) {
+ CScope_InitObjectIterator(&iter, vbase->base->nspace);
+ while (1) {
+ if (!(scan = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ break;
+
+ if (scan->name == func->name) {
+ if (
+ IS_TYPE_FUNC(scan->type) &&
+ scan->datatype == DVFUNC &&
+ !(TYPE_FUNC(scan->type)->flags & FUNC_FLAGS_20) &&
+ CClass_GetOverrideKind(TYPE_FUNC(func->type), TYPE_FUNC(scan->type), 0)
+ )
+ {
+ *resultClass = vbase->base;
+ *resultOffset = CSOM_GetTokenOffset(scan);
+ return;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ CError_FATAL(1731);
+}
+
+static ENode *CSOM_ComputeSOMSelf(TypeClass *tclass, ENode *selfExpr) {
+ ENode *expr;
+ Object obj;
+
+ expr = create_objectrefnode(tclass->sominfo->classdataobject);
+ expr = makediadicnode(expr, intconstnode(TYPE(&stsignedlong), 8), EADD);
+ expr->rtype = CDecl_NewPointerType(TYPE(&SOMIDT_type));
+ expr = makemonadicnode(expr, EINDIRECT);
+
+ memclrw(&obj, sizeof(Object));
+ obj.otype = OT_OBJECT;
+ obj.type = TYPE(&SOMIDT_type);
+ obj.name = no_name_node;
+ obj.datatype = DFUNC;
+ selfExpr = funccallexpr(&obj, selfExpr, NULL, NULL, NULL);
+
+ CError_ASSERT(1761, ENODE_IS(selfExpr, EFUNCCALL));
+
+ selfExpr->data.funccall.funcref = expr;
+
+ return selfExpr;
+}
+
+ENode *CSOM_SOMSelfObjectExpr(TypeClass *tclass) {
+ ObjectList *list;
+ Object *obj;
+
+ for (list = locals; list; list = list->next) {
+ if (list->object->name == csom_selfname)
+ return create_objectnode(list->object);
+ }
+
+ obj = CParser_NewLocalDataObject(NULL, 1);
+ obj->name = csom_selfname;
+ obj->type = CDecl_NewPointerType(TYPE(tclass));
+ CFunc_SetupLocalVarInfo(obj);
+ return create_objectnode(obj);
+}
+
+void CSOM_InitSOMSelf(TypeClass *tclass, Statement *stmt) {
+ ObjectList *list;
+ HashNameNode *name;
+ ENode *selfExpr;
+
+ name = GetHashNameNodeExport("__somself");
+ for (list = locals; list; list = list->next) {
+ if (list->object->name == name) {
+ selfExpr = CClass_CreateThisSelfExpr();
+ CError_ASSERT(1811, selfExpr);
+
+ selfExpr = CSOM_ComputeSOMSelf(tclass, selfExpr);
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = makediadicnode(create_objectnode(list->object), selfExpr, EASS);
+ break;
+ }
+ }
+}
+
+ENode *CSOM_EnvCheck(ENode *funccall, ENodeList *checkArg) {
+ ENodeList *arg; // r26
+ ENodeList *arg2; // r28
+ ENode *expr26; // r26
+ ENode *expr27; // r27
+ ENode *expr28; // r28
+ Type *returnType; // r31
+
+ returnType = funccall->rtype;
+ CError_ASSERT(1842, arg = funccall->data.funccall.args);
+
+ if (arg == checkArg)
+ CError_ASSERT(1845, arg = arg->next);
+
+ CError_ASSERT(1847, arg2 = arg->next);
+
+ if (arg2 == checkArg)
+ CError_ASSERT(1850, arg2 = arg2->next);
+
+ CError_ASSERT(1852, IS_TYPE_POINTER_ONLY(arg2->node->rtype));
+
+ if (!IS_TYPE_VOID(funccall->data.funccall.functype->functype)) {
+ if (checkArg) {
+ if (ENODE_IS(checkArg->node, ETEMP)) {
+ if (checkArg->node->data.temp.uniqueid == 0)
+ checkArg->node->data.temp.uniqueid = CParser_GetUniqueID();
+
+ expr26 = lalloc(sizeof(ENode));
+ *expr26 = *checkArg->node;
+ expr26->data.temp.needs_dtor = 0;
+ } else {
+ expr26 = CExpr_GetETEMPCopy(checkArg->node);
+ }
+ } else {
+ expr26 = CExpr_GetETEMPCopy(funccall);
+ }
+ } else {
+ expr26 = NULL;
+ }
+
+ if (!ENODE_IS(arg2->node, EOBJREF)) {
+ if (ENODE_IS_INDIRECT_TO(arg2->node, EOBJREF) && arg2->node->data.monadic->data.objref->datatype == DLOCAL) {
+ expr27 = lalloc(sizeof(ENode));
+ *expr27 = *arg2->node;
+ } else {
+ expr27 = CExpr_GetETEMPCopy(arg2->node);
+ }
+ } else {
+ expr27 = lalloc(sizeof(ENode));
+ *expr27 = *arg2->node;
+ }
+
+ if (copts.som_call_optimize) {
+ funccall = makediadicnode(funccall, funccallexpr(rt_som_check, expr27, NULL, NULL, NULL), ECOMMA);
+ if (expr26)
+ funccall = makediadicnode(funccall, expr26, ECOMMA);
+ } else {
+ expr28 = lalloc(sizeof(ENode));
+ *expr28 = *expr27;
+ expr28 = makemonadicnode(expr28, EINDIRECT);
+ expr28->rtype = TYPE(&stsignedlong);
+
+ funccall = CSOM_MakeTempCondition(
+ funccall,
+ expr28,
+ funccallexpr(rt_som_check, expr27, NULL, NULL, NULL),
+ expr26);
+ }
+
+ funccall->rtype = returnType;
+ return funccall;
+}
+
+static Boolean CSOM_CanUseGlueCall(TypeFunc *tfunc) {
+ int gprCounter;
+ int fprCounter;
+ FuncArg *arg;
+
+ gprCounter = 8;
+ fprCounter = 13;
+ if (CMach_GetFunctionResultClass(tfunc) != 0)
+ gprCounter = 7;
+
+ for (arg = tfunc->args; arg; arg = arg->next) {
+ if (arg == &elipsis || arg == &oldstyle)
+ return 0;
+
+ switch (arg->type->type) {
+ case TYPEINT:
+ case TYPEENUM:
+ case TYPEPOINTER:
+ if (--gprCounter < 0)
+ return 0;
+ break;
+ case TYPEFLOAT:
+ if (--fprCounter < 0)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static char *CSOM_AppendString(char *dst, char *src) {
+ int ch;
+ while ((ch = *(src++)))
+ *(dst++) = ch;
+ return dst;
+}
+
+static ENode *CSOM_SOMGlueCall(TypeClass *tclass, SInt32 offset, Object *object) {
+ UInt8 funcResultClass;
+ UInt32 bufsize;
+ char *buf;
+ char *ptr;
+ Object *stubObj;
+ CSOMStub *stub;
+ ENode *expr;
+ char mybuf[256];
+ char numberbuf[16];
+
+ for (stub = csom_stubs; stub; stub = stub->next) {
+ if (stub->tclass == tclass && stub->offset == offset)
+ break;
+ }
+
+ if (!stub) {
+ funcResultClass = CMach_GetFunctionResultClass(TYPE_FUNC(object->type));
+
+ bufsize = strlen(tclass->sominfo->classdataobject->name->name) + 32;
+ buf = (bufsize > sizeof(mybuf)) ? lalloc(bufsize) : mybuf;
+
+ ptr = CSOM_AppendString(buf, "___glue_");
+ if (tclass->sominfo->oidl_callstyle == 0) {
+ if (funcResultClass == 0) {
+ *(ptr++) = '4';
+ } else {
+ *(ptr++) = '5';
+ }
+ } else {
+ *(ptr++) = '_';
+ }
+ *(ptr++) = '_';
+
+ sprintf(numberbuf, "%ld", strlen(tclass->sominfo->classdataobject->name->name));
+ ptr = CSOM_AppendString(ptr, numberbuf);
+ ptr = CSOM_AppendString(ptr, tclass->sominfo->classdataobject->name->name);
+ *(ptr++) = '_';
+ sprintf(numberbuf, "%" PRId32, offset);
+ ptr = CSOM_AppendString(ptr, numberbuf);
+ *ptr = 0;
+
+ stubObj = CParser_NewCompilerDefFunctionObject();
+ stubObj->nspace = cscope_root;
+ stubObj->name = GetHashNameNodeExport(buf);
+ stubObj->u.func.linkname = stubObj->name;
+ stubObj->type = object->type;
+ stubObj->qual = object->qual | Q_20000;
+ stubObj->flags = OBJECT_INTERNAL;
+ CScope_AddObject(stubObj->nspace, stubObj->name, OBJ_BASE(stubObj));
+
+ stub = galloc(sizeof(CSOMStub));
+ stub->next = csom_stubs;
+ stub->object = stubObj;
+ stub->tclass = tclass;
+ stub->offset = offset;
+ csom_stubs = stub;
+
+ if (tclass->sominfo->oidl_callstyle == 0) {
+ if (funcResultClass == 0)
+ stub->x10 = 0;
+ else
+ stub->x10 = 1;
+ } else {
+ stub->x10 = 2;
+ }
+ }
+
+ expr = create_objectrefnode(stub->object);
+ expr->rtype = CDecl_NewPointerType(object->type);
+ return expr;
+}
+
+ENode *CSOM_MemberVarAccess(BClassList *path, ObjMemberVar *ivar, ENode *thisExpr) {
+ if (!thisExpr) {
+ if (
+ !cscope_currentfunc ||
+ !cscope_currentclass ||
+ !cscope_is_member_func ||
+ !(thisExpr = CClass_CreateThisSelfExpr())
+ )
+ {
+ CError_Error(CErrorStr221);
+ return NULL;
+ }
+ }
+
+ CError_ASSERT(2069, ENODE_IS(thisExpr, EINDIRECT));
+
+ thisExpr = thisExpr->data.monadic;
+
+ if (
+ path->next == NULL &&
+ cscope_currentclass == TYPE_CLASS(path->type) &&
+ ENODE_IS(thisExpr, EOBJREF) &&
+ thisExpr->data.objref->name == this_name_node
+ )
+ {
+ thisExpr = CSOM_SOMSelfObjectExpr(cscope_currentclass);
+ }
+ else
+ {
+ CClass_CheckPathAccess(path, NULL, ivar->access);
+ if (ivar->has_path)
+ path = OBJ_MEMBER_VAR_PATH(ivar)->path;
+ while (path->next)
+ path = path->next;
+ thisExpr = CSOM_ComputeSOMSelf(TYPE_CLASS(path->type), thisExpr);
+ }
+
+ thisExpr = makemonadicnode(thisExpr, EINDIRECT);
+ thisExpr->rtype = path->type;
+ return CClass_AccessMember(thisExpr, ivar->type, ivar->qual, ivar->offset);
+}
+
+ENode *CSOM_MethodAccess(BClassList *path, Object *func, Boolean flag) {
+ TypeClass *tclass;
+ TypeClass *tclass2;
+ TypeClass *tclass3;
+ ENode *expr;
+ SInt32 offset;
+ ClassList *base;
+
+ CError_ASSERT(2107, path != NULL);
+
+ tclass = TYPE_CLASS(path->type);
+ if (path->next)
+ path = path->next;
+ tclass2 = TYPE_CLASS(path->type);
+
+ if (flag) {
+ SInt32 counter;
+ ENode *indirectExpr;
+ Object *resolveFunc;
+
+ counter = 0;
+ if (tclass != tclass2) {
+ for (base = tclass->bases; base; base = base->next) {
+ counter++;
+ if (base->base == tclass2)
+ break;
+ }
+
+ if (!base)
+ CError_Error(CErrorStr279);
+ }
+
+ CSOM_FindIntroClassOffset(tclass2, func, &tclass3, &offset);
+ expr = create_objectrefnode(tclass3->sominfo->classdataobject);
+ expr = makediadicnode(expr, intconstnode(TYPE(&stsignedlong), offset), EADD);
+ indirectExpr = makemonadicnode(expr, EINDIRECT);
+ indirectExpr->rtype = CDecl_NewPointerType(func->type);
+
+ resolveFunc = CSOM_FindRTFunc("somParentNumResolve", "ppip");
+ if (!resolveFunc)
+ return nullnode();
+
+ expr = funccallexpr(
+ resolveFunc,
+ create_objectrefnode(tclass->sominfo->classdataobject),
+ intconstnode(TYPE(&stsignedint), counter),
+ indirectExpr,
+ NULL);
+ expr->rtype = indirectExpr->rtype;
+ if (copts.som_env_check && tclass3->sominfo->oidl_callstyle == 0)
+ expr->flags = expr->flags | ENODE_FLAG_10;
+ } else {
+ CSOM_FindIntroClassOffset(tclass2, func, &tclass3, &offset);
+ if (copts.som_call_optimize && CSOM_CanUseGlueCall(TYPE_FUNC(func->type)))
+ return CSOM_SOMGlueCall(tclass3, offset, func);
+
+ expr = create_objectrefnode(tclass3->sominfo->classdataobject);
+ expr = makediadicnode(expr, intconstnode(TYPE(&stsignedlong), offset), EADD);
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = CDecl_NewPointerType(func->type);
+ if (copts.som_env_check && tclass3->sominfo->oidl_callstyle == 0)
+ expr->flags = expr->flags | ENODE_FLAG_10;
+ }
+
+ return expr;
+}
diff --git a/compiler_and_linker/FrontEnd/C/CTemplateClass.c b/compiler_and_linker/FrontEnd/C/CTemplateClass.c
new file mode 100644
index 0000000..8b3b889
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CTemplateClass.c
@@ -0,0 +1,1632 @@
+#include "compiler/CTemplateClass.h"
+#include "compiler/CABI.h"
+#include "compiler/CBrowse.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CInline.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CScope.h"
+#include "compiler/CTemplateFunc.h"
+#include "compiler/CTemplateNew.h"
+#include "compiler/CTemplateTools.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/templates.h"
+
+TemplClass *CTemplClass_GetMasterTemplate(TemplClass *tmclass) {
+ if (tmclass->inst_parent) {
+ tmclass = TEMPL_CLASS(tmclass->theclass.nspace->theclass);
+ CError_ASSERT(42, tmclass->theclass.flags & CLASS_IS_TEMPL);
+ }
+
+ return tmclass;
+}
+
+static void CTemplClass_SetupActionErrorRef(TemplateAction *action, TStreamElement **saved) {
+ CError_ResetErrorSkip();
+ CError_LockErrorPos(&action->source_ref, saved);
+}
+
+static void CTemplClass_RestoreActionErrorRef(TStreamElement **saved) {
+ CError_ResetErrorSkip();
+ CError_UnlockErrorPos(saved);
+}
+
+static void CTemplClass_AppendTemplateAction(TemplClass *tmclass, TemplateAction *action) {
+ TemplateAction *last;
+
+ action->source_ref = *CPrep_CurStreamElement();
+
+ if ((last = tmclass->actions)) {
+ while (last->next)
+ last = last->next;
+ last->next = action;
+ } else {
+ tmclass->actions = action;
+ }
+}
+
+static DefAction *CTemplClass_NewDefAction(TypeDeduce *deduce, TemplateAction *action) {
+ DefAction *defAction = lalloc(sizeof(DefAction));
+ defAction->next = deduce->defActions;
+ defAction->action = action;
+ deduce->defActions = defAction;
+ return defAction;
+}
+
+static void CTemplClass_InsertTemplateAction(TemplClass *tmclass, TemplateAction *action) {
+ action->source_ref = *CPrep_CurStreamElement();
+ action->next = tmclass->actions;
+ tmclass->actions = action;
+}
+
+void CTemplClass_RegisterUsingDecl(TemplClass *tmclass, TypeTemplDep *type, AccessType access) {
+ TemplateAction *action;
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_USINGDECL;
+ action->u.usingdecl.type = type;
+ action->u.usingdecl.access = access;
+
+ CTemplClass_AppendTemplateAction(tmclass, action);
+}
+
+void CTemplClass_RegisterFriend(TemplClass *tmclass, DeclInfo *di) {
+ TemplateFriend *tfriend;
+ TemplateAction *action;
+
+ tfriend = galloc(sizeof(TemplateFriend));
+ memclrw(tfriend, sizeof(TemplateFriend));
+
+ if (tk == '{' && IS_TYPE_FUNC(di->thetype)) {
+ di->qual |= Q_INLINE;
+ TYPE_FUNC(di->thetype)->flags |= FUNC_DEFINED | FUNC_IS_TEMPL_INSTANCE;
+ tfriend->fileoffset = cparser_fileoffset;
+
+ CPrep_StreamGetBlock(&tfriend->stream, NULL, 1);
+
+ if (lookahead() == ';')
+ tk = lex();
+ else
+ tk = ';';
+ }
+
+ CDecl_PackDeclInfo(&tfriend->decl, di);
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_FRIEND;
+ action->u.tfriend = tfriend;
+
+ CTemplClass_AppendTemplateAction(tmclass, action);
+}
+
+void CTemplClass_RegisterBaseClass(TemplClass *tmclass, Type *type, AccessType access, Boolean is_virtual) {
+ TemplateAction *action;
+ ClassList *insert_after;
+
+ if ((insert_after = tmclass->theclass.bases)) {
+ while (insert_after->next)
+ insert_after = insert_after->next;
+ }
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_BASE;
+ action->u.base.type = type;
+ action->u.base.insert_after = insert_after;
+ action->u.base.access = access;
+ action->u.base.is_virtual = is_virtual;
+
+ CTemplClass_InsertTemplateAction(tmclass, action);
+}
+
+void CTemplClass_RegisterEnumType(TemplClass *tmclass, TypeEnum *enumtype) {
+ TemplateAction *action;
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_ENUMTYPE;
+ action->u.enumtype = enumtype;
+
+ CTemplClass_AppendTemplateAction(tmclass, action);
+}
+
+void CTemplClass_RegisterEnumerator(TemplClass *tmclass, ObjEnumConst *objenumconst, ENode *initexpr) {
+ TemplateAction *action;
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_ENUMERATOR;
+ action->u.enumerator.objenumconst = objenumconst;
+ action->u.enumerator.initexpr = initexpr ? CInline_CopyExpression(initexpr, CopyMode1) : NULL;
+
+ CTemplClass_AppendTemplateAction(tmclass, action);
+}
+
+void CTemplClass_RegisterObjectInit(TemplClass *tmclass, Object *object, ENode *initexpr) {
+ TemplateAction *action;
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_OBJECTINIT;
+ action->u.objectinit.object = object;
+ action->u.objectinit.initexpr = CInline_CopyExpression(initexpr, CopyMode1);
+
+ CTemplClass_AppendTemplateAction(tmclass, action);
+}
+
+void CTemplClass_RegisterObjectDef(TemplClass *tmclass, ObjBase *refobj) {
+ TemplateAction *action;
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_OBJECTDEF;
+ action->u.refobj = refobj;
+
+ CTemplClass_AppendTemplateAction(tmclass, action);
+}
+
+void CTemplClass_CompleteClass(TemplClass *templ, ClassLayout *de) {
+ templ->lex_order_count = de->lex_order_count;
+ if (de->has_vtable)
+ templ->flags |= TEMPLCLASS_HAS_VTABLE;
+ templ->theclass.flags |= CLASS_COMPLETED;
+}
+
+static TemplClassInst *CTemplClass_NewInstance(TemplClass *templ, TemplArg *inst_args, TemplArg *oargs) {
+ TemplClassInst *inst;
+ ObjTypeTag *tag;
+ NameSpace *nspace;
+ HashNameNode *name;
+
+ CError_ASSERT(288, !templ->pspec_owner);
+
+ inst = galloc(sizeof(TemplClassInst));
+ memclrw(inst, sizeof(TemplClassInst));
+
+ inst->next = templ->instances;
+ templ->instances = inst;
+
+ if (templ->templ__params)
+ name = CMangler_TemplateInstanceName(templ->theclass.classname, oargs ? oargs : inst_args);
+ else
+ name = templ->theclass.classname;
+
+ inst->inst_args = inst_args;
+ inst->oargs = oargs;
+ inst->parent = templ->inst_parent;
+
+ nspace = CScope_NewListNameSpace(name, 1);
+ nspace->theclass = TYPE_CLASS(inst);
+ if (templ->templ_parent && templ->inst_parent) {
+ nspace->parent = TYPE_CLASS(templ->inst_parent)->nspace;
+ } else {
+ NameSpace *scan = templ->theclass.nspace->parent;
+ while (scan->is_templ)
+ scan = scan->parent;
+ nspace->parent = scan;
+ }
+
+ inst->theclass.type = TYPECLASS;
+ inst->theclass.flags = CLASS_IS_TEMPL_INST;
+ inst->theclass.nspace = nspace;
+ inst->theclass.classname = templ->theclass.classname;
+ inst->theclass.mode = templ->theclass.mode;
+ inst->theclass.eflags = templ->theclass.eflags;
+ inst->templ = templ;
+
+ tag = galloc(sizeof(ObjTypeTag));
+ memclrw(tag, sizeof(ObjTypeTag));
+
+ tag->otype = OT_TYPETAG;
+ tag->access = ACCESSPUBLIC;
+ tag->type = TYPE(inst);
+ CScope_AddObject(nspace, templ->theclass.classname, OBJ_BASE(tag));
+
+ return inst;
+}
+
+TemplClassInst *CTemplClass_GetInstance(TemplClass *tmclass, TemplArg *inst_args, TemplArg *oargs) {
+ TemplClassInst *inst;
+
+ for (inst = tmclass->instances; inst; inst = inst->next) {
+ CError_ASSERT(353, !oargs);
+
+ if (CTemplTool_EqualArgs(inst_args, inst->oargs ? inst->oargs : inst->inst_args))
+ return inst;
+ }
+
+ return CTemplClass_NewInstance(tmclass, inst_args, oargs);
+}
+
+TemplateMember *CTemplClass_DefineMember(TemplClass *tmclass, Object *object, FileOffsetInfo *foi, TokenStream *stream) {
+ TemplateMember *member;
+
+ for (member = tmclass->members; member; member = member->next) {
+ if (member->object == object) {
+ CError_Error(CErrorStr333, object);
+ return member;
+ }
+ }
+
+ member = galloc(sizeof(TemplateMember));
+ memclrw(member, sizeof(TemplateMember));
+ member->next = tmclass->members;
+ tmclass->members = member;
+
+ member->params = NULL;
+ member->object = object;
+ member->fileoffset = *foi;
+ member->stream = *stream;
+
+ return member;
+}
+
+static void CTemplClass_ParseBody(TemplClass *templ, short mode, SInt32 *offset) {
+ DeclInfo di;
+
+ templ->align = copts.structalignment;
+
+ memclrw(&di, sizeof(di));
+ di.file = CPrep_BrowserCurrentFile();
+ CPrep_BrowserFilePosition(&di.file2, &di.sourceoffset);
+ di.sourceoffset = *offset;
+ di.x28 = templ;
+
+ CDecl_ParseClass(&di, mode, 1, 0);
+
+ if (tk == TK_UU_ATTRIBUTE_UU)
+ CParser_ParseAttribute(di.thetype, NULL);
+ if (tk != ';')
+ CError_Error(CErrorStr123);
+
+ CBrowse_NewTemplateClass(templ, di.file2, di.sourceoffset, CPrep_BrowserFileOffset() + 1);
+}
+
+void CTemplClass_ParsePartialSpecialization(DeclFucker *what_is_this, TemplParam *params, short mode, SInt32 *offset) {
+ Type *type;
+ NameSpace *nspace;
+ TemplArg *args;
+ TemplPartialSpec *pspec;
+ TemplClass *templ;
+ TemplArg *arg;
+ TemplParam *param;
+
+ nspace = what_is_this->nspace;
+
+ if ((tk = lex()) != TK_IDENTIFIER) {
+ CError_Error(CErrorStr107);
+ return;
+ }
+
+ if (!(type = CScope_GetLocalTagType(nspace, tkidentifier))) {
+ CError_Error(CErrorStr140, tkidentifier->name);
+ return;
+ }
+
+ if (!IS_TEMPL_CLASS(type)) {
+ CError_Error(CErrorStr132, tkidentifier->name);
+ return;
+ }
+
+ if ((tk = lex()) != '<')
+ CError_FATAL(469);
+
+ for (param = params; param; param = param->next) {
+ switch (param->pid.type) {
+ case TPT_TYPE:
+ if (!param->data.typeparam.type)
+ continue;
+ CError_Error(CErrorStr344);
+ break;
+
+ case TPT_NONTYPE:
+ if (!param->data.paramdecl.defaultarg)
+ continue;
+ CError_Error(CErrorStr344);
+ break;
+
+ case TPT_TEMPLATE:
+ if (!param->data.templparam.defaultarg)
+ continue;
+ CError_Error(CErrorStr344);
+ break;
+
+ default:
+ CError_FATAL(501);
+ }
+
+ break;
+ }
+
+ args = CTempl_ParseUncheckTemplArgs(TEMPL_CLASS(type)->templ__params, 0);
+ tk = lex();
+
+ arg = args;
+ param = TEMPL_CLASS(type)->templ__params;
+ while (1) {
+ if (!arg) {
+ if (!param)
+ break;
+ CError_Error(CErrorStr344);
+ return;
+ }
+ if (!param) {
+ CError_Error(CErrorStr344);
+ return;
+ }
+ if (param->pid.type != arg->pid.type) {
+ CError_Error(CErrorStr344);
+ return;
+ }
+ arg = arg->next;
+ param = param->next;
+ }
+
+ if (CTemplTool_IsSameTemplate(TEMPL_CLASS(type)->templ__params, args))
+ CError_Error(CErrorStr344);
+
+ for (pspec = TEMPL_CLASS(type)->pspecs; pspec; pspec = pspec->next) {
+ if (CTemplTool_EqualParams(pspec->templ->templ__params, params, 0) && CTemplTool_EqualArgs(pspec->args, args))
+ break;
+ }
+
+ if (!pspec) {
+ templ = galloc(sizeof(TemplClass));
+ memclrw(templ, sizeof(TemplClass));
+
+ templ->templ__params = params;
+ CDecl_DefineClass(nspace, TEMPL_CLASS(type)->theclass.classname, TYPE_CLASS(templ), mode, 0, 0);
+
+ templ->theclass.flags = CLASS_IS_TEMPL;
+ templ->pspec_owner = TEMPL_CLASS(type);
+
+ pspec = galloc(sizeof(TemplPartialSpec));
+ memclrw(pspec, sizeof(TemplPartialSpec));
+
+ pspec->templ = templ;
+ pspec->args = CTemplTool_MakeGlobalTemplArgCopy(args);
+ pspec->next = TEMPL_CLASS(type)->pspecs;
+ TEMPL_CLASS(type)->pspecs = pspec;
+ } else {
+ if ((pspec->templ->theclass.flags & CLASS_COMPLETED) && tk != ';') {
+ CError_Error(CErrorStr132, TEMPL_CLASS(type)->theclass.classname->name);
+ return;
+ }
+
+ if (tk == ':' || tk == '{')
+ CTemplTool_EqualParams(pspec->templ->templ__params, params, 1);
+ }
+
+ switch (tk) {
+ case ':':
+ case '{':
+ CTemplClass_ParseBody(pspec->templ, mode, offset);
+ break;
+ case ';':
+ break;
+ default:
+ CError_Error(CErrorStr121);
+ }
+}
+
+void CTemplClass_ParseClass(DeclFucker *what_is_this, TemplParam *params, short mode, SInt32 *offset) {
+ TemplClass *templ;
+ NameSpace *nspace;
+ Type *type;
+ UInt8 classDeclSpec = 0;
+
+ nspace = what_is_this->nspace;
+ if ((tk = lex()) == TK_UU_DECLSPEC)
+ CDecl_ParseClassDeclSpec(&classDeclSpec);
+
+ if (tk != TK_IDENTIFIER) {
+ CError_Error(CErrorStr107);
+ return;
+ }
+
+ type = CScope_GetLocalTagType(nspace, tkidentifier);
+ if (!type) {
+ templ = galloc(sizeof(TemplClass));
+ memclrw(templ, sizeof(TemplClass));
+
+ templ->next = ctempl_templates;
+ ctempl_templates = templ;
+
+ templ->templ__params = params;
+ CDecl_DefineClass(nspace, tkidentifier, TYPE_CLASS(templ), mode, 0, 1);
+ templ->theclass.flags = CLASS_IS_TEMPL;
+ templ->theclass.eflags = classDeclSpec;
+
+ tk = lex();
+ if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL)) {
+ TemplateAction *action;
+
+ templ->templ_parent = TEMPL_CLASS(nspace->theclass);
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_NESTEDCLASS;
+ action->u.tclasstype = templ;
+ CTemplClass_AppendTemplateAction(templ->templ_parent, action);
+ }
+ } else {
+ if (!IS_TEMPL_CLASS(type)) {
+ CError_Error(CErrorStr132, tkidentifier->name);
+ return;
+ }
+
+ templ = TEMPL_CLASS(type);
+ if (!CTemplTool_EqualParams(templ->templ__params, params, 0)) {
+ CError_Error(CErrorStr132, templ->theclass.classname->name);
+ return;
+ }
+
+ CTemplTool_MergeDefaultArgs(templ->templ__params, params);
+ templ->theclass.eflags |= classDeclSpec;
+
+ tk = lex();
+
+ if ((templ->theclass.flags & CLASS_COMPLETED) && tk != ';') {
+ CError_Error(CErrorStr132, templ->theclass.classname->name);
+ return;
+ }
+
+ if (tk != ';')
+ CTemplTool_EqualParams(templ->templ__params, params, 1);
+ }
+
+ switch (tk) {
+ case ':':
+ case '{':
+ CTemplClass_ParseBody(templ, mode, offset);
+ break;
+ case ';':
+ break;
+ default:
+ CError_Error(CErrorStr121);
+ }
+}
+
+static Boolean CTemplClass_TypeParamCompare(TemplArg *arg, Type *type, UInt32 qual) {
+ return is_typesame(type, arg->data.typeparam.type) && arg->data.typeparam.qual == qual;
+}
+
+static TemplArg *CTemplClass_PartialTemplateArgMatch(TemplPartialSpec *pspec, TemplArg *args, Boolean flag) {
+ TemplArg *argA;
+ TemplArg *argB;
+ int i;
+ DeduceInfo info;
+
+ if (!CTemplTool_InitDeduceInfo(&info, pspec->templ->templ__params, NULL, 1))
+ return NULL;
+
+ argA = pspec->args;
+ argB = args;
+ while (1) {
+ if (!argA) {
+ if (argB)
+ return NULL;
+
+ for (i = 0; i < info.maxCount; i++) {
+ if (!info.args[i].is_deduced)
+ return NULL;
+ }
+
+ if (flag)
+ return CTemplTool_MakeTemplArgList(&info);
+ else
+ return args;
+ }
+
+ if (!argB)
+ return NULL;
+
+ if (argA->pid.type != argB->pid.type)
+ return NULL;
+
+ switch (argA->pid.type) {
+ case TPT_TYPE:
+ if (CTemplTool_IsTemplateArgumentDependentType(argA->data.typeparam.type)) {
+ if (!CTempl_DeduceType(
+ argA->data.typeparam.type, argA->data.typeparam.qual,
+ argB->data.typeparam.type, argB->data.typeparam.qual,
+ info.args, 0, 0
+ ))
+ return NULL;
+ } else {
+ if (
+ !is_typesame(argA->data.typeparam.type, argB->data.typeparam.type) ||
+ argA->data.typeparam.qual != argB->data.typeparam.qual
+ )
+ return NULL;
+ }
+ break;
+
+ case TPT_NONTYPE:
+ if (CTemplTool_IsTemplateArgumentDependentExpression(argA->data.paramdecl.expr)) {
+ i = CTempl_GetTemplateArgumentExpressionIndex(argA);
+ CError_ASSERT(789, i >= 0);
+
+ if (info.args[i].is_deduced) {
+ if (!CTemplTool_EqualExprTypes(argB->data.paramdecl.expr, info.args[i].data.paramdecl.expr))
+ return NULL;
+ } else {
+ info.args[i].data.paramdecl.expr = argB->data.paramdecl.expr;
+ info.args[i].pid.type = TPT_NONTYPE;
+ info.args[i].is_deduced = 1;
+ }
+ } else {
+ if (!CTemplTool_EqualExprTypes(argB->data.paramdecl.expr, argA->data.paramdecl.expr))
+ return NULL;
+ }
+ break;
+
+ case TPT_TEMPLATE:
+ if (CTemplTool_IsTemplateArgumentDependentType(argA->data.ttargtype)) {
+ if (!CTempl_DeduceType(
+ argA->data.ttargtype, 0,
+ argB->data.ttargtype, 0,
+ info.args, 0, 0
+ ))
+ return NULL;
+ } else {
+ if (!is_typesame(argA->data.ttargtype, argB->data.ttargtype))
+ return NULL;
+ }
+ break;
+
+ default:
+ CError_FATAL(830);
+ }
+
+ argA = argA->next;
+ argB = argB->next;
+ }
+}
+
+static Boolean CTemplClass_PartialClassIsAtLeastAsSpecialized(TemplPartialSpec *pspec1, TemplPartialSpec *pspec2) {
+ TemplArg *argA;
+ TemplArg *argB;
+ int i;
+ DeduceInfo info;
+
+ if (!CTemplTool_InitDeduceInfo(&info, pspec2->templ->templ__params, NULL, 1))
+ return 0;
+
+ argA = pspec1->args;
+ argB = pspec2->args;
+
+ while (1) {
+ if (!argA) {
+ CError_ASSERT(856, !argB);
+
+ for (i = 0; i < info.maxCount; i++) {
+ if (!info.args[i].is_deduced)
+ return 0;
+ }
+
+ return 1;
+ }
+
+ CError_ASSERT(865, argB);
+ CError_ASSERT(866, argA->pid.type == argB->pid.type);
+
+ switch (argA->pid.type) {
+ case TPT_TYPE:
+ if (!CTempl_DeduceType(
+ argB->data.typeparam.type, argB->data.typeparam.qual,
+ argA->data.typeparam.type, argA->data.typeparam.qual,
+ info.args, 0, 0
+ ))
+ return 0;
+ break;
+
+ case TPT_NONTYPE:
+ if (CTemplTool_IsTemplateArgumentDependentExpression(argB->data.paramdecl.expr)) {
+ i = CTempl_GetTemplateArgumentExpressionIndex(argB);
+ CError_ASSERT(907, i >= 0);
+
+ if (info.args[i].is_deduced) {
+ if (argA->data.paramdecl.expr) {
+ if (!info.args[i].data.paramdecl.expr || !CTemplTool_EqualExprTypes(argA->data.paramdecl.expr, info.args[i].data.paramdecl.expr))
+ return 0;
+ } else {
+ if (info.args[i].data.paramdecl.expr || argA->pid.index != info.args[i].pid.index)
+ return 0;
+ }
+ } else {
+ info.args[i].data.paramdecl.expr = argA->data.paramdecl.expr;
+ info.args[i].pid.index = argA->pid.index;
+ info.args[i].pid.type = TPT_NONTYPE;
+ info.args[i].is_deduced = 1;
+ }
+ } else {
+ if (
+ !argA->data.paramdecl.expr ||
+ !CTemplTool_EqualExprTypes(argA->data.paramdecl.expr, argB->data.paramdecl.expr)
+ )
+ return 0;
+ }
+ break;
+
+ case TPT_TEMPLATE:
+ if (!CTempl_DeduceType(
+ argB->data.ttargtype, 0,
+ argA->data.ttargtype, 0,
+ info.args, 0, 0
+ ))
+ return 0;
+ break;
+
+ default:
+ CError_FATAL(955);
+ }
+
+ argA = argA->next;
+ argB = argB->next;
+ }
+}
+
+static Boolean CTemplClass_PartialClassIsMoreSpecialized(TemplPartialSpec *pspec1, TemplPartialSpec *pspec2) {
+ return CTemplClass_PartialClassIsAtLeastAsSpecialized(pspec1, pspec2) &&
+ !CTemplClass_PartialClassIsAtLeastAsSpecialized(pspec2, pspec1);
+}
+
+typedef struct PSpecList {
+ struct PSpecList *next;
+ TemplPartialSpec *pspec;
+} PSpecList;
+
+static PSpecList *CTemplClass_FindMostSpecializedPartialSpecializations(PSpecList *list) {
+ PSpecList **array;
+ PSpecList *scan;
+ int i;
+ int j;
+ int count;
+
+ scan = list;
+ count = 0;
+ while (scan) {
+ scan = scan->next;
+ count++;
+ }
+
+ array = lalloc(sizeof(PSpecList *) * count);
+ for (i = 0, scan = list; scan; scan = scan->next)
+ array[i++] = scan;
+
+ for (i = 0; i < count; i++) {
+ if (array[i]) {
+ for (j = 0; j < count; j++) {
+ if (array[j] && i != j && CTemplClass_PartialClassIsMoreSpecialized(array[i]->pspec, array[j]->pspec))
+ array[j] = NULL;
+ }
+ }
+ }
+
+ for (i = 0, list = NULL; i < count; i++) {
+ if (array[i]) {
+ if (!list)
+ list = array[i];
+ else
+ array[j]->next = array[i];
+ array[i]->next = NULL;
+ j = i;
+ }
+ }
+
+ return list;
+}
+
+Boolean CTemplClass_FindPartialTemplate(TemplArg *args, TemplClass **resultTempl, TemplArg **resultArgs) {
+ TemplPartialSpec *pspec;
+ PSpecList *list;
+ TemplClassInst *inst;
+
+ for (inst = (*resultTempl)->instances; inst; inst = inst->next) {
+ if (inst->is_instantiated || inst->is_specialized) {
+ if (CTemplTool_EqualArgs(args, inst->oargs ? inst->oargs : inst->inst_args))
+ return 0;
+ }
+ }
+
+ list = NULL;
+ for (pspec = (*resultTempl)->pspecs; pspec; pspec = pspec->next) {
+ if (CTemplClass_PartialTemplateArgMatch(pspec, args, 0)) {
+ PSpecList *entry = lalloc(sizeof(PSpecList));
+ entry->next = list;
+ entry->pspec = pspec;
+ list = entry;
+ }
+ }
+
+ if (list) {
+ if (list->next) {
+ list = CTemplClass_FindMostSpecializedPartialSpecializations(list);
+ if (list->next)
+ CError_Error(CErrorStr346);
+ }
+
+ if (!list->pspec->templ->templ__params) {
+ *resultTempl = list->pspec->templ;
+ *resultArgs = NULL;
+ return 1;
+ }
+
+ *resultTempl = list->pspec->templ;
+ *resultArgs = CTemplClass_PartialTemplateArgMatch(list->pspec, args, 1);
+ return *resultArgs != NULL;
+ } else {
+ return 0;
+ }
+}
+
+TemplClass *CTemplClass_DefineNestedClass(TemplClass *parent, HashNameNode *name, short mode) {
+ TemplateAction *action;
+ TemplClass *templ;
+
+ templ = galloc(sizeof(TemplClass));
+ memclrw(templ, sizeof(TemplClass));
+
+ templ->next = ctempl_templates;
+ ctempl_templates = templ;
+
+ templ->templ_parent = parent;
+ templ->templ__params = NULL;
+ CDecl_DefineClass(parent->theclass.nspace, name, TYPE_CLASS(templ), mode, 0, 1);
+
+ templ->theclass.flags = CLASS_IS_TEMPL;
+ templ->align = copts.structalignment;
+
+ action = galloc(sizeof(TemplateAction));
+ memclrw(action, sizeof(TemplateAction));
+
+ action->type = TAT_NESTEDCLASS;
+ action->u.tclasstype = templ;
+ CTemplClass_AppendTemplateAction(parent, action);
+
+ return templ;
+}
+
+static void CTemplClass_CopyNestedClass(TypeDeduce *deduce, TemplClass *templ) {
+ ObjTypeTag *tag;
+
+ tag = galloc(sizeof(ObjTypeTag));
+ memclrw(tag, sizeof(ObjTypeTag));
+
+ tag->otype = OT_TYPETAG;
+ tag->access = ACCESSPUBLIC;
+
+ if (!templ->templ__params) {
+ TemplClassInst *inst = CTemplClass_NewInstance(templ, NULL, NULL);
+ inst->parent = deduce->inst;
+ inst->theclass.nspace->parent = deduce->inst->theclass.nspace;
+
+ tag->type = TYPE(inst);
+ } else {
+ TemplClass *copy = galloc(sizeof(TemplClass));
+ memclrw(copy, sizeof(TemplClass));
+
+ copy->next = ctempl_templates;
+ ctempl_templates = copy;
+
+ copy->theclass = templ->theclass;
+ copy->templ_parent = deduce->tmclass;
+ copy->inst_parent = deduce->inst;
+ copy->templ__params = templ->templ__params;
+ copy->members = NULL;
+ copy->instances = NULL;
+ copy->pspecs = NULL;
+ copy->actions = templ->actions;
+ copy->lex_order_count = templ->lex_order_count;
+ copy->align = templ->align;
+ copy->flags = templ->flags;
+
+ tag->type = TYPE(copy);
+ }
+
+ CScope_AddObject(deduce->inst->theclass.nspace, templ->theclass.classname, OBJ_BASE(tag));
+}
+
+static void CTemplClass_CopyBaseClasses(TypeDeduce *deduce, TemplClassInst *inst, TemplClass *templ) {
+ TemplateAction *action;
+ ClassList *newBase;
+ ClassList *templbase;
+ ClassList *instbase;
+ ClassList *base;
+ UInt32 qual = 0;
+
+ for (base = templ->theclass.bases; base; base = base->next) {
+ ClassList *scan;
+ newBase = galloc(sizeof(ClassList));
+ *newBase = *base;
+ newBase->next = NULL;
+
+ if ((scan = inst->theclass.bases)) {
+ while (1) {
+ if (scan->base == newBase->base) {
+ CError_Error(CErrorStr131);
+ break;
+ }
+ if (!scan->next) {
+ scan->next = newBase;
+ break;
+ }
+ scan = scan->next;
+ }
+ } else {
+ inst->theclass.bases = newBase;
+ }
+ }
+
+ for (action = deduce->tmclass->actions; action; action = action->next) {
+ if (action->type == TAT_BASE) {
+ TStreamElement *save;
+
+ CTemplClass_SetupActionErrorRef(action, &save);
+
+ newBase = galloc(sizeof(ClassList));
+ memclrw(newBase, sizeof(ClassList));
+
+ newBase->base = TYPE_CLASS(CTemplTool_DeduceTypeCopy(deduce, action->u.base.type, &qual));
+ newBase->access = action->u.base.access;
+ newBase->is_virtual = action->u.base.is_virtual;
+
+ if (IS_TYPE_CLASS(newBase->base)) {
+ if (newBase->base->size == 0) {
+ CDecl_CompleteType(TYPE(newBase->base));
+ IsCompleteType(TYPE(newBase->base));
+ }
+
+ if (CDecl_CheckNewBase(TYPE_CLASS(inst), newBase->base, newBase->is_virtual)) {
+ if (action->u.base.insert_after) {
+ templbase = templ->theclass.bases;
+ instbase = inst->theclass.bases;
+ while (1) {
+ CError_ASSERT(1222, templbase && instbase);
+
+ if (templbase == action->u.base.insert_after) {
+ newBase->next = instbase->next;
+ instbase->next = newBase;
+ break;
+ }
+
+ templbase = templbase->next;
+ instbase = instbase->next;
+ }
+ } else {
+ newBase->next = inst->theclass.bases;
+ inst->theclass.bases = newBase;
+ }
+ }
+ } else {
+ CError_Error(CErrorStr131);
+ }
+
+ CTemplClass_RestoreActionErrorRef(&save);
+ }
+ }
+
+ if (inst->theclass.flags & CLASS_HAS_VBASES)
+ CDecl_MakeVBaseList(TYPE_CLASS(inst));
+}
+
+static void CTemplClass_CopyEnum(TypeDeduce *deduce, TemplateAction *action) {
+ TypeEnum *destenum;
+ TypeEnum *srcenum;
+ ObjEnumConst **destptr;
+ ObjEnumConst *src;
+ TemplateAction *scanaction;
+
+ srcenum = action->u.enumtype;
+ destenum = galloc(sizeof(TypeEnum));
+ memclrw(destenum, sizeof(TypeEnum));
+
+ destenum->type = TYPEENUM;
+ destenum->size = srcenum->size;
+ destenum->nspace = deduce->inst->theclass.nspace;
+ destenum->enumtype = srcenum->enumtype;
+ destenum->enumname = srcenum->enumname;
+
+ if (destenum->enumname)
+ CScope_DefineTypeTag(destenum->nspace, destenum->enumname, TYPE(destenum));
+
+ src = srcenum->enumlist;
+ destptr = &destenum->enumlist;
+ while (src) {
+ ObjEnumConst *dest;
+
+ dest = galloc(sizeof(ObjEnumConst));
+ *dest = *src;
+
+ *destptr = dest;
+ dest->next = NULL;
+ dest->type = TYPE(destenum);
+ CScope_AddObject(deduce->inst->theclass.nspace, dest->name, OBJ_BASE(dest));
+
+ src = src->next;
+ destptr = &(*destptr)->next;
+ }
+
+ for (scanaction = deduce->tmclass->actions; scanaction; scanaction = scanaction->next) {
+ if (scanaction->type == TAT_ENUMERATOR && scanaction->u.enumerator.objenumconst->type == TYPE(srcenum)) {
+ CTemplClass_NewDefAction(deduce, action)->enumtype = destenum;
+ return;
+ }
+ }
+}
+
+static void CTemplClass_CompleteEnumType(TypeDeduce *deduce, TemplateAction *action, TypeEnum *destenum) {
+ TypeEnum *srcenum;
+ ObjEnumConst *dest;
+ TemplateAction *scanaction;
+ ENode *expr;
+ ObjEnumConst *src;
+
+ srcenum = action->u.enumtype;
+
+ for (scanaction = deduce->tmclass->actions; scanaction; scanaction = scanaction->next) {
+ if (scanaction->type == TAT_ENUMERATOR) {
+ src = scanaction->u.enumerator.objenumconst;
+ if (src->type == TYPE(srcenum)) {
+ TStreamElement *save;
+
+ CTemplClass_SetupActionErrorRef(scanaction, &save);
+
+ dest = destenum->enumlist;
+ while (dest) {
+ if (dest->name == src->name)
+ break;
+ dest = dest->next;
+ }
+
+ CError_ASSERT(1332, dest);
+
+ if (scanaction->u.enumerator.initexpr) {
+ expr = CTemplTool_DeduceExpr(deduce, scanaction->u.enumerator.initexpr);
+ if (!ENODE_IS(expr, EINTCONST)) {
+ CError_Error(CErrorStr124);
+ CTemplClass_RestoreActionErrorRef(&save);
+ break;
+ }
+ } else {
+ CError_ASSERT(1347, expr);
+ expr->data.intval = CInt64_Add(expr->data.intval, cint64_one);
+ }
+
+ dest->val = expr->data.intval;
+ dest->type = expr->rtype;
+ CTemplClass_RestoreActionErrorRef(&save);
+ }
+ }
+ }
+
+ CDecl_ComputeUnderlyingEnumType(destenum);
+}
+
+static void CTemplClass_CopyObjMemberVarPath(TypeDeduce *deduce, ObjMemberVarPath *ivar) {
+ ObjMemberVarPath *copy;
+
+ copy = galloc(sizeof(ObjMemberVarPath));
+ *copy = *ivar;
+
+ if (copy->path && copy->path->type == TYPE(deduce->tmclass)) {
+ copy->path = CClass_GetPathCopy(copy->path, 1);
+ copy->path->type = TYPE(deduce->inst);
+ }
+
+ CScope_AddObject(deduce->inst->theclass.nspace, copy->name, OBJ_BASE(copy));
+}
+
+static void CTemplClass_CopyIVars(TypeDeduce *deduce, TemplClassInst *inst, TemplClass *templ) {
+ ObjMemberVar *src;
+ ObjMemberVar *dest;
+ ObjMemberVar **destptr;
+ TemplateAction *scanaction;
+
+ src = templ->theclass.ivars;
+ destptr = &inst->theclass.ivars;
+
+ while (src) {
+ CError_ASSERT(1397, !src->has_path);
+
+ dest = galloc(sizeof(ObjMemberVar));
+ *dest = *src;
+
+ for (scanaction = deduce->tmclass->actions; scanaction; scanaction = scanaction->next) {
+ if (scanaction->type == TAT_OBJECTDEF && scanaction->u.refobj == OBJ_BASE(src)) {
+ CTemplClass_NewDefAction(deduce, scanaction)->refobj = OBJ_BASE(dest);
+ break;
+ }
+ }
+
+ if (!scanaction) {
+ dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual);
+ if (dest->type->size == 0) {
+ CDecl_CompleteType(dest->type);
+ IsCompleteType(dest->type);
+ }
+ }
+
+ if (dest->name && dest->name != no_name_node)
+ CScope_AddObject(inst->theclass.nspace, dest->name, OBJ_BASE(dest));
+
+ *destptr = dest;
+ destptr = &dest->next;
+ src = src->next;
+ }
+}
+
+static void CTemplClass_CopyObjType(TypeDeduce *deduce, ObjType *src, HashNameNode *name) {
+ TemplateAction *scanaction;
+ NameSpaceObjectList *list;
+ NameSpaceObjectList *newlist;
+ ObjType *dest;
+
+ for (scanaction = deduce->tmclass->actions; scanaction; scanaction = scanaction->next) {
+ if (scanaction->type == TAT_OBJECTDEF && scanaction->u.refobj == OBJ_BASE(src))
+ break;
+ }
+
+ dest = galloc(sizeof(ObjType));
+ *dest = *src;
+
+ if (scanaction)
+ CTemplClass_NewDefAction(deduce, scanaction)->refobj = OBJ_BASE(dest);
+ else
+ dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual);
+
+ if ((list = CScope_FindName(deduce->inst->theclass.nspace, name)) && list->object->otype == OT_TYPETAG) {
+ CError_ASSERT(1470, list->next == NULL);
+
+ newlist = galloc(sizeof(NameSpaceObjectList));
+ newlist->object = list->object;
+ newlist->next = NULL;
+
+ list->object = OBJ_BASE(dest);
+ list->next = newlist;
+ } else {
+ CScope_AddObject(deduce->inst->theclass.nspace, name, OBJ_BASE(dest));
+ }
+}
+
+static void CTemplClass_CopyObjTypeTag(TypeDeduce *deduce, ObjTypeTag *src, HashNameNode *name) {
+ UInt32 qual = 0;
+ ObjTypeTag *dest = galloc(sizeof(ObjTypeTag));
+
+ *dest = *src;
+ dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &qual);
+
+ CScope_AddObject(deduce->inst->theclass.nspace, name, OBJ_BASE(dest));
+}
+
+static void CTemplClass_CopyMemberTemplate(TypeDeduce *deduce, Object *src) {
+ TemplateFunction *desttempl;
+ Object *dest;
+ TemplateFunction *srctempl;
+ TemplateAction *action;
+
+ srctempl = src->u.func.u.templ;
+ CError_ASSERT(1516, srctempl && srctempl->params);
+
+ for (action = deduce->tmclass->actions; action; action = action->next) {
+ if (action->type == TAT_OBJECTDEF && action->u.refobj == OBJ_BASE(src))
+ break;
+ }
+
+ desttempl = galloc(sizeof(TemplateFunction));
+ *desttempl = *srctempl;
+
+ desttempl->next = ctempl_templatefuncs;
+ ctempl_templatefuncs = desttempl;
+
+ desttempl->unk4 = srctempl;
+
+ dest = galloc(sizeof(Object));
+ *dest = *src;
+
+ dest->u.func.u.templ = desttempl;
+ dest->nspace = deduce->inst->theclass.nspace;
+
+ CError_ASSERT(1541, !deduce->x15);
+ deduce->x15 = 1;
+ deduce->nindex = srctempl->params->pid.nindex;
+
+ if (action)
+ CTemplClass_NewDefAction(deduce, action)->refobj = OBJ_BASE(dest);
+ else
+ dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual);
+
+ deduce->x15 = 0;
+
+ CError_ASSERT(1553, IS_TYPE_FUNC(dest->type));
+
+ TYPE_FUNC(dest->type)->flags |= FUNC_IS_TEMPL;
+
+ if (
+ (TYPE_FUNC(dest->type)->flags & FUNC_IS_CTOR) &&
+ deduce->x17 &&
+ !action
+ )
+ {
+ FuncArg *arg;
+ CError_ASSERT(1560, TYPE_FUNC(dest->type)->args);
+ arg = CParser_NewFuncArg();
+ arg->type = TYPE(&stsignedshort);
+ arg->next = TYPE_FUNC(dest->type)->args->next;
+ TYPE_FUNC(dest->type)->args->next = arg;
+ }
+
+ CScope_AddObject(deduce->inst->theclass.nspace, dest->name, OBJ_BASE(dest));
+}
+
+static void CTemplClass_CopyObject(TypeDeduce *deduce, Object *src) {
+ ObjectTemplated *dest;
+ TemplateAction *action;
+ TemplateAction *action2;
+ Boolean flag;
+
+ flag = 1;
+ if (src->nspace != deduce->tmclass->theclass.nspace) {
+ CError_ASSERT(1587, src->datatype == DALIAS);
+ flag = 0;
+ }
+
+ if (IS_TEMPL_FUNC(src->type)) {
+ CTemplClass_CopyMemberTemplate(deduce, src);
+ return;
+ }
+
+ for (action = deduce->tmclass->actions; action; action = action->next) {
+ if (action->type == TAT_OBJECTDEF && action->u.refobj == OBJ_BASE(src))
+ break;
+ }
+
+ dest = galloc(sizeof(ObjectTemplated));
+ dest->object = *src;
+
+ if (action)
+ CTemplClass_NewDefAction(deduce, action)->refobj = OBJ_BASE(dest);
+ else
+ dest->object.type = CTemplTool_DeduceTypeCopy(deduce, dest->object.type, &dest->object.qual);
+
+ if (flag)
+ dest->object.nspace = deduce->inst->theclass.nspace;
+
+ dest->object.qual |= Q_IS_TEMPLATED;
+ dest->parent = src;
+
+ if (IS_TYPE_FUNC(dest->object.type))
+ TYPE_FUNC(dest->object.type)->flags &= ~FUNC_DEFINED;
+
+ switch (dest->object.datatype) {
+ case DDATA:
+ dest->object.u.data.linkname = NULL;
+ for (action2 = deduce->tmclass->actions; action2; action2 = action2->next) {
+ if (action2->type == TAT_OBJECTINIT && action2->u.objectinit.object == src) {
+ CTemplClass_NewDefAction(deduce, action2)->refobj = OBJ_BASE(dest);
+ break;
+ }
+ }
+ break;
+
+ case DABSOLUTE:
+ break;
+
+ case DFUNC:
+ case DVFUNC:
+ dest->object.u.func.linkname = NULL;
+ CError_ASSERT(1650, IS_TYPE_FUNC(dest->object.type));
+ CError_ASSERT(1651, !dest->object.u.func.u.templ && !dest->object.u.func.defargdata);
+
+ if (
+ (TYPE_FUNC(dest->object.type)->flags & FUNC_IS_CTOR) &&
+ deduce->x17 &&
+ !action
+ )
+ {
+ FuncArg *arg;
+ CError_ASSERT(1657, TYPE_FUNC(dest->object.type)->args);
+ arg = CParser_NewFuncArg();
+ arg->type = TYPE(&stsignedshort);
+ arg->next = TYPE_FUNC(dest->object.type)->args->next;
+ TYPE_FUNC(dest->object.type)->args->next = arg;
+ }
+
+ if (TYPE_FUNC(dest->object.type)->flags & FUNC_CONVERSION) {
+ CError_ASSERT(1665, IS_TYPE_FUNC(src->type));
+ if (CTemplTool_IsTemplateArgumentDependentType(TYPE_FUNC(src->type)->functype)) {
+ CError_ASSERT(1668, action);
+ return;
+ }
+ }
+
+ break;
+
+ case DINLINEFUNC:
+ break;
+
+ case DALIAS:
+ if (dest->object.u.alias.member && dest->object.u.alias.member->type == TYPE(deduce->tmclass)) {
+ dest->object.u.alias.member = CClass_GetPathCopy(dest->object.u.alias.member, 1);
+ dest->object.u.alias.member->type = TYPE(deduce->inst);
+ }
+ break;
+
+ case DLOCAL:
+ case DEXPR:
+ CError_FATAL(1688);
+
+ default:
+ CError_FATAL(1691);
+ }
+
+ CScope_AddObject(deduce->inst->theclass.nspace, dest->object.name, OBJ_BASE(dest));
+}
+
+static void CTemplClass_CompleteObject(TypeDeduce *deduce, TemplateAction *action, ObjBase *refobj) {
+ if (refobj->otype == OT_MEMBERVAR) {
+ ObjMemberVar *ivar = OBJ_MEMBER_VAR(refobj);
+ ivar->type = CTemplTool_DeduceTypeCopy(deduce, ivar->type, &ivar->qual);
+
+ if (ivar->type->size == 0) {
+ CDecl_CompleteType(ivar->type);
+ if (copts.experimental) {
+ if (ivar->next || ivar->type->size != 0 || !IS_TYPE_ARRAY(ivar->type))
+ IsCompleteType(ivar->type);
+ } else {
+ IsCompleteType(ivar->type);
+ }
+ }
+ } else if (refobj->otype == OT_TYPE) {
+ ObjType *obj = OBJ_TYPE(refobj);
+ obj->type = CTemplTool_DeduceTypeCopy(deduce, obj->type, &obj->qual);
+ } else {
+ Object *dest;
+ Object *src;
+
+ CError_ASSERT(1737, refobj->otype == OT_OBJECT);
+
+ dest = OBJECT(refobj);
+ src = OBJECT(action->u.refobj);
+
+ if (IS_TEMPL_FUNC(src->type)) {
+ TemplateFunction *templ = src->u.func.u.templ;
+ CError_ASSERT(1747, templ);
+ CError_ASSERT(1748, !deduce->x15);
+
+ deduce->x15 = 1;
+ deduce->nindex = templ->params->pid.nindex;
+ dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual);
+ deduce->x15 = 0;
+
+ CError_ASSERT(1753, IS_TYPE_FUNC(dest->type));
+ TYPE_FUNC(dest->type)->flags |= FUNC_IS_TEMPL;
+ } else {
+ dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual);
+ dest->qual |= Q_IS_TEMPLATED;
+
+ if (IS_TYPE_FUNC(dest->type))
+ TYPE_FUNC(dest->type)->flags &= ~FUNC_DEFINED;
+
+ switch (dest->datatype) {
+ case DFUNC:
+ case DVFUNC:
+ CError_ASSERT(1769, IS_TYPE_FUNC(dest->type));
+ if (TYPE_FUNC(dest->type)->flags & FUNC_CONVERSION) {
+ CError_ASSERT(1772, IS_TYPE_FUNC(dest->type));
+ if (CTemplTool_IsTemplateArgumentDependentType(TYPE_FUNC(src->type)->functype)) {
+ dest->name = CMangler_ConversionFuncName(
+ TYPE_FUNC(dest->type)->functype, TYPE_FUNC(dest->type)->qual);
+ CScope_AddObject(deduce->inst->theclass.nspace, dest->name, OBJ_BASE(dest));
+ }
+ }
+
+ if ((TYPE_FUNC(dest->type)->flags & FUNC_IS_CTOR) && deduce->x17) {
+ FuncArg *arg;
+ CError_ASSERT(1786, TYPE_FUNC(dest->type)->args);
+ arg = CParser_NewFuncArg();
+ arg->type = TYPE(&stsignedshort);
+ arg->next = TYPE_FUNC(dest->type)->args->next;
+ TYPE_FUNC(dest->type)->args->next = arg;
+ }
+
+ break;
+ }
+ }
+ }
+}
+
+static void CTemplClass_CompleteObjectInit(TypeDeduce *deduce, TemplateAction *action, Object *object) {
+ ENode *expr = CTemplTool_DeduceExpr(deduce, action->u.objectinit.initexpr);
+
+ if (ENODE_IS(expr, EINTCONST) && (object->qual & Q_CONST) && IS_TYPE_INT_OR_ENUM(object->type)) {
+ object->u.data.u.intconst = expr->data.intval;
+ object->qual |= Q_INLINE_DATA | Q_20000;
+ } else {
+ CError_Error(CErrorStr354, object->name->name);
+ }
+}
+
+static void CTemplClass_CopyNameSpace(TypeDeduce *deduce, TemplClassInst *inst, TemplClass *templ) {
+ NameSpaceName *nsname;
+ NameSpaceObjectList *list;
+
+ CError_ASSERT(1830, !templ->theclass.nspace->is_hash);
+
+ for (nsname = templ->theclass.nspace->data.list; nsname; nsname = nsname->next) {
+ for (list = &nsname->first; list; list = list->next) {
+ switch (list->object->otype) {
+ case OT_ENUMCONST:
+ break;
+ case OT_MEMBERVAR:
+ if (OBJ_MEMBER_VAR(list->object)->has_path)
+ CTemplClass_CopyObjMemberVarPath(deduce, OBJ_MEMBER_VAR_PATH(list->object));
+ break;
+ case OT_TYPE:
+ CTemplClass_CopyObjType(deduce, OBJ_TYPE(list->object), nsname->name);
+ break;
+ case OT_TYPETAG:
+ break;
+ case OT_NAMESPACE:
+ CError_FATAL(1854);
+ case OT_OBJECT:
+ CTemplClass_CopyObject(deduce, OBJECT(list->object));
+ break;
+ default:
+ CError_FATAL(1861);
+ }
+ }
+ }
+}
+
+static void CTemplClass_CopyUsingDecl(TypeDeduce *deduce, TypeTemplDep *type, AccessType access) {
+ TypeClass *tclass;
+ UInt32 qual = 0;
+
+ CError_ASSERT(1878, IS_TYPE_TEMPLATE(type) && type->dtype == TEMPLDEP_QUALNAME);
+
+ tclass = TYPE_CLASS(CTemplTool_DeduceTypeCopy(deduce, TYPE(type->u.qual.type), &qual));
+ if (!IS_TYPE_CLASS(tclass)) {
+ CError_Error(CErrorStr340, type->u.qual.name->name);
+ return;
+ }
+
+ CDecl_CompleteType(TYPE(tclass));
+ CScope_AddClassUsingDeclaration(TYPE_CLASS(deduce->inst), tclass, type->u.qual.name, access);
+}
+
+static void CTemplClass_CopyFriend(TypeDeduce *deduce, TemplateFriend *tfriend) {
+ TemplArg *arg;
+ Object *funcobj;
+ Boolean flag;
+ CScopeSave saveScope;
+ DeclInfo di;
+
+ CDecl_UnpackDeclInfo(&di, &tfriend->decl);
+
+ if (CTemplTool_IsTemplateArgumentDependentType(di.thetype))
+ di.thetype = CTemplTool_DeduceTypeCopy(deduce, di.thetype, &di.qual);
+
+ if (di.expltargs) {
+ di.expltargs = CTemplTool_MakeGlobalTemplArgCopy(di.expltargs);
+ for (arg = di.expltargs; arg; arg = arg->next) {
+ switch (arg->pid.type) {
+ case TPT_TYPE:
+ if (CTemplTool_IsTemplateArgumentDependentType(arg->data.typeparam.type))
+ arg->data.typeparam.type = CTemplTool_DeduceTypeCopy(deduce, arg->data.typeparam.type, &arg->data.typeparam.qual);
+ break;
+ case TPT_NONTYPE:
+ if (CTemplTool_IsTemplateArgumentDependentExpression(arg->data.paramdecl.expr))
+ arg->data.paramdecl.expr = CTemplTool_DeduceExpr(deduce, arg->data.paramdecl.expr);
+ break;
+ case TPT_TEMPLATE:
+ default:
+ CError_FATAL(1930);
+ }
+ }
+ }
+
+ if (IS_TYPE_FUNC(di.thetype)) {
+ CScope_SetNameSpaceScope(CScope_FindGlobalNS(deduce->inst->theclass.nspace), &saveScope);
+ funcobj = CDecl_GetFunctionObject(&di, NULL, &flag, 0);
+ CScope_RestoreScope(&saveScope);
+
+ if (funcobj) {
+ CDecl_AddFriend(TYPE_CLASS(deduce->inst), funcobj, NULL);
+ if (tfriend->stream.tokens)
+ CInline_AddInlineFunctionAction(funcobj, TYPE_CLASS(deduce->inst), &tfriend->fileoffset, &tfriend->stream, 0);
+ } else {
+ CError_Error(CErrorStr201);
+ }
+ } else {
+ CError_ASSERT(1963, IS_TYPE_CLASS(di.thetype));
+ CDecl_AddFriend(TYPE_CLASS(deduce->inst), NULL, TYPE_CLASS(di.thetype));
+ }
+}
+
+Boolean CTempl_InstantiateTemplateClass(TypeClass *tclass) {
+ TemplClassInst *inst;
+ ParserTryBlock *tryBlock;
+ TemplateAction *action;
+ DefAction *defAction;
+ UInt8 saveAlignMode;
+
+ TypeDeduce deduce;
+ TemplStack stack;
+ CScopeSave saveScope;
+ ClassLayout layout;
+ TemplClass *templ;
+ TStreamElement *saveErrorRef;
+ TemplArg *inst_args;
+
+ CError_ASSERT(1989, tclass->flags & CLASS_IS_TEMPL_INST);
+
+ if (tclass->flags & CLASS_COMPLETED)
+ return 1;
+
+ inst = TEMPL_CLASS_INST(tclass);
+ if (inst->is_specialized)
+ return 0;
+
+ templ = inst->templ;
+ if (!(templ->flags & TEMPLCLASS_FLAGS_2))
+ templ = CTemplClass_GetMasterTemplate(templ);
+
+ if (templ->pspecs && CTemplClass_FindPartialTemplate(inst->inst_args, &templ, &inst_args)) {
+ CError_ASSERT(2013, !inst->oargs);
+ inst->templ = templ;
+ inst->oargs = inst->inst_args;
+ inst->inst_args = inst_args;
+ }
+
+ if (!(templ->theclass.flags & CLASS_COMPLETED))
+ return 0;
+
+ if (inst->is_instantiated)
+ return 0;
+
+ inst->is_instantiated = 1;
+ CScope_SetClassScope(tclass, &saveScope);
+ CTemplTool_PushInstance(&stack, tclass, NULL);
+
+ tryBlock = trychain;
+ trychain = NULL;
+
+ memclrw(&deduce, sizeof(deduce));
+ deduce.tmclass = templ;
+ deduce.inst = inst;
+ deduce.params = templ->templ__params;
+ deduce.args = inst->inst_args;
+
+ CError_ASSERT(2045, !templ->theclass.sominfo);
+ CError_ASSERT(2047, !templ->theclass.objcinfo);
+ CError_ASSERT(2049, !templ->theclass.vtable);
+
+ inst->theclass.flags |= templ->theclass.flags &
+ (CLASS_ABSTRACT | CLASS_SINGLE_OBJECT | CLASS_HAS_VBASES | CLASS_IS_CONVERTIBLE | CLASS_COM_OBJECT);
+
+ CTemplClass_CopyBaseClasses(&deduce, inst, templ);
+
+ deduce.x17 = (inst->theclass.flags & CLASS_HAS_VBASES) && !(templ->theclass.flags & CLASS_HAS_VBASES);
+
+ for (action = templ->actions; action; action = action->next) {
+ switch (action->type) {
+ case TAT_NESTEDCLASS:
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CopyNestedClass(&deduce, action->u.tclasstype);
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ case TAT_ENUMTYPE:
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CopyEnum(&deduce, action);
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ case TAT_FRIEND:
+ case TAT_ENUMERATOR:
+ case TAT_BASE:
+ case TAT_OBJECTINIT:
+ case TAT_USINGDECL:
+ case TAT_OBJECTDEF:
+ break;
+ default:
+ CError_FATAL(2094);
+ }
+ }
+
+ CTemplClass_CopyIVars(&deduce, inst, templ);
+ CTemplClass_CopyNameSpace(&deduce, inst, templ);
+
+ CError_ASSERT(2105, !templ->theclass.friends);
+
+ for (action = templ->actions; action; action = action->next) {
+ switch (action->type) {
+ case TAT_NESTEDCLASS:
+ break;
+ case TAT_ENUMTYPE:
+ for (defAction = deduce.defActions; defAction; defAction = defAction->next) {
+ if (defAction->action == action) {
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CompleteEnumType(&deduce, action, defAction->enumtype);
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ }
+ }
+ break;
+ case TAT_FRIEND:
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CopyFriend(&deduce, action->u.tfriend);
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ case TAT_ENUMERATOR:
+ break;
+ case TAT_BASE:
+ break;
+ case TAT_OBJECTINIT:
+ for (defAction = deduce.defActions; ; defAction = defAction->next) {
+ CError_ASSERT(2136, defAction);
+ if (defAction->action == action) {
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CompleteObjectInit(&deduce, action, OBJECT(defAction->refobj));
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ }
+ }
+ break;
+ case TAT_USINGDECL:
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CopyUsingDecl(&deduce, action->u.usingdecl.type, action->u.usingdecl.access);
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ case TAT_OBJECTDEF:
+ for (defAction = deduce.defActions; ; defAction = defAction->next) {
+ CError_ASSERT(2156, defAction);
+ if (defAction->action == action) {
+ CTemplClass_SetupActionErrorRef(action, &saveErrorRef);
+ CTemplClass_CompleteObject(&deduce, action, defAction->refobj);
+ CTemplClass_RestoreActionErrorRef(&saveErrorRef);
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ memclrw(&layout, sizeof(layout));
+ layout.lex_order_count = templ->lex_order_count;
+ layout.has_vtable = templ->flags & TEMPLCLASS_HAS_VTABLE;
+
+ saveAlignMode = copts.structalignment;
+ copts.structalignment = templ->align;
+ CDecl_CompleteClass(&layout, TYPE_CLASS(inst));
+ copts.structalignment = saveAlignMode;
+
+ if (templ->theclass.align > inst->theclass.align) {
+ inst->theclass.align = templ->theclass.align;
+ inst->theclass.size += CABI_StructSizeAlignValue(TYPE(inst), inst->theclass.size);
+ }
+
+ CTemplTool_PopInstance(&stack);
+ CScope_RestoreScope(&saveScope);
+ trychain = tryBlock;
+
+ return 1;
+}
diff --git a/compiler_and_linker/FrontEnd/C/CTemplateFunc.c b/compiler_and_linker/FrontEnd/C/CTemplateFunc.c
new file mode 100644
index 0000000..3c5de98
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CTemplateFunc.c
@@ -0,0 +1,1383 @@
+#include "compiler/CTemplateFunc.h"
+#include "compiler/CABI.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CInline.h"
+#include "compiler/CInt64.h"
+#include "compiler/CParser.h"
+#include "compiler/CTemplateTools.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/templates.h"
+#include "compiler/types.h"
+
+static Boolean ctempl_conversion_deduction;
+static UInt8 ctempl_explicitargs_nindex;
+static int ctempl_explicitargs_num;
+static Boolean ctempl_explicitargs_all;
+
+// forward decls
+static Boolean CTempl_DeduceTypeTemplDep(TypeTemplDep *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag);
+static Boolean CTempl_DeduceType1(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag);
+
+static void CTemplFunc_SetupTypeDeduce(TypeDeduce *deduce, TemplateFunction *templ, TemplArg *args) {
+ memclrw(deduce, sizeof(TypeDeduce));
+ if (templ->tfunc->nspace->theclass && (templ->tfunc->nspace->theclass->flags & CLASS_IS_TEMPL))
+ deduce->tmclass = TEMPL_CLASS(templ->tfunc->nspace->theclass);
+ deduce->params = templ->params;
+ deduce->args = args;
+}
+
+Boolean CTempl_CanDeduceFunc(Object *object, TypeFunc *tfunc, TemplArg *args) {
+ DeduceInfo info;
+ int i;
+
+ if (CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(object)->params, args, 0)) {
+ if (CTempl_DeduceType(object->type, 0, TYPE(tfunc), 0, info.args, 0, 0)) {
+ for (i = 0; i < info.maxCount; i++) {
+ if (!info.args[i].is_deduced)
+ return 0;
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static TemplFuncInstance *CTempl_GetCreateFuncInstance(Object *funcobj, TemplArg *args, Object *object2) {
+ TemplFuncInstance *inst;
+ TemplateFunction *templ;
+ Object *instobj;
+ TemplParam *param;
+ TemplArg *arg;
+ TemplArg *last;
+ short paramCount;
+ short i;
+ TypeDeduce deduce;
+
+ templ = CTemplTool_GetFuncTempl(funcobj);
+
+ paramCount = 0;
+ param = templ->params;
+ while (param) {
+ param = param->next;
+ paramCount++;
+ }
+
+ for (i = 1, arg = args; i < paramCount; i++, arg++)
+ arg->next = arg + 1;
+ arg->next = NULL;
+
+ for (inst = templ->instances; inst; inst = inst->next) {
+ if (CTemplTool_EqualArgs(inst->args, args)) {
+ if (object2)
+ inst->object = object2;
+ return inst;
+ }
+ }
+
+ inst = galloc(sizeof(TemplFuncInstance));
+ memclrw(inst, sizeof(TemplFuncInstance));
+
+ for (i = 0, arg = NULL; i < paramCount; i++) {
+ if (arg) {
+ last->next = galloc(sizeof(TemplArg));
+ last = last->next;
+ } else {
+ last = galloc(sizeof(TemplArg));
+ arg = last;
+ }
+
+ *last = *args;
+ last->next = NULL;
+ args++;
+
+ if (last->pid.type == TPT_NONTYPE) {
+ CError_ASSERT(114, last->data.paramdecl.expr);
+ last->data.paramdecl.expr = CInline_CopyExpression(last->data.paramdecl.expr, CopyMode1);
+ }
+ }
+
+ inst->args = arg;
+ inst->next = templ->instances;
+ templ->instances = inst;
+
+ if (!object2) {
+ instobj = CParser_NewFunctionObject(NULL);
+ instobj->access = funcobj->access;
+ instobj->nspace = funcobj->nspace;
+ instobj->sclass = funcobj->sclass;
+ instobj->qual = funcobj->qual | Q_MANGLE_NAME;
+ instobj->name = templ->name;
+ instobj->u.func.inst = inst;
+
+ CTemplFunc_SetupTypeDeduce(&deduce, templ, inst->args);
+ if (funcobj->nspace->theclass && (funcobj->nspace->theclass->flags & CLASS_IS_TEMPL_INST)) {
+ deduce.tmclass = TEMPL_CLASS_INST(funcobj->nspace->theclass)->templ;
+ deduce.inst = TEMPL_CLASS_INST(funcobj->nspace->theclass);
+ }
+
+ instobj->type = CTemplTool_DeduceTypeCopy(&deduce, funcobj->type, &instobj->qual);
+ inst->object = instobj;
+
+ if (IS_TYPE_FUNC(instobj->type)) {
+ TYPE_FUNC(instobj->type)->flags &= ~FUNC_DEFINED;
+ if (TYPE_FUNC(instobj->type)->flags & FUNC_IS_CTOR) {
+ FuncArg *funcarg;
+ CError_ASSERT(152, TYPE_FUNC(instobj->type)->flags & FUNC_METHOD);
+ CError_ASSERT(153, funcarg = TYPE_FUNC(instobj->type)->args);
+
+ if (TYPE_METHOD(instobj->type)->theclass->flags & CLASS_HAS_VBASES)
+ CError_ASSERT(156, funcarg = funcarg->next);
+
+ if (funcarg->next)
+ CDecl_CheckCtorIntegrity(funcarg->next, TYPE_METHOD(instobj->type)->theclass);
+ }
+ }
+
+ if ((instobj->qual & Q_INLINE) && templ->stream.tokens)
+ CInline_AddTemplateFunctionAction(instobj, templ, inst);
+
+ } else {
+ inst->object = object2;
+ }
+
+ return inst;
+}
+
+TemplFuncInstance *CTempl_CheckFuncInstance(Object *object1, TypeFunc *tfunc, TemplArg *args, Object *object2) {
+ DeduceInfo info;
+ int i;
+
+ if (!CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(object1)->params, args, 1))
+ return NULL;
+
+ if (!CTempl_DeduceType(object1->type, 0, TYPE(tfunc), 0, info.args, 0, 0))
+ return NULL;
+
+ i = 0;
+ while (i < info.maxCount) {
+ if (!info.args[i++].is_deduced)
+ return NULL;
+ }
+
+ return CTempl_GetCreateFuncInstance(object1, info.args, object2);
+}
+
+TemplFuncInstance *CTempl_DeduceFunc(Object *object1, TypeFunc *tfunc, TemplArg *args, Object *object2, Boolean flag) {
+ return CTempl_CheckFuncInstance(object1, tfunc, args, object2);
+}
+
+static Boolean CTempl_FuncIsAtLeastAsSpecialized(Object *func1, Object *func2) {
+ int i;
+ FuncArg *arg1;
+ FuncArg *arg2;
+ Type *type1;
+ Type *type2;
+ UInt32 qual1;
+ UInt32 qual2;
+ DeduceInfo info;
+
+ arg1 = TYPE_FUNC(func2->type)->args;
+ if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(func2->type)))
+ arg1 = arg1->next;
+
+ i = 0;
+ while (1) {
+ if (!arg1)
+ break;
+ CError_ASSERT(231, arg1->type != &stvoid);
+ if (arg1 == &elipsis)
+ break;
+ if (arg1 == &oldstyle)
+ break;
+ arg1 = arg1->next;
+ i++;
+ }
+
+ if (!CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(func2)->params, NULL, 0))
+ return 0;
+
+ arg1 = TYPE_FUNC(func1->type)->args;
+ if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(func1->type)))
+ arg1 = arg1->next;
+
+ arg2 = TYPE_FUNC(func2->type)->args;
+ if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(func2->type)))
+ arg2 = arg2->next;
+
+ while (i > 0) {
+ if (!arg1)
+ break;
+ if (arg1 == &elipsis)
+ break;
+ if (arg1 == &oldstyle)
+ break;
+
+ CError_ASSERT(255, arg2);
+
+ type1 = arg1->type;
+ qual1 = arg1->qual & (Q_CONST | Q_VOLATILE);
+ qual2 = arg2->qual & (Q_CONST | Q_VOLATILE);
+ type2 = arg2->type;
+
+ if (!CTemplTool_IsTemplateArgumentDependentType(type2)) {
+ if (IS_TYPE_REFERENCE(type1))
+ type1 = TPTR_TARGET(type1);
+ type1 = CParser_RemoveTopMostQualifiers(type1, &qual1);
+
+ if (IS_TYPE_REFERENCE(type2))
+ type2 = TPTR_TARGET(type2);
+ type2 = CParser_RemoveTopMostQualifiers(type2, &qual2);
+
+ if (!is_typesame(type1, type2) || qual1 != qual2)
+ return 0;
+ } else {
+ if (!CTempl_DeduceType(type2, qual2, type1, qual1, info.args, 0, 0))
+ return 0;
+ }
+
+ arg1 = arg1->next;
+ arg2 = arg2->next;
+ i--;
+ }
+
+ return 1;
+}
+
+Boolean CTempl_FuncIsMoreSpecialized(Object *object1, Object *object2) {
+ return CTempl_FuncIsAtLeastAsSpecialized(object1, object2) && !CTempl_FuncIsAtLeastAsSpecialized(object2, object1);
+}
+
+Object *CTempl_PartialOrdering(Object *object, ObjectList *list, int count) {
+ int i;
+ int j;
+ Object **array;
+ ObjectList *scan;
+ Object *arrayBuffer[16];
+
+ for (count = 1, scan = list; scan; scan = scan->next) {
+ if (IS_TEMPL_FUNC(scan->object->type))
+ count++;
+ }
+
+ if (count > 16)
+ array = lalloc(sizeof(Object *) * count);
+ else
+ array = arrayBuffer;
+
+ array[0] = object;
+ for (i = 1, scan = list; scan; scan = scan->next) {
+ if (IS_TEMPL_FUNC(scan->object->type))
+ array[i++] = scan->object;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (array[i]) {
+ for (j = 0; j < count; j++) {
+ if (array[j] && i != j && CTempl_FuncIsMoreSpecialized(array[i], array[j]))
+ array[j] = NULL;
+ }
+ }
+ }
+
+ object = NULL;
+
+ for (i = 0; i < count; i++) {
+ if (array[i]) {
+ if (object)
+ return NULL;
+ object = array[i];
+ }
+ }
+
+ return object;
+}
+
+int CTempl_GetTemplateArgumentExpressionIndex(TemplArg *arg) {
+ CError_ASSERT(529, arg->data.paramdecl.expr);
+
+ if (ENODE_IS(arg->data.paramdecl.expr, ETEMPLDEP) && arg->data.paramdecl.expr->data.templdep.subtype == TDE_PARAM)
+ return arg->data.paramdecl.expr->data.templdep.u.pid.index;
+
+ return -1;
+}
+
+static Type *CTempl_GetSpecifiedType(TemplateFunction *templ, Type *type, UInt32 qual, TemplArg *args, UInt32 *resultQual) {
+ TypeDeduce deduce;
+
+ CTemplFunc_SetupTypeDeduce(&deduce, templ, args);
+ *resultQual = qual;
+ return CTemplTool_DeduceTypeCopy(&deduce, type, resultQual);
+}
+
+static Boolean CTempl_DeduceTemplateArgs(TemplArg *args1, TemplArg *args2, TemplArg *argArray) {
+ int index;
+
+ while (1) {
+ if (!args1)
+ return !args2;
+ if (!args2)
+ return 0;
+
+ if (args1->pid.type != args2->pid.type)
+ return 0;
+
+ switch (args1->pid.type) {
+ case TPT_TYPE:
+ if (!CTempl_DeduceType1(
+ args1->data.typeparam.type, args1->data.typeparam.qual,
+ args2->data.typeparam.type, args2->data.typeparam.qual,
+ argArray, 1
+ ))
+ return 0;
+ break;
+
+ case TPT_NONTYPE:
+ if (CTemplTool_IsTemplateArgumentDependentExpression(args1->data.paramdecl.expr)) {
+ index = CTempl_GetTemplateArgumentExpressionIndex(args1);
+ if (index < 0)
+ return 1;
+
+ if (argArray[index].is_deduced) {
+ if (!CTemplTool_EqualExprTypes(args2->data.paramdecl.expr, argArray[index].data.paramdecl.expr))
+ return 0;
+ } else {
+ argArray[index].data.paramdecl.expr = args2->data.paramdecl.expr;
+ argArray[index].pid.type = TPT_NONTYPE;
+ argArray[index].is_deduced = 1;
+ }
+ } else {
+ if (!CTemplTool_EqualExprTypes(args2->data.paramdecl.expr, args1->data.paramdecl.expr))
+ return 0;
+ }
+ break;
+
+ case TPT_TEMPLATE:
+ if (!IS_TEMPL_CLASS(args2->data.ttargtype))
+ return 0;
+
+ index = args1->pid.index;
+ if (argArray[index].is_deduced) {
+ if (args2->data.ttargtype != argArray[index].data.ttargtype)
+ return 0;
+ } else {
+ argArray[index].data.ttargtype = args2->data.ttargtype;
+ argArray[index].pid.type = TPT_TEMPLATE;
+ argArray[index].is_deduced = 1;
+ }
+ break;
+
+ default:
+ CError_FATAL(640);
+ }
+
+ args1 = args1->next;
+ args2 = args2->next;
+ }
+}
+
+static Boolean CTempl_DeduceTemplDepTemplate(TemplClass *templ1, TemplArg *args1, TemplClass *templ2, TemplArg *args2, TemplArg *argArray) {
+ if (templ1 != templ2)
+ return 0;
+
+ return CTempl_DeduceTemplateArgs(args2, args1, argArray);
+}
+
+static Boolean CTempl_DeduceTemplateType(TemplClass *templ, TemplArg *args, TemplClassInst *inst, TemplArg *argArray) {
+ TemplClassInst *scan;
+
+ for (scan = templ->instances; scan; scan = scan->next) {
+ if (scan == inst)
+ return CTempl_DeduceTemplateArgs(args, scan->oargs ? scan->oargs : scan->inst_args, argArray);
+ }
+
+ return 0;
+}
+
+static Boolean CTempl_DeduceTemplateTypeBase(TemplClass *templ, TemplArg *args, TemplClassInst *inst, TemplArg *argArray, Boolean flag) {
+ ClassList *base;
+
+ if (CTempl_DeduceTemplateType(templ, args, inst, argArray))
+ return 1;
+
+ if (flag) {
+ for (base = inst->theclass.bases; base; base = base->next) {
+ if (CTempl_DeduceTemplateType(templ, args, TEMPL_CLASS_INST(base->base), argArray)) {
+ ctempl_conversion_deduction = 1;
+ return 1;
+ }
+ }
+
+ for (base = inst->theclass.bases; base; base = base->next) {
+ if (CTempl_DeduceTemplateTypeBase(templ, args, TEMPL_CLASS_INST(base->base), argArray, 1)) {
+ ctempl_conversion_deduction = 1;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static Boolean CTempl_DeduceQualTemplate(TypeTemplDep *type1, TemplArg *args1, Type *type2, TemplArg *argArray) {
+ int index;
+
+ if (type1->dtype == TEMPLDEP_ARGUMENT && type1->u.pid.type == TPT_TEMPLATE) {
+ index = type1->u.pid.index;
+ if (IS_TEMPL_CLASS_INST(type2)) {
+ if (argArray[index].is_deduced) {
+ if (argArray[index].data.ttargtype != TYPE(TEMPL_CLASS_INST(type2)->templ))
+ return 0;
+ } else {
+ argArray[index].data.ttargtype = TYPE(TEMPL_CLASS_INST(type2)->templ);
+ argArray[index].pid.type = TPT_TEMPLATE;
+ argArray[index].is_deduced = 1;
+ }
+
+ return CTempl_DeduceTemplateArgs(args1, TEMPL_CLASS_INST(type2)->inst_args, argArray);
+ }
+
+ if (IS_TYPE_TEMPLATE(type2)) {
+ if (TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_TEMPLATE) {
+ if (argArray[index].is_deduced) {
+ if (argArray[index].data.ttargtype != TYPE(TYPE_TEMPLATE(type2)->u.templ.templ))
+ return 0;
+ } else {
+ argArray[index].data.ttargtype = TYPE(TYPE_TEMPLATE(type2)->u.templ.templ);
+ argArray[index].pid.type = TPT_TEMPLATE;
+ argArray[index].is_deduced = 1;
+ }
+
+ return CTempl_DeduceTemplateArgs(args1, TYPE_TEMPLATE(type2)->u.templ.args, argArray);
+ }
+
+ if (TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_QUALTEMPL) {
+ return
+ CTempl_DeduceTypeTemplDep(type1, 0, TYPE(TYPE_TEMPLATE(type2)->u.qualtempl.type), 0, argArray, 1) &&
+ CTempl_DeduceTemplateArgs(args1, TYPE_TEMPLATE(type2)->u.qualtempl.args, argArray);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static Boolean CTempl_DeduceTypeTemplDep(TypeTemplDep *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag) {
+ Type *tmptype;
+ UInt32 tmpqual;
+ short index;
+ Boolean f;
+ UInt32 modqual;
+
+ switch (type1->dtype) {
+ case TEMPLDEP_ARGUMENT:
+ index = type1->u.pid.index;
+ tmptype = type2;
+ if (type1->u.pid.type == TPT_TEMPLATE) {
+ if (argArray[index].is_deduced) {
+ if (!is_typesame(tmptype, argArray[index].data.ttargtype))
+ return 0;
+ } else {
+ argArray[index].data.ttargtype = type2;
+ argArray[index].pid.type = TPT_TEMPLATE;
+ argArray[index].is_deduced = 1;
+ }
+ return 1;
+ }
+
+ switch (type2->type) {
+ case TYPEPOINTER:
+ tmpqual = qual2;
+ f = 0;
+ qual2 = TPTR_QUAL(type2);
+ modqual = qual2;
+
+ if ((modqual & Q_CONST) && (qual1 & Q_CONST)) {
+ modqual &= ~Q_CONST;
+ f = 1;
+ }
+ if ((modqual & Q_VOLATILE) && (qual1 & Q_VOLATILE)) {
+ modqual &= ~Q_VOLATILE;
+ f = 1;
+ }
+
+ if (f) {
+ tmptype = galloc(sizeof(TypePointer));
+ *TYPE_POINTER(tmptype) = *TYPE_POINTER(type2);
+ TPTR_QUAL(tmptype) = modqual;
+ }
+
+ if (flag && (qual2 | modqual) != (qual1 | modqual))
+ return 0;
+
+ break;
+
+ case TYPEMEMBERPOINTER:
+ tmpqual = qual2;
+ f = 0;
+ qual2 = TYPE_MEMBER_POINTER(type2)->qual;
+ modqual = qual2;
+
+ if ((modqual & Q_CONST) && (qual1 & Q_CONST)) {
+ modqual &= ~Q_CONST;
+ f = 1;
+ }
+ if ((modqual & Q_VOLATILE) && (qual1 & Q_VOLATILE)) {
+ modqual &= ~Q_VOLATILE;
+ f = 1;
+ }
+
+ if (f) {
+ tmptype = galloc(sizeof(TypeMemberPointer));
+ *TYPE_MEMBER_POINTER(tmptype) = *TYPE_MEMBER_POINTER(type2);
+ TYPE_MEMBER_POINTER(tmptype)->qual = modqual;
+ }
+
+ if (flag && (qual2 | modqual) != (qual1 | modqual))
+ return 0;
+
+ break;
+
+ default:
+ tmpqual = 0;
+ if ((qual2 & Q_CONST) && !(qual1 & Q_CONST))
+ tmpqual |= Q_CONST;
+ if ((qual2 & Q_VOLATILE) && !(qual1 & Q_VOLATILE))
+ tmpqual |= Q_VOLATILE;
+
+ if (flag && (qual2 | tmpqual) != (qual1 | tmpqual))
+ return 0;
+ }
+
+ if (argArray[index].is_deduced) {
+ if (!is_typesame(tmptype, argArray[index].data.typeparam.type) || tmpqual != argArray[index].data.typeparam.qual)
+ return 0;
+ } else {
+ argArray[index].data.typeparam.type = tmptype;
+ argArray[index].data.typeparam.qual = tmpqual;
+ argArray[index].pid.type = TPT_TYPE;
+ argArray[index].is_deduced = 1;
+ }
+ return 1;
+
+ case TEMPLDEP_QUALNAME:
+ return 1;
+
+ case TEMPLDEP_TEMPLATE:
+ if (IS_TYPE_CLASS(type2))
+ return CTempl_DeduceTemplateTypeBase(
+ type1->u.templ.templ, type1->u.templ.args,
+ TEMPL_CLASS_INST(type2), argArray, 0);
+
+ if (IS_TYPE_TEMPLATE(type2) && TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_TEMPLATE)
+ return CTempl_DeduceTemplDepTemplate(
+ TYPE_TEMPLATE(type2)->u.templ.templ, TYPE_TEMPLATE(type2)->u.templ.args,
+ type1->u.templ.templ, type1->u.templ.args,
+ argArray
+ );
+
+ return 0;
+
+ case TEMPLDEP_ARRAY:
+ if (IS_TYPE_ARRAY(type2)) {
+ SInt32 elements;
+
+ if (!CTempl_DeduceType1(type1->u.array.type, qual1, TPTR_TARGET(type2), qual2, argArray, flag))
+ return 0;
+
+ if (ENODE_IS(type1->u.array.index, EINTCONST)) {
+ CError_ASSERT(961, TPTR_TARGET(type2)->size);
+ return (type2->size / TPTR_TARGET(type2)->size) == CInt64_GetULong(&type1->u.array.index->data.intval);
+ }
+
+ if (!ENODE_IS(type1->u.array.index, ETEMPLDEP) || type1->u.array.index->data.templdep.subtype != TDE_PARAM)
+ return 1;
+
+ CError_ASSERT(970, TPTR_TARGET(type2)->size);
+
+ elements = type2->size / TPTR_TARGET(type2)->size;
+ index = type1->u.array.index->data.templdep.u.pid.index;
+ if (argArray[index].is_deduced) {
+ CError_ASSERT(976, ENODE_IS(argArray[index].data.paramdecl.expr, EINTCONST));
+ return elements == CInt64_GetULong(&argArray[index].data.paramdecl.expr->data.intval);
+ } else {
+ argArray[index].data.paramdecl.expr = intconstnode(CABI_GetPtrDiffTType(), elements);
+ argArray[index].pid.type = TPT_NONTYPE;
+ argArray[index].is_deduced = 1;
+ return 1;
+ }
+ } else if (IS_TYPE_TEMPLATE(type2) && TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_ARRAY) {
+ if (!CTempl_DeduceType1(type1->u.array.type, qual1, TYPE_TEMPLATE(type2)->u.array.type, qual2, argArray, flag))
+ return 0;
+
+ if (ENODE_IS(type1->u.array.index, EINTCONST)) {
+ return ENODE_IS(TYPE_TEMPLATE(type2)->u.array.index, EINTCONST) &&
+ CInt64_Equal(type1->u.array.index->data.intval, TYPE_TEMPLATE(type2)->u.array.index->data.intval);
+ }
+
+ if (!ENODE_IS(type1->u.array.index, ETEMPLDEP) || type1->u.array.index->data.templdep.subtype != TDE_PARAM)
+ return 1;
+
+ index = type1->u.array.index->data.templdep.u.pid.index;
+ if (argArray[index].is_deduced) {
+ return CTemplTool_EqualExprTypes(TYPE_TEMPLATE(type2)->u.array.index, argArray[index].data.paramdecl.expr);
+ } else {
+ argArray[index].data.paramdecl.expr = TYPE_TEMPLATE(type2)->u.array.index;
+ argArray[index].pid.type = TPT_NONTYPE;
+ argArray[index].is_deduced = 1;
+ return 1;
+ }
+ }
+
+ return 0;
+
+ case TEMPLDEP_QUALTEMPL:
+ return CTempl_DeduceQualTemplate(type1->u.qualtempl.type, type1->u.qualtempl.args, type2, argArray);
+
+ case TEMPLDEP_BITFIELD:
+ default:
+ CError_FATAL(1022);
+ return 1;
+ }
+}
+
+static Boolean CTempl_DeduceFuncType(TypeFunc *tfunc1, TypeFunc *tfunc2, TemplArg *argArray) {
+ FuncArg *arg1;
+ FuncArg *arg2;
+ Type *type2;
+ Type *type1;
+ UInt32 qual2;
+ UInt32 qual1;
+
+ arg1 = tfunc1->args;
+ arg2 = tfunc2->args;
+
+ if (IS_TYPEFUNC_NONSTATIC_METHOD(tfunc1) && !IS_TYPEFUNC_METHOD(tfunc2)) {
+ CError_ASSERT(1045, arg1);
+ arg1 = arg1->next;
+ }
+
+ while (1) {
+ if (arg1 == NULL)
+ return !arg2;
+ if (arg1 == &oldstyle)
+ return arg2 == &oldstyle;
+ if (arg1 == &elipsis)
+ return arg2 == &elipsis;
+
+ if (arg2 == NULL || arg2 == &oldstyle || arg2 == &elipsis)
+ return 0;
+
+ qual2 = arg2->qual;
+ type2 = CParser_RemoveTopMostQualifiers(arg2->type, &qual2);
+
+ qual1 = arg1->qual;
+ type1 = CParser_RemoveTopMostQualifiers(arg1->type, &qual1);
+
+ if (!CTempl_DeduceType1(type1, qual1, type2, qual2, argArray, 1))
+ return 0;
+
+ arg1 = arg1->next;
+ arg2 = arg2->next;
+ }
+}
+
+static Boolean CTempl_DeduceType1(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag) {
+ while (1) {
+ switch (type1->type) {
+ case TYPETEMPLATE:
+ return CTempl_DeduceTypeTemplDep(TYPE_TEMPLATE(type1), qual1, type2, qual2, argArray, flag);
+
+ case TYPEVOID:
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPESTRUCT:
+ case TYPECLASS:
+ return type1 == type2;
+
+ case TYPEMEMBERPOINTER:
+ if (type1->type != type2->type || TYPE_MEMBER_POINTER(type1)->qual != TYPE_MEMBER_POINTER(type2)->qual)
+ return 0;
+ if (!CTempl_DeduceType1(TYPE_MEMBER_POINTER(type1)->ty1, qual1, TYPE_MEMBER_POINTER(type2)->ty1, qual2, argArray, flag))
+ return 0;
+ type1 = TYPE_MEMBER_POINTER(type1)->ty2;
+ type2 = TYPE_MEMBER_POINTER(type2)->ty2;
+ continue;
+
+ case TYPEARRAY:
+ if (type2->type != TYPEARRAY)
+ return 0;
+ type1 = TPTR_TARGET(type1);
+ type2 = TPTR_TARGET(type2);
+ continue;
+
+ case TYPEPOINTER:
+ if (type2->type != TYPEPOINTER || TPTR_QUAL(type1) != TPTR_QUAL(type2))
+ return 0;
+ type1 = TPTR_TARGET(type1);
+ type2 = TPTR_TARGET(type2);
+ continue;
+
+ case TYPEFUNC:
+ if (type1->type != type2->type)
+ return 0;
+
+ if (CTempl_DeduceType1(TYPE_FUNC(type1)->functype, TYPE_FUNC(type1)->qual, TYPE_FUNC(type2)->functype, TYPE_FUNC(type2)->qual, argArray, flag))
+ return CTempl_DeduceFuncType(TYPE_FUNC(type1), TYPE_FUNC(type2), argArray);
+
+ return 0;
+
+ default:
+ CError_FATAL(1124);
+ }
+ }
+}
+
+static Boolean CTempl_DeduceType2(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray) {
+ while (1) {
+ switch (type1->type) {
+ case TYPEPOINTER:
+ if (type2->type != TYPEPOINTER)
+ return 0;
+ if (!CParser_IsSameOrMoreCVQualified(TPTR_QUAL(type2), TPTR_QUAL(type1)))
+ return 0;
+ type1 = TPTR_TARGET(type1);
+ type2 = TPTR_TARGET(type2);
+ continue;
+
+ case TYPEMEMBERPOINTER:
+ if (type2->type != TYPEMEMBERPOINTER)
+ return 0;
+ if (!CParser_IsSameOrMoreCVQualified(TYPE_MEMBER_POINTER(type2)->qual, TYPE_MEMBER_POINTER(type1)->qual))
+ return 0;
+ if (!CTempl_DeduceType2(TYPE_MEMBER_POINTER(type1)->ty1, qual1, TYPE_MEMBER_POINTER(type2)->ty1, qual2, argArray))
+ return 0;
+ type1 = TYPE_MEMBER_POINTER(type1)->ty2;
+ type2 = TYPE_MEMBER_POINTER(type2)->ty2;
+ continue;
+
+ default:
+ if (CParser_IsSameOrMoreCVQualified(qual2, qual1))
+ return CTempl_DeduceType1(type1, qual2, type2, qual2, argArray, 0);
+ return 0;
+ }
+ }
+}
+
+static Boolean CTempl_DeduceType3(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray) {
+ Boolean flag = 0;
+
+ while (1) {
+ switch (type1->type) {
+ case TYPEPOINTER:
+ flag = 1;
+ if (type2->type != TYPEPOINTER)
+ return 0;
+ if (!CParser_IsSameOrMoreCVQualified(TPTR_QUAL(type2), TPTR_QUAL(type1)))
+ return 0;
+ type1 = TPTR_TARGET(type1);
+ type2 = TPTR_TARGET(type2);
+ continue;
+
+ case TYPEMEMBERPOINTER:
+ flag = 1;
+ if (type2->type != TYPEMEMBERPOINTER)
+ return 0;
+ if (!CParser_IsSameOrMoreCVQualified(TYPE_MEMBER_POINTER(type2)->qual, TYPE_MEMBER_POINTER(type1)->qual))
+ return 0;
+ if (!CTempl_DeduceType2(TYPE_MEMBER_POINTER(type1)->ty1, qual1, TYPE_MEMBER_POINTER(type2)->ty1, qual2, argArray))
+ return 0;
+ type1 = TYPE_MEMBER_POINTER(type1)->ty2;
+ type2 = TYPE_MEMBER_POINTER(type2)->ty2;
+ continue;
+
+ default:
+ if (!flag)
+ return 0;
+ if (CParser_IsSameOrMoreCVQualified(qual2, qual1))
+ return CTempl_DeduceType1(type1, qual2, type2, qual2, argArray, 0);
+ return 0;
+ }
+ }
+}
+
+static Boolean CTempl_DeduceType4(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray) {
+ if (IS_TYPE_POINTER_ONLY(type1)) {
+ if (!IS_TYPE_POINTER_ONLY(type2))
+ return 0;
+
+ if (!CParser_IsSameOrMoreCVQualified(TPTR_QUAL(type1), TPTR_QUAL(type2)))
+ return 0;
+
+ type1 = TPTR_TARGET(type1);
+ type2 = TPTR_TARGET(type2);
+ }
+
+ if (IS_TYPE_TEMPLATE(type1) && TYPE_TEMPLATE(type1)->dtype == TEMPLDEP_TEMPLATE && IS_TYPE_CLASS(type2)) {
+ if (CParser_IsSameOrMoreCVQualified(qual1, qual2))
+ return CTempl_DeduceTemplateTypeBase(
+ TYPE_TEMPLATE(type1)->u.templ.templ,
+ TYPE_TEMPLATE(type1)->u.templ.args,
+ TEMPL_CLASS_INST(type2),
+ argArray,
+ 1);
+ else
+ return 0;
+ }
+
+ return 0;
+}
+
+Boolean CTempl_DeduceType(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag1, Boolean flag2) {
+ Boolean flag31;
+ Boolean flag8;
+
+ flag31 = 0;
+ flag8 = 1;
+
+ if (flag1 || flag2) {
+ if (IS_TYPE_REFERENCE(type1)) {
+ type1 = TPTR_TARGET(type1);
+ flag31 = 1;
+ } else {
+ switch (type2->type) {
+ case TYPEFUNC:
+ type2 = CDecl_NewPointerType(type2);
+ break;
+ case TYPEARRAY:
+ type2 = CDecl_NewPointerType(TPTR_TARGET(type2));
+ break;
+ }
+
+ type1 = CParser_RemoveTopMostQualifiers(type1, &qual1);
+ type2 = CParser_RemoveTopMostQualifiers(type2, &qual2);
+ }
+ flag8 = 0;
+ }
+
+ if (CTempl_DeduceType1(type1, qual1, type2, qual2, argArray, flag8))
+ return 1;
+
+ if (flag1 || flag2) {
+ if (flag31 && CTempl_DeduceType2(type1, qual1, type2, qual2, argArray))
+ return 1;
+ if (CTempl_DeduceType3(type1, qual1, type2, qual2, argArray))
+ return 1;
+ if (flag1 && CTempl_DeduceType4(type1, qual1, type2, qual2, argArray))
+ return 1;
+ }
+
+ return 0;
+}
+
+static Boolean CTempl_TypeNeedsDeduction(Type *type) {
+ FuncArg *arg;
+ Boolean result;
+
+ while (1) {
+ switch (type->type) {
+ case TYPETEMPLATE:
+ switch (TYPE_TEMPLATE(type)->dtype) {
+ case TEMPLDEP_ARGUMENT:
+ if (
+ TYPE_TEMPLATE(type)->u.pid.index >= ctempl_explicitargs_num ||
+ TYPE_TEMPLATE(type)->u.pid.nindex != ctempl_explicitargs_nindex
+ )
+ ctempl_explicitargs_all = 0;
+ return 1;
+
+ case TEMPLDEP_QUALNAME:
+ CTempl_TypeNeedsDeduction(TYPE(TYPE_TEMPLATE(type)->u.qual.type));
+ return 1;
+
+ case TEMPLDEP_TEMPLATE:
+ ctempl_explicitargs_all = 0;
+ return 1;
+
+ case TEMPLDEP_ARRAY:
+ CTempl_TypeNeedsDeduction(TYPE_TEMPLATE(type)->u.array.type);
+ ctempl_explicitargs_all = 0;
+ return 1;
+
+ case TEMPLDEP_QUALTEMPL:
+ CTempl_TypeNeedsDeduction(TYPE(TYPE_TEMPLATE(type)->u.qualtempl.type));
+ ctempl_explicitargs_all = 0;
+ return 1;
+
+ case TEMPLDEP_BITFIELD:
+ default:
+ CError_FATAL(1357);
+ }
+
+ case TYPEVOID:
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPESTRUCT:
+ case TYPECLASS:
+ return 0;
+
+ case TYPEMEMBERPOINTER:
+ result = 0;
+ if (CTempl_TypeNeedsDeduction(TYPE_MEMBER_POINTER(type)->ty1))
+ result = 1;
+ if (CTempl_TypeNeedsDeduction(TYPE_MEMBER_POINTER(type)->ty2))
+ result = 1;
+ return result;
+
+ case TYPEPOINTER:
+ case TYPEARRAY:
+ type = TPTR_TARGET(type);
+ continue;
+
+ case TYPEFUNC:
+ result = 0;
+ for (arg = TYPE_FUNC(type)->args; arg && arg != &elipsis; arg = arg->next) {
+ if (CTempl_TypeNeedsDeduction(arg->type))
+ result = 1;
+ }
+
+ if (CTempl_TypeNeedsDeduction(TYPE_FUNC(type)->functype))
+ result = 1;
+ return result;
+
+ default:
+ CError_FATAL(1389);
+ }
+ }
+}
+
+static Boolean CTempl_MatchTemplFunc(Object *object, DeduceInfo *info, FuncArg *args, ENodeList *exprs, Match13 *match13ptr) {
+ Match13 match13;
+ int i;
+
+ memclrw(&match13, sizeof(match13));
+
+ while (1) {
+ if (!args || args->type == &stvoid) {
+ if (!exprs)
+ break;
+ return 0;
+ }
+
+ if (args == &elipsis)
+ break;
+ if (args == &oldstyle)
+ break;
+
+ if (!exprs) {
+ if (args->dexpr)
+ break;
+ return 0;
+ }
+
+ ctempl_explicitargs_nindex = info->x12C;
+ ctempl_explicitargs_num = info->count;
+ ctempl_explicitargs_all = 1;
+
+ if (CTempl_TypeNeedsDeduction(args->type)) {
+ if (!ctempl_explicitargs_all) {
+ UInt32 cv2;
+ UInt32 cv1;
+ Type *type2;
+ Type *type1;
+ UInt32 qual2;
+ UInt32 qual1;
+
+ type1 = args->type;
+ qual1 = args->qual & (Q_CONST | Q_VOLATILE);
+
+ type2 = exprs->node->rtype;
+ qual2 = ENODE_QUALS(exprs->node);
+
+ if (IS_TYPE_REFERENCE(type1)) {
+ type1 = TPTR_TARGET(type1);
+ cv1 = CParser_GetCVTypeQualifiers(type1, qual1);
+ cv2 = CParser_GetCVTypeQualifiers(type2, qual2);
+ if (
+ (!(cv1 & Q_CONST) && (cv2 & Q_CONST)) ||
+ (!(cv1 & Q_VOLATILE) && (cv2 & Q_VOLATILE))
+ )
+ return 0;
+
+ if (!(cv1 & Q_CONST) && !CExpr_IsLValue(exprs->node))
+ return 0;
+ }
+
+ type1 = CParser_RemoveTopMostQualifiers(type1, &qual1);
+ type2 = CParser_RemoveTopMostQualifiers(type2, &qual2);
+
+ if (ENODE_IS(exprs->node, EOBJREF) && IS_TEMPL_FUNC(exprs->node->data.objref->type))
+ return 0;
+
+ if (ENODE_IS(exprs->node, EOBJLIST)) {
+ NameSpaceObjectList *list;
+
+ for (list = exprs->node->data.objlist.list; list; list = list->next) {
+ if (list->object->otype == OT_OBJECT && IS_TEMPL_FUNC(OBJECT(list->object)->type))
+ break;
+ }
+
+ if (list)
+ return 0;
+
+ if (IS_TYPE_FUNC(type2))
+ type2 = CDecl_NewPointerType(type2);
+ }
+
+ ctempl_conversion_deduction = 0;
+ if (!CTempl_DeduceType(type1, qual1, type2, qual2, info->args, 1, 0))
+ return 0;
+
+ if (ctempl_conversion_deduction)
+ match13.anotherm5.x4++;
+ else
+ match13.anotherm5.x0++;
+
+ if (IS_TYPE_POINTER_ONLY(args->type))
+ CExpr_MatchCV(type2, qual2, args->type, args->qual, &match13);
+
+ } else {
+ Type *type;
+ UInt32 qual;
+
+ type = CTempl_GetSpecifiedType(CTemplTool_GetFuncTempl(object), args->type, args->qual, info->args, &qual);
+ if (type && !CExpr_MatchAssign(type, qual, exprs->node, &match13))
+ return 0;
+ }
+ } else {
+ if (copts.old_argmatch && !CExpr_MatchAssign(args->type, args->qual, exprs->node, &match13))
+ return 0;
+ }
+
+ exprs = exprs->next;
+ args = args->next;
+ }
+
+ for (i = 0; i < info->maxCount; i++) {
+ if (!info->args[i].is_deduced)
+ return 0;
+ info->args[i].next = &info->args[i + 1];
+ }
+ info->args[info->maxCount].next = NULL;
+
+ return CExpr_MatchCompare(object, match13ptr, &match13);
+}
+
+void CTempl_FuncMatch(NameSpaceObjectList *list, TemplArg *args, ENodeList *argexprs, Match13 *match13ptr, ENode *expr) {
+ Object *obj;
+ Object *success;
+ Object *object1;
+ FuncMatchArgs funcMatchArgs;
+ DeduceInfo info;
+ DeduceInfo info2;
+
+ object1 = match13ptr->obj;
+ success = NULL;
+ while (list) {
+ obj = OBJECT(list->object);
+ if (
+ obj->otype == OT_OBJECT &&
+ IS_TEMPL_FUNC(obj->type) &&
+ CExpr_GetFuncMatchArgs(obj, argexprs, expr, &funcMatchArgs) &&
+ CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(obj)->params, args, 0) &&
+ CTempl_MatchTemplFunc(obj, &info, funcMatchArgs.args, funcMatchArgs.exprs, match13ptr)
+ )
+ {
+ info2 = info;
+ if (info.args == info.argBuffer)
+ info2.args = info2.argBuffer;
+ success = obj;
+ }
+ list = list->next;
+ }
+
+ if (success) {
+ if (match13ptr->list) {
+ ENodeList *argexpr = argexprs;
+ int argexprcount = 0;
+ while (argexpr) {
+ argexpr = argexpr->next;
+ argexprcount++;
+ }
+
+ obj = CTempl_PartialOrdering(match13ptr->obj, match13ptr->list, argexprcount);
+ if (!obj) {
+ CError_OverloadedFunctionError(match13ptr->obj, match13ptr->list);
+ match13ptr->list = NULL;
+ if (object1)
+ match13ptr->obj = object1;
+ else
+ match13ptr->obj = CTempl_GetCreateFuncInstance(success, info2.args, NULL)->object;
+ } else {
+ NameSpaceObjectList mylist;
+ mylist.next = NULL;
+ mylist.object = OBJ_BASE(obj);
+ memclrw(match13ptr, sizeof(Match13));
+ CTempl_FuncMatch(&mylist, args, argexprs, match13ptr, expr);
+ }
+ } else {
+ match13ptr->obj = CTempl_GetCreateFuncInstance(success, info2.args, NULL)->object;
+ }
+ } else {
+ match13ptr->obj = object1;
+ }
+}
+
+static Boolean CExpr_DeduceFromObjList(FuncArg *arg, NameSpaceObjectList *list, DeduceInfo *info) {
+ TemplArg *savebuf;
+ NameSpaceObjectList *scan;
+ SInt32 size;
+
+ for (scan = list; scan; scan = scan->next) {
+ if (scan->object->otype == OT_OBJECT && IS_TEMPL_FUNC(OBJECT(scan->object)->type))
+ return 0;
+ }
+
+ size = sizeof(TemplArg) * info->maxCount;
+ savebuf = lalloc(size);
+
+ for (scan = list; scan; scan = scan->next) {
+ if (scan->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(scan->object)->type)) {
+ Object *obj;
+
+ memcpy(savebuf, info->args, size);
+
+ obj = OBJECT(scan->object);
+ if (CTempl_DeduceType(
+ arg->type, arg->qual & (Q_CONST | Q_VOLATILE),
+ obj->type, obj->qual,
+ savebuf, 1, 0
+ ))
+ {
+ memcpy(info->args, savebuf, size);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+Object *CTempl_DeduceFromFunctionCall(Object *funcobj, TemplArg *templargs, ENodeList *argexprs) {
+ DeduceInfo info;
+ FuncArg *arg;
+ int i;
+
+ CError_ASSERT(1655, IS_TEMPL_FUNC(funcobj->type));
+
+ if (CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(funcobj)->params, templargs, 0)) {
+ arg = TYPE_FUNC(funcobj->type)->args;
+ if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(funcobj->type))) {
+ CError_ASSERT(1664, arg);
+ arg = arg->next;
+ }
+
+ while (1) {
+ if (!arg || arg->type == &stvoid) {
+ if (argexprs)
+ return NULL;
+ break;
+ }
+
+ if (arg == &elipsis)
+ break;
+ if (arg == &oldstyle)
+ break;
+
+ if (!argexprs) {
+ if (arg->dexpr)
+ break;
+ return NULL;
+ }
+
+ ctempl_explicitargs_nindex = info.x12C;
+ ctempl_explicitargs_num = info.count;
+ ctempl_explicitargs_all = 1;
+
+ if (CTempl_TypeNeedsDeduction(arg->type) && !ctempl_explicitargs_all) {
+ ENode *node = argexprs->node;
+
+ if (ENODE_IS(node, EOBJREF) && IS_TEMPL_FUNC(node->data.objref->type))
+ return NULL;
+
+ if (ENODE_IS(node, EOBJLIST)) {
+ if (!CExpr_DeduceFromObjList(arg, node->data.objlist.list, &info))
+ return NULL;
+ } else {
+ if (!CTempl_DeduceType(
+ arg->type, arg->qual & (Q_CONST | Q_VOLATILE),
+ node->rtype, ENODE_QUALS(node),
+ info.args, 1, 0))
+ return NULL;
+ }
+ }
+
+ argexprs = argexprs->next;
+ arg = arg->next;
+ }
+
+ for (i = 0; i < info.maxCount; i++) {
+ if (!info.args[i].is_deduced)
+ return 0;
+ info.args[i].next = &info.args[i + 1];
+ }
+ info.args[info.maxCount].next = NULL;
+
+ return CTempl_GetCreateFuncInstance(funcobj, info.args, NULL)->object;
+ } else {
+ return NULL;
+ }
+}
+
+Object *CTempl_DeduceFromConversion(Object *funcobj, Type *type, UInt32 qual) {
+ DeduceInfo info;
+ int i;
+
+ CError_ASSERT(1745, IS_TEMPL_FUNC(funcobj->type));
+
+ if (!CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(funcobj)->params, NULL, 0))
+ return NULL;
+
+ ctempl_explicitargs_nindex = info.x12C;
+ ctempl_explicitargs_num = info.count;
+ ctempl_explicitargs_all = 1;
+
+ if (!CTempl_TypeNeedsDeduction(TYPE_FUNC(funcobj->type)->functype))
+ return NULL;
+
+ if (!CTempl_DeduceType(TYPE_FUNC(funcobj->type)->functype, TYPE_FUNC(funcobj->type)->qual, type, qual, info.args, 0, 1))
+ return NULL;
+
+ for (i = 0; i < info.maxCount; i++) {
+ if (!info.args[i].is_deduced)
+ return 0;
+ info.args[i].next = &info.args[i + 1];
+ }
+ info.args[info.maxCount].next = NULL;
+
+ return CTempl_GetCreateFuncInstance(funcobj, info.args, NULL)->object;
+}
+
+static int CTemplFunc_TemplateNestLevel(NameSpace *nspace) {
+ int level = 0;
+
+ while (nspace) {
+ if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL_ANY))
+ level++;
+ nspace = nspace->parent;
+ }
+
+ return level;
+}
+
+static Boolean CTemplFunc_SameFuncType(TypeFunc *a, TypeFunc *b) {
+ FuncArg *arg1;
+ FuncArg *arg2;
+
+ CError_ASSERT(1800, IS_TYPE_FUNC(a) && IS_TYPE_FUNC(b));
+
+ if (!is_typesame(a->functype, b->functype))
+ return 0;
+
+ if (a->qual != b->qual)
+ return 0;
+
+ if ((a->flags & FUNC_CALL_CONV_MASK) != (b->flags & FUNC_CALL_CONV_MASK))
+ return 0;
+
+ arg1 = a->args;
+ if ((a->flags & FUNC_METHOD) && !TYPE_METHOD(a)->is_static) {
+ CError_ASSERT(1808, arg1);
+ arg1 = arg1->next;
+ }
+
+ arg2 = b->args;
+ if ((b->flags & FUNC_METHOD) && !TYPE_METHOD(b)->is_static) {
+ CError_ASSERT(1814, arg2);
+ arg2 = arg2->next;
+ }
+
+ return is_arglistsame(arg1, arg2);
+}
+
+Object *CTempl_TemplateFunctionCheck(DeclInfo *di, NameSpaceObjectList *nsol) {
+ TemplArg *arg;
+ TemplFuncInstance *inst;
+ Object *object;
+
+ for (arg = di->expltargs; arg; arg = arg->next) {
+ switch (arg->pid.type) {
+ case TPT_TYPE:
+ if (CTemplTool_IsTemplateArgumentDependentType(arg->data.typeparam.type))
+ break;
+ continue;
+ case TPT_NONTYPE:
+ if (CTemplTool_IsTemplateArgumentDependentExpression(arg->data.paramdecl.expr))
+ break;
+ continue;
+ default:
+ CError_FATAL(1844);
+ }
+
+ break;
+ }
+
+ if (arg) {
+ while (nsol) {
+ object = OBJECT(nsol->object);
+ if (
+ object->otype == OT_OBJECT &&
+ IS_TEMPL_FUNC(object->type) &&
+ CTemplTool_IsSameTemplate(CTemplTool_GetFuncTempl(object)->params, di->expltargs) &&
+ CTemplFunc_SameFuncType(TYPE_FUNC(OBJECT(nsol->object)->type), TYPE_FUNC(di->thetype))
+ )
+ return OBJECT(nsol->object);
+
+ nsol = nsol->next;
+ }
+ } else {
+ while (nsol) {
+ object = OBJECT(nsol->object);
+ if (
+ object->otype == OT_OBJECT &&
+ IS_TEMPL_FUNC(object->type) &&
+ (inst = CTempl_DeduceFunc(object, TYPE_FUNC(di->thetype), di->expltargs, NULL, 1))
+ )
+ {
+ if (di->x3C) {
+ if (!(di->qual & Q_INLINE)) {
+ if (!inst->is_specialized)
+ inst->object->qual &= ~Q_INLINE;
+ } else {
+ inst->object->qual |= Q_INLINE;
+ }
+
+ if (!inst->is_specialized && inst->is_instantiated)
+ CError_Error(CErrorStr335);
+
+ if (di->x3C != (CTemplFunc_TemplateNestLevel(inst->object->nspace) + 1))
+ CError_Warning(CErrorStr335);
+
+ inst->is_specialized = 1;
+ di->x3C = 0;
+ }
+
+ CTemplTool_MergeArgNames(TYPE_FUNC(di->thetype), TYPE_FUNC(inst->object->type));
+ di->x38 = CTemplTool_GetFuncTempl(OBJECT(nsol->object));
+ return inst->object;
+ }
+ nsol = nsol->next;
+ }
+ }
+
+ CError_ResetErrorSkip();
+ CError_Error(CErrorStr335);
+ di->x3C = 0;
+ return NULL;
+}
diff --git a/compiler_and_linker/FrontEnd/C/CTemplateNew.c b/compiler_and_linker/FrontEnd/C/CTemplateNew.c
new file mode 100644
index 0000000..c33534a
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CTemplateNew.c
@@ -0,0 +1,1880 @@
+#include "compiler/CTemplateNew.h"
+#include "compiler/CBrowse.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInit.h"
+#include "compiler/CInline.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CScope.h"
+#include "compiler/CTemplateClass.h"
+#include "compiler/CTemplateTools.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/ObjGenMachO.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/templates.h"
+
+TemplClass *ctempl_templates;
+TemplateFunction *ctempl_templatefuncs;
+TemplStack *ctempl_curinstance;
+static jmp_buf ctempl_parseparse;
+static Boolean ctempl_scanfuncparams;
+
+// forward decls
+static TemplParam *CTempl_ParseParamList(NameSpace *nspace, UInt8 nindex);
+static Boolean CTempl_GenClassInstance(TemplClassInst *inst, Boolean flag);
+
+void CTempl_Setup(void) {
+ ctempl_curinstance = NULL;
+ ctempl_templates = NULL;
+ ctempl_templatefuncs = NULL;
+ ctempl_instdepth = 0;
+ ctempl_scanfuncparams = 0;
+}
+
+void CTempl_Cleanup(void) {
+}
+
+static short CTempl_MemberParseLex(void) {
+ switch ((tk = lex())) {
+ case ';':
+ case '=':
+ case '{':
+ case '}':
+ longjmp(ctempl_parseparse, 1);
+ }
+
+ return tk;
+}
+
+static void CTempl_MemberParseTemplArgList(void) {
+ struct {
+ char ch;
+ char flag;
+ } stack[256];
+ int pos;
+
+ stack[0].ch = '>';
+ stack[0].flag = 1;
+ pos = 0;
+ while (1) {
+ switch (CTempl_MemberParseLex()) {
+ case '<':
+ if (stack[pos].flag) {
+ if (pos >= 255)
+ longjmp(ctempl_parseparse, 1);
+ stack[++pos].ch = '>';
+ stack[pos].flag = 1;
+ }
+ continue;
+ case '(':
+ if (pos >= 255)
+ longjmp(ctempl_parseparse, 1);
+ stack[++pos].ch = ')';
+ stack[pos].flag = 0;
+ continue;
+ case '[':
+ if (pos >= 255)
+ longjmp(ctempl_parseparse, 1);
+ stack[++pos].ch = ']';
+ stack[pos].flag = 0;
+ continue;
+ case '>':
+ if (!(stack[pos].flag))
+ continue;
+ case ')':
+ case ']':
+ break;
+ default:
+ continue;
+ }
+
+ if (tk != stack[pos].ch)
+ longjmp(ctempl_parseparse, 1);
+ if (--pos < 0)
+ break;
+ }
+}
+
+static Type *CTempl_MemberParseTempl(HashNameNode *name) {
+ Type *type;
+
+ type = CScope_GetTagType(cscope_current, name);
+ if (!type || !IS_TEMPL_CLASS(type))
+ longjmp(ctempl_parseparse, 1);
+
+ CTempl_MemberParseTemplArgList();
+ if (lookahead() != TK_COLON_COLON)
+ return NULL;
+ CTempl_MemberParseLex();
+
+ while (1) {
+ switch (CTempl_MemberParseLex()) {
+ case TK_IDENTIFIER:
+ switch (lookahead()) {
+ case '(':
+ case ')':
+ case ';':
+ case '=':
+ case '[':
+ return type;
+ case TK_COLON_COLON:
+ CTempl_MemberParseLex();
+ continue;
+ default:
+ return NULL;
+ }
+ break;
+ case '~':
+ case TK_OPERATOR:
+ return type;
+ default:
+ return NULL;
+ }
+ }
+}
+
+static Boolean CTempl_ParseTemplateMember(void) {
+ HashNameNode *name;
+ SInt32 state;
+
+ CPrep_UnLex();
+ CPrep_TokenStreamGetState(&state);
+
+ if (setjmp(ctempl_parseparse) == 0) {
+ while (1) {
+ switch (CTempl_MemberParseLex()) {
+ case TK_IDENTIFIER:
+ name = tkidentifier;
+ switch (lookahead()) {
+ case '<':
+ CTempl_MemberParseLex();
+ if (CTempl_MemberParseTempl(name)) {
+ CError_FATAL(228);
+ return 1;
+ }
+ break;
+ case TK_COLON_COLON:
+ CTempl_MemberParseLex();
+ while (1) {
+ if (CTempl_MemberParseLex() != TK_IDENTIFIER)
+ break;
+ if (lookahead() != TK_COLON_COLON)
+ break;
+ CTempl_MemberParseLex();
+ }
+ break;
+ }
+ break;
+ case 0:
+ return 0;
+ default:
+ continue;
+ }
+ break;
+ }
+
+ while (1) {
+ switch (CTempl_MemberParseLex()) {
+ case TK_IDENTIFIER:
+ name = tkidentifier;
+ if (CTempl_MemberParseLex() == '<') {
+ if (CTempl_MemberParseTempl(name)) {
+ CError_FATAL(265);
+ return 1;
+ }
+ }
+ break;
+ case 0:
+ return 0;
+ default:
+ continue;
+ }
+ break;
+ }
+ }
+
+ CPrep_TokenStreamSetState(&state);
+ tk = lex();
+ return 0;
+}
+
+static Type *CTempl_ParseTemplArgType(UInt32 *resultQual) {
+ DeclInfo di;
+
+ memclrw(&di, sizeof(di));
+ CParser_GetDeclSpecs(&di, 0);
+
+ if (di.storageclass)
+ CError_Error(CErrorStr177);
+ if (di.x48)
+ CError_Error(CErrorStr121);
+
+ CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_REFERENCE | Q_ALIGNED_MASK));
+
+ scandeclarator(&di);
+ if (di.name)
+ CError_Error(CErrorStr121);
+
+ CTemplTool_CheckTemplArgType(di.thetype);
+
+ *resultQual = di.qual;
+ return di.thetype;
+}
+
+static ENode *CTempl_ParseTemplArgExpr(Type *type, UInt32 qual) {
+ ENode *expr;
+ ENode *copy;
+
+ disallowgreaterthan = 1;
+ if (copts.old_argmatch)
+ expr = conv_assignment_expression();
+ else
+ expr = assignment_expression();
+ disallowgreaterthan = 0;
+
+ if (type && !CTemplTool_IsTemplateArgumentDependentType(type) && !IS_TYPE_TEMPLDEPEXPR(expr->rtype)) {
+ expr = argumentpromotion(expr, type, qual, 1);
+ if (IS_TYPE_POINTER_ONLY(type)) {
+ if (ENODE_IS(expr, ETYPCON) && ENODE_IS(expr->data.monadic, EINTCONST))
+ expr = expr->data.monadic;
+ if (ENODE_IS(expr, EINTCONST))
+ expr->rtype = type;
+ }
+ }
+
+ if (!IS_TYPE_TEMPLDEPEXPR(expr->rtype)) {
+ if (!copts.old_argmatch)
+ expr = pointer_generation(expr);
+
+ switch (expr->type) {
+ case EINTCONST:
+ break;
+ case EOBJREF:
+ if (CParser_HasInternalLinkage2(expr->data.objref))
+ CError_Error(CErrorStr357);
+ break;
+ case EOBJLIST:
+ CError_Error(CErrorStr199);
+ expr = nullnode();
+ break;
+ default:
+ CError_Error(CErrorStr371);
+ expr = nullnode();
+ }
+
+ copy = galloc(sizeof(ENode));
+ *copy = *expr;
+ return copy;
+ } else {
+ return CInline_CopyExpression(expr, CopyMode1);
+ }
+}
+
+static Type *CTempl_ParseTemplArgTempl(TemplParam *params) {
+ NameResult pr;
+
+ if (
+ (tk != TK_IDENTIFIER && tk != TK_COLON_COLON) ||
+ !CScope_ParseDeclName(&pr) ||
+ !pr.type
+ )
+ {
+ CError_Error(CErrorStr121);
+ tk = lex();
+ return NULL;
+ }
+
+ if (IS_TEMPL_CLASS(pr.type)) {
+ if (params && !CTemplTool_EqualParams(params->data.templparam.plist, TEMPL_CLASS(pr.type)->templ__params, 0)) {
+ CError_Error(CErrorStr235);
+ tk = lex();
+ return NULL;
+ }
+ } else {
+ if (!CTemplTool_IsTemplateArgumentDependentType(pr.type))
+ CError_Error(CErrorStr146);
+ }
+
+ tk = lex();
+ return pr.type;
+}
+
+static UInt8 CTempl_GetTemplateNestIndex(NameSpace *nspace) {
+ UInt8 count = 0;
+
+ while (nspace) {
+ if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL_ANY))
+ count++;
+ nspace = nspace->parent;
+ }
+
+ return count;
+}
+
+static TemplParam *CTempl_ParseParam(NameSpace *nspace, TemplParam *param, UInt16 index, UInt8 nindex) {
+ DeclInfo di;
+ SInt32 savedState;
+ short startToken;
+
+ param = galloc(sizeof(TemplParam));
+ memclrw(param, sizeof(TemplParam));
+
+ param->pid.index = index;
+ param->pid.nindex = nindex;
+
+ CPrep_TokenStreamGetState(&savedState);
+
+ switch ((startToken = tk)) {
+ case TK_CLASS:
+ case TK_TYPENAME:
+ if ((tk = lex()) == TK_IDENTIFIER) {
+ param->name = tkidentifier;
+ tk = lex();
+ }
+
+ switch (tk) {
+ case ',':
+ case '>':
+ break;
+ case '=':
+ tk = lex();
+ param->data.typeparam.type = CTempl_ParseTemplArgType(&param->data.typeparam.qual);
+ break;
+ default:
+ param->name = NULL;
+ CPrep_TokenStreamSetState(&savedState);
+ tk = startToken;
+ goto defaultProc;
+ }
+
+ param->pid.type = TPT_TYPE;
+ break;
+
+ case TK_TEMPLATE:
+ if ((tk = lex()) != '<') {
+ CError_Error(CErrorStr230);
+ return NULL;
+ }
+
+ tk = lex();
+ param->data.templparam.plist = CTempl_ParseParamList(nspace, 0);
+
+ if (tk == '>')
+ tk = lex();
+ else
+ CError_Error(CErrorStr231);
+
+ if (tk == TK_CLASS)
+ tk = lex();
+ else
+ CError_Error(CErrorStr121);
+
+ if (tk == TK_IDENTIFIER) {
+ param->name = tkidentifier;
+ tk = lex();
+ }
+
+ if (tk == '=') {
+ tk = lex();
+ param->data.templparam.defaultarg = CTempl_ParseTemplArgTempl(param);
+ }
+
+ param->pid.type = TPT_TEMPLATE;
+ break;
+
+ default:
+ defaultProc:
+ memclrw(&di, sizeof(di));
+ CParser_GetDeclSpecs(&di, 0);
+
+ if (di.storageclass)
+ CError_Error(CErrorStr177);
+
+ CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_REFERENCE | Q_ALIGNED_MASK));
+
+ scandeclarator(&di);
+
+ switch (di.thetype->type) {
+ case TYPEARRAY:
+ di.thetype = CDecl_NewPointerType(TPTR_TARGET(di.thetype));
+ break;
+ case TYPEFUNC:
+ di.thetype = CDecl_NewPointerType(di.thetype);
+ break;
+ case TYPEMEMBERPOINTER:
+ CError_Error(CErrorStr190);
+ di.thetype = TYPE(&stsignedint);
+ break;
+ case TYPEINT:
+ case TYPEENUM:
+ case TYPETEMPLATE:
+ case TYPEPOINTER:
+ break;
+ default:
+ CError_Error(CErrorStr229);
+ di.thetype = TYPE(&stsignedint);
+ }
+
+ di.thetype = CParser_RemoveTopMostQualifiers(di.thetype, &di.qual);
+ param->name = di.name;
+ param->data.paramdecl.type = di.thetype;
+ param->data.paramdecl.qual = di.qual;
+ if (tk == '=') {
+ tk = lex();
+ param->data.paramdecl.defaultarg = CTempl_ParseTemplArgExpr(di.thetype, di.qual);
+ }
+
+ param->pid.type = TPT_NONTYPE;
+ break;
+ }
+
+ if (param->name)
+ CTemplTool_InsertTemplateParameter(nspace, param);
+
+ return param;
+}
+
+static TemplParam *CTempl_ParseParamList(NameSpace *nspace, UInt8 nindex) {
+ TemplParam *params;
+ TemplParam **ptr;
+ TemplParam *param;
+ TemplParam *scan;
+ UInt16 index;
+
+ params = NULL;
+ index = 0;
+ ptr = &params;
+
+ while (1) {
+ param = CTempl_ParseParam(nspace, params, index, nindex);
+ if (!param)
+ break;
+
+ if (param->name) {
+ for (scan = params; scan; scan = scan->next) {
+ if (scan->name == param->name)
+ CError_Error(CErrorStr122, param->name->name);
+ }
+ }
+
+ *ptr = param;
+ ptr = &param->next;
+
+ if (tk != ',')
+ break;
+
+ tk = lex();
+ index++;
+ }
+
+ if (!params)
+ CError_Error(CErrorStr229);
+
+ return params;
+}
+
+TemplArg *CTempl_ParseUncheckTemplArgs(TemplParam *params, Boolean is_global) {
+ TemplArg *args;
+ TemplArg *last;
+ UInt16 index;
+
+ if (tk != '<') {
+ CError_Error(CErrorStr230);
+ return NULL;
+ }
+
+ if ((tk = lex()) == '>')
+ return NULL;
+
+ args = NULL;
+ index = 0;
+ while (1) {
+ if (is_global) {
+ if (args) {
+ last->next = galloc(sizeof(TemplArg));
+ last = last->next;
+ } else {
+ last = galloc(sizeof(TemplArg));
+ args = last;
+ }
+ } else {
+ if (args) {
+ last->next = lalloc(sizeof(TemplArg));
+ last = last->next;
+ } else {
+ last = galloc(sizeof(TemplArg));
+ args = last;
+ }
+ }
+
+ last->next = NULL;
+
+ if (!params) {
+ Type *type;
+ UInt32 qual;
+ Boolean flag;
+
+ last->pid.index = index;
+ last->pid.nindex = 0;
+
+ if ((type = CParser_ParseTypeID(&qual, &flag))) {
+ if (flag) {
+ last->data.ttargtype = type;
+ last->pid.type = TPT_TEMPLATE;
+ } else {
+ last->data.typeparam.type = type;
+ last->data.typeparam.qual = qual;
+ last->pid.type = TPT_TYPE;
+ }
+ } else {
+ last->data.paramdecl.expr = CTempl_ParseTemplArgExpr(NULL, 0);
+ last->pid.type = TPT_NONTYPE;
+ }
+ } else {
+ last->pid = params->pid;
+ switch (last->pid.type) {
+ case TPT_TYPE:
+ last->data.typeparam.type = CTempl_ParseTemplArgType(&last->data.typeparam.qual);
+ break;
+ case TPT_NONTYPE:
+ last->data.paramdecl.expr = CTempl_ParseTemplArgExpr(NULL, 0);
+ break;
+ case TPT_TEMPLATE:
+ if (!(last->data.ttargtype = CTempl_ParseTemplArgTempl(params)))
+ return NULL;
+ break;
+ default:
+ CError_FATAL(674);
+ }
+ params = params->next;
+ }
+
+ if (tk == '>')
+ return args;
+
+ if (tk != ',') {
+ CError_Error(CErrorStr116);
+ return NULL;
+ }
+
+ tk = lex();
+ index++;
+ }
+}
+
+static TemplArg *CTempl_ParseTemplArgs(TemplClass **resultTempl, TemplArg **resultArgs) {
+ TemplParam *param;
+ TemplParam *params;
+ TemplArg *args;
+ TemplArg **ptr;
+ TemplArg *arg;
+
+ params = (*resultTempl)->templ__params;
+ *resultArgs = NULL;
+
+ if (tk != '<') {
+ CError_Error(CErrorStr230);
+ return NULL;
+ }
+
+ tk = lex();
+
+ param = params;
+ args = NULL;
+ ptr = &args;
+
+ while (param) {
+ arg = galloc(sizeof(TemplArg));
+ memclrw(arg, sizeof(TemplArg));
+
+ *ptr = arg;
+ ptr = &arg->next;
+
+ arg->pid = param->pid;
+
+ if (tk != '>') {
+ switch (arg->pid.type) {
+ case TPT_TYPE:
+ arg->data.typeparam.type = CTempl_ParseTemplArgType(&arg->data.typeparam.qual);
+ break;
+
+ case TPT_NONTYPE:
+ if (CTemplTool_IsTemplateArgumentDependentType(param->data.paramdecl.type)) {
+ Type *type;
+ UInt32 qual;
+
+ type = CTemplTool_DeduceArgDepType(args, param->data.paramdecl.type, param->data.paramdecl.qual, &qual);
+ arg->data.paramdecl.expr = CTempl_ParseTemplArgExpr(type, qual);
+ } else {
+ arg->data.paramdecl.expr = CTempl_ParseTemplArgExpr(param->data.paramdecl.type, param->data.paramdecl.qual);
+ }
+ break;
+
+ case TPT_TEMPLATE:
+ if (!(arg->data.ttargtype = CTempl_ParseTemplArgTempl(param)))
+ return NULL;
+ break;
+
+ default:
+ CError_FATAL(742);
+ }
+
+ if (tk != '>') {
+ if (tk != ',') {
+ CError_Error(CErrorStr232);
+ return NULL;
+ }
+
+ if ((tk = lex()) == '>') {
+ CError_Error(CErrorStr232);
+ return NULL;
+ }
+ }
+ } else {
+ switch (arg->pid.type) {
+ case TPT_TYPE:
+ if (!param->data.typeparam.type) {
+ CError_Error(CErrorStr232);
+ return NULL;
+ }
+
+ arg->data.typeparam.type = param->data.typeparam.type;
+ arg->data.typeparam.qual = param->data.typeparam.qual;
+
+ if (CTemplTool_IsTemplateArgumentDependentType(param->data.typeparam.type)) {
+ TypeDeduce deduce;
+ memclrw(&deduce, sizeof(deduce));
+ deduce.tmclass = *resultTempl;
+ deduce.inst = NULL;
+ deduce.params = params;
+ deduce.args = args;
+
+ arg->data.typeparam.qual = param->data.typeparam.qual;
+ arg->data.typeparam.type = CTemplTool_DeduceTypeCopy(&deduce, arg->data.typeparam.type, &arg->data.typeparam.qual);
+ }
+ break;
+
+ case TPT_NONTYPE:
+ if (!param->data.paramdecl.defaultarg) {
+ CError_Error(CErrorStr232);
+ return NULL;
+ }
+
+ if (IS_TYPE_TEMPLDEPEXPR(param->data.paramdecl.defaultarg->rtype)) {
+ TypeDeduce deduce;
+ memclrw(&deduce, sizeof(deduce));
+ deduce.tmclass = *resultTempl;
+ deduce.inst = NULL;
+ deduce.params = params;
+ deduce.args = args;
+
+ arg->data.paramdecl.expr = CInline_CopyExpression(
+ CTemplTool_DeduceExpr(&deduce, param->data.paramdecl.defaultarg), CopyMode1);
+ } else {
+ arg->data.paramdecl.expr = param->data.paramdecl.defaultarg;
+ }
+ break;
+
+ case TPT_TEMPLATE:
+ if (!param->data.templparam.defaultarg) {
+ CError_Error(CErrorStr232);
+ return NULL;
+ }
+
+ if (IS_TEMPL_CLASS(param->data.templparam.defaultarg)) {
+ arg->data.ttargtype = param->data.templparam.defaultarg;
+ break;
+ }
+
+ if (CTemplTool_IsTemplateArgumentDependentType(param->data.templparam.defaultarg)) {
+ CError_Error(CErrorStr190);
+ return NULL;
+ }
+
+ CError_FATAL(817);
+
+ default:
+ CError_FATAL(820);
+ }
+ }
+
+ param = param->next;
+ }
+
+ if (tk != '>') {
+ CError_Error(CErrorStr231);
+ return NULL;
+ }
+
+ if ((*resultTempl)->pspecs)
+ return args;
+
+ return args;
+}
+
+Type *CTempl_ParseTemplTemplParam(TypeTemplDep *type) {
+ TemplArg *args;
+ Type *newType;
+
+ tk = lex();
+ if (!(args = CTempl_ParseUncheckTemplArgs(NULL, 1))) {
+ CError_Error(CErrorStr121);
+ return TYPE(&stsignedint);
+ }
+
+ newType = CDecl_NewTemplDepType(TEMPLDEP_QUALTEMPL);
+ TYPE_TEMPLATE(newType)->u.qualtempl.type = type;
+ TYPE_TEMPLATE(newType)->u.qualtempl.args = args;
+ return newType;
+}
+
+Type *CTempl_ClassGetType(TemplClass *templ) {
+ TemplClass *owner;
+ TemplArg *ownerArgs;
+ TemplArg *args;
+ Type *type;
+
+ owner = templ;
+ if (templ->pspec_owner)
+ owner = templ->pspec_owner;
+
+ if (!(args = CTempl_ParseTemplArgs(&owner, &ownerArgs)))
+ return &stvoid;
+
+ if ((type = CTemplTool_IsDependentTemplate(owner, args)))
+ return type;
+
+ return TYPE(CTemplClass_GetInstance(owner, args, ownerArgs));
+}
+
+static void CTempl_SetupClassParamNameSpace(DeclFucker *what_is_this, TypeClass *tclass) {
+ cscope_current = tclass->nspace;
+}
+
+Boolean CTempl_IsQualifiedMember(DeclInfo *di, Type *type, NameSpace **resultnspace) {
+ if (
+ TYPE_TEMPLATE(type)->dtype == TEMPLDEP_QUALNAME &&
+ (type = CTemplTool_GetSelfRefTemplate(TYPE(TYPE_TEMPLATE(type)->u.qual.type)))
+ )
+ {
+ *resultnspace = TYPE_CLASS(type)->nspace;
+ CError_ASSERT(948, di->fucker34 && (*resultnspace)->theclass);
+
+ CTempl_SetupClassParamNameSpace(di->fucker34, (*resultnspace)->theclass);
+ di->fucker34 = NULL;
+ return 1;
+ }
+
+ return 0;
+}
+
+static void *CTempl_ParseMemberFunction(int unk1, int unk2, int unk3, Object *func) {
+ // no idea what should've been here, it's not called
+
+ CError_ASSERT(974, TYPE_FUNC(func->type)->flags & FUNC_METHOD);
+
+ return NULL;
+}
+
+static void CTempl_ParseMember(TemplParam *params, TemplClass *templ, DeclInfo *di, SInt32 *startOffset) {
+ Object *object;
+ NameSpaceObjectList *nsol;
+ TokenStream stream;
+ CPrepFileInfo *file;
+ SInt32 offset;
+ Boolean saveForceLoc;
+ TemplateMember *member;
+
+ if (templ->theclass.flags & CLASS_IS_TEMPL)
+ di->thetype = CTemplTool_ResolveMemberSelfRefs(templ, di->thetype, &di->qual);
+
+ if (IS_TYPE_FUNC(di->thetype)) {
+ Boolean flag;
+ if (!(object = CDecl_GetFunctionObject(di, NULL, &flag, 0))) {
+ CError_Error(CErrorStr140, di->name->name);
+ return;
+ }
+
+ if (tk != '{' && tk != TK_TRY && tk != ':') {
+ if (tk != ';')
+ CError_Error(CErrorStr123);
+ else
+ tk = lex();
+ return;
+ }
+
+ if (
+ (TYPE_FUNC(object->type)->flags & FUNC_DEFINED) &&
+ (!(TYPE_FUNC(object->type)->flags & FUNC_IS_TEMPL) || object->u.func.u.templ->instances)
+ )
+ CError_Error(CErrorStr333, object);
+
+ TYPE_FUNC(object->type)->flags |= FUNC_IS_TEMPL_INSTANCE | FUNC_DEFINED;
+
+ CPrep_StreamGetBlock(&stream, NULL, 1);
+ saveForceLoc = gForceSourceLoc;
+ gForceSourceLoc = 1;
+ CPrep_BrowserFilePosition(&file, &offset);
+ gForceSourceLoc = saveForceLoc;
+
+ if (file && file->recordbrowseinfo && *startOffset >= 0 && offset > *startOffset)
+ CBrowse_NewFunction(object, file, file, *startOffset, offset + 1);
+ } else {
+ if (!(nsol = CScope_GetLocalObject(templ->theclass.nspace, di->name))) {
+ CError_Error(CErrorStr140, di->name->name);
+ return;
+ }
+
+ object = OBJECT(nsol->object);
+ if (object->otype != OT_OBJECT) {
+ CError_Error(CErrorStr122, di->name->name);
+ return;
+ }
+
+ if (
+ !is_typesame(di->thetype, object->type) ||
+ (object->qual & (Q_CONST | Q_VOLATILE | Q_PASCAL)) != (di->qual & (Q_CONST | Q_VOLATILE | Q_PASCAL))
+ )
+ {
+ CError_Error(CErrorStr249, CError_GetObjectName(object), object->type, object->qual, di->thetype, di->qual);
+ return;
+ }
+
+ CError_ASSERT(1070, object->datatype == DDATA);
+
+ CPrep_StreamGetSemicolon(&stream, NULL);
+ }
+
+ if (stream.tokens) {
+ if (IS_TEMPL_FUNC(object->type) != 0) {
+ if (!CTemplTool_EqualParams(object->u.func.u.templ->params, params, 0))
+ CError_Error(CErrorStr235);
+
+ object->u.func.u.templ->stream = stream;
+ } else {
+ if (!(templ->theclass.flags & CLASS_IS_TEMPL)) {
+ CError_Error(CErrorStr190);
+ return;
+ }
+
+ member = CTemplClass_DefineMember(templ, object, &cparser_fileoffset, &stream);
+ if (templ->templ__params) {
+ if (!CTemplTool_EqualParams(templ->templ__params, params, 0)) {
+ CError_Error(CErrorStr235);
+ return;
+ }
+
+ member->params = params;
+ }
+ }
+ }
+}
+
+static TemplateFunction *CTempl_DeclareTemplateFunction(DeclInfo *di, TemplParam *params, TypeClass *tclass, AccessType access, Boolean flag) {
+ TemplateFunction *templ;
+ Object *object;
+
+ if (tclass) {
+ CError_ASSERT(1122, cscope_current->theclass);
+ di->thetype = TYPE(CDecl_MakeTypeMemberFunc(TYPE_FUNC(di->thetype), cscope_current->theclass, flag));
+ } else {
+ access = ACCESSPUBLIC;
+ }
+
+ templ = galloc(sizeof(TemplateFunction));
+ memclrw(templ, sizeof(TemplateFunction));
+
+ templ->next = ctempl_templatefuncs;
+ ctempl_templatefuncs = templ;
+
+ templ->params = params;
+ templ->name = di->name;
+ templ->deftoken = symdecltoken;
+
+ object = CParser_NewFunctionObject(NULL);
+ object->access = access;
+ object->name = di->name;
+ object->u.func.linkname = CParser_GetUniqueName();
+ object->type = di->thetype;
+ object->qual = di->qual | Q_MANGLE_NAME;
+ object->sclass = di->storageclass;
+ TYPE_FUNC(object->type)->flags |= FUNC_IS_TEMPL;
+ object->u.func.u.templ = templ;
+
+ if (di->qual & Q_INLINE)
+ object->sclass = TK_STATIC;
+
+ templ->tfunc = object;
+ CScope_AddObject(cscope_current, di->name, OBJ_BASE(object));
+
+ return templ;
+}
+
+static void CTempl_ParseTemplateFunction(TemplateFunction *templ, TypeClass *tclass, SInt32 *startOffset) {
+ Object *object;
+ CPrepFileInfo *file;
+ SInt32 offset;
+ Boolean saveForceLoc;
+
+ object = templ->tfunc;
+
+ if (tk == '{' || tk == ':' || tk == TK_TRY) {
+ if (tclass) {
+ object->qual |= Q_INLINE;
+ object->sclass = TK_STATIC;
+ }
+
+ if (TYPE_FUNC(object->type)->flags & FUNC_DEFINED)
+ CError_Error(CErrorStr333, object);
+
+ TYPE_FUNC(object->type)->flags |= FUNC_DEFINED | FUNC_IS_TEMPL_INSTANCE;
+
+ CPrep_StreamGetBlock(&templ->stream, NULL, 0);
+
+ if (lookahead() == ';')
+ tk = lex();
+ else
+ tk = ';';
+
+ saveForceLoc = gForceSourceLoc;
+ gForceSourceLoc = 1;
+ CPrep_BrowserFilePosition(&file, &offset);
+ gForceSourceLoc = saveForceLoc;
+
+ if (file && *startOffset >= 0 && offset > *startOffset) {
+ templ->srcfile = file;
+ templ->startoffset = *startOffset;
+ templ->endoffset = offset + 1;
+ if (cparamblkptr->browseoptions.recordTemplates && file->recordbrowseinfo)
+ CBrowse_NewTemplateFunc(templ);
+ }
+
+ } else {
+ if (tk != ';')
+ CError_Error(CErrorStr121);
+ }
+}
+
+static HashNameNode *CTempl_FindConversionFuncName(TypeClass *tclass, Type *type, UInt32 qual) {
+ Object *object;
+ CScopeObjectIterator iter;
+
+ CScope_InitObjectIterator(&iter, tclass->nspace);
+ do {
+ if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter))))
+ return NULL;
+ } while (
+ !IS_TYPE_FUNC(object->type) ||
+ !(TYPE_FUNC(object->type)->flags & FUNC_CONVERSION) ||
+ (TYPE_FUNC(object->type)->qual & (Q_CONST | Q_VOLATILE)) != (qual & (Q_CONST | Q_VOLATILE)) ||
+ !is_typesame(TYPE_FUNC(object->type)->functype, type)
+ );
+
+ return object->name;
+}
+
+static void CTempl_ParseConversionFunctionTemplate(DeclInfo *di, DeclFucker *what_is_this, TemplParam *params, TypeClass *tclass, SInt32 *startOffset, AccessType access) {
+ tk = lex();
+ if (!tclass) {
+ CError_Error(CErrorStr121);
+ return;
+ }
+
+ tclass->flags = tclass->flags | CLASS_IS_CONVERTIBLE;
+ CError_QualifierCheck(di->qual & ~Q_INLINE);
+
+ conversion_type_name(di);
+ CDecl_NewConvFuncType(di);
+
+ if (cscope_current->is_templ) {
+ CError_ASSERT(1260, cscope_current == what_is_this->nspace);
+ cscope_current = what_is_this->nspace->parent;
+ }
+
+ CTempl_ParseTemplateFunction(CTempl_DeclareTemplateFunction(di, params, tclass, access, 0), tclass, startOffset);
+}
+
+static void CTempl_ParseFunctionOrMemberTemplate(DeclFucker *what_is_this, TemplParam *params, TypeClass *tclass, SInt32 *startOffset, AccessType access, Boolean mysteryFlag) {
+ NameSpaceObjectList *nsol;
+ Object *object;
+ TemplParam *param;
+ TemplateFunction *templfunc;
+ Boolean disallowCVFlag;
+ TypeClass *tclass2;
+ Type *type;
+ UInt32 qual;
+ DeclInfo di;
+
+ for (param = params; param; param = param->next) {
+ switch (param->pid.type) {
+ case TPT_TYPE:
+ if (param->data.typeparam.type) {
+ CError_Error(CErrorStr378);
+ param->data.typeparam.type = NULL;
+ }
+ break;
+ case TPT_NONTYPE:
+ if (param->data.paramdecl.defaultarg) {
+ CError_Error(CErrorStr378);
+ param->data.paramdecl.defaultarg = NULL;
+ }
+ break;
+ case TPT_TEMPLATE:
+ if (param->data.templparam.defaultarg) {
+ CError_Error(CErrorStr378);
+ param->data.templparam.defaultarg = NULL;
+ }
+ break;
+ default:
+ CError_FATAL(1317);
+ }
+ }
+
+ disallowCVFlag = 0;
+ ctempl_scanfuncparams = 1;
+
+ memclrw(&di, sizeof(di));
+ di.x51 = mysteryFlag;
+
+ if (tk == TK_OPERATOR) {
+ CTempl_ParseConversionFunctionTemplate(&di, what_is_this, params, tclass, startOffset, access);
+ return;
+ }
+
+ CParser_GetDeclSpecs(&di, 1);
+ if (tk == ';' && IS_TEMPL_CLASS(di.thetype))
+ return;
+
+ if (di.x10 || di.x14) {
+ TypeFunc *tfunc;
+
+ if (di.x14) {
+ di.x10 = OBJECT(di.x14->object);
+ CError_ASSERT(1342, di.x10->otype == OT_OBJECT);
+ }
+
+ CError_ASSERT(1344, IS_TYPE_FUNC(di.x10->type));
+
+ tfunc = TYPE_FUNC(di.x10->type);
+ if (tfunc->flags & FUNC_CONVERSION) {
+ di.thetype = tfunc->functype;
+ di.qual |= tfunc->qual;
+ di.nspace = di.x10->nspace;
+ di.name = di.x10->name;
+ } else if (tfunc->flags & FUNC_IS_CTOR) {
+ di.thetype = TYPE(&void_ptr);
+ di.nspace = di.x10->nspace;
+ di.name = di.x10->name;
+ } else {
+ CError_Error(CErrorStr121);
+ return;
+ }
+
+ if ((tk = lex()) == '(') {
+ tk = lex();
+ CDecl_ParseDirectFuncDecl(&di);
+ if (IS_TYPE_FUNC(di.thetype))
+ goto skipPastStuff;
+ } else {
+ CError_Error(CErrorStr114);
+ }
+ }
+
+ if (di.storageclass) {
+ if (tclass) {
+ if (di.storageclass == TK_STATIC)
+ disallowCVFlag = 1;
+ else
+ CError_Error(CErrorStr177);
+ di.storageclass = 0;
+ } else {
+ if (di.storageclass != TK_STATIC && di.storageclass != TK_EXTERN) {
+ CError_Error(CErrorStr177);
+ di.storageclass = 0;
+ }
+ }
+ }
+
+ CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_ASM | Q_PASCAL | Q_INLINE | Q_EXPLICIT | Q_20000 | Q_WEAK | Q_ALIGNED_MASK));
+
+ if (tk == TK_OPERATOR && di.x4A) {
+ CTempl_ParseConversionFunctionTemplate(&di, what_is_this, params, tclass, startOffset, access);
+ return;
+ }
+
+ if (!di.x53) {
+ if (tclass && IS_TYPE_CLASS(di.thetype) && TYPE_CLASS(di.thetype) == tclass && tk == '(') {
+ CError_ASSERT(1418, cscope_current == tclass->nspace);
+ CError_QualifierCheck(di.qual & ~(Q_INLINE | Q_EXPLICIT));
+
+ di.thetype = TYPE(&void_ptr);
+ di.x4B = 1;
+
+ tk = lex();
+ CDecl_ParseDirectFuncDecl(&di);
+
+ if (IS_TYPE_FUNC(di.thetype)) {
+ if (TYPE_FUNC(di.thetype)->args && !TYPE_FUNC(di.thetype)->args->next && TYPE_FUNC(di.thetype)->args->type == TYPE(tclass)) {
+ CError_Error(CErrorStr239);
+ TYPE_FUNC(di.thetype)->args = NULL;
+ }
+
+ if (tclass->flags & CLASS_HAS_VBASES)
+ CDecl_AddArgument(TYPE_FUNC(di.thetype), TYPE(&stsignedshort));
+
+ TYPE_FUNC(di.thetype)->flags |= FUNC_IS_CTOR;
+ di.name = constructor_name_node;
+
+ what_is_this->nspace->tparams = NULL;
+
+ CTempl_ParseTemplateFunction(
+ CTempl_DeclareTemplateFunction(&di, params, tclass, access, disallowCVFlag),
+ tclass, startOffset);
+
+ return;
+ } else {
+ CError_Error(CErrorStr241);
+ }
+ }
+
+ if (IS_TYPE_TEMPLATE(di.thetype)) {
+ if (
+ tk == '(' &&
+ TYPE_TEMPLATE(di.thetype)->dtype == TEMPLDEP_QUALNAME &&
+ (tclass2 = TYPE_CLASS(CTemplTool_GetSelfRefTemplate(TYPE(TYPE_TEMPLATE(di.thetype)->u.qual.type)))) &&
+ TYPE_TEMPLATE(di.thetype)->u.qual.name == tclass2->classname
+ )
+ {
+ if (tclass)
+ CError_Error(CErrorStr229);
+
+ di.thetype = TYPE(&void_ptr);
+ di.x4B = 1;
+
+ CTempl_SetupClassParamNameSpace(what_is_this, tclass2);
+
+ tk = lex();
+ CDecl_ParseDirectFuncDecl(&di);
+
+ if (IS_TYPE_FUNC(di.thetype)) {
+ di.name = constructor_name_node;
+ if (tclass2->flags & CLASS_HAS_VBASES)
+ CDecl_AddArgument(TYPE_FUNC(di.thetype), TYPE(&stsignedshort));
+
+ TYPE_FUNC(di.thetype)->flags |= FUNC_IS_CTOR;
+ CTempl_ParseMember(params, TEMPL_CLASS(tclass2), &di, startOffset);
+ } else {
+ CError_Error(CErrorStr241);
+ }
+
+ return;
+ }
+
+ if (
+ tk == TK_COLON_COLON &&
+ TYPE_TEMPLATE(di.thetype)->dtype == TEMPLDEP_TEMPLATE &&
+ (tclass2 = TYPE_CLASS(CTemplTool_GetSelfRefTemplate(di.thetype)))
+ )
+ {
+ if (tclass)
+ CError_Error(CErrorStr229);
+
+ if ((tk = lex()) == '~') {
+ if (
+ (tk = lex()) != TK_IDENTIFIER ||
+ tkidentifier != tclass2->classname ||
+ (tk = lex()) != '('
+ )
+ {
+ if (tk == '<') {
+ DeclInfo di2;
+
+ CPrep_UnLex();
+ tk = TK_IDENTIFIER;
+ tkidentifier = tclass2->classname;
+
+ memclrw(&di2, sizeof(di2));
+ CParser_GetDeclSpecs(&di2, 0);
+ if (tk != '(')
+ CError_Error(CErrorStr241);
+
+ if (di2.thetype != TYPE(tclass2) && (!IS_TYPE_TEMPLATE(di2.thetype) || CTemplTool_IsTemplate(
+ TYPE_TEMPLATE(di2.thetype)) != TEMPL_CLASS(tclass2)))
+ {
+ CError_Error(CErrorStr241);
+ }
+ } else {
+ CError_Error(CErrorStr241);
+ }
+ }
+
+ di.thetype = TYPE(&void_ptr);
+
+ CTempl_SetupClassParamNameSpace(what_is_this, tclass2);
+ tk = lex();
+ CDecl_ParseDirectFuncDecl(&di);
+
+ if (IS_TYPE_FUNC(di.thetype)) {
+ if (tclass2->sominfo)
+ di.qual |= Q_VIRTUAL;
+ else
+ CDecl_AddArgument(TYPE_FUNC(di.thetype), TYPE(&stsignedshort));
+
+ di.name = destructor_name_node;
+ TYPE_FUNC(di.thetype)->flags |= FUNC_IS_DTOR;
+ CTempl_ParseMember(params, TEMPL_CLASS(tclass2), &di, startOffset);
+ } else {
+ CError_Error(CErrorStr241);
+ }
+ } else if (tk == TK_OPERATOR) {
+ CTempl_SetupClassParamNameSpace(what_is_this, tclass2);
+ if (CMangler_OperatorName((tk = lex()))) {
+ CError_Error(CErrorStr349);
+ return;
+ }
+
+ CError_QualifierCheck(di.qual & ~(Q_INLINE | Q_VIRTUAL));
+ conversion_type_name(&di);
+
+ type = di.thetype;
+ qual = di.qual;
+ CDecl_NewConvFuncType(&di);
+
+ if (CTemplTool_IsTemplateArgumentDependentType(type)) {
+ di.name = CTempl_FindConversionFuncName(tclass2, type, qual);
+ if (!di.name) {
+ CError_Error(CErrorStr150, "conversion function");
+ return;
+ }
+ }
+ CTempl_ParseMember(params, TEMPL_CLASS(tclass2), &di, startOffset);
+ } else {
+ CError_Error(CErrorStr121);
+ }
+
+ return;
+ }
+
+ if (TYPE_TEMPLATE(di.thetype)->dtype == TEMPLDEP_QUALNAME && !di.x49)
+ CError_Warning(CErrorStr355);
+ }
+ }
+
+ di.x30 = params;
+ di.fucker34 = what_is_this;
+ scandeclarator(&di);
+ ctempl_scanfuncparams = 0;
+
+skipPastStuff:
+ if (cscope_current->is_templ) {
+ CError_ASSERT(1589, cscope_current == what_is_this->nspace);
+ what_is_this->nspace->tparams = NULL;
+ }
+
+ if (!di.name) {
+ CError_Error(CErrorStr229);
+ return;
+ }
+
+ if (di.nspace) {
+ if (di.nspace->theclass) {
+ if (tclass)
+ CError_Error(CErrorStr229);
+ CTempl_ParseMember(params, TEMPL_CLASS(di.nspace->theclass), &di, startOffset);
+ return;
+ }
+
+ if (!IS_TYPE_FUNC(di.thetype)) {
+ CError_Error(CErrorStr229);
+ return;
+ }
+
+ CScope_FindName(di.nspace, di.name);
+ } else {
+ if (!IS_TYPE_FUNC(di.thetype)) {
+ CError_Error(CErrorStr229);
+ return;
+ }
+
+ CScope_FindName(cscope_current, di.name);
+ }
+
+ nsol = CScope_FindName(di.nspace ? di.nspace : cscope_current, di.name);
+ while (nsol) {
+ object = OBJECT(nsol->object);
+ if (object->otype == OT_OBJECT && IS_TEMPL_FUNC(object->type)) {
+ templfunc = CTemplTool_GetFuncTempl(object);
+ if (CTemplTool_EqualParams(templfunc->params, params, 0) && is_typesame(object->type, di.thetype)) {
+ if (tk != ';' && templfunc->stream.tokens)
+ CError_Error(CErrorStr234);
+
+ if (tk == '{' || tk == ':' || tk == TK_TRY)
+ CError_ASSERT(1654, CTemplTool_EqualParams(templfunc->params, params, 1));
+
+ if (di.qual & Q_INLINE)
+ object->qual |= Q_INLINE;
+ TYPE_FUNC(object->type)->args = TYPE_FUNC(di.thetype)->args;
+ break;
+ }
+ }
+ nsol = nsol->next;
+ }
+
+ if (!nsol) {
+ if (di.nspace)
+ CError_Error(CErrorStr229);
+ templfunc = CTempl_DeclareTemplateFunction(&di, params, tclass, access, disallowCVFlag);
+ }
+
+ CTempl_ParseTemplateFunction(templfunc, tclass, startOffset);
+}
+
+static void CTempl_ExplicitInstantiation(void) {
+ Boolean flag;
+ short saveToken;
+ Object *object;
+ DeclInfo di;
+
+ memclrw(&di, sizeof(di));
+ di.x51 = 1;
+ flag = 1;
+
+ if (tk == TK_IDENTIFIER && !strcmp(tkidentifier->name, "__dont_instantiate")) {
+ flag = 0;
+ tk = lex();
+ }
+
+ switch (tk) {
+ case TK_STRUCT:
+ case TK_UNION:
+ case TK_CLASS:
+ memclrw(&di, sizeof(di));
+ CParser_GetDeclSpecs(&di, 0);
+ if (tk == ';') {
+ if (IS_TEMPL_CLASS_INST(di.thetype)) {
+ CTempl_InstantiateTemplateClass(TYPE_CLASS(di.thetype));
+ if ((TYPE_CLASS(di.thetype)->flags & CLASS_COMPLETED) && !(TYPE_CLASS(di.thetype)->eflags & CLASS_EFLAGS_IMPORT)) {
+ if (flag)
+ CTempl_GenClassInstance(TEMPL_CLASS_INST(di.thetype), 1);
+ else
+ TEMPL_CLASS_INST(di.thetype)->is_extern = 1;
+ } else {
+ CError_Error(CErrorStr136, TYPE_CLASS(di.thetype), 0);
+ }
+ } else {
+ CError_Error(CErrorStr238);
+ }
+ return;
+ }
+ break;
+ default:
+ memclrw(&di, sizeof(di));
+ CParser_GetDeclSpecs(&di, 0);
+ }
+
+ di.x51 = 1;
+
+ scandeclarator(&di);
+
+ saveToken = tk;
+
+ di.x38 = NULL;
+ if (
+ di.name &&
+ IS_TYPE_FUNC(di.thetype) &&
+ (object = CDecl_GetFunctionObject(&di, di.nspace, NULL, 1)) &&
+ IS_TYPE_FUNC(object->type) &&
+ object->u.func.inst &&
+ di.x38
+ )
+ {
+ if (!flag)
+ object->u.func.inst->is_extern = 1;
+ else
+ CTempl_GenFuncInstance(di.x38, object->u.func.inst, 1);
+ } else {
+ CError_Error(CErrorStr238);
+ }
+
+ if (saveToken != ';')
+ CError_Error(CErrorStr123);
+}
+
+static void CTempl_ExplicitSpecialization(void) {
+ Boolean flag;
+ TemplParam *params;
+ int counter;
+ DeclFucker what_is_this;
+ DeclInfo di;
+
+ flag = 0;
+ counter = 1;
+ while (tk == TK_TEMPLATE) {
+ if ((tk = lex()) != '<') {
+ CError_Error(CErrorStr230);
+ break;
+ }
+
+ if ((tk = lex()) != '>') {
+ if (!flag) {
+ what_is_this.nspace = cscope_current;
+ what_is_this.mystery4 = NULL;
+ cscope_current->tparams = NULL;
+ flag = 1;
+ }
+
+ params = CTempl_ParseParamList(what_is_this.nspace, counter);
+ if (tk != '>')
+ CError_Error(CErrorStr231);
+ } else {
+ if (flag)
+ CError_Error(CErrorStr335);
+ }
+
+ counter++;
+ tk = lex();
+ }
+
+ if (flag) {
+ SInt32 startOffset = -1;
+ CTempl_ParseFunctionOrMemberTemplate(&what_is_this, params, NULL, &startOffset, ACCESSPUBLIC, 1);
+ return;
+ }
+
+ memclrw(&di, sizeof(di));
+ di.x3C = counter;
+ di.x51 = 1;
+ CParser_GetDeclSpecs(&di, 1);
+
+ if (tk == ';') {
+ if (IS_TEMPL_CLASS_INST(di.thetype))
+ TEMPL_CLASS_INST(di.thetype)->is_specialized = 1;
+ else
+ CError_Error(CErrorStr335);
+ } else {
+ scandeclaratorlist(&di);
+ if ((tk != ';' && tk != '}') || di.x3C)
+ CError_Error(CErrorStr335);
+ }
+
+ if (flag)
+ what_is_this.nspace->tparams = NULL;
+}
+
+void CTempl_Parse(TemplClass *templ, AccessType access) {
+ TemplParam *params;
+ UInt8 i;
+ short mode;
+ Boolean flag;
+ UInt8 classDeclSpec;
+ SInt32 startOffset;
+ SInt32 savedState;
+ CScopeSave savedScope;
+ DeclFucker what_is_this;
+
+ startOffset = CPrep_BrowserFileOffset();
+ CScope_GetScope(&savedScope);
+
+ if ((tk = lex()) != '<') {
+ if (templ)
+ CError_Error(CErrorStr238);
+ CTempl_ExplicitInstantiation();
+ CScope_RestoreScope(&savedScope);
+ return;
+ }
+
+ if ((tk = lex()) == '>') {
+ if (templ)
+ CError_Error(CErrorStr335);
+ tk = lex();
+ CTempl_ExplicitSpecialization();
+ CScope_RestoreScope(&savedScope);
+ return;
+ }
+
+ what_is_this.nspace = cscope_current;
+ what_is_this.mystery4 = NULL;
+ cscope_current->tparams = NULL;
+ i = CTempl_GetTemplateNestIndex(what_is_this.nspace);
+
+ while (1) {
+ params = CTempl_ParseParamList(what_is_this.nspace, i);
+ if (tk != '>')
+ CError_Error(CErrorStr231);
+
+ if ((tk = lex()) != TK_TEMPLATE)
+ break;
+
+ if (templ)
+ CError_Error(CErrorStr121);
+
+ if ((tk = lex()) != '<')
+ CError_Error(CErrorStr230);
+ else
+ tk = lex();
+
+ i++;
+ }
+
+ switch (tk) {
+ case TK_CLASS:
+ mode = CLASS_MODE_CLASS;
+ break;
+ case TK_UNION:
+ mode = CLASS_MODE_UNION;
+ break;
+ case TK_STRUCT:
+ mode = CLASS_MODE_STRUCT;
+ break;
+ default:
+ mode = -1;
+ }
+
+ if (mode >= 0) {
+ classDeclSpec = 0;
+ flag = 0;
+
+ CPrep_TokenStreamGetState(&savedState);
+ if ((tk = lex()) == TK_UU_DECLSPEC)
+ CDecl_ParseClassDeclSpec(&classDeclSpec);
+
+ if (tk == TK_IDENTIFIER) {
+ if ((tk = lex()) == '<') {
+ if (setjmp(ctempl_parseparse) == 0) {
+ CTempl_MemberParseTemplArgList();
+ flag = 1;
+ tk = lex();
+ }
+ }
+
+ switch (tk) {
+ case ':':
+ case ';':
+ case '{':
+ CPrep_TokenStreamSetCurState(&savedState);
+ if (flag)
+ CTemplClass_ParsePartialSpecialization(&what_is_this, params, mode, &startOffset);
+ else
+ CTemplClass_ParseClass(&what_is_this, params, mode, &startOffset);
+ goto done;
+ }
+ }
+
+ CPrep_TokenStreamSetCurState(&savedState);
+ }
+
+ CTempl_ParseFunctionOrMemberTemplate(&what_is_this, params, TYPE_CLASS(templ), &startOffset, access, 0);
+
+done:
+ what_is_this.nspace->tparams = NULL;
+ CScope_RestoreScope(&savedScope);
+}
+
+void CTempl_ParseInstanceScopeFunction(Object *funcobj, TemplClassInst *inst, TypeClass *tclass) {
+ TemplParam *params;
+ NameSpace *nspace;
+ TemplateMember *member;
+ Object *parent;
+ DeclInfo di;
+ CScopeSave savedScope;
+ TemplStack stack;
+
+ params = inst->templ->templ__params;
+ if (funcobj->qual & Q_IS_TEMPLATED) {
+ for (member = CTemplClass_GetMasterTemplate(inst->templ)->members, parent = OBJECT_TEMPL(funcobj)->parent; member; member = member->next) {
+ if (member->object == parent) {
+ if (member->params)
+ params = member->params;
+ break;
+ }
+ }
+ }
+
+ CTemplTool_PushInstance(&stack, NULL, funcobj);
+ nspace = CTemplTool_InsertTemplateArgumentNameSpace(params, inst, &savedScope);
+ if (tclass)
+ cscope_current = tclass->nspace;
+
+ memclrw(&di, sizeof(di));
+ CFunc_ParseFuncDef(funcobj, &di, NULL, 0, 0, tclass ? cscope_current : NULL);
+
+ CTemplTool_RemoveTemplateArgumentNameSpace(nspace, inst, &savedScope);
+ CTemplTool_PopInstance(&stack);
+}
+
+Boolean CTempl_GenFuncInstance(TemplateFunction *templ, TemplFuncInstance *inst, Boolean flag) {
+ Boolean saveDebugInfo;
+ NameSpace *nspace;
+ SInt32 streamState;
+ TemplStack stack;
+ DeclInfo di;
+
+ if (!flag && copts.no_implicit_templates && inst->object->sclass != TK_STATIC)
+ return 0;
+
+ if (inst->is_extern && !flag)
+ return 0;
+
+ while (1) {
+ if (templ->stream.tokens)
+ break;
+ if (!templ->unk4)
+ break;
+ templ = templ->unk4;
+ }
+
+ if (!templ->stream.tokens) {
+ if (flag) {
+ CError_SetErrorToken(&templ->deftoken);
+ CError_Error(CErrorStr233, inst->object);
+ }
+ return 0;
+ }
+
+ inst->is_instantiated = 1;
+
+ CPrep_StreamInsert(&templ->stream, &streamState);
+
+ saveDebugInfo = copts.filesyminfo;
+ if (copts.nosyminline || !templ->deftoken.tokenfile)
+ copts.filesyminfo = 0;
+
+ CError_ASSERT(2112, (tk = lex()) == '{' || tk == ':' || tk == TK_TRY);
+
+ symdecltoken = *CPrep_CurStreamElement();
+
+ if (copts.filesyminfo) {
+ CPrep_NewFileOffsetInfo(&cparser_fileoffset, &templ->deftoken);
+ symdecloffset = cparser_fileoffset.tokenline;
+ }
+
+ if (inst->object->sclass != TK_STATIC)
+ inst->object->qual |= Q_WEAK;
+
+ memclrw(&di, sizeof(di));
+ di.file2 = templ->srcfile;
+ di.file = CPrep_BrowserCurrentFile();
+ di.sourceoffset = templ->startoffset;
+
+ CTemplTool_PushInstance(&stack, NULL, inst->object);
+ CTemplTool_MergeArgNames(TYPE_FUNC(templ->tfunc->type), TYPE_FUNC(inst->object->type));
+
+ nspace = CTemplTool_SetupTemplateArgumentNameSpace(templ->params, inst->args, 0);
+ nspace->parent = inst->object->nspace;
+ inst->object->nspace = nspace;
+
+ CTemplTool_SetupOuterTemplateArgumentNameSpace(nspace);
+ CFunc_ParseFuncDef(inst->object, &di, NULL, 0, 0, nspace);
+ CTemplTool_RemoveOuterTemplateArgumentNameSpace(nspace);
+
+ inst->object->nspace = nspace->parent;
+
+ CTemplTool_PopInstance(&stack);
+
+ CPrep_StreamRemove(&templ->stream, &streamState);
+ copts.filesyminfo = saveDebugInfo;
+
+ if (di.file->recordbrowseinfo)
+ CBrowse_NewFunction(inst->object, di.file, di.file2, di.sourceoffset, templ->endoffset);
+
+ return 1;
+}
+
+void CTempl_InstantiateMember(TemplClass *templ, TemplClassInst *inst, TemplateMember *tmemb, Object *object, Boolean flag) {
+ Boolean saveDebugInfo;
+ NameSpace *nspace;
+ Boolean saveSourceLoc;
+
+ DeclInfo di;
+ CScopeSave savedScope;
+ TemplStack stack;
+ SInt32 savedState;
+
+ if (!flag && copts.no_implicit_templates)
+ return;
+
+ CTemplTool_PushInstance(&stack, NULL, object);
+ nspace = CTemplTool_InsertTemplateArgumentNameSpace(
+ tmemb->params ? tmemb->params : templ->templ__params, inst, &savedScope);
+ CPrep_StreamInsert(&tmemb->stream, &savedState);
+
+ saveSourceLoc = gForceSourceLoc;
+ gForceSourceLoc = 1;
+ symdecltoken.tokenoffset = tmemb->startoffset;
+ tk = lex();
+
+ symdecltoken = *CPrep_CurStreamElement();
+
+ saveDebugInfo = copts.filesyminfo;
+ if (copts.filesyminfo) {
+ CPrep_NewFileOffsetInfo(&cparser_fileoffset, &symdecltoken);
+ symdecloffset = cparser_fileoffset.tokenline;
+ }
+
+ if (object->sclass != TK_STATIC)
+ object->qual |= Q_WEAK;
+
+ memclrw(&di, sizeof(di));
+ di.file2 = tmemb->srcfile;
+ di.file = CPrep_BrowserCurrentFile();
+ di.sourceoffset = tmemb->startoffset;
+
+ switch (object->datatype) {
+ case DFUNC:
+ case DVFUNC:
+ CTemplTool_MergeArgNames(TYPE_FUNC(tmemb->object->type), TYPE_FUNC(object->type));
+ CFunc_ParseFuncDef(object, &di, TYPE_CLASS(inst), 0, 0, NULL);
+ break;
+
+ case DDATA:
+ CDecl_CompleteType(object->type);
+ CInit_InitializeData(object);
+ break;
+
+ default:
+ CError_FATAL(2227);
+ }
+
+ CTemplTool_PopInstance(&stack);
+ CTemplTool_RemoveTemplateArgumentNameSpace(nspace, inst, &savedScope);
+ CPrep_StreamRemove(&tmemb->stream, &savedState);
+ copts.filesyminfo = saveDebugInfo;
+ gForceSourceLoc = saveSourceLoc;
+}
+
+static Boolean CTempl_GenMemberInstance(TemplClassInst *inst, ObjectTemplated *objtempl, Boolean flag) {
+ TemplateMember *member;
+ Object *parent = objtempl->parent;
+
+ for (member = CTemplClass_GetMasterTemplate(inst->templ)->members; member; member = member->next) {
+ if (member->object == parent) {
+ CTempl_InstantiateMember(inst->templ, inst, member, OBJECT(objtempl), flag);
+ return 1;
+ }
+ }
+
+ if (flag)
+ CError_Warning(CErrorStr233, objtempl);
+ return 0;
+}
+
+static Boolean CTempl_GenClassInstance(TemplClassInst *inst, Boolean flag) {
+ Object *object;
+ Boolean result;
+ CScopeObjectIterator iter;
+
+ result = 0;
+
+ if (!flag && copts.no_implicit_templates)
+ return 0;
+ if (!flag && inst->is_extern)
+ return 0;
+
+ CScope_InitObjectIterator(&iter, inst->theclass.nspace);
+ while ((object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) {
+ if (IS_TYPE_FUNC(object->type) && object->datatype != DALIAS) {
+ if (
+ (flag || (object->flags & OBJECT_FLAGS_2)) &&
+ !(TYPE_FUNC(object->type)->flags & (FUNC_DEFINED | FUNC_AUTO_GENERATED)) &&
+ CTempl_GenMemberInstance(inst, OBJECT_TEMPL(object), flag) &&
+ (TYPE_FUNC(object->type)->flags & FUNC_DEFINED)
+ )
+ result = 1;
+ } else {
+ if (
+ !inst->static_instantiated &&
+ object->datatype == DDATA &&
+ !(object->qual & Q_INLINE_DATA) &&
+ !(object->flags & OBJECT_DEFINED) &&
+ CTempl_GenMemberInstance(inst, OBJECT_TEMPL(object), flag)
+ )
+ result = 1;
+ }
+ }
+
+ inst->static_instantiated = 1;
+ return result;
+}
+
+Boolean CTempl_Instantiate(void) {
+ Boolean result = 0;
+ TemplClass *templ;
+ TemplClassInst *inst;
+ TemplPartialSpec *pspec;
+ TemplFuncInstance *instf;
+ TemplateFunction *templf;
+
+ for (templ = ctempl_templates; templ; templ = templ->next) {
+ for (inst = templ->instances; inst; inst = inst->next) {
+ if (
+ (inst->theclass.flags & CLASS_IS_TEMPL_INST) &&
+ !inst->is_specialized &&
+ CTempl_GenClassInstance(inst, 0)
+ )
+ result = 1;
+ }
+
+ for (pspec = templ->pspecs; pspec; pspec = pspec->next) {
+ for (inst = pspec->templ->instances; inst; inst = inst->next) {
+ if (
+ (inst->theclass.flags & CLASS_IS_TEMPL_INST) &&
+ !inst->is_specialized &&
+ CTempl_GenClassInstance(inst, 0)
+ )
+ result = 1;
+ }
+ }
+ }
+
+ for (templf = ctempl_templatefuncs; templf; templf = templf->next) {
+ for (instf = templf->instances; instf; instf = instf->next) {
+ if (
+ !instf->is_instantiated &&
+ !instf->is_specialized &&
+ (instf->object->flags & OBJECT_FLAGS_2) &&
+ !(TYPE_FUNC(instf->object->type)->flags & FUNC_DEFINED)
+ )
+ {
+ instf->is_instantiated = 1;
+ if (CTempl_GenFuncInstance(templf, instf, 0))
+ result = 1;
+ }
+ }
+ }
+
+ return result;
+}
+
+Boolean CTempl_InlineFunctionCheck(Object *funcobj) {
+ TemplClassInst *inst;
+ TemplateMember *member;
+ Object *parent;
+
+ CError_ASSERT(2422, IS_TYPE_FUNC(funcobj->type) && (funcobj->qual & Q_IS_TEMPLATED));
+
+ if (!(TYPE_FUNC(funcobj->type)->flags & FUNC_DEFINED)) {
+ inst = TEMPL_CLASS_INST(TYPE_METHOD(funcobj->type)->theclass);
+ if (!inst->is_specialized) {
+ parent = OBJECT_TEMPL(funcobj)->parent;
+ if (parent->qual & Q_INLINE) {
+ for (member = CTemplClass_GetMasterTemplate(inst->templ)->members; member; member = member->next) {
+ funcobj->qual |= Q_INLINE;
+ if (member->object == parent) {
+ CTemplTool_MergeArgNames(TYPE_FUNC(member->object->type), TYPE_FUNC(funcobj->type));
+ CInline_AddInlineFunctionAction(funcobj, TYPE_CLASS(inst), &member->fileoffset, &member->stream, 0);
+ return 1;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/compiler_and_linker/FrontEnd/C/CTemplateTools.c b/compiler_and_linker/FrontEnd/C/CTemplateTools.c
new file mode 100644
index 0000000..0e77e74
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CTemplateTools.c
@@ -0,0 +1,1962 @@
+#include "compiler/CTemplateTools.h"
+#include "compiler/CABI.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInline.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/CScope.h"
+#include "compiler/CTemplateClass.h"
+#include "compiler/CTemplateNew.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/enode.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/templates.h"
+#include "compiler/types.h"
+
+short ctempl_instdepth;
+
+void CTemplTool_PushInstance(TemplStack *stack, TypeClass *tmclass, Object *func) {
+ if (tmclass) {
+ stack->u.theclass = tmclass;
+ stack->is_func = 0;
+ } else {
+ stack->u.func = func;
+ stack->is_func = 1;
+ }
+ stack->next = ctempl_curinstance;
+ ctempl_curinstance = stack;
+
+ if (++ctempl_instdepth >= 64)
+ CError_ErrorTerm(CErrorStr314);
+}
+
+void CTemplTool_PopInstance(TemplStack *stack) {
+ CError_ASSERT(53, ctempl_curinstance == stack);
+
+ ctempl_curinstance = stack->next;
+ if (--ctempl_instdepth < 0)
+ ctempl_instdepth = 0;
+}
+
+ENode *CTempTool_GetPTMTemplArgExpr(ENode *expr, Type *type) {
+ NameSpaceObjectList *list;
+
+ CError_ASSERT(69, ENODE_IS(expr, EMEMBER));
+ CError_ASSERT(70, IS_TYPE_MEMBERPOINTER(type));
+
+ if (!copts.cpp_extensions) {
+ if (!expr->data.emember->x11 || !expr->data.emember->pr_1D)
+ CError_Warning(CErrorStr331);
+ }
+
+ type = TYPE_MEMBER_POINTER(type)->ty1;
+ for (list = expr->data.emember->list; list; list = list->next) {
+ if (list->object->otype == OT_MEMBERVAR) {
+ if (!is_typeequal(OBJ_MEMBER_VAR(list->object)->type, type))
+ CError_Error(CErrorStr146);
+ return expr;
+ }
+
+ if (list->object->otype == OT_OBJECT && is_memberpointerequal(OBJECT(list->object)->type, type)) {
+ if (expr->data.emember->list != list || list->next) {
+ // rewrite the EMEMBER to contain just one node
+ expr->data.emember->list = galloc(sizeof(NameSpaceObjectList));
+ *expr->data.emember->list = *list;
+ expr->data.emember->list->next = NULL;
+ }
+ break;
+ }
+ }
+
+ if (!list)
+ CError_Error(CErrorStr146);
+
+ return expr;
+}
+
+Boolean CTemplTool_InitDeduceInfo(DeduceInfo *info, TemplParam *params, TemplArg *args, Boolean flag) {
+ int i;
+ TemplArg *buffer;
+ TemplParam *param;
+
+ if (!params) {
+ info->args = info->argBuffer;
+ info->maxCount = 0;
+ info->x12C = 0xFF;
+ return 1;
+ }
+
+ memclrw(info, sizeof(DeduceInfo));
+
+ i = 0;
+ param = params;
+ while (param) {
+ param = param->next;
+ i++;
+ }
+
+ if (i > 16) {
+ buffer = lalloc(i * sizeof(TemplArg));
+ memclrw(buffer, i * sizeof(TemplArg));
+ } else {
+ buffer = info->argBuffer;
+ }
+ info->args = buffer;
+ info->maxCount = i;
+ info->x12C = params->pid.nindex;
+
+ for (param = params, i = 0; param; param = param->next, i++)
+ buffer[i].pid = param->pid;
+
+ i = 0;
+ param = params;
+ while (args) {
+ if (!param || param->pid.type != args->pid.type)
+ return 0;
+
+ buffer[i].data = args->data;
+ if (i > 0)
+ buffer[i - 1].next = &buffer[i];
+ buffer[i].next = NULL;
+ buffer[i].is_deduced = 1;
+ info->count++;
+
+ if (param->pid.type == TPT_NONTYPE && !CTemplTool_IsTemplateArgumentDependentType(param->data.paramdecl.type)) {
+ if (CExpr_CanImplicitlyConvert(buffer[i].data.paramdecl.expr, param->data.paramdecl.type, param->data.paramdecl.qual)) {
+ buffer[i].data.paramdecl.expr = CExpr_AssignmentPromotion(
+ buffer[i].data.paramdecl.expr, param->data.paramdecl.type, param->data.paramdecl.qual, 0);
+ } else {
+ return 0;
+ }
+ }
+
+ args = args->next;
+ param = param->next;
+ i++;
+ }
+
+ if (flag) {
+ for (param = params, i = 0; param; param = param->next, i++) {
+ if (!buffer[i].is_deduced && !param->name) {
+ switch (param->pid.type) {
+ case TPT_TYPE:
+ buffer[i].data.typeparam.type = &stvoid;
+ break;
+ case TPT_NONTYPE:
+ buffer[i].data.paramdecl.expr = nullnode();
+ break;
+ case TPT_TEMPLATE:
+ default:
+ CError_FATAL(208);
+ }
+ buffer[i].is_deduced = 1;
+ }
+ }
+ }
+
+ return 1;
+}
+
+void CTemplTool_InsertTemplateParameter(NameSpace *nspace, TemplParam *param) {
+ Type *type;
+ ObjType *obj;
+ NameSpaceName *nsn;
+
+ type = CDecl_NewTemplDepType(TEMPLDEP_ARGUMENT);
+ TYPE_TEMPLATE(type)->u.pid = param->pid;
+
+ obj = galloc(sizeof(ObjType));
+ memclrw(obj, sizeof(ObjType));
+ obj->otype = OT_TYPE;
+ obj->access = ACCESSPUBLIC;
+ obj->type = type;
+
+ for (nsn = nspace->tparams; nsn; nsn = nsn->next) {
+ if (nsn->name == param->name) {
+ CError_Error(CErrorStr122, param->name->name);
+ return;
+ }
+ }
+
+ nsn = galloc(sizeof(NameSpaceName));
+ memclrw(nsn, sizeof(NameSpaceName));
+
+ nsn->name = param->name;
+ nsn->first.object = OBJ_BASE(obj);
+
+ nsn->next = nspace->tparams;
+ nspace->tparams = nsn;
+}
+
+TemplArg *CTemplTool_MakeTemplArgList(DeduceInfo *info) {
+ TemplArg *args;
+ TemplArg *last;
+ int i;
+
+ for (i = 0; i < info->maxCount; i++) {
+ if (i) {
+ last->next = galloc(sizeof(TemplArg));
+ last = last->next;
+ } else {
+ args = last = galloc(sizeof(TemplArg));
+ }
+
+ *last = info->args[i];
+ }
+
+ last->next = NULL;
+ return args;
+}
+
+Boolean CTemplTool_IsIdenticalTemplArgList(TemplArg *args, TemplParam *params) {
+ while (args) {
+ if (!params)
+ return 0;
+
+ CError_ASSERT(297, params->pid.type == args->pid.type);
+
+ switch (args->pid.type) {
+ case TPT_TYPE:
+ if (
+ !IS_TYPE_TEMPLATE(args->data.typeparam.type) ||
+ TYPE_TEMPLATE(args->data.typeparam.type)->dtype != TEMPLDEP_ARGUMENT ||
+ TYPE_TEMPLATE(args->data.typeparam.type)->u.pid.index != params->pid.index ||
+ TYPE_TEMPLATE(args->data.typeparam.type)->u.pid.nindex != params->pid.nindex
+ )
+ return 0;
+ break;
+ case TPT_NONTYPE:
+ if (
+ !ENODE_IS(args->data.paramdecl.expr, ETEMPLDEP) ||
+ args->data.paramdecl.expr->data.templdep.subtype != TDE_PARAM ||
+ args->data.paramdecl.expr->data.templdep.u.pid.index != params->pid.index ||
+ args->data.paramdecl.expr->data.templdep.u.pid.nindex != params->pid.nindex
+ )
+ return 0;
+ break;
+ case TPT_TEMPLATE:
+ if (
+ !IS_TYPE_TEMPLATE(args->data.ttargtype) ||
+ TYPE_TEMPLATE(args->data.ttargtype)->dtype != TEMPLDEP_ARGUMENT ||
+ TYPE_TEMPLATE(args->data.ttargtype)->u.pid.index != params->pid.index ||
+ TYPE_TEMPLATE(args->data.ttargtype)->u.pid.nindex != params->pid.nindex
+ )
+ return 0;
+ break;
+ default:
+ CError_FATAL(331);
+ }
+
+ args = args->next;
+ params = params->next;
+ }
+
+ return !params;
+}
+
+Type *CTemplTool_GetSelfRefTemplate(Type *type) {
+ TemplClass *templ;
+ TemplArg *args;
+
+ CError_ASSERT(347, IS_TYPE_TEMPLATE(type));
+
+ if (TYPE_TEMPLATE(type)->dtype == TEMPLDEP_TEMPLATE) {
+ if (CTemplTool_IsIdenticalTemplArgList(
+ TYPE_TEMPLATE(type)->u.templ.args,
+ TYPE_TEMPLATE(type)->u.templ.templ->templ__params))
+ return TYPE(TYPE_TEMPLATE(type)->u.templ.templ);
+
+ if (TYPE_TEMPLATE(type)->u.templ.templ->pspecs) {
+ templ = TYPE_TEMPLATE(type)->u.templ.templ;
+ if (
+ CTemplClass_FindPartialTemplate(TYPE_TEMPLATE(type)->u.templ.args, &templ, &args) &&
+ CTemplTool_IsIdenticalTemplArgList(args, templ->templ__params)
+ )
+ return TYPE(templ);
+ }
+
+ return NULL;
+ }
+
+ if (TYPE_TEMPLATE(type)->dtype == TEMPLDEP_QUALNAME) {
+ Type *t = CTemplTool_GetSelfRefTemplate(TYPE(TYPE_TEMPLATE(type)->u.qual.type));
+ if (
+ t &&
+ (t = CScope_GetLocalTagType(TYPE_CLASS(t)->nspace, TYPE_TEMPLATE(type)->u.qual.name)) &&
+ IS_TEMPL_CLASS(t) &&
+ !TEMPL_CLASS(t)->templ__params
+ )
+ return t;
+
+ return NULL;
+ }
+
+ if (TYPE_TEMPLATE(type)->dtype == TEMPLDEP_QUALTEMPL) {
+ Type *t;
+
+ CError_ASSERT(389, TYPE_TEMPLATE(TYPE_TEMPLATE(type)->u.qualtempl.type)->dtype == TEMPLDEP_QUALNAME);
+
+ t = CTemplTool_GetSelfRefTemplate(TYPE(TYPE_TEMPLATE(TYPE_TEMPLATE(type)->u.qualtempl.type)->u.qual.type));
+ if (
+ t &&
+ (t = CScope_GetLocalTagType(TYPE_CLASS(t)->nspace, TYPE_TEMPLATE(TYPE_TEMPLATE(type)->u.qualtempl.type)->u.qual.name)) &&
+ IS_TEMPL_CLASS(t)
+ )
+ {
+ TemplClass *tm = TEMPL_CLASS(t);
+ if (CTemplTool_IsIdenticalTemplArgList(TYPE_TEMPLATE(type)->u.qualtempl.args, tm->templ__params))
+ return TYPE(tm);
+ }
+ }
+
+ return NULL;
+}
+
+TemplateFunction *CTemplTool_GetFuncTempl(Object *object) {
+ while (object->datatype == DALIAS)
+ object = object->u.alias.object;
+
+ CError_ASSERT(416, IS_TEMPL_FUNC(object->type));
+ return object->u.func.u.templ;
+}
+
+Boolean CTemplTool_ParamHasDefaultArg(TemplParam *param) {
+ switch (param->pid.type) {
+ case TPT_TYPE:
+ return param->data.typeparam.type != NULL;
+ case TPT_NONTYPE:
+ return param->data.paramdecl.defaultarg != NULL;
+ case TPT_TEMPLATE:
+ default:
+ CError_FATAL(438);
+ return 0;
+ }
+}
+
+void CTemplTool_MergeDefaultArgs(TemplParam *dest, TemplParam *src) {
+ while (1) {
+ if (!dest) {
+ CError_ASSERT(455, !src);
+ return;
+ }
+
+ CError_ASSERT(458, src);
+ CError_ASSERT(459, dest->pid.type == src->pid.type);
+
+ switch (dest->pid.type) {
+ case TPT_TYPE:
+ if (!dest->data.typeparam.type && src->data.typeparam.type)
+ dest->data = src->data;
+ break;
+ case TPT_NONTYPE:
+ if (!dest->data.paramdecl.defaultarg && src->data.paramdecl.defaultarg)
+ dest->data = src->data;
+ break;
+ case TPT_TEMPLATE:
+ if (!dest->data.templparam.defaultarg && src->data.templparam.defaultarg)
+ dest->data = src->data;
+ break;
+ default:
+ CError_FATAL(484);
+ }
+
+ dest = dest->next;
+ src = src->next;
+ }
+}
+
+static FuncArg *CTemplTool_GetFirstRealArg(TypeFunc *tfunc) {
+ FuncArg *arg = tfunc->args;
+
+ if (IS_TYPEFUNC_NONSTATIC_METHOD(tfunc)) {
+ CError_ASSERT(502, arg);
+ arg = arg->next;
+ if ((tfunc->flags & FUNC_IS_CTOR) && (TYPE_METHOD(tfunc)->theclass->flags & CLASS_HAS_VBASES)) {
+ CError_ASSERT(507, arg);
+ arg = arg->next;
+ }
+ }
+
+ return arg;
+}
+
+void CTemplTool_MergeArgNames(TypeFunc *src, TypeFunc *dest) {
+ FuncArg *destArg;
+ FuncArg *srcArg;
+
+ CError_ASSERT(524, IS_TYPE_FUNC(dest) && IS_TYPE_FUNC(src));
+
+ srcArg = CTemplTool_GetFirstRealArg(src);
+ destArg = CTemplTool_GetFirstRealArg(dest);
+
+ while (1) {
+ if (!srcArg || !destArg || srcArg == &elipsis || destArg == &elipsis) {
+ CError_ASSERT(531, srcArg == destArg);
+ break;
+ }
+
+ destArg->name = srcArg->name;
+ srcArg = srcArg->next;
+ destArg = destArg->next;
+ }
+
+ if (IS_TYPEFUNC_NONSTATIC_METHOD(dest)) {
+ CError_ASSERT(538, destArg = dest->args);
+ if (!destArg->name)
+ destArg->name = this_name_node;
+ }
+}
+
+Boolean CTemplTool_EqualParams(TemplParam *a, TemplParam *b, Boolean copyNames) {
+ while (1) {
+ if (!a)
+ return !b;
+ if (!b)
+ return 0;
+
+ if (a->pid.type != b->pid.type)
+ return 0;
+
+ if (copyNames)
+ a->name = b->name;
+
+ switch (a->pid.type) {
+ case TPT_TYPE:
+ break;
+ case TPT_NONTYPE:
+ if (
+ !is_typesame(a->data.paramdecl.type, b->data.paramdecl.type) ||
+ a->data.paramdecl.qual != b->data.paramdecl.qual
+ )
+ return 0;
+ break;
+ case TPT_TEMPLATE:
+ break;
+ default:
+ CError_FATAL(576);
+ }
+
+ a = a->next;
+ b = b->next;
+ }
+}
+
+NameSpace *CTemplTool_SetupTemplateArgumentNameSpace(TemplParam *params, TemplArg *args, Boolean is_global) {
+ NameSpace *nspace;
+ Boolean clear_global;
+ ObjType *objType;
+ Object *object;
+
+ clear_global = 0;
+ if (!is_global && trychain) {
+ clear_global = 1;
+ is_global = 1;
+ }
+
+ nspace = CScope_NewListNameSpace(NULL, is_global);
+ nspace->is_templ = 1;
+
+ if (clear_global)
+ nspace->is_global = 0;
+
+ if (!params)
+ return nspace;
+
+ while (params) {
+ CError_ASSERT(607, args);
+
+ if (params->name) {
+ switch (args->pid.type) {
+ case TPT_TYPE:
+ if (is_global) {
+ objType = galloc(sizeof(ObjType));
+ memclrw(objType, sizeof(ObjType));
+ } else {
+ objType = lalloc(sizeof(ObjType));
+ memclrw(objType, sizeof(ObjType));
+ }
+ objType->otype = OT_TYPE;
+ objType->access = ACCESSPUBLIC;
+ objType->type = args->data.typeparam.type;
+ objType->qual = args->data.typeparam.qual;
+ CScope_AddObject(nspace, params->name, OBJ_BASE(objType));
+ break;
+ case TPT_NONTYPE:
+ if (is_global) {
+ object = galloc(sizeof(Object));
+ memclrw(object, sizeof(Object));
+ } else {
+ object = lalloc(sizeof(Object));
+ memclrw(object, sizeof(Object));
+ }
+ object->otype = OT_OBJECT;
+ object->access = ACCESSPUBLIC;
+ object->nspace = nspace;
+ object->name = params->name;
+ object->type = args->data.paramdecl.expr->rtype;
+ object->qual = ENODE_QUALS(args->data.paramdecl.expr);
+ object->datatype = DEXPR;
+ object->u.expr = args->data.paramdecl.expr;
+ if (IS_TYPE_REFERENCE(params->data.paramdecl.type)) {
+ CError_ASSERT(652, IS_TYPE_POINTER_ONLY(object->u.expr->rtype));
+ object->u.expr = makemonadicnode(object->u.expr, EINDIRECT);
+ object->u.expr->rtype = TPTR_TARGET(params->data.paramdecl.type);
+ }
+ if (is_global)
+ object->u.expr = CInline_CopyExpression(object->u.expr, CopyMode1);
+ CScope_AddObject(nspace, params->name, OBJ_BASE(object));
+ break;
+ case TPT_TEMPLATE:
+ if (is_global) {
+ objType = galloc(sizeof(ObjType));
+ memclrw(objType, sizeof(ObjType));
+ } else {
+ objType = lalloc(sizeof(ObjType));
+ memclrw(objType, sizeof(ObjType));
+ }
+ objType->otype = OT_TYPE;
+ objType->access = ACCESSPUBLIC;
+ objType->type = args->data.ttargtype;
+ objType->qual = 0;
+ CScope_AddObject(nspace, params->name, OBJ_BASE(objType));
+ break;
+ default:
+ CError_FATAL(681);
+ }
+ }
+
+ params = params->next;
+ args = args->next;
+ }
+
+ CError_ASSERT(685, !args);
+
+ return nspace;
+}
+
+void CTemplTool_SetupOuterTemplateArgumentNameSpace(NameSpace *nspace) {
+ NameSpace *newns;
+
+ while (nspace) {
+ if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL_INST)) {
+ newns = CTemplTool_SetupTemplateArgumentNameSpace(
+ TEMPL_CLASS_INST(nspace->theclass)->templ->templ__params,
+ TEMPL_CLASS_INST(nspace->theclass)->inst_args,
+ 0);
+ newns->parent = nspace->parent;
+ nspace->parent = newns;
+ }
+
+ nspace = nspace->parent;
+ }
+}
+
+NameSpace *CTemplTool_InsertTemplateArgumentNameSpace(TemplParam *params, TemplClassInst *inst, CScopeSave *save) {
+ NameSpace *nspace = CTemplTool_SetupTemplateArgumentNameSpace(params, inst->inst_args, 0);
+
+ nspace->parent = inst->theclass.nspace->parent;
+ inst->theclass.nspace->parent = nspace;
+
+ CTemplTool_SetupOuterTemplateArgumentNameSpace(nspace);
+ CScope_SetNameSpaceScope(inst->theclass.nspace, save);
+
+ return nspace;
+}
+
+void CTemplTool_RemoveOuterTemplateArgumentNameSpace(NameSpace *nspace) {
+ while (nspace->parent) {
+ if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL_INST) && nspace->parent->is_templ)
+ nspace->parent = nspace->parent->parent;
+ nspace = nspace->parent;
+ }
+}
+
+void CTemplTool_RemoveTemplateArgumentNameSpace(NameSpace *nspace, TemplClassInst *inst, CScopeSave *save) {
+ CTemplTool_RemoveOuterTemplateArgumentNameSpace(inst->theclass.nspace);
+ CScope_RestoreScope(save);
+}
+
+Boolean CTemplTool_IsTemplateArgumentDependentType(Type *type) {
+ FuncArg *arg;
+
+ while (1) {
+ switch (type->type) {
+ case TYPETEMPLATE:
+ return 1;
+ case TYPEVOID:
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPESTRUCT:
+ return 0;
+ case TYPECLASS:
+ return (TYPE_CLASS(type)->flags & CLASS_IS_TEMPL) ? 1 : 0;
+ case TYPEMEMBERPOINTER:
+ if (CTemplTool_IsTemplateArgumentDependentType(TYPE_MEMBER_POINTER(type)->ty1))
+ return 1;
+ type = TYPE_MEMBER_POINTER(type)->ty2;
+ continue;
+ case TYPEPOINTER:
+ case TYPEARRAY:
+ type = TPTR_TARGET(type);
+ continue;
+ case TYPEFUNC:
+ for (arg = TYPE_FUNC(type)->args; arg && arg != &elipsis && arg != &oldstyle; arg = arg->next) {
+ if (CTemplTool_IsTemplateArgumentDependentType(arg->type))
+ return 1;
+ }
+ type = TYPE_FUNC(type)->functype;
+ continue;
+ case TYPEBITFIELD:
+ type = TYPE_BITFIELD(type)->bitfieldtype;
+ continue;
+ case TYPETEMPLDEPEXPR:
+ return 1;
+ default:
+ CError_FATAL(822);
+ }
+ }
+}
+
+Boolean CTemplTool_IsTemplateArgumentDependentExpression(ENode *expr) {
+ if (!expr)
+ return 0;
+
+ if (IS_TYPE_TEMPLDEPEXPR(expr->rtype))
+ return 1;
+
+ return 0;
+}
+
+Boolean CTemplTool_IsSameTemplate(TemplParam *params, TemplArg *args) {
+ while (1) {
+ if (!args) {
+ CError_ASSERT(850, !params);
+ return 1;
+ }
+
+ CError_ASSERT(853, params && args->pid.type == params->pid.type);
+
+ switch (args->pid.type) {
+ case TPT_TYPE:
+ if (
+ !IS_TYPE_TEMPLATE(args->data.typeparam.type) ||
+ TYPE_TEMPLATE(args->data.typeparam.type)->dtype != TEMPLDEP_ARGUMENT ||
+ TYPE_TEMPLATE(args->data.typeparam.type)->u.pid.nindex != params->pid.nindex ||
+ TYPE_TEMPLATE(args->data.typeparam.type)->u.pid.index != params->pid.index ||
+ args->data.typeparam.qual != 0
+ )
+ return 0;
+ break;
+ case TPT_NONTYPE:
+ if (
+ !ENODE_IS(args->data.paramdecl.expr, ETEMPLDEP) ||
+ args->data.paramdecl.expr->data.templdep.subtype != TDE_PARAM ||
+ args->data.paramdecl.expr->data.templdep.u.pid.nindex != params->pid.nindex ||
+ args->data.paramdecl.expr->data.templdep.u.pid.index != params->pid.index
+ )
+ return 0;
+ break;
+ case TPT_TEMPLATE:
+ if (!IS_TYPE_TEMPLATE(args->data.ttargtype))
+ return 0;
+ break;
+ default:
+ CError_FATAL(886);
+ }
+
+ args = args->next;
+ params = params->next;
+ }
+}
+
+TemplClass *CTemplTool_IsTemplate(TypeTemplDep *ttd) {
+ if (ttd->dtype == TEMPLDEP_QUALNAME && ttd->u.qual.type->dtype == TEMPLDEP_TEMPLATE)
+ ttd = ttd->u.qual.type;
+ else if (ttd->dtype != TEMPLDEP_TEMPLATE)
+ return NULL;
+
+ if (CTemplTool_IsSameTemplate(ttd->u.templ.templ->templ__params, ttd->u.templ.args))
+ return ttd->u.templ.templ;
+ else
+ return NULL;
+}
+
+Type *CTemplTool_IsDependentTemplate(TemplClass *tmclass, TemplArg *args) {
+ TemplParam *param;
+ TemplArg *arg;
+ Type *type;
+
+ if (!tmclass->templ_parent || tmclass->inst_parent) {
+ arg = args;
+ param = tmclass->templ__params;
+ while (1) {
+ if (!arg) {
+ CError_ASSERT(988, !param);
+ return NULL;
+ }
+
+ CError_ASSERT(991, param && arg->pid.type == param->pid.type);
+
+ switch (arg->pid.type) {
+ case TPT_TYPE:
+ if (CTemplTool_IsTemplateArgumentDependentType(arg->data.typeparam.type))
+ goto done;
+ break;
+ case TPT_NONTYPE:
+ if (CTemplTool_IsTemplateArgumentDependentExpression(arg->data.paramdecl.expr))
+ goto done;
+ break;
+ case TPT_TEMPLATE:
+ if (!IS_TYPE_CLASS(arg->data.ttargtype) && CTemplTool_IsTemplateArgumentDependentType(arg->data.ttargtype))
+ goto done;
+ break;
+ default:
+ CError_FATAL(1008);
+ goto done;
+ }
+
+ arg = arg->next;
+ param = param->next;
+ }
+ }
+done:
+ if (cscope_current->theclass == TYPE_CLASS(tmclass) && CTemplTool_IsSameTemplate(tmclass->templ__params, args))
+ return TYPE(tmclass);
+
+ type = CDecl_NewTemplDepType(TEMPLDEP_TEMPLATE);
+ TYPE_TEMPLATE(type)->u.templ.templ = tmclass;
+ TYPE_TEMPLATE(type)->u.templ.args = args;
+ return type;
+}
+
+Boolean CTemplTool_EqualExprTypes(ENode *a, ENode *b) {
+ Object *objA;
+ Object *objB;
+
+ if (!a || !b)
+ return 0;
+ if (a->type != b->type)
+ return 0;
+
+ switch (a->type) {
+ case EINTCONST:
+ return CInt64_Equal(a->data.intval, b->data.intval);
+ case EOBJREF:
+ objA = a->data.objref;
+ while (objA->datatype == DALIAS)
+ objA = objA->u.alias.object;
+ objB = b->data.objref;
+ while (objB->datatype == DALIAS)
+ objB = objB->u.alias.object;
+ return objA == objB;
+ case EMEMBER:
+ return a->data.emember->list == b->data.emember->list;
+ case ETEMPLDEP:
+ if (a->data.templdep.subtype != b->data.templdep.subtype)
+ return 0;
+
+ switch (a->data.templdep.subtype) {
+ case TDE_PARAM:
+ return a->data.templdep.u.pid.nindex == b->data.templdep.u.pid.nindex &&
+ a->data.templdep.u.pid.index == b->data.templdep.u.pid.index;
+ case TDE_SIZEOF:
+ case TDE_ALIGNOF:
+ return is_typesame(a->data.templdep.u.typeexpr.type, b->data.templdep.u.typeexpr.type);
+ case TDE_CAST:
+ return is_typesame(a->data.templdep.u.cast.type, b->data.templdep.u.cast.type) &&
+ a->data.templdep.u.cast.qual == b->data.templdep.u.cast.qual;
+ case TDE_QUALNAME:
+ return is_typesame(TYPE(a->data.templdep.u.qual.type), TYPE(b->data.templdep.u.qual.type)) &&
+ a->data.templdep.u.qual.name == b->data.templdep.u.qual.name;
+ case TDE_OBJ:
+ return a->data.templdep.u.obj == b->data.templdep.u.obj;
+ case TDE_ADDRESS_OF:
+ return CTemplTool_EqualExprTypes(a->data.templdep.u.monadic, b->data.templdep.u.monadic);
+ default:
+ CError_FATAL(1086);
+ }
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ 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 EROTL:
+ case EROTR:
+ return CTemplTool_EqualExprTypes(a->data.diadic.left, b->data.diadic.left) &&
+ CTemplTool_EqualExprTypes(a->data.diadic.right, b->data.diadic.right);
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ return CTemplTool_EqualExprTypes(a->data.monadic, b->data.monadic);
+ case ECOND:
+ return CTemplTool_EqualExprTypes(a->data.cond.cond, b->data.cond.cond) &&
+ CTemplTool_EqualExprTypes(a->data.cond.expr1, b->data.cond.expr1) &&
+ CTemplTool_EqualExprTypes(a->data.cond.expr2, b->data.cond.expr2);
+ default:
+ CError_FATAL(1122);
+ return 0;
+ }
+}
+
+ENode *CTempl_MakeTemplDepExpr(ENode *left, ENodeType nt, ENode *right) {
+ if (!IS_TYPE_TEMPLDEPEXPR(right->rtype)) {
+ right = pointer_generation(right);
+ if (!ENODE_IS(right, EINTCONST)) {
+ CError_Error(CErrorStr348);
+ right = nullnode();
+ }
+ }
+
+ if (left) {
+ if (!IS_TYPE_TEMPLDEPEXPR(left->rtype)) {
+ left = pointer_generation(left);
+ if (!ENODE_IS(left, EINTCONST)) {
+ CError_Error(CErrorStr348);
+ left = nullnode();
+ }
+ }
+
+ left = makediadicnode(left, right, nt);
+ } else {
+ left = makemonadicnode(right, nt);
+ }
+
+ left->rtype = &sttemplexpr;
+ return left;
+}
+
+void CTemplTool_CheckTemplArgType(Type *type) {
+ while (IS_TYPE_POINTER_ONLY(type))
+ type = TPTR_TARGET(type);
+
+ if (IS_TYPE_CLASS(type)) {
+ if (IsTempName(TYPE_CLASS(type)->classname) || CScope_IsInLocalNameSpace(TYPE_CLASS(type)->nspace))
+ CError_Error(CErrorStr232);
+ }
+}
+
+Boolean CTemplTool_EqualArgs(TemplArg *a, TemplArg *b) {
+ while (a) {
+ if (!b || a->pid.type != b->pid.type)
+ return 0;
+
+ switch (a->pid.type) {
+ case TPT_TYPE:
+ if (
+ !is_typesame(a->data.typeparam.type, b->data.typeparam.type) ||
+ a->data.typeparam.qual != b->data.typeparam.qual
+ )
+ return 0;
+ break;
+ case TPT_NONTYPE:
+ if (!CTemplTool_EqualExprTypes(a->data.paramdecl.expr, b->data.paramdecl.expr))
+ return 0;
+ break;
+ case TPT_TEMPLATE:
+ if (!is_typesame(a->data.ttargtype, b->data.ttargtype))
+ return 0;
+ break;
+ default:
+ CError_FATAL(1215);
+ }
+
+ a = a->next;
+ b = b->next;
+ }
+
+ if (b)
+ return 0;
+
+ return 1;
+}
+
+TemplArg *CTemplTool_MakeGlobalTemplArgCopy(TemplArg *args) {
+ TemplArg *firstCopy;
+ TemplArg *copy;
+
+ firstCopy = NULL;
+ while (args) {
+ if (firstCopy) {
+ copy->next = galloc(sizeof(TemplArg));
+ copy = copy->next;
+ } else {
+ copy = galloc(sizeof(TemplArg));
+ firstCopy = copy;
+ }
+
+ *copy = *args;
+ if (copy->pid.type == TPT_NONTYPE && copy->data.paramdecl.expr)
+ copy->data.paramdecl.expr = CInline_CopyExpression(copy->data.paramdecl.expr, CopyMode1);
+
+ args = args->next;
+ }
+
+ return firstCopy;
+}
+
+Boolean CTemplTool_TemplDepTypeCompare(TypeTemplDep *a, TypeTemplDep *b) {
+ if (a == b)
+ return 1;
+ if (a->dtype != b->dtype)
+ return 0;
+
+ switch (a->dtype) {
+ case TEMPLDEP_ARGUMENT:
+ return a->u.pid.nindex == b->u.pid.nindex &&
+ a->u.pid.index == b->u.pid.index;
+ case TEMPLDEP_QUALNAME:
+ return CTemplTool_TemplDepTypeCompare(a->u.qual.type, b->u.qual.type) &&
+ a->u.qual.name == b->u.qual.name;
+ case TEMPLDEP_TEMPLATE:
+ return a->u.templ.templ == b->u.templ.templ &&
+ CTemplTool_EqualArgs(a->u.templ.args, b->u.templ.args);
+ case TEMPLDEP_ARRAY:
+ return is_typesame(a->u.array.type, b->u.array.type) &&
+ CTemplTool_EqualExprTypes(a->u.array.index, b->u.array.index);
+ case TEMPLDEP_QUALTEMPL:
+ return CTemplTool_TemplDepTypeCompare(a->u.qualtempl.type, b->u.qualtempl.type) &&
+ CTemplTool_EqualArgs(a->u.qualtempl.args, b->u.qualtempl.args);
+ case TEMPLDEP_BITFIELD:
+ return is_typesame(a->u.bitfield.type, b->u.bitfield.type) &&
+ CTemplTool_EqualExprTypes(a->u.bitfield.size, b->u.bitfield.size);
+ default:
+ CError_FATAL(1286);
+ return 0;
+ }
+}
+
+Type *CTemplTool_DeduceArgDepType(TemplArg *args, Type *type, UInt32 qual, UInt32 *resultQual) {
+ TemplArg *arg;
+
+ *resultQual = qual;
+
+ if (IS_TYPE_TEMPLATE(type) && TYPE_TEMPLATE(type)->dtype == TEMPLDEP_ARGUMENT) {
+ arg = args;
+ while (1) {
+ if (!arg)
+ return NULL;
+
+ if (
+ arg->pid.index == TYPE_TEMPLATE(type)->u.pid.index &&
+ arg->pid.nindex == TYPE_TEMPLATE(type)->u.pid.nindex
+ )
+ break;
+
+ arg = arg->next;
+ }
+
+ CError_ASSERT(1314, arg->pid.type == TPT_TYPE);
+ *resultQual |= arg->data.typeparam.qual;
+ return arg->data.typeparam.type;
+ }
+
+ return NULL;
+}
+
+static TemplClassInst *CTemplTool_FindNestedClassInstance(TemplClass *a, TemplClass *b, TemplClassInst *c) {
+ TemplClass *array[32];
+ TemplClassInst *inst;
+ int i;
+
+ array[0] = a;
+ i = 0;
+ while (1) {
+ CError_ASSERT(1338, i < 32);
+ CError_ASSERT(1339, a = a->templ_parent);
+
+ if (a == b)
+ break;
+
+ CError_ASSERT(1341, a->templ__params == NULL);
+
+ array[++i] = a;
+ }
+
+ while (1) {
+ inst = array[i--]->instances;
+ while (1) {
+ CError_ASSERT(1350, inst);
+ if (inst->parent == c)
+ break;
+ inst = inst->next;
+ }
+
+ c = inst;
+ if (i < 0)
+ break;
+
+ if ((inst->theclass.flags & (CLASS_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST)
+ CTempl_InstantiateTemplateClass(TYPE_CLASS(inst));
+ }
+
+ return inst;
+}
+
+static TemplClassInst *CTemplTool_FindNestedClass(TemplClass *a, TemplClassInst *b, TemplClass *c) {
+ TemplClass *scan;
+
+ while (1) {
+ for (scan = c->templ_parent; scan; scan = scan->templ_parent) {
+ if (scan == a)
+ return CTemplTool_FindNestedClassInstance(c, a, b);
+ }
+
+ a = a->templ_parent;
+ if (!a)
+ break;
+
+ b = b->parent;
+ CError_ASSERT(1377, b);
+ }
+
+ return NULL;
+}
+
+static Type *CTemplTool_FindTemplateInstance(TypeDeduce *deduce, TemplClass *templ) {
+ TemplClass *scantempl;
+ TemplClass *dtempl;
+ TemplClassInst *scaninst;
+ TemplClassInst *dinst;
+
+ dtempl = deduce->tmclass;
+ CError_ASSERT(1393, dtempl);
+
+ dinst = deduce->inst;
+ if (!dinst) {
+ if (!dtempl->templ_parent || !dtempl->inst_parent)
+ return TYPE(templ);
+
+ dtempl = dtempl->templ_parent;
+ dinst = deduce->tmclass->inst_parent;
+ }
+
+ scantempl = dtempl;
+ scaninst = dinst;
+ while (1) {
+ if (scantempl == templ)
+ return TYPE(scaninst);
+
+ if (!scantempl->templ_parent && scantempl->pspec_owner)
+ scantempl = scantempl->pspec_owner;
+
+ scantempl = scantempl->templ_parent;
+ if (!scantempl)
+ break;
+
+ CError_ASSERT(1416, scaninst = scaninst->parent);
+ }
+
+ if (dtempl->flags & TEMPLCLASS_FLAGS_2) {
+ scantempl = TEMPL_CLASS(dtempl->theclass.nspace->theclass);
+ CError_ASSERT(1422, scantempl->theclass.flags & CLASS_IS_TEMPL);
+ scaninst = dinst;
+
+ while (1) {
+ if (scantempl == templ)
+ return TYPE(scaninst);
+
+ scantempl = scantempl->templ_parent;
+ if (!scantempl)
+ break;
+
+ CError_ASSERT(1430, scaninst = scaninst->parent);
+ }
+ }
+
+ if (!templ->templ__params && (scaninst = CTemplTool_FindNestedClass(dtempl, dinst, templ)))
+ return TYPE(scaninst);
+
+ CError_FATAL(1477);
+ return NULL;
+}
+
+static ENode *CTemplTool_DeduceExprCheck(ENode *expr) {
+ if (expr->type != EINTCONST) {
+ CError_Error(CErrorStr348);
+ expr = nullnode();
+ }
+
+ return expr;
+}
+
+static ENodeList *CTemplTool_DeduceExprList(TypeDeduce *deduce, ENodeList *list) {
+ ENodeList *resultList;
+ ENodeList *last;
+
+ resultList = NULL;
+ while (list) {
+ if (resultList) {
+ last->next = lalloc(sizeof(ENodeList));
+ last = last->next;
+ } else {
+ last = lalloc(sizeof(ENodeList));
+ resultList = last;
+ }
+
+ *last = *list;
+ last->node = CTemplTool_DeduceExpr(deduce, last->node);
+
+ list = list->next;
+ }
+
+ return resultList;
+}
+
+ENode *CTemplTool_DeduceExpr(TypeDeduce *deduce, ENode *expr) {
+ TemplArg *arg;
+ TemplClassInst *inst;
+ ENode *newExpr;
+ NameSpaceObjectList *nsObjectList;
+ TStreamElement *saved;
+ NameResult pr;
+ Type *type;
+ UInt32 qual;
+
+ if (!CTemplTool_IsTemplateArgumentDependentExpression(expr)) {
+ newExpr = lalloc(sizeof(ENode));
+ *newExpr = *expr;
+ return newExpr;
+ }
+
+ switch (expr->type) {
+ case ETEMPLDEP:
+ switch (expr->data.templdep.subtype) {
+ case TDE_PARAM:
+ if (deduce->x15 && expr->data.templdep.u.pid.nindex == deduce->nindex) {
+ newExpr = lalloc(sizeof(ENode));
+ *newExpr = *expr;
+ return newExpr;
+ }
+
+ for (arg = deduce->args; arg; arg = arg->next) {
+ if (
+ arg->pid.index == expr->data.templdep.u.pid.index &&
+ arg->pid.nindex == expr->data.templdep.u.pid.nindex
+ )
+ {
+ CError_ASSERT(1562, arg->pid.type == TPT_NONTYPE && arg->data.paramdecl.expr);
+ newExpr = lalloc(sizeof(ENode));
+ *newExpr = *arg->data.paramdecl.expr;
+ return newExpr;
+ }
+ }
+
+ for (inst = deduce->inst; inst; inst = inst->parent) {
+ for (arg = inst->inst_args; arg; arg = arg->next) {
+ if (
+ arg->pid.index == expr->data.templdep.u.pid.index &&
+ arg->pid.nindex == expr->data.templdep.u.pid.nindex
+ )
+ {
+ CError_ASSERT(1575, arg->pid.type == TPT_NONTYPE && arg->data.paramdecl.expr);
+ newExpr = lalloc(sizeof(ENode));
+ *newExpr = *arg->data.paramdecl.expr;
+ return newExpr;
+ }
+ }
+ }
+
+ CError_FATAL(1582);
+
+ case TDE_SIZEOF:
+ qual = 0;
+ type = CTemplTool_DeduceTypeCopy(deduce, TYPE(expr->data.templdep.u.typeexpr.type), &qual);
+ CDecl_CompleteType(type);
+
+ if (CTemplTool_IsTemplateArgumentDependentType(type)) {
+ newExpr = lalloc(sizeof(ENode));
+ *newExpr = *expr;
+ newExpr->data.templdep.u.typeexpr.type = type;
+ return newExpr;
+ }
+
+ return intconstnode(CABI_GetSizeTType(), type->size);
+
+ case TDE_ALIGNOF:
+ qual = 0;
+ type = CTemplTool_DeduceTypeCopy(deduce, TYPE(expr->data.templdep.u.typeexpr.type), &qual);
+ CDecl_CompleteType(type);
+
+ if (CTemplTool_IsTemplateArgumentDependentType(type)) {
+ newExpr = lalloc(sizeof(ENode));
+ *newExpr = *expr;
+ newExpr->data.templdep.u.typeexpr.type = type;
+ return newExpr;
+ }
+
+ return intconstnode(CABI_GetSizeTType(), CMach_GetTypeAlign(type));
+
+ case TDE_CAST:
+ qual = expr->data.templdep.u.cast.qual;
+ type = CTemplTool_DeduceTypeCopy(deduce, expr->data.templdep.u.cast.type, &qual);
+ return CExpr_DoExplicitConversion(type, qual, CTemplTool_DeduceExprList(deduce, expr->data.templdep.u.cast.args));
+
+ case TDE_QUALNAME:
+ qual = 0;
+ type = CTemplTool_DeduceTypeCopy(deduce, TYPE(expr->data.templdep.u.qual.type), &qual);
+
+ if (IS_TYPE_CLASS(type)) {
+ CDecl_CompleteType(type);
+ if (CScope_FindQualifiedClassMember(&pr, TYPE_CLASS(type), expr->data.templdep.u.qual.name))
+ return pointer_generation(CExpr_MakeNameLookupResultExpr(&pr));
+
+ CError_Error(CErrorStr150, expr->data.templdep.u.qual.name->name);
+ } else if (IS_TYPE_TEMPLATE(type) && !deduce->inst) {
+ newExpr = lalloc(sizeof(ENode));
+ *newExpr = *expr;
+ newExpr->data.templdep.u.qual.type = TYPE_TEMPLATE(type);
+ return newExpr;
+ } else {
+ CError_Error(CErrorStr340, expr->data.templdep.u.qual.name->name);
+ }
+
+ return nullnode();
+
+ case TDE_OBJ:
+ type = CTemplTool_FindTemplateInstance(deduce, TEMPL_CLASS(expr->data.templdep.u.obj->nspace->theclass));
+ CError_ASSERT(1651, type && IS_TYPE_CLASS(type));
+
+ nsObjectList = CScope_GetLocalObject(TYPE_CLASS(type)->nspace, expr->data.templdep.u.obj->name);
+ CError_ASSERT(1654, nsObjectList);
+
+ memclrw(&pr, sizeof(pr));
+ pr.obj_10 = nsObjectList->object;
+ return pointer_generation(CExpr_MakeNameLookupResultExpr(&pr));
+
+ case TDE_SOURCEREF:
+ CError_LockErrorPos(expr->data.templdep.u.sourceref.token, &saved);
+ newExpr = CTemplTool_DeduceExpr(deduce, expr->data.templdep.u.sourceref.expr);
+ CError_UnlockErrorPos(&saved);
+ return newExpr;
+
+ case TDE_ADDRESS_OF:
+ return getnodeaddress(CTemplTool_DeduceExpr(deduce, expr->data.templdep.u.monadic), 1);
+
+ default:
+ CError_FATAL(1671);
+ }
+ case EFUNCCALL:
+ newExpr = CExpr_PointerGeneration(CTemplTool_DeduceExpr(deduce, expr->data.funccall.funcref));
+ return CExpr_MakeFunctionCall(newExpr, CTemplTool_DeduceExprList(deduce, expr->data.funccall.args));
+ case ELOGNOT:
+ return CExpr_New_ELOGNOT_Node(CTemplTool_DeduceExpr(deduce, expr->data.monadic));
+ case EMONMIN:
+ return CExpr_New_EMONMIN_Node(CTemplTool_DeduceExpr(deduce, expr->data.monadic));
+ case EBINNOT:
+ return CExpr_New_EBINNOT_Node(CTemplTool_DeduceExpr(deduce, expr->data.monadic));
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ 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 EROTL:
+ case EROTR:
+ return CExpr_NewDyadicNode(
+ CTemplTool_DeduceExpr(deduce, expr->data.diadic.left),
+ expr->type,
+ CTemplTool_DeduceExpr(deduce, expr->data.diadic.right));
+ case ECOND:
+ return CExpr_New_ECOND_Node(
+ CTemplTool_DeduceExpr(deduce, expr->data.cond.cond),
+ CTemplTool_DeduceExpr(deduce, expr->data.cond.expr1),
+ CTemplTool_DeduceExpr(deduce, expr->data.cond.expr2));
+ default:
+ CError_FATAL(1727);
+ case EINTCONST:
+ newExpr = lalloc(sizeof(ENode));
+ *newExpr = *expr;
+ return newExpr;
+ }
+}
+
+ENode *CTemplTool_DeduceDefaultArg(Object *func, ENode *expr) {
+ TypeDeduce deduce;
+
+ memclrw(&deduce, sizeof(deduce));
+ CError_ASSERT(1747, IS_TYPE_FUNC(func->type));
+
+ if (func->u.func.inst)
+ deduce.args = func->u.func.inst->args;
+
+ if ((TYPE_FUNC(func->type)->flags & FUNC_METHOD) && (TYPE_METHOD(func->type)->theclass->flags & CLASS_IS_TEMPL_INST)) {
+ deduce.inst = TEMPL_CLASS_INST(TYPE_METHOD(func->type)->theclass);
+ deduce.tmclass = TEMPL_CLASS_INST(TYPE_METHOD(func->type)->theclass)->templ;
+ }
+
+ return CTemplTool_DeduceExpr(&deduce, expr);
+}
+
+static TemplClass *CTemplTool_FindNestedTemplateInstance(TypeDeduce *deduce, TemplClass *templ) {
+ TemplClass *dtempl;
+ TemplClassInst *dinst;
+ Type *type;
+
+ if (templ->inst_parent)
+ return templ;
+
+ CError_ASSERT(1776, (dtempl = deduce->tmclass) && (dinst = deduce->inst));
+
+ while (1) {
+ if (
+ templ->templ_parent == dtempl &&
+ (type = CScope_GetLocalTagType(dinst->theclass.nspace, templ->theclass.classname)) &&
+ IS_TEMPL_CLASS(type) &&
+ TEMPL_CLASS(type)->templ_parent == templ->templ_parent
+ )
+ return TEMPL_CLASS(type);
+
+ dtempl = dtempl->templ_parent;
+ if (!dtempl)
+ break;
+
+ dinst = dinst->parent;
+ CError_ASSERT(1790, dinst);
+ }
+
+ return templ;
+}
+
+static Type *CTemplTool_DeduceClassInstanceCopy(TypeDeduce *deduce, TemplClass *templ, TemplArg *args) {
+ TemplArg *arg;
+ TemplArg *deducedArgs;
+ TemplArg *last;
+ TemplParam *param;
+ UInt32 qual;
+ Type *type;
+
+ if (templ->templ_parent)
+ templ = CTemplTool_FindNestedTemplateInstance(deduce, templ);
+
+ arg = args;
+ deducedArgs = NULL;
+ param = templ->templ__params;
+
+ while (arg) {
+ if (deducedArgs) {
+ last->next = galloc(sizeof(TemplArg));
+ last = last->next;
+ } else {
+ last = galloc(sizeof(TemplArg));
+ deducedArgs = last;
+ }
+
+ *last = *arg;
+
+ if (!param || param->pid.type != last->pid.type) {
+ CError_Error(CErrorStr374);
+ return &stvoid;
+ }
+
+ last->pid = param->pid;
+ param = param->next;
+
+ switch (last->pid.type) {
+ case TPT_TYPE:
+ last->data.typeparam.type = CTemplTool_DeduceTypeCopy(deduce, last->data.typeparam.type, &last->data.typeparam.qual);
+ break;
+
+ case TPT_NONTYPE:
+ if (!last->data.paramdecl.expr) {
+ CError_FATAL(1873);
+ } else if (CTemplTool_IsTemplateArgumentDependentExpression(last->data.paramdecl.expr)) {
+ last->data.paramdecl.expr = pointer_generation(CTemplTool_DeduceExpr(deduce, last->data.paramdecl.expr));
+ last->data.paramdecl.expr = CInline_CopyExpression(last->data.paramdecl.expr, CopyMode1);
+ }
+ break;
+
+ case TPT_TEMPLATE:
+ qual = 0;
+ last->data.ttargtype = CTemplTool_DeduceTypeCopy(deduce, last->data.ttargtype, &qual);
+ break;
+
+ default:
+ CError_FATAL(1891);
+ }
+
+ arg = arg->next;
+ }
+
+ for (arg = deducedArgs; arg; arg = arg->next) {
+ switch (arg->pid.type) {
+ case TPT_TYPE:
+ if (CTemplTool_IsTemplateArgumentDependentType(arg->data.typeparam.type))
+ break;
+ continue;
+
+ case TPT_NONTYPE:
+ if (CTemplTool_IsTemplateArgumentDependentExpression(arg->data.paramdecl.expr))
+ break;
+
+ switch (arg->data.paramdecl.expr->type) {
+ case EINTCONST:
+ case EOBJLIST:
+ case EMEMBER:
+ break;
+ case EOBJREF:
+ if (CParser_HasInternalLinkage2(arg->data.paramdecl.expr->data.objref))
+ CError_Error(CErrorStr357);
+ break;
+ default:
+ CError_Error(CErrorStr371);
+ arg->data.paramdecl.expr = nullnode();
+ break;
+ }
+ continue;
+
+ case TPT_TEMPLATE:
+ if (!IS_TYPE_CLASS(arg->data.ttargtype) && CTemplTool_IsTemplateArgumentDependentType(arg->data.ttargtype))
+ break;
+ continue;
+
+ default:
+ CError_FATAL(1937);
+ }
+
+ break;
+ }
+
+ if (arg) {
+ type = CDecl_NewTemplDepType(TEMPLDEP_TEMPLATE);
+ TYPE_TEMPLATE(type)->u.templ.templ = templ;
+ TYPE_TEMPLATE(type)->u.templ.args = deducedArgs;
+ return type;
+ }
+
+ if ((type = CTemplTool_IsDependentTemplate(templ, deducedArgs)))
+ return type;
+
+ return TYPE(CTemplClass_GetInstance(templ, deducedArgs, NULL));
+}
+
+static TemplArg *CTemplTool_FindTemplArg(TemplArg *args, TemplParamID pid) {
+ while (args) {
+ if (args->pid.index == pid.index && args->pid.nindex == pid.nindex) {
+ CError_ASSERT(1984, pid.type == args->pid.type);
+ return args;
+ }
+ args = args->next;
+ }
+
+ return NULL;
+}
+
+static TemplArg *CTemplTool_DeduceTemplArg(TypeDeduce *deduce, TemplParamID pid) {
+ TemplClass *tmclass;
+ TemplClassInst *inst;
+ TemplArg *arg;
+
+ if ((arg = CTemplTool_FindTemplArg(deduce->args, pid)))
+ return arg;
+
+ tmclass = deduce->tmclass;
+ CError_ASSERT(2008, tmclass);
+
+ inst = deduce->inst;
+ if (!inst) {
+ CError_ASSERT(2011, tmclass->templ_parent && tmclass->inst_parent);
+ inst = deduce->tmclass->inst_parent;
+ }
+
+ while (1) {
+ if ((arg = CTemplTool_FindTemplArg(inst->inst_args, pid)))
+ return arg;
+
+ inst = inst->parent;
+ CError_ASSERT(2022, inst);
+ }
+}
+
+static Type *CTemplTool_DeduceArrayCopy(TypeDeduce *deduce, Type *type, ENode *index, UInt32 *resultQual) {
+ if (CTemplTool_IsTemplateArgumentDependentType(type))
+ type = CTemplTool_DeduceTypeCopy(deduce, type, resultQual);
+
+ index = CTemplTool_DeduceExpr(deduce, index);
+
+ if (ENODE_IS(index, EINTCONST)) {
+ if (CInt64_IsNegative(&index->data.intval)) {
+ CError_Error(CErrorStr124);
+ index->data.intval = cint64_one;
+ }
+
+ if (!CDecl_CheckArrayIntegr(type))
+ type = TYPE(&stsignedchar);
+
+ type = CDecl_NewArrayType(type, type->size * CInt64_GetULong(&index->data.intval));
+ } else {
+ if (!deduce->x16)
+ CError_Error(CErrorStr124);
+ }
+
+ return type;
+}
+
+static Type *CTemplTool_DeduceBitfieldCopy(TypeDeduce *deduce, Type *type, ENode *size, UInt32 *resultQual) {
+ TypeBitfield *tbitfield;
+ short sizeval;
+ short maxsize;
+
+ if (CTemplTool_IsTemplateArgumentDependentType(type)) {
+ UInt32 qual = 0;
+ type = CTemplTool_DeduceTypeCopy(deduce, type, &qual);
+ }
+
+ if (!IS_TYPE_INT_OR_ENUM(type)) {
+ CError_Error(CErrorStr138);
+ type = TYPE(&stunsignedint);
+ }
+
+ switch (type->size) {
+ case 1:
+ maxsize = 8;
+ break;
+ case 2:
+ maxsize = 16;
+ break;
+ case 4:
+ maxsize = 32;
+ break;
+ default:
+ CError_Error(CErrorStr138);
+ return type;
+ }
+
+ if (!ENODE_IS(size, EINTCONST)) {
+ size = CTemplTool_DeduceExpr(deduce, size);
+ if (!ENODE_IS(size, EINTCONST)) {
+ CError_Error(CErrorStr124);
+ return type;
+ }
+ }
+
+ sizeval = CInt64_GetULong(&size->data.intval);
+ if (sizeval > maxsize || CInt64_IsNegative(&size->data.intval)) {
+ CError_Error(CErrorStr138);
+ sizeval = 1;
+ }
+
+ tbitfield = galloc(sizeof(TypeBitfield));
+ memclrw(tbitfield, sizeof(TypeBitfield));
+
+ tbitfield->type = TYPEBITFIELD;
+ tbitfield->size = type->size;
+ tbitfield->bitfieldtype = type;
+ tbitfield->bitlength = sizeval;
+
+ return TYPE(tbitfield);
+}
+
+static Type *CTemplTool_DeduceTemplDepType(TypeDeduce *deduce, TypeTemplDep *tdt, UInt32 *resultQual) {
+ Type *type;
+ UInt32 qual;
+ TemplArg *arg;
+
+ qual = 0;
+
+ if (deduce->x14) {
+ type = CTemplTool_GetSelfRefTemplate(TYPE(tdt));
+ if (type && type == TYPE(deduce->tmclass))
+ return type;
+
+ switch (tdt->dtype) {
+ case TEMPLDEP_ARGUMENT:
+ return TYPE(tdt);
+
+ case TEMPLDEP_QUALNAME:
+ type = CTemplTool_DeduceTypeCopy(deduce, TYPE(tdt->u.qual.type), &qual);
+ if (type == TYPE(tdt->u.qual.type))
+ return TYPE(tdt);
+
+ if (!IS_TYPE_CLASS(type)) {
+ TypeTemplDep *tdtCopy;
+ CError_ASSERT(2157, IS_TYPE_TEMPLATE(type));
+ tdtCopy = galloc(sizeof(TypeTemplDep));
+ *tdtCopy = *tdt;
+ tdtCopy->u.qual.type = TYPE_TEMPLATE(type);
+ return TYPE(tdtCopy);
+ } else if ((type = CScope_GetType(TYPE_CLASS(type)->nspace, tdt->u.qual.name, resultQual))) {
+ return type;
+ } else {
+ CError_Error(CErrorStr150, tdt->u.qual.name->name);
+ return TYPE(tdt);
+ }
+
+ case TEMPLDEP_TEMPLATE:
+ for (arg = tdt->u.templ.args; arg; arg = arg->next) {
+ if (arg->pid.type == TPT_TYPE)
+ arg->data.typeparam.type = CTemplTool_DeduceTypeCopy(deduce, arg->data.typeparam.type, &arg->data.typeparam.qual);
+ }
+ return TYPE(tdt);
+
+ case TEMPLDEP_ARRAY:
+ tdt->u.array.type = CTemplTool_DeduceTypeCopy(deduce, tdt->u.array.type, &qual);
+ return TYPE(tdt);
+
+ case TEMPLDEP_QUALTEMPL:
+ tdt->u.qualtempl.type = TYPE_TEMPLATE(CTemplTool_DeduceTemplDepType(deduce, tdt->u.qualtempl.type, &qual));
+ for (arg = tdt->u.qualtempl.args; arg; arg = arg->next) {
+ if (arg->pid.type == TPT_TYPE)
+ arg->data.typeparam.type = CTemplTool_DeduceTypeCopy(deduce, arg->data.typeparam.type, &arg->data.typeparam.qual);
+ }
+ return TYPE(tdt);
+
+ case TEMPLDEP_BITFIELD:
+ tdt->u.bitfield.type = CTemplTool_DeduceTypeCopy(deduce, tdt->u.bitfield.type, &qual);
+ return TYPE(tdt);
+ }
+ } else {
+ switch (tdt->dtype) {
+ case TEMPLDEP_ARGUMENT:
+ if (deduce->x15 && tdt->u.pid.nindex == deduce->nindex)
+ return TYPE(tdt);
+
+ arg = CTemplTool_DeduceTemplArg(deduce, tdt->u.pid);
+ if (arg->pid.type == TPT_TEMPLATE) {
+ CError_ASSERT(2222, IS_TEMPL_CLASS(arg->data.typeparam.type));
+ *resultQual = arg->data.typeparam.qual;
+ return arg->data.typeparam.type;
+ }
+
+ CError_ASSERT(2226, arg->pid.type == TPT_TYPE);
+ *resultQual = arg->data.typeparam.qual;
+ return arg->data.typeparam.type;
+
+ case TEMPLDEP_QUALNAME:
+ type = CTemplTool_DeduceTypeCopy(deduce, TYPE(tdt->u.qual.type), &qual);
+ if (IS_TYPE_CLASS(type)) {
+ CDecl_CompleteType(type);
+ if ((type = CScope_GetType(TYPE_CLASS(type)->nspace, tdt->u.qual.name, resultQual))) {
+ return type;
+ } else {
+ CError_Error(CErrorStr150, tdt->u.qual.name->name);
+ }
+ } else {
+ if ((deduce->x15 || !deduce->inst) && IS_TYPE_TEMPLATE(type)) {
+ TypeTemplDep *tdtCopy = galloc(sizeof(TypeTemplDep));
+ *tdtCopy = *tdt;
+ tdtCopy->u.qual.type = TYPE_TEMPLATE(type);
+ return TYPE(tdtCopy);
+ } else {
+ CError_Error(CErrorStr340, tdt->u.qual.name->name);
+ }
+ }
+ return TYPE(&stsignedint);
+
+ case TEMPLDEP_TEMPLATE:
+ return CTemplTool_DeduceClassInstanceCopy(deduce, tdt->u.templ.templ, tdt->u.templ.args);
+
+ case TEMPLDEP_ARRAY:
+ return CTemplTool_DeduceArrayCopy(deduce, tdt->u.array.type, tdt->u.array.index, resultQual);
+
+ case TEMPLDEP_QUALTEMPL:
+ type = CTemplTool_DeduceTypeCopy(deduce, TYPE(tdt->u.qualtempl.type), &qual);
+ if (!IS_TEMPL_CLASS(type)) {
+ CError_Error(CErrorStr121);
+ return TYPE(&stsignedint);
+ }
+ return CTemplTool_DeduceClassInstanceCopy(deduce, TEMPL_CLASS(type), tdt->u.qualtempl.args);
+
+ case TEMPLDEP_BITFIELD:
+ return CTemplTool_DeduceBitfieldCopy(deduce, tdt->u.bitfield.type, tdt->u.bitfield.size, resultQual);
+ }
+ }
+
+ CError_FATAL(2275);
+ return NULL;
+}
+
+static Type *CTemplTool_DeduceTypeQualCopy(TypeDeduce *deduce, Type *type, UInt32 *resultQual) {
+ Type *innerType;
+ UInt32 qual;
+ UInt32 innerQual;
+ TypePointer *newPtr;
+
+ qual = *resultQual;
+
+ if (IS_TYPE_POINTER_ONLY(type) && IS_TYPE_TEMPLATE(TPTR_TARGET(type))) {
+ innerQual = 0;
+ innerType = CTemplTool_DeduceTemplDepType(deduce, TYPE_TEMPLATE(TPTR_TARGET(type)), &innerQual);
+
+ newPtr = galloc(sizeof(TypePointer));
+ *newPtr = *TYPE_POINTER(type);
+
+ if (IS_TYPE_POINTER_ONLY(innerType)) {
+ newPtr->target = galloc(sizeof(TypePointer));
+ *TYPE_POINTER(newPtr->target) = *TYPE_POINTER(innerType);
+ *resultQual = innerQual & (Q_CONST | Q_VOLATILE);
+ TPTR_QUAL(newPtr->target) |= qual & (Q_CONST | Q_VOLATILE);
+ } else if (IS_TYPE_MEMBERPOINTER(innerType)) {
+ newPtr->target = galloc(sizeof(TypeMemberPointer));
+ *TYPE_MEMBER_POINTER(newPtr->target) = *TYPE_MEMBER_POINTER(innerType);
+ *resultQual = innerQual & (Q_CONST | Q_VOLATILE);
+ TYPE_MEMBER_POINTER(newPtr->target)->qual |= qual & (Q_CONST | Q_VOLATILE);
+ } else {
+ newPtr->target = innerType;
+ *resultQual = (qual | innerQual) & (Q_CONST | Q_VOLATILE);
+ }
+
+ return TYPE(newPtr);
+ }
+
+ return CTemplTool_DeduceTypeCopy(deduce, type, resultQual);
+}
+
+FuncArg *CTemplTool_DeduceArgCopy(TypeDeduce *deduce, FuncArg *args) {
+ FuncArg *resultArgs;
+ FuncArg *last;
+
+ if (args == &oldstyle || args == &elipsis)
+ return args;
+
+ resultArgs = NULL;
+
+ while (args) {
+ if (args == &elipsis) {
+ last->next = args;
+ break;
+ }
+
+ if (resultArgs) {
+ last->next = galloc(sizeof(FuncArg));
+ last = last->next;
+ } else {
+ last = galloc(sizeof(FuncArg));
+ resultArgs = last;
+ }
+
+ *last = *args;
+ last->type = CTemplTool_DeduceTypeQualCopy(deduce, last->type, &last->qual);
+ CanCreateObject(last->type);
+
+ args = args->next;
+ }
+
+ return resultArgs;
+}
+
+static ExceptSpecList *CTemplTool_DeduceExSpecCopy(TypeDeduce *deduce, ExceptSpecList *exspec) {
+ ExceptSpecList *copy;
+
+ copy = galloc(sizeof(ExceptSpecList));
+ *copy = *exspec;
+
+ if (copy->type && CTemplTool_IsTemplateArgumentDependentType(copy->type))
+ copy->type = CTemplTool_DeduceTypeCopy(deduce, copy->type, &copy->qual);
+
+ if (copy->next)
+ copy->next = CTemplTool_DeduceExSpecCopy(deduce, copy->next);
+
+ return copy;
+}
+
+Type *CTemplTool_DeduceTypeCopy(TypeDeduce *deduce, Type *type, UInt32 *resultQual) {
+ TemplClassInst *inst;
+ Type *deduced;
+ UInt32 qual2;
+ UInt32 qual;
+
+ switch (type->type) {
+ case TYPETEMPLATE:
+ qual = 0;
+ deduced = CTemplTool_DeduceTemplDepType(deduce, TYPE_TEMPLATE(type), &qual);
+ if (*resultQual & (Q_CONST | Q_VOLATILE)) {
+ if (IS_TYPE_POINTER_ONLY(deduced)) {
+ TypePointer *newPtr = galloc(sizeof(TypePointer));
+ *newPtr = *TYPE_POINTER(deduced);
+ newPtr->qual |= *resultQual & (Q_CONST | Q_VOLATILE);
+ *resultQual &= ~(Q_CONST | Q_VOLATILE);
+ deduced = TYPE(newPtr);
+ } else if (IS_TYPE_MEMBERPOINTER(deduced)) {
+ TypeMemberPointer *newPtr = galloc(sizeof(TypeMemberPointer));
+ *newPtr = *TYPE_MEMBER_POINTER(deduced);
+ newPtr->qual |= *resultQual & (Q_CONST | Q_VOLATILE);
+ *resultQual &= ~(Q_CONST | Q_VOLATILE);
+ deduced = TYPE(newPtr);
+ }
+ }
+ *resultQual |= qual;
+ return deduced;
+
+ case TYPEVOID:
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPESTRUCT:
+ return type;
+
+ case TYPEENUM:
+ if (
+ TYPE_ENUM(type)->nspace->theclass &&
+ (TYPE_ENUM(type)->nspace->theclass->flags & CLASS_IS_TEMPL) &&
+ !deduce->x14
+ )
+ {
+ CError_ASSERT(2471, TYPE_ENUM(type)->enumname);
+ inst = TEMPL_CLASS_INST(CTemplTool_FindTemplateInstance(deduce, TEMPL_CLASS(TYPE_ENUM(type)->nspace->theclass)));
+ CError_ASSERT(2473, inst && inst->theclass.type == TYPECLASS);
+
+ CDecl_CompleteType(TYPE(inst));
+ type = CScope_GetLocalTagType(inst->theclass.nspace, TYPE_ENUM(type)->enumname);
+ CError_ASSERT(2477, type);
+ return type;
+ }
+ return type;
+
+ case TYPECLASS:
+ if (!deduce->x14) {
+ if (TYPE_CLASS(type)->flags & CLASS_IS_TEMPL)
+ return CTemplTool_FindTemplateInstance(deduce, TEMPL_CLASS(type));
+
+ if (TYPE_CLASS(type)->nspace->theclass && (TYPE_CLASS(type)->nspace->theclass->flags & CLASS_IS_TEMPL)) {
+ CError_ASSERT(2492, deduce->inst);
+ CError_ASSERT(2493, TYPE_CLASS(type)->classname);
+
+ type = CScope_GetLocalTagType(deduce->inst->theclass.nspace, TYPE_CLASS(type)->classname);
+ CError_ASSERT(2496, type);
+ return type;
+ }
+ }
+
+ return type;
+
+ case TYPEARRAY: {
+ SInt32 elements;
+
+ elements = TPTR_TARGET(type)->size;
+ if (elements > 0)
+ elements = type->size / elements;
+
+ deduced = galloc(sizeof(TypePointer));
+ *TYPE_POINTER(deduced) = *TYPE_POINTER(type);
+ TPTR_TARGET(deduced) = CTemplTool_DeduceTypeCopy(deduce, TPTR_TARGET(type), resultQual);
+
+ do {
+ type = TPTR_TARGET(type);
+ } while (IS_TYPE_ARRAY(type));
+
+ if (IS_TYPE_TEMPLATE(type)) {
+ CDecl_CompleteType(TPTR_TARGET(deduced));
+ deduced->size = TPTR_TARGET(deduced)->size * elements;
+ }
+
+ return deduced;
+ }
+
+ case TYPEPOINTER:
+ deduced = galloc(sizeof(TypePointer));
+ *TYPE_POINTER(deduced) = *TYPE_POINTER(type);
+ TPTR_TARGET(deduced) = CTemplTool_DeduceTypeCopy(deduce, TPTR_TARGET(type), resultQual);
+ return deduced;
+
+ case TYPEBITFIELD:
+ deduced = galloc(sizeof(TypeBitfield));
+ *TYPE_BITFIELD(deduced) = *TYPE_BITFIELD(type);
+ TYPE_BITFIELD(deduced)->bitfieldtype = CTemplTool_DeduceTypeCopy(deduce, TYPE_BITFIELD(type)->bitfieldtype, resultQual);
+ return deduced;
+
+ case TYPEMEMBERPOINTER:
+ deduced = galloc(sizeof(TypeMemberPointer));
+ *TYPE_MEMBER_POINTER(deduced) = *TYPE_MEMBER_POINTER(type);
+ TYPE_MEMBER_POINTER(deduced)->ty1 = CTemplTool_DeduceTypeCopy(deduce, TYPE_MEMBER_POINTER(type)->ty1, resultQual);
+ qual2 = 0;
+ TYPE_MEMBER_POINTER(deduced)->ty2 = CTemplTool_DeduceTypeCopy(deduce, TYPE_MEMBER_POINTER(type)->ty2, &qual2);
+
+ if (
+ !IS_TYPE_CLASS(TYPE_MEMBER_POINTER(deduced)->ty2) &&
+ !deduce->x14 &&
+ !deduce->x15 &&
+ !deduce->x16
+ )
+ {
+ CError_Error(CErrorStr232);
+ return TYPE_MEMBER_POINTER(deduced)->ty1;
+ }
+ return deduced;
+
+ case TYPEFUNC:
+ if (TYPE_FUNC(type)->flags & FUNC_METHOD) {
+ qual2 = 0;
+ deduced = galloc(sizeof(TypeMemberFunc));
+ *TYPE_METHOD(deduced) = *TYPE_METHOD(type);
+ TYPE_METHOD(deduced)->funcid = 0;
+ TYPE_METHOD(deduced)->theclass = TYPE_CLASS(CTemplTool_DeduceTypeQualCopy(deduce, TYPE(TYPE_METHOD(type)->theclass), &qual2));
+ CError_ASSERT(2556, IS_TYPE_CLASS(TYPE_METHOD(deduced)->theclass));
+ } else {
+ deduced = galloc(sizeof(TypeFunc));
+ *TYPE_FUNC(deduced) = *TYPE_FUNC(type);
+ }
+
+ TYPE_FUNC(deduced)->flags &= ~FUNC_IS_TEMPL;
+
+ qual2 = TYPE_FUNC(type)->qual;
+ TYPE_FUNC(deduced)->functype = CTemplTool_DeduceTypeQualCopy(deduce, TYPE_FUNC(type)->functype, &qual2);
+ TYPE_FUNC(deduced)->qual = qual2;
+
+ TYPE_FUNC(deduced)->args = CTemplTool_DeduceArgCopy(deduce, TYPE_FUNC(type)->args);
+ if (TYPE_FUNC(type)->exspecs)
+ TYPE_FUNC(deduced)->exspecs = CTemplTool_DeduceExSpecCopy(deduce, TYPE_FUNC(type)->exspecs);
+
+ CDecl_SetResultReg(TYPE_FUNC(deduced));
+ return deduced;
+
+ case TYPETEMPLDEPEXPR:
+ CError_Error(CErrorStr190);
+ return &stvoid;
+
+ default:
+ CError_FATAL(2580);
+ return NULL;
+ }
+}
+
+Type *CTemplTool_ResolveMemberSelfRefs(TemplClass *templ, Type *type, UInt32 *resultQual) {
+ TypeDeduce deduce;
+
+ memclrw(&deduce, sizeof(deduce));
+ deduce.tmclass = templ;
+ deduce.x14 = 1;
+
+ if (IS_TYPE_FUNC(type)) {
+ TYPE_FUNC(type)->functype = CTemplTool_DeduceTypeCopy(&deduce, TYPE_FUNC(type)->functype, &TYPE_FUNC(type)->qual);
+ TYPE_FUNC(type)->args = CTemplTool_DeduceArgCopy(&deduce, TYPE_FUNC(type)->args);
+ CDecl_SetResultReg(TYPE_FUNC(type));
+ } else {
+ type = CTemplTool_DeduceTypeCopy(&deduce, type, resultQual);
+ }
+
+ return type;
+}
+
+Boolean CTemplTool_IsSameTemplateType(Type *a, Type *b) {
+ return CTemplTool_GetSelfRefTemplate(b) == a;
+}
diff --git a/compiler_and_linker/FrontEnd/Common/CIRTransform.c b/compiler_and_linker/FrontEnd/Common/CIRTransform.c
new file mode 100644
index 0000000..b91f6af
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Common/CIRTransform.c
@@ -0,0 +1,534 @@
+#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;
+}
diff --git a/compiler_and_linker/FrontEnd/Common/COptimizer.c b/compiler_and_linker/FrontEnd/Common/COptimizer.c
new file mode 100644
index 0000000..3c83ae6
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Common/COptimizer.c
@@ -0,0 +1,1831 @@
+#include "compiler/COptimizer.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/enode.h"
+#include "compiler/objects.h"
+#include "compiler/CodeGen.h"
+#include "compiler/Switch.h"
+#include "compiler/Exceptions.h"
+#include "../Optimizer/IrOptimizer.h"
+#include "cos.h"
+
+COptBlock *basicblocks;
+Boolean copt_isleaffunction;
+static Boolean stmtchanged;
+static COptBlock *currentblock;
+static ENode *mexpr;
+static short setbytes;
+static COptCSE *csenodes[MAXEXPR];
+static COptCSEList *cselist;
+static short extravars;
+static Boolean cse_found;
+static Boolean cse_invals;
+static Boolean static_for_inlines;
+static short replaces;
+static ENode *objrefnode;
+static int objrefnodes;
+
+static short bitmasks[] = {
+ 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
+ 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000
+};
+
+// forward decls
+static COptCSE *cse_expression(ENode *expr);
+
+static COptCSE *cse_new(ENode *expr) {
+ COptCSE *cse = oalloc(sizeof(COptCSE));
+ cse->expr = expr;
+ cse->replaced = NULL;
+ cse->block = currentblock;
+ cse->mexpr = mexpr;
+ cse->left = NULL;
+ cse->right = NULL;
+ cse->x1C = 1;
+ return cse;
+}
+
+static COptCSE *cse_append(COptCSE *cse, ENode *expr) {
+ COptCSEList *list = oalloc(sizeof(COptCSEList));
+ list->next = cselist;
+ cselist = list;
+ list->cse = cse;
+ list->expr = expr;
+ return cse;
+}
+
+static void cse_cleanup(void) {
+ COptCSEList *scanlist;
+ COptCSEList *prevlist;
+ COptCSE *scan;
+ COptCSE *prev;
+ short op;
+
+ scanlist = cselist;
+ while (scanlist && !scanlist->cse)
+ scanlist = scanlist->next;
+ cselist = scanlist;
+
+ if (scanlist) {
+ do {
+ prevlist = scanlist;
+ do {
+ scanlist = scanlist->next;
+ } while (scanlist && !scanlist->cse);
+ prevlist->next = scanlist;
+ } while (scanlist);
+ }
+
+ for (op = 0; op < MAXEXPR; op++) {
+ scan = csenodes[op];
+ while (scan && scan->x1C < 0)
+ scan = scan->next;
+ csenodes[op] = scan;
+
+ if (scan) {
+ do {
+ prev = scan;
+ do {
+ scan = scan->next;
+ } while (scan && scan->x1C < 0);
+ prev->next = scan;
+ } while (scan);
+ }
+ }
+}
+
+static void cse_inval(COptCSE *cse) {
+ COptCSEList *scanlist;
+ COptCSE *scan;
+ short op;
+
+ if (cse) {
+ for (scanlist = cselist; scanlist; scanlist = scanlist->next) {
+ if (scanlist->cse == cse) {
+ scanlist->cse = NULL;
+ scanlist->expr = NULL;
+ }
+ }
+
+ cse->x1C = -1;
+ cse->left = NULL;
+ cse->right = NULL;
+
+ for (op = 0; op < MAXEXPR; op++) {
+ for (scan = csenodes[op]; scan; scan = scan->next) {
+ if (scan->left == cse || scan->right == cse)
+ cse_inval(scan);
+ }
+ }
+ }
+}
+
+static void cse_update_usages(COptCSE *cse, short amount) {
+ cse->x1C /= amount;
+ if (cse->left)
+ cse_update_usages(cse->left, amount);
+ if (cse->right)
+ cse_update_usages(cse->right, amount);
+}
+
+static void cse_replace(ENode *expr, COptCSE *cse) {
+ COptCSEList *list;
+
+ for (list = cselist; list; list = list->next) {
+ if (list->cse == cse) {
+ *list->expr = *expr;
+ replaces++;
+ list->cse = NULL;
+ list->expr = NULL;
+ }
+ }
+}
+
+static short cse_objectcost(Object *obj) {
+ if (obj->datatype == DLOCAL && !obj->u.var.info->noregister)
+ return 0;
+ return 1;
+}
+
+static void cse_treereplacemexpr(COptCSE *cse, ENode *from, ENode *to) {
+ if (cse->mexpr == from)
+ cse->mexpr = to;
+ if (cse->left)
+ cse_treereplacemexpr(cse->left, from, to);
+ if (cse->right)
+ cse_treereplacemexpr(cse->right, from, to);
+}
+
+static Boolean cse_issubcse(COptCSE *a, COptCSE *b) {
+ if (a == b)
+ return 1;
+ if (b->left && cse_issubcse(a, b->left))
+ return 1;
+ if (b->right && cse_issubcse(a, b->right))
+ return 1;
+
+ return 0;
+}
+
+static short cse_cost(COptCSE *cse) {
+ short cost;
+
+ if (cse) {
+ while (ENODE_IS(cse->expr, ETYPCON) && cse->expr->rtype->type == cse->expr->data.monadic->rtype->type && cse->expr->rtype->size == cse->expr->data.monadic->rtype->size)
+ cse = cse->left;
+
+ if (ENODE_IS_INDIRECT_TO(cse->expr, EOBJREF))
+ return cse_objectcost(cse->expr->data.monadic->data.objref);
+
+ cost = 1;
+ if (!copts.optimizesize) {
+ if (ENODE_IS3(cse->expr, EMUL, EDIV, EMODULO))
+ cost = 2;
+ }
+ return cse_cost(cse->left) + cse_cost(cse->right) + cost;
+ }
+
+ return 0;
+}
+
+static void cse_remove(void) {
+ short op; // r27
+ COptCSE *cse; // r25
+ COptCSE *best_cse; // r28
+ int best_cost; // r30
+ Object *obj; // r31
+ Boolean did_replacement; // r24
+ VarInfo *vi; // r27
+ ObjectList *objlist;
+ ENode *expr1;
+ ENode *expr2;
+ ENode *expr3;
+ ENode *expr4;
+ ENode *mexprsave;
+ COptCSEList *list;
+ short cost;
+
+ while (1) {
+ op = 0;
+ best_cse = NULL;
+ best_cost = 0;
+ did_replacement = 0;
+
+ for (; op < MAXEXPR; op++) {
+ switch (op) {
+ case EINTCONST:
+ case EFLOATCONST:
+ case EOBJREF:
+ case EVECTOR128CONST:
+ break;
+ default:
+ for (cse = csenodes[op]; cse; cse = cse->next) {
+ if (cse->x1C > 1 && (cost = cse_cost(cse)) > 4) {
+ if (cse->replaced) {
+ replaces = 0;
+ cse_replace(cse->replaced, cse);
+ CError_ASSERT(348, replaces >= 1);
+ cse_found = 1;
+ did_replacement = 1;
+ cse_update_usages(cse, cse->x1C);
+ } else {
+ if ((cse->x1C * cost) > best_cost) {
+ best_cse = cse;
+ best_cost = cse->x1C * cost;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (did_replacement)
+ continue;
+ if (!best_cse || extravars >= 256)
+ return;
+
+ obj = lalloc(sizeof(Object));
+ memclrw(obj, sizeof(Object));
+ obj->name = CParser_GetUniqueName();
+ obj->type = cse->expr->rtype;
+ obj->datatype = DLOCAL;
+ vi = CodeGen_GetNewVarInfo();
+ obj->u.var.info = vi;
+
+ objlist = lalloc(sizeof(ObjectList));
+ objlist->object = obj;
+ objlist->next = locals;
+ locals = objlist;
+
+ vi->used = 1;
+ vi->usage = cse->x1C + 1;
+
+ expr1 = lalloc(sizeof(ENode));
+ expr1->type = EOBJREF;
+ expr1->cost = 0;
+ expr1->flags = 0;
+ expr1->data.objref = obj;
+ expr1->rtype = CDecl_NewPointerType(obj->type);
+
+ expr2 = lalloc(sizeof(ENode));
+ expr2->type = EINDIRECT;
+ expr2->cost = 1;
+ expr2->flags = 0;
+ expr2->data.monadic = expr1;
+ expr2->rtype = obj->type;
+
+ expr3 = lalloc(sizeof(ENode));
+ expr3->type = EASS;
+ expr3->cost = -1;
+ expr3->flags = 0;
+ expr3->rtype = obj->type;
+ expr3->data.diadic.left = expr2;
+ expr3->data.diadic.right = lalloc(sizeof(ENode));
+
+ *expr3->data.diadic.right = *cse->expr;
+ cse->expr = expr3->data.diadic.right;
+
+ replaces = 0;
+ cse_replace(expr2, cse);
+ cse->replaced = expr2;
+
+ if (replaces < 2)
+ CError_FATAL(390);
+ else
+ cse_found = 1;
+
+ expr4 = lalloc(sizeof(ENode));
+ *expr4 = *cse->mexpr;
+
+ cse->mexpr->type = ECOMMA;
+ cse->mexpr->data.diadic.left = expr3;
+ cse->mexpr->data.diadic.right = expr4;
+
+ cse_update_usages(cse, cse->x1C);
+ extravars++;
+
+ mexprsave = cse->mexpr;
+ if (mexpr == mexprsave)
+ mexpr = expr4;
+
+ for (list = cselist; list; list = list->next) {
+ if (list->cse && !cse_issubcse(list->cse, cse)) {
+ if (list->cse->mexpr == mexprsave)
+ list->cse->mexpr = expr4;
+ if (list->cse->expr == mexprsave)
+ list->cse->expr = expr4;
+ if (list->expr == mexprsave)
+ list->expr = expr4;
+ }
+ }
+ }
+}
+
+static COptCSE *cse_intconst(ENode *expr) {
+ COptCSE *cse = csenodes[EINTCONST];
+
+ for (; cse; cse = cse->next) {
+ if (expr->rtype == cse->expr->rtype)
+ if (CInt64_Equal(cse->expr->data.intval, expr->data.intval))
+ return cse;
+ }
+
+ cse = cse_new(expr);
+ cse->next = csenodes[EINTCONST];
+ csenodes[EINTCONST] = cse;
+ return cse;
+}
+
+static COptCSE *cse_floatconst(ENode *expr) {
+ COptCSE *cse = csenodes[EFLOATCONST];
+ Float val = expr->data.floatval;
+
+ for (; cse; cse = cse->next) {
+ if (CMach_CalcFloatDiadicBool(cse->expr->rtype, cse->expr->data.floatval, TK_LOGICAL_EQ, val))
+ if (expr->rtype == cse->expr->rtype)
+ return cse;
+ }
+
+ cse = cse_new(expr);
+ cse->next = csenodes[EFLOATCONST];
+ csenodes[EFLOATCONST] = cse;
+ return cse;
+}
+
+static COptCSE *cse_vectorconst(ENode *expr) {
+ COptCSE *cse = csenodes[EVECTOR128CONST];
+ MWVector128 val = expr->data.vector128val;
+
+ for (; cse; cse = cse->next) {
+ if (CMach_CalcVectorDiadicBool(cse->expr->rtype, &cse->expr->data.vector128val, TK_LOGICAL_EQ, &val))
+ if (expr->rtype == cse->expr->rtype)
+ return cse;
+ }
+
+ cse = cse_new(expr);
+ cse->next = csenodes[EVECTOR128CONST];
+ csenodes[EVECTOR128CONST] = cse;
+ return cse;
+}
+
+static COptCSE *cse_objref(ENode *expr) {
+ COptCSE *cse = csenodes[EOBJREF];
+ Object *obj = expr->data.objref;
+
+ for (; cse; cse = cse->next) {
+ if (cse->expr->data.objref == obj)
+ return cse;
+ }
+
+ cse = cse_new(expr);
+ cse->next = csenodes[EOBJREF];
+ csenodes[EOBJREF] = cse;
+ return cse;
+}
+
+static COptCSE *cse_add_monadic_node(ENode *outer, COptCSE *innercse) {
+ COptCSE *cse;
+
+ if (!innercse)
+ return NULL;
+
+ for (cse = csenodes[outer->type]; cse; cse = cse->next) {
+ if (cse->left == innercse && cse->expr->rtype == outer->rtype) {
+ CError_ASSERT(524, cse->expr != outer);
+ cse->x1C++;
+ return cse;
+ }
+ }
+
+ cse = cse_new(outer);
+ cse->next = csenodes[outer->type];
+ csenodes[outer->type] = cse;
+ cse->left = innercse;
+ return cse;
+}
+
+static COptCSE *cse_add_typecon_node(ENode *outer, COptCSE *innercse) {
+ COptCSE *cse;
+
+ if (!innercse)
+ return NULL;
+
+ for (cse = csenodes[outer->type]; cse; cse = cse->next) {
+ if (cse->left == innercse && cse->expr->rtype == outer->rtype) {
+ CError_ASSERT(552, cse->expr != outer);
+ cse->x1C++;
+ return cse;
+ }
+ }
+
+ cse = cse_new(outer);
+ cse->next = csenodes[outer->type];
+ csenodes[outer->type] = cse;
+ cse->left = innercse;
+ return cse;
+}
+
+static COptCSE *cse_add_diadic_node(ENode *outer, COptCSE *leftcse, COptCSE *rightcse) {
+ COptCSE *cse;
+
+ if (!leftcse || !rightcse)
+ return NULL;
+
+ for (cse = csenodes[outer->type]; cse; cse = cse->next) {
+ if (cse->left == leftcse && cse->right == rightcse) {
+ CError_ASSERT(581, cse->expr != outer);
+ cse->x1C++;
+ return cse;
+ }
+ }
+
+ cse = cse_new(outer);
+ cse->next = csenodes[outer->type];
+ csenodes[outer->type] = cse;
+ cse->left = leftcse;
+ cse->right = rightcse;
+ return cse;
+}
+
+static COptCSE *cse_add_commdiadic_node(ENode *outer, COptCSE *leftcse, COptCSE *rightcse) {
+ COptCSE *cse;
+
+ if (!leftcse || !rightcse)
+ return NULL;
+
+ for (cse = csenodes[outer->type]; cse; cse = cse->next) {
+ if ((cse->left == leftcse && cse->right == rightcse) || (cse->left == rightcse && cse->right == leftcse)) {
+ CError_ASSERT(612, cse->expr != outer);
+ cse->x1C++;
+ return cse;
+ }
+ }
+
+ cse = cse_new(outer);
+ cse->next = csenodes[outer->type];
+ csenodes[outer->type] = cse;
+ cse->left = leftcse;
+ cse->right = rightcse;
+ return cse;
+}
+
+static void sfind_objref(ENode *expr) {
+ while (1) {
+ switch (expr->type) {
+ case ETYPCON:
+ expr = expr->data.monadic;
+ break;
+ case EOBJREF:
+ objrefnode = expr;
+ objrefnodes++;
+ return;
+ case EADD:
+ case ESUB:
+ sfind_objref(expr->data.diadic.left);
+ expr = expr->data.diadic.right;
+ break;
+ default:
+ return;
+ }
+ }
+}
+
+static ENode *find_objref_node(ENode *expr) {
+ objrefnode = NULL;
+ objrefnodes = 0;
+ sfind_objref(expr);
+ if (objrefnodes == 1)
+ return objrefnode;
+ else
+ return NULL;
+}
+
+static void cse_mem_modify(void) {
+ COptCSE *cse;
+
+ for (cse = csenodes[EINDIRECT]; cse; cse = cse->next) {
+ if (ENODE_IS(cse->expr->data.monadic, EOBJREF)) {
+ Object *obj = cse->expr->data.monadic->data.objref;
+ CError_ASSERT(672, obj->datatype != DALIAS);
+ if (obj->datatype == DLOCAL && !obj->u.var.info->noregister)
+ continue;
+ }
+
+ cse_inval(cse);
+ }
+}
+
+static void cse_modify_expression(ENode *expr) {
+ if (!expr) {
+ short op;
+
+ cse_remove();
+ for (op = 0; op < MAXEXPR; op++)
+ csenodes[op] = NULL;
+
+ cselist = NULL;
+ freeoheap();
+ } else {
+ ENode *objnode;
+ Object *obj;
+ COptCSE *cse;
+
+ cse_invals = 1;
+ if (ENODE_IS(expr, EINDIRECT) && (objnode = find_objref_node(expr->data.monadic))) {
+ do {
+ obj = objnode->data.objref;
+ cse_remove();
+ for (cse = csenodes[EINDIRECT]; cse; cse = cse->next) {
+ if ((objnode = find_objref_node(cse->expr->data.monadic)) && obj == objnode->data.objref)
+ cse_inval(cse);
+ }
+
+ objnode = find_objref_node(expr->data.monadic);
+ if (!objnode) {
+ cse_mem_modify();
+ break;
+ }
+ } while (obj != objnode->data.objref);
+ } else {
+ cse_remove();
+ cse_mem_modify();
+ }
+ }
+}
+
+static void cse_pascalcall(ENode *expr) {
+ ENodeList *list;
+
+ for (list = expr->data.funccall.args; list; list = list->next)
+ cse_expression(list->node);
+
+ if (ENODE_IS(expr, EFUNCCALLP))
+ cse_expression(expr->data.funccall.funcref);
+
+ cse_remove();
+ cse_mem_modify();
+}
+
+static Boolean cse_pusharg(ENodeList *exprs, FuncArg *args) {
+ Boolean result;
+
+ if (!exprs)
+ return 1;
+
+ if (args && args != &elipsis && args != &oldstyle)
+ args = args->next;
+ if (exprs->next)
+ result = cse_pusharg(exprs->next, args);
+
+ cse_expression(exprs->node);
+ return result;
+}
+
+static void cse_ccall(ENode *expr) {
+ if (cse_pusharg(expr->data.funccall.args, expr->data.funccall.functype->args)) {
+ if (ENODE_IS(expr, EFUNCCALL))
+ cse_expression(expr->data.funccall.funcref);
+
+ cse_remove();
+ cse_mem_modify();
+ } else {
+ cse_modify_expression(NULL);
+ }
+}
+
+static COptCSE *cse_expression(ENode *expr) {
+ ENode *save;
+ COptCSE *tmp;
+ ENodeType nt = expr->type;
+
+ switch (nt) {
+ case EFUNCCALL:
+ cse_ccall(expr);
+ return NULL;
+ case EFUNCCALLP:
+ cse_pascalcall(expr);
+ return NULL;
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ save = mexpr;
+ mexpr = expr;
+ CError_ASSERT(816, ENODE_IS(expr->data.monadic, EINDIRECT));
+
+ cse_expression(expr->data.monadic->data.monadic);
+ cse_modify_expression(expr->data.monadic);
+ mexpr = save;
+ return NULL;
+
+ case EINDIRECT:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case EFORCELOAD:
+ return cse_append(cse_add_monadic_node(expr, cse_expression(expr->data.monadic)), expr);
+
+ case ETYPCON:
+ return cse_append(cse_add_typecon_node(expr, cse_expression(expr->data.monadic)), expr);
+
+ case EMUL:
+ case EMULV:
+ case EADDV:
+ case EADD:
+ case EEQU:
+ case ENOTEQU:
+ case EAND:
+ case EXOR:
+ case EOR:
+ tmp = cse_expression(expr->data.diadic.left);
+ if (expr->type == nt)
+ return cse_append(cse_add_commdiadic_node(expr, tmp, cse_expression(expr->data.diadic.right)), expr);
+ else
+ return NULL;
+
+ case EDIV:
+ case EMODULO:
+ case ESUBV:
+ case ESUB:
+ case ESHL:
+ case ESHR:
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EPMODULO:
+ case EROTL:
+ case EROTR:
+ case EBTST:
+ tmp = cse_expression(expr->data.diadic.left);
+ if (expr->type == nt)
+ return cse_append(cse_add_diadic_node(expr, tmp, cse_expression(expr->data.diadic.right)), expr);
+ else
+ return NULL;
+
+ case EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ CError_ASSERT(887, ENODE_IS(expr->data.diadic.left, EINDIRECT));
+ save = mexpr;
+ mexpr = expr;
+ cse_expression(expr->data.diadic.right);
+ if (expr->type == nt) {
+ cse_expression(expr->data.diadic.left->data.monadic);
+ cse_modify_expression(expr->data.diadic.left);
+ mexpr = save;
+ return NULL;
+ } else {
+ cse_modify_expression(NULL);
+ return NULL;
+ }
+
+ case ECOMMA:
+ cse_expression(expr->data.diadic.left);
+ save = mexpr;
+ mexpr = expr->data.diadic.right;
+ tmp = cse_expression(expr->data.diadic.right);
+ mexpr = save;
+ return tmp;
+
+ case EINTCONST:
+ return cse_intconst(expr);
+ case EFLOATCONST:
+ return cse_floatconst(expr);
+ case EVECTOR128CONST:
+ return cse_vectorconst(expr);
+ case EOBJREF:
+ return cse_objref(expr);
+
+ case EBITFIELD:
+ cse_modify_expression(NULL);
+ return NULL;
+
+ case ECOND:
+ cse_expression(expr->data.cond.cond);
+ cse_modify_expression(NULL);
+ return NULL;
+
+ case ENULLCHECK:
+ cse_expression(expr->data.nullcheck.nullcheckexpr);
+ cse_modify_expression(NULL);
+ return NULL;
+
+ case ELAND:
+ case ELOR:
+ cse_expression(expr->data.diadic.left);
+ cse_modify_expression(NULL);
+ return NULL;
+
+ case ESTRINGCONST:
+ case ELABEL:
+ return NULL;
+
+ case EPRECOMP:
+ CError_FATAL(948);
+
+ default:
+ CError_FATAL(951);
+ return NULL;
+ }
+}
+
+static void cse_block(COptBlock *block) {
+ Statement *stmt;
+ COptBlock *check;
+ COptBlockList *scan;
+ COptBlock *best;
+ short i;
+ SInt32 counter;
+ UInt32 starttime;
+
+ starttime = COS_GetTicks();
+ counter = 0;
+
+ while (1) {
+ cse_invals = 0;
+ currentblock = block;
+ block->x1E = 1;
+
+ for (stmt = block->stmt, i = block->x1C; i > 0; stmt = stmt->next, i--) {
+ switch (stmt->type) {
+ case ST_EXPRESSION:
+ case ST_SWITCH:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ mexpr = stmt->expr;
+ cse_expression(mexpr);
+ break;
+ case ST_RETURN:
+ mexpr = stmt->expr;
+ if (mexpr)
+ cse_expression(mexpr);
+ break;
+ }
+ }
+
+ i = 0;
+ for (scan = block->blocks2; scan; scan = scan->next) {
+ check = scan->block;
+ if (!check->x1E && check->blocks && !check->blocks->next && check->blocks->block == block) {
+ best = check;
+ i++;
+ }
+ }
+
+ if (i != 1)
+ break;
+
+ block = best;
+ if (COS_GetTicks() > (starttime + 60)) {
+ if (counter++ & 1) {
+ if (CWDisplayLines(cparamblkptr->context, lines))
+ CError_UserBreak();
+ } else {
+ if (CWDisplayLines(cparamblkptr->context, lines + 1))
+ CError_UserBreak();
+ }
+ starttime = COS_GetTicks();
+ }
+
+ if (cse_invals)
+ cse_cleanup();
+ }
+
+ cse_remove();
+}
+
+static void CSE(void) {
+ COptBlock *block;
+
+ for (block = basicblocks->next; block; block = block->next)
+ block->x1E = 0;
+
+ for (block = basicblocks->next; block; block = block->next) {
+ if (!block->x1E) {
+ short op;
+
+ for (op = 0; op < MAXEXPR; op++)
+ csenodes[op] = NULL;
+
+ cselist = NULL;
+ cse_found = 0;
+ cse_block(block);
+ freeoheap();
+ }
+ }
+}
+
+static short TestSetBit(short *set, short bit) {
+ return set[bit >> 4] & bitmasks[bit & 15];
+}
+
+static void SetSetBit(short *set, short bit) {
+ set[bit >> 4] |= bitmasks[bit & 15];
+}
+
+UInt32 RegAllocMask(short var) {
+ COptBlock *block;
+ UInt32 mask = 0;
+
+ for (block = basicblocks; block; block = block->next) {
+ if (TestSetBit(block->set1, var) || TestSetBit(block->set2, var))
+ mask |= block->allocmask;
+ }
+
+ return mask;
+}
+
+void MarkRegAllocMask(short var, short bit, Boolean flag) {
+ COptBlock *block;
+ UInt32 mask = 1 << bit;
+
+ if (flag) {
+ for (block = basicblocks; block; block = block->next) {
+ if (TestSetBit(block->set1, var) || TestSetBit(block->set2, var))
+ block->allocmask |= mask;
+ }
+ } else {
+ for (block = basicblocks; block; block = block->next) {
+ block->allocmask |= mask;
+ }
+ }
+}
+
+static COptBlock *newblock(void) {
+ COptBlock *block;
+ short i;
+ short max;
+
+ block = lalloc(sizeof(COptBlock) + (setbytes * 2));
+ block->x1E = 0;
+ block->next = NULL;
+ block->blocks = NULL;
+ block->blocks2 = NULL;
+ block->allocmask = 0;
+ block->set1 = (short *) (((long) block) + sizeof(COptBlock));
+ block->set2 = (short *) (((long) block) + setbytes + sizeof(COptBlock));
+
+ for (i = 0, max = setbytes / 2; i < max; i++) {
+ block->set1[i] = 0;
+ block->set2[i] = 0;
+ }
+
+ return block;
+}
+
+static void MarkFollow(COptBlock *block) {
+ COptBlockList *list;
+
+restart:
+ block->x1E = 1;
+ if ((list = block->blocks2)) {
+ while (1) {
+ if (!list->block->x1E) {
+ if (!list->next) {
+ block = list->block;
+ goto restart;
+ }
+ MarkFollow(list->block);
+ list = list->next;
+ } else {
+ list = list->next;
+ if (!list)
+ break;
+ }
+ }
+ }
+}
+
+static Boolean CheckInit(short var) {
+ Boolean result;
+ COptBlock *block;
+
+ result = 1;
+ for (block = basicblocks; block; block = block->next) {
+ if (!block->x1E && TestSetBit(block->set2, var))
+ MarkFollow(block);
+ }
+
+ for (block = basicblocks; block; block = block->next) {
+ if (!block->x1E) {
+ if (TestSetBit(block->set1, var))
+ result = 0;
+ } else {
+ block->x1E = 0;
+ }
+ }
+
+ return result;
+}
+
+static void CheckVarInit(void) {
+ COptBlock *block;
+ VarInfo *vi;
+ ObjectList *list;
+
+ for (block = basicblocks; block; block = block->next)
+ block->x1E = 0;
+
+ for (list = locals; list; list = list->next) {
+ if (list->object->datatype == DLOCAL && !IsTempName(list->object->name) && !is_volatile_object(list->object)) {
+ vi = list->object->u.var.info;
+ if (vi->used && !CheckInit(vi->varnumber)) {
+ if (!IS_TYPE_CLASS(list->object->type) || !CClass_IsEmpty(TYPE_CLASS(list->object->type))) {
+ CError_SetErrorToken(&vi->deftoken);
+ CError_Warning(CErrorStr185, list->object->name->name);
+ }
+ }
+ }
+ }
+}
+
+static void AddVar(Object *obj, Boolean whichSet) {
+ VarInfo *vi;
+
+ if (obj->datatype == DLOCAL) {
+ vi = obj->u.var.info;
+ if (!whichSet) {
+ SetSetBit(currentblock->set1, vi->varnumber);
+ } else {
+ if (!TestSetBit(currentblock->set1, vi->varnumber))
+ SetSetBit(currentblock->set2, vi->varnumber);
+ }
+ }
+}
+
+static void CheckExpr(ENode *expr) {
+ ENodeList *list;
+
+ while (1) {
+ switch (expr->type) {
+ case EINDIRECT:
+ if (ENODE_IS(expr->data.monadic, EOBJREF)) {
+ AddVar(expr->data.monadic->data.objref, 0);
+ return;
+ }
+ expr = expr->data.monadic;
+ break;
+ case EOBJREF:
+ AddVar(expr->data.objref, 1);
+ return;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ CheckExpr(expr->data.funccall.funcref);
+ for (list = expr->data.funccall.args; list; list = list->next)
+ CheckExpr(list->node);
+ return;
+ case ECOND:
+ CheckExpr(expr->data.cond.cond);
+ CheckExpr(expr->data.cond.expr1);
+ CheckExpr(expr->data.cond.expr2);
+ return;
+ case EASS:
+ if (ENODE_IS_INDIRECT_TO(expr->data.diadic.left, EOBJREF)) {
+ CheckExpr(expr->data.diadic.right);
+ AddVar(expr->data.diadic.left->data.monadic->data.objref, 1);
+ return;
+ }
+ 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 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:
+ CheckExpr(expr->data.diadic.left);
+ expr = expr->data.diadic.right;
+ break;
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case EFORCELOAD:
+ case ETYPCON:
+ case EBITFIELD:
+ expr = expr->data.monadic;
+ break;
+ case ENULLCHECK:
+ CheckExpr(expr->data.nullcheck.nullcheckexpr);
+ expr = expr->data.nullcheck.condexpr;
+ break;
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EPRECOMP:
+ case ELABEL:
+ case EVECTOR128CONST:
+ return;
+ default:
+ CError_FATAL(1332);
+ }
+ }
+}
+
+static short CheckPath(COptBlock *block, short var) {
+ COptBlockList *list;
+
+ if (block->x1E)
+ return TestSetBit(block->set1, var);
+
+ block->x1E = 1;
+ if (TestSetBit(block->set1, var))
+ return -1;
+ if (TestSetBit(block->set2, var))
+ return 0;
+
+ for (list = block->blocks2; list; list = list->next) {
+ if (CheckPath(list->block, var)) {
+ SetSetBit(block->set1, var);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void MarkPre(COptBlock *block, short var) {
+ COptBlockList *list;
+
+restart:
+ block->x1E = 1;
+ for (list = block->blocks; list; list = list->next) {
+ if (!list->block->x1E) {
+ if (!TestSetBit(list->block->set2, var)) {
+ SetSetBit(list->block->set1, var);
+ if (!list->next) {
+ block = list->block;
+ goto restart;
+ }
+ MarkPre(list->block, var);
+ } else {
+ list->block->x1E = 1;
+ }
+ }
+ }
+}
+
+static void CheckVarUsage(void) {
+ short local;
+ COptBlock *block;
+ short counter;
+
+ for (currentblock = basicblocks; currentblock; currentblock = currentblock->next) {
+ Statement *stmt = currentblock->stmt;
+ if (currentblock->x1C > 0 && stmt->type == ST_LABEL && (stmt->flags & StmtFlag_1)) {
+ short i;
+ for (i = 0; i < localcount; i++)
+ SetSetBit(currentblock->set2, i);
+ }
+
+ for (counter = currentblock->x1C; counter > 0; counter--) {
+ if (stmt->type >= ST_EXPRESSION && stmt->type <= ST_GOTOEXPR && stmt->expr)
+ CheckExpr(stmt->expr);
+ stmt = stmt->next;
+ }
+ }
+
+ for (local = 0; local < localcount; local++) {
+ for (block = basicblocks; block; block = block->next) {
+ if (!block->x1E && TestSetBit(block->set1, local))
+ MarkPre(block, local);
+ }
+ for (block = basicblocks; block; block = block->next) {
+ block->x1E = 0;
+ }
+ }
+}
+
+static void SplitCommaExpressions(void) {
+ COptBlock *block;
+ Statement *stmt;
+ ENode *expr;
+ Statement *stmtcopy;
+ short counter;
+ Boolean flag;
+
+ block = basicblocks->next;
+ while (block) {
+ stmt = block->stmt;
+ counter = block->x1C;
+ flag = 1;
+ while (counter > 0) {
+ if (stmt->type >= ST_EXPRESSION && stmt->type <= ST_GOTOEXPR) {
+ if ((expr = stmt->expr) && ENODE_IS(expr, ECOMMA)) {
+ stmtcopy = lalloc(sizeof(Statement));
+ *stmtcopy = *stmt;
+ stmt->next = stmtcopy;
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = expr->data.diadic.left;
+ stmtcopy->expr = expr->data.diadic.right;
+ block->x1C++;
+ flag = 0;
+ break;
+ }
+ }
+
+ stmt = stmt->next;
+ counter--;
+ }
+
+ if (flag)
+ block = block->next;
+ }
+}
+
+static void BasicBlockAnalyze(Statement *stmt) {
+ COptBlock *block;
+ ObjectList *objlist;
+ COptBlockList *scan;
+ COptBlockList *list;
+ CLabel *label;
+ COptBlock *iblock;
+ COptBlock *oblock;
+ SwitchCase *swcase;
+
+ setbytes = 2 * ((localcount - 1) / 16) + 2;
+ if (copts.globaloptimizer) {
+ setbytes += 32;
+ extravars = 0;
+ }
+
+ block = newblock();
+ basicblocks = block;
+ block->stmt = NULL;
+ block->x1C = 0;
+
+ if (stmt) {
+ list = lalloc(sizeof(COptBlockList));
+ list->next = NULL;
+ block->blocks2 = list;
+ list->block = (COptBlock *) stmt;
+ }
+
+ for (objlist = arguments; objlist; objlist = objlist->next) {
+ SetSetBit(block->set2, objlist->object->u.var.info->varnumber);
+ }
+
+ while (stmt) {
+ int counter;
+
+ block->next = newblock();
+ block = block->next;
+ block->stmt = stmt;
+ counter = 1;
+
+ innerLoop:
+ switch (stmt->type) {
+ case ST_ASM:
+ label = InlineAsm_GetReferencedLabel(stmt);
+ if (!label)
+ goto jumpahead;
+ list = lalloc(sizeof(COptBlockList));
+ list->next = block->blocks2;
+ block->blocks2 = list;
+ list->block = (COptBlock *) label->stmt;
+ if (stmt->next) {
+ list = lalloc(sizeof(COptBlockList));
+ list->next = block->blocks2;
+ block->blocks2 = list;
+ list->block = (COptBlock *) stmt->next;
+ }
+ stmt = stmt->next;
+ block->x1C = counter;
+ continue;
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_ENTRY:
+ if (stmt->next && stmt->next->type != ST_LABEL) {
+ stmt = stmt->next;
+ counter++;
+ goto innerLoop;
+ }
+ break;
+ case ST_EXPRESSION:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ jumpahead:
+ if (stmt->next && stmt->next->type == ST_GOTO) {
+ stmt = stmt->next;
+ counter++;
+ goto innerLoop;
+ }
+ break;
+ }
+
+ switch (stmt->type) {
+ case ST_SWITCH:
+ label = ((SwitchInfo *) stmt->label)->defaultlabel;
+ if (label != cleanreturnlabel) {
+ list = lalloc(sizeof(COptBlockList));
+ list->next = block->blocks2;
+ block->blocks2 = list;
+ list->block = (COptBlock *) label->stmt;
+ }
+ for (swcase = ((SwitchInfo *) stmt->label)->cases; swcase; swcase = swcase->next) {
+ label = swcase->label;
+ if (label != cleanreturnlabel) {
+ list = lalloc(sizeof(COptBlockList));
+ list->next = block->blocks2;
+ block->blocks2 = list;
+ list->block = (COptBlock *) label->stmt;
+ }
+ }
+ break;
+ case ST_RETURN:
+ case ST_EXIT:
+ case ST_GOTOEXPR:
+ break;
+ case ST_GOTO:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ case ST_OVF:
+ label = stmt->label;
+ if (label != cleanreturnlabel) {
+ list = lalloc(sizeof(COptBlockList));
+ list->next = block->blocks2;
+ block->blocks2 = list;
+ list->block = (COptBlock *) label->stmt;
+ }
+ if (stmt->type == ST_GOTO)
+ break;
+ default:
+ if (stmt->next) {
+ list = lalloc(sizeof(COptBlockList));
+ list->next = block->blocks2;
+ block->blocks2 = list;
+ list->block = (COptBlock *) stmt->next;
+ }
+ break;
+ }
+
+ stmt = stmt->next;
+ block->x1C = counter;
+ }
+
+ for (oblock = basicblocks; oblock; oblock = oblock->next) {
+ for (scan = oblock->blocks2; scan; scan = scan->next) {
+ stmt = (Statement *) scan->block;
+ for (iblock = basicblocks->next; iblock; iblock = iblock->next) {
+ if (iblock->stmt == stmt) {
+ scan->block = iblock;
+ list = lalloc(sizeof(COptBlockList));
+ list->next = iblock->blocks;
+ iblock->blocks = list;
+ list->block = oblock;
+ break;
+ }
+ }
+
+ CError_ASSERT(1602, iblock);
+ }
+ }
+
+ SplitCommaExpressions();
+ CheckVarUsage();
+}
+
+static CLabel *finallabel(CLabel *label, Statement *stmt) {
+ Statement *scan;
+
+ for (scan = label->stmt; scan; scan = scan->next) {
+ if (scan->type > ST_LABEL) {
+ if (scan == stmt)
+ return label;
+ if (scan->type == ST_GOTO) {
+ if (scan->label != label)
+ stmtchanged = 1;
+ return scan->label;
+ }
+ return label;
+ }
+ }
+
+ return label;
+}
+
+static void optimizegoto(Statement *stmt) {
+ Statement *scan;
+
+ for (scan = stmt->next; scan; scan = scan->next) {
+ if (stmt->label->stmt == scan) {
+ stmt->type = ST_NOP;
+ stmtchanged = 1;
+ return;
+ }
+ if (scan->type > ST_LABEL)
+ break;
+ }
+
+ stmt->label = finallabel(stmt->label, stmt);
+}
+
+static void removeif(Statement *stmt, Boolean flag) {
+ if (((stmt->type == ST_IFGOTO) && flag) || ((stmt->type == ST_IFNGOTO) && !flag)) {
+ Statement *copy = lalloc(sizeof(Statement));
+ *copy = *stmt;
+ copy->type = ST_GOTO;
+ stmt->next = copy;
+ }
+ stmt->type = ST_EXPRESSION;
+ stmtchanged = 1;
+}
+
+static void optimizeif(Statement *stmt) {
+ Statement *scan;
+ Statement *scan2;
+ Boolean flag;
+
+ if (iszero(stmt->expr)) {
+ removeif(stmt, 0);
+ return;
+ }
+ if (isnotzero(stmt->expr)) {
+ removeif(stmt, 1);
+ return;
+ }
+
+ for (scan = stmt->next, flag = 0; scan; scan = scan->next) {
+ if (scan->type > ST_LABEL) {
+ if (scan->type == ST_GOTO) {
+ if (scan->label == stmt->label) {
+ stmt->type = ST_EXPRESSION;
+ stmtchanged = 1;
+ return;
+ }
+
+ if (!flag) {
+ for (scan2 = scan->next; scan2; scan2 = scan2->next) {
+ if (scan2->type > ST_LABEL)
+ break;
+ if (stmt->label->stmt == scan2) {
+ stmt->label = scan->label;
+ scan->type = ST_NOP;
+ if (stmt->type == ST_IFGOTO)
+ stmt->type = ST_IFNGOTO;
+ else
+ stmt->type = ST_IFGOTO;
+ stmtchanged = 1;
+ stmt->label = finallabel(stmt->label, stmt);
+ return;
+ }
+ }
+ }
+ } else if (scan->type == ST_RETURN && !scan->expr && !static_for_inlines && !flag) {
+ for (scan2 = scan->next; scan2; scan2 = scan2->next) {
+ if (scan2->type > ST_LABEL)
+ break;
+ if (stmt->label->stmt == scan2) {
+ stmt->label = cleanreturnlabel;
+ needs_cleanup = 1;
+ scan->type = ST_NOP;
+ if (stmt->type == ST_IFGOTO)
+ stmt->type = ST_IFNGOTO;
+ else
+ stmt->type = ST_IFGOTO;
+ stmtchanged = 1;
+ return;
+ }
+ }
+ }
+ break;
+ }
+
+ if (scan->type == ST_LABEL)
+ flag = 1;
+
+ if (stmt->label->stmt == scan) {
+ stmt->type = ST_EXPRESSION;
+ stmtchanged = 1;
+ return;
+ }
+ }
+
+ stmt->label = finallabel(stmt->label, stmt);
+}
+
+static void optimizeswitch(Statement *stmt) {
+ SwitchInfo *info;
+ SwitchCase *swcase;
+
+ info = (SwitchInfo *) stmt->label;
+ CError_ASSERT(1746, info && info->cases && info->defaultlabel);
+
+ info->defaultlabel = finallabel(info->defaultlabel, stmt);
+ for (swcase = info->cases; swcase; swcase = swcase->next)
+ swcase->label = finallabel(swcase->label, stmt);
+
+ if (ENODE_IS(stmt->expr, EINTCONST)) {
+ for (swcase = info->cases; swcase; swcase = swcase->next) {
+ if (CInt64_GreaterEqual(swcase->min, stmt->expr->data.intval) && CInt64_LessEqual(swcase->max, stmt->expr->data.intval))
+ break;
+ }
+
+ stmt->type = ST_GOTO;
+ stmt->label = swcase ? swcase->label : info->defaultlabel;
+ }
+}
+
+static void removeunusedlabels(Statement *stmt) {
+ Statement *scan;
+ CLabel *label;
+ SwitchCase *swcase;
+ ExceptionAction *action;
+
+ for (scan = stmt; scan; scan = scan->next)
+ scan->marked = 0;
+
+ for (scan = stmt; scan; scan = scan->next) {
+ switch (scan->type) {
+ case ST_GOTO:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ case ST_OVF:
+ if (scan->label->stmt)
+ scan->label->stmt->marked = 1;
+ break;
+ case ST_SWITCH:
+ ((SwitchInfo *) scan->label)->defaultlabel->stmt->marked = 1;
+ for (swcase = ((SwitchInfo *) scan->label)->cases; swcase; swcase = swcase->next)
+ swcase->label->stmt->marked = 1;
+ break;
+ case ST_ASM:
+ if ((label = InlineAsm_GetReferencedLabel(scan)))
+ label->stmt->marked = 1;
+ if ((label = InlineAsm_GetReferencedLabel2(scan)))
+ label->stmt->marked = 1;
+ break;
+ case ST_BEGINLOOP:
+ ((LoopInfo *) scan->expr)->stmt->marked = 1;
+ break;
+ case ST_ENDLOOP:
+ if (scan->next->type == ST_GOTO && scan->next->next->type == ST_LABEL)
+ scan->next->next->marked = 1;
+ break;
+ default:
+ for (action = scan->dobjstack; action; action = action->prev) {
+ if (action->type == EAT_CATCHBLOCK) {
+ action->data.catch_block.catch_label->stmt->marked = 1;
+ action->data.catch_block.catch_label->stmt->flags = action->data.catch_block.catch_label->stmt->flags | StmtFlag_1;
+ } else if (action->type == EAT_SPECIFICATION) {
+ action->data.specification.unexp_label->stmt->marked = 1;
+ action->data.specification.unexp_label->stmt->flags = action->data.specification.unexp_label->stmt->flags | StmtFlag_1;
+ }
+ }
+ }
+ }
+
+ for (scan = stmt; scan; scan = scan->next) {
+ if (scan->type == ST_LABEL && !scan->marked && !(scan->flags & StmtFlag_1)) {
+ scan->type = ST_NOP;
+ stmtchanged = 1;
+ }
+ }
+}
+
+static void optimizebranches(Statement *stmt) {
+ removeunusedlabels(stmt);
+ while (stmt) {
+ switch (stmt->type) {
+ case ST_GOTO:
+ optimizegoto(stmt);
+ break;
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ optimizeif(stmt);
+ break;
+ case ST_SWITCH:
+ optimizeswitch(stmt);
+ break;
+ }
+ stmt = stmt->next;
+ }
+}
+
+void SetVarUsage(Object *obj, Boolean noregister) {
+ VarInfo *vi;
+ CError_ASSERT(1875, obj->datatype != DALIAS);
+
+ if (obj->datatype == DLOCAL || obj->datatype == DNONLAZYPTR) {
+ vi = obj->u.var.info;
+ vi->used = 1;
+ if (!copts.globaloptimizer) {
+ if (copts.optimizesize)
+ vi->usage++;
+ else
+ vi->usage += curstmtvalue;
+ }
+
+ if (noregister)
+ vi->noregister = 1;
+ }
+}
+
+static void checkexpression(ENode *expr) {
+ ENodeList *list;
+
+ while (1) {
+ switch (expr->type) {
+ case EOBJREF:
+ SetVarUsage(expr->data.objref, 1);
+ return;
+ case EINDIRECT:
+ if (ENODE_IS(expr->data.monadic, EOBJREF)) {
+ SetVarUsage(expr->data.monadic->data.objref, 0);
+ return;
+ }
+ expr = expr->data.monadic;
+ break;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ copt_isleaffunction = 0;
+ checkexpression(expr->data.funccall.funcref);
+ for (list = expr->data.funccall.args; list; list = list->next)
+ checkexpression(list->node);
+ return;
+ case ECOND:
+ case ECONDASS:
+ checkexpression(expr->data.cond.cond);
+ checkexpression(expr->data.cond.expr1);
+ checkexpression(expr->data.cond.expr2);
+ return;
+ 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:
+ checkexpression(expr->data.diadic.left);
+ expr = expr->data.diadic.right;
+ break;
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case EFORCELOAD:
+ case ETYPCON:
+ case EBITFIELD:
+ expr = expr->data.monadic;
+ break;
+ case ENULLCHECK:
+ checkexpression(expr->data.nullcheck.nullcheckexpr);
+ expr = expr->data.nullcheck.condexpr;
+ break;
+ case EINTCONST:
+ case EFLOATCONST:
+ case EPRECOMP:
+ case ELABEL:
+ case EVECTOR128CONST:
+ return;
+ case ESTRINGCONST:
+ return;
+ default:
+ CError_FATAL(1998);
+ }
+ }
+}
+
+static void checklocalusage(Statement *stmt) {
+ Statement *scan;
+
+ for (scan = stmt; scan; scan = scan->next) {
+ if (scan->type >= ST_EXPRESSION && scan->type <= ST_GOTOEXPR && scan->expr) {
+ curstmtvalue = scan->value;
+ checkexpression(scan->expr);
+ } else if (scan->type == ST_ASM) {
+ curstmtvalue = scan->value;
+ InlineAsm_CheckLocalUsage(scan);
+ }
+ }
+}
+
+static void colorcode(Statement *stmt) {
+ CLabel *label;
+ SwitchCase *swcase;
+
+ while (stmt && !stmt->marked) {
+ stmt->marked = 1;
+ switch (stmt->type) {
+ case ST_GOTOEXPR:
+ return;
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ case ST_OVF:
+ colorcode(stmt->label->stmt);
+ break;
+ case ST_GOTO:
+ case ST_EXIT:
+ stmt = stmt->label->stmt;
+ continue;
+ case ST_RETURN:
+ return;
+ case ST_SWITCH:
+ for (swcase = ((SwitchInfo *) stmt->label)->cases; swcase; swcase = swcase->next)
+ colorcode(swcase->label->stmt);
+ stmt = ((SwitchInfo *) stmt->label)->defaultlabel->stmt;
+ continue;
+ case ST_ASM:
+ if ((label = InlineAsm_GetReferencedLabel(stmt)))
+ colorcode(label->stmt);
+ if ((label = InlineAsm_GetReferencedLabel2(stmt)))
+ colorcode(label->stmt);
+ break;
+ case ST_ENDLOOP:
+ if (stmt->next && stmt->next->type == ST_GOTO) {
+ stmt = stmt->next;
+ stmt->marked = 1;
+ }
+ break;
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_EXPRESSION:
+ case ST_ENTRY:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_BEGINLOOP:
+ break;
+ default:
+ CError_FATAL(2096);
+ }
+ stmt = stmt->next;
+ }
+}
+
+static void removeunusedcode(Statement *stmt) {
+ Statement *scan;
+
+ for (scan = stmt; scan; scan = scan->next)
+ scan->marked = 0;
+
+ colorcode(stmt);
+ for (scan = stmt; scan; scan = scan->next) {
+ if (!scan->marked && (scan->flags & StmtFlag_1))
+ colorcode(scan);
+ }
+
+ for (scan = stmt; scan; scan = scan->next) {
+ if (!scan->marked && scan->type != ST_NOP) {
+ scan->type = ST_NOP;
+ stmtchanged = 1;
+ }
+ }
+}
+
+static void COpt_ReturnCheck(Object *obj, Statement *stmt) {
+ if ((copts.pedantic || copts.cplusplus) && obj && TYPE_FUNC(obj->type)->functype != &stvoid) {
+ while (stmt) {
+ if (!stmt->next && stmt->type != ST_GOTO && stmt->type != ST_RETURN) {
+ CError_Warning(CErrorStr184);
+ break;
+ }
+
+ if (stmt->type == ST_RETURN && !stmt->expr && !(stmt->flags & StmtFlag_8)) {
+ CError_Warning(CErrorStr184);
+ break;
+ }
+
+ stmt = stmt->next;
+ }
+ }
+}
+
+static void COpt_Optimize(Object *obj, Statement *stmt) {
+ Statement **ptr;
+
+ do {
+ stmtchanged = 0;
+ optimizebranches(stmt->next);
+ removeunusedcode(stmt->next);
+ } while (stmtchanged);
+
+ ptr = &stmt->next;
+ while (*ptr) {
+ if ((*ptr)->type == ST_NOP)
+ *ptr = (*ptr)->next;
+ else
+ ptr = &(*ptr)->next;
+ }
+}
+
+static void COpt_ELABELCallBack(ENode *expr) {
+ CError_ASSERT(2195, expr->data.label->stmt && expr->data.label->stmt->type == ST_LABEL);
+ expr->data.label->stmt->flags = expr->data.label->stmt->flags | StmtFlag_1;
+}
+
+void COpt_SimpleOptimizer(Object *obj, Statement *stmt) {
+ Statement *scan;
+
+ for (scan = stmt; scan; scan = scan->next) {
+ if ((scan->type >= ST_EXPRESSION && scan->type <= ST_GOTOEXPR) && scan->expr)
+ CExpr_SearchExprTree(scan->expr, COpt_ELABELCallBack, 1, ELABEL);
+ }
+
+ static_for_inlines = 1;
+ cleanreturnlabel = NULL;
+ COpt_Optimize(obj, stmt);
+ COpt_ReturnCheck(obj, stmt);
+}
+
+Statement *COpt_Optimizer(Object *obj, Statement *stmt) {
+ copt_isleaffunction = 1;
+ if (copts.globaloptimizer)
+ stmt = IRO_Optimizer(obj, stmt);
+
+ static_for_inlines = 0;
+ COpt_Optimize(obj, stmt);
+
+ if (obj && !(obj->qual & Q_INLINE))
+ COpt_ReturnCheck(obj, stmt);
+
+ checklocalusage(stmt->next);
+ return stmt;
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/BitVector.h b/compiler_and_linker/FrontEnd/Optimizer/BitVector.h
new file mode 100644
index 0000000..a6830d6
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/BitVector.h
@@ -0,0 +1,36 @@
+#ifndef COMPILER_IROBITVECT_H
+#define COMPILER_IROBITVECT_H
+
+#include "compiler/common.h"
+#include "compiler/CError.h"
+
+typedef struct BitVector {
+ UInt32 size;
+ UInt32 data[0];
+} BitVector;
+
+extern void Bv_AllocVector(BitVector **bv, UInt32 size);
+extern void Bv_AllocVectorLocal(BitVector **bv, UInt32 size);
+extern void Bv_ClearBit(UInt32 bit, BitVector *bv);
+extern void Bv_And(const BitVector *a, BitVector *b);
+extern void Bv_Or(const BitVector *a, BitVector *b);
+extern Boolean Bv_BitsInCommon(const BitVector *a, const BitVector *b);
+extern Boolean Bv_Compare(const BitVector *a, const BitVector *b);
+extern void Bv_Minus(const BitVector *a, BitVector *b);
+extern void Bv_Copy(const BitVector *src, BitVector *dst);
+extern void Bv_Clear(BitVector *bv);
+extern void Bv_Set(BitVector *bv);
+extern Boolean Bv_IsSubset(const BitVector *a, const BitVector *b);
+extern Boolean Bv_IsEmpty(const BitVector *bv);
+
+CW_INLINE void Bv_SetBit(UInt32 bit, BitVector *bv) {
+ if ((bit / 32) < bv->size) {
+ bv->data[bit / 32] |= 1 << (bit & 31);
+ } else {
+ CError_FATAL(56);
+ }
+}
+
+#define Bv_IsBitSet(_bit, _bv) ( (((_bit) >> 5) < (_bv)->size) && ((_bv)->data[(_bit) >> 5] & (1 << ((_bit) & 31))) )
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IROUseDef.c b/compiler_and_linker/FrontEnd/Optimizer/IROUseDef.c
new file mode 100644
index 0000000..ba3f817
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IROUseDef.c
@@ -0,0 +1,1432 @@
+#include "IROUseDef.h"
+#include "IroDump.h"
+#include "IroVars.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroMalloc.h"
+#include "IroPointerAnalysis.h"
+#include "IroTransform.h"
+#include "IroUtil.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/InlineAsmPPC.h"
+
+ENodeType IRO_NonAssignmentOp[MAXEXPR];
+typedef CInt64 (*AssignmentFoldingFunc)(CInt64, CInt64);
+static AssignmentFoldingFunc AssignmentFoldingFunction[MAXEXPR];
+static SInt32 NumDefs;
+static IRODef *FirstDef;
+static IRODef *LastDef;
+static SInt32 NumUses;
+static BitVector *Reaches;
+static BitVector *MightReachAnyUse;
+static BitVector *alldefs;
+static BitVector *alluses;
+static BitVector *defset;
+static BitVector *useset;
+IROUse *IRO_FirstVarUse;
+IROUse *IRO_LastVarUse;
+
+// forward decls
+static void AddDefToRange(IRODef *def);
+
+static void MakeDef(VarRecord *var, IROLinear *linear, IRONode *node, Boolean flag) {
+ IRODef *def = oalloc(sizeof(IRODef));
+
+ def->index = NumDefs++;
+ def->node = node;
+ def->linear = linear;
+ def->var = var;
+ def->globalnext = NULL;
+ def->x18 = 0;
+ def->x1A = Inline_IsObjectData(var->object);
+ def->x1B = var->xB;
+ def->x1C = flag;
+ def->x1D = 0;
+
+ if (FirstDef)
+ LastDef->globalnext = def;
+ else
+ FirstDef = def;
+ LastDef = def;
+
+ def->varnext = var->defs;
+ var->defs = def;
+}
+
+static void MakeUse(VarRecord *var, IROLinear *linear, IRONode *node) {
+ IROUse *use = oalloc(sizeof(IROUse));
+
+ use->index = NumUses++;
+ use->node = node;
+ use->linear = linear;
+ use->var = var;
+ use->globalnext = NULL;
+ use->x1C = 0;
+
+ if (IRO_FirstVarUse)
+ IRO_LastVarUse->globalnext = use;
+ else
+ IRO_FirstVarUse = use;
+ IRO_LastVarUse = use;
+
+ use->varnext = var->uses;
+ var->uses = use;
+}
+
+static void FindDefsAndUses(void) {
+ VarRecord *var;
+ IROLinear *linear;
+ IRONode *node;
+
+ NumDefs = 0;
+ NumUses = 0;
+ IRO_FirstVarUse = NULL;
+ FirstDef = NULL;
+
+ for (var = IRO_FirstVar; var; var = var->next) {
+ var->defs = NULL;
+ var->uses = NULL;
+ var->xC = 0;
+ }
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ for (linear = node->first; linear; linear = linear->next) {
+ if (IS_LINEAR_ENODE(linear, EOBJREF)) {
+ Object *obj = linear->u.node->data.objref;
+ if ((linear->flags & IROLF_Ind) && (!(linear->flags & IROLF_Assigned) || (linear->flags & IROLF_Used))) {
+ if ((var = IRO_FindVar(obj, 0, 1)))
+ MakeUse(var, linear, node);
+ }
+ }
+
+ if (IRO_IsAssignment(linear) && (var = IRO_FindAssigned(linear))) {
+ MakeDef(
+ var,
+ linear,
+ node,
+ (linear->rtype->size == var->object->type->size) && !IRO_IsBitField
+ );
+ }
+
+ if (linear->type == IROLinearAsm) {
+ IAEffects effects;
+ int i;
+ CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects);
+
+ for (i = 0; i < effects.numoperands; i++) {
+ var = IRO_FindVar(effects.operands[i].object, 0, 1);
+ switch (effects.operands[i].type) {
+ case IAEffect_0:
+ MakeUse(var, linear, node);
+ break;
+ case IAEffect_1:
+ MakeDef(
+ var,
+ linear,
+ node,
+ (effects.operands[i].offset == 0) && (effects.operands[i].size == var->object->type->size)
+ );
+ break;
+ case IAEffect_2:
+ MakeDef(var, linear, node, 0);
+ break;
+ case IAEffect_4:
+ MakeUse(var, linear, node);
+ MakeDef(
+ var,
+ linear,
+ node,
+ (effects.operands[i].offset == 0) && (effects.operands[i].size == var->object->type->size)
+ );
+ break;
+ }
+ }
+ }
+
+ if (linear == node->last)
+ break;
+ }
+ }
+
+ for (var = IRO_FirstVar; var; var = var->next)
+ MakeDef(var, NULL, NULL, 1);
+}
+
+static void MarkUses(Object *obj) {
+ VarRecord *var;
+ IRODef *def;
+
+ if ((var = IRO_FindVar(obj, 0, 1))) {
+ for (def = var->defs; def; def = def->varnext) {
+ if (Bv_IsBitSet(def->index, Reaches)) {
+ Bv_SetBit(def->index, MightReachAnyUse);
+ def->x18++;
+ }
+ }
+
+ var->xC = 1;
+ }
+}
+
+static Boolean IsIncOrDec(IROLinear *linear) {
+ switch (linear->type) {
+ case IROLinearOp1Arg:
+ if (linear->nodetype == EPOSTINC || linear->nodetype == EPOSTDEC || linear->nodetype == EPREINC || linear->nodetype == EPREDEC) {
+ if (!(linear->u.monadic->flags & IROLF_BitfieldIndirect))
+ return 1;
+ }
+ break;
+ case IROLinearOp2Arg:
+ if (linear->nodetype == EADDASS || linear->nodetype == ESUBASS) {
+ if (IRO_IsIntConstant(linear->u.diadic.right) && !(linear->u.diadic.left->flags & IROLF_BitfieldIndirect))
+ return 1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static Boolean IsOtherSelfAssignment(IROLinear *linear) {
+ switch (linear->type) {
+ case IROLinearOp2Arg:
+ switch (linear->nodetype) {
+ case EMULASS:
+ case EDIVASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ if (IRO_IsIntConstant(linear->u.diadic.right))
+ return 1;
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+CInt64 IRO_GetSelfAssignmentVal(IROLinear *linear) {
+ CInt64 result;
+
+ if (linear->type == IROLinearOp1Arg) {
+ switch (linear->nodetype) {
+ case EPOSTINC:
+ case EPREINC:
+ CInt64_SetLong(&result, 1);
+ break;
+ case EPOSTDEC:
+ case EPREDEC:
+ CInt64_SetLong(&result, -1);
+ break;
+ default:
+ CError_FATAL(445);
+ }
+
+ if (IS_TYPE_POINTER_ONLY(linear->rtype)) {
+ CInt64 mul;
+ CInt64_SetLong(&mul, TPTR_TARGET(linear->rtype)->size);
+ result = CInt64_Mul(result, mul);
+ }
+ } else if (linear->type == IROLinearOp2Arg) {
+ switch (linear->nodetype) {
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ result = linear->u.diadic.right->u.node->data.intval;
+ break;
+ case ESUBASS:
+ result = linear->u.diadic.right->u.node->data.intval;
+ result = CInt64_Neg(result);
+ break;
+ default:
+ CError_FATAL(491);
+ }
+ } else {
+ CError_FATAL(496);
+ }
+
+ return result;
+}
+
+static void UpdateUse(IROLinear *linear, CInt64 val, Type *type) {
+ IROLinear *father;
+ IROLinear *repl;
+ IROLinear *newdiadic;
+
+ if ((father = IRO_LocateFather(linear))) {
+ switch (father->type) {
+ case IROLinearOp1Arg:
+ switch (father->nodetype) {
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ val = CInt64_Add(val, IRO_GetSelfAssignmentVal(father));
+ father->nodetype = EADDASS;
+ father->type = IROLinearOp2Arg;
+ repl = IRO_NewIntConst(val, type);
+ father->u.diadic.right = repl;
+ IRO_PasteAfter(repl, repl, linear);
+ return;
+ }
+ break;
+ case IROLinearOp2Arg:
+ if (IRO_IsIntConstant(father->u.diadic.right)) {
+ switch (father->nodetype) {
+ case EADD:
+ case EADDASS:
+ father->u.diadic.right->u.node->data.intval = CInt64_Add(
+ father->u.diadic.right->u.node->data.intval, val);
+ return;
+ case ESUB:
+ case ESUBASS:
+ father->u.diadic.right->u.node->data.intval = CInt64_Sub(
+ father->u.diadic.right->u.node->data.intval, val);
+ return;
+ }
+ }
+ break;
+ }
+ }
+
+ repl = IRO_NewIntConst(val, type);
+ newdiadic = IRO_NewLinear(IROLinearOp2Arg);
+ newdiadic->index = ++IRO_NumLinear;
+ newdiadic->nodetype = EADD;
+ newdiadic->u.diadic.left = linear;
+ newdiadic->u.diadic.right = repl;
+ newdiadic->rtype = linear->rtype;
+ repl->next = newdiadic;
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(linear, newdiadic);
+ IRO_PasteAfter(repl, newdiadic, linear);
+}
+
+void IRO_InitializeNonAssignmentOpArray(void) {
+ int i;
+
+ for (i = 0; i < MAXEXPR; i++)
+ IRO_NonAssignmentOp[i] = MAXEXPR;
+
+ IRO_NonAssignmentOp[EPOSTINC] = MAXEXPR;
+ IRO_NonAssignmentOp[EPOSTDEC] = MAXEXPR;
+ IRO_NonAssignmentOp[EPREINC] = MAXEXPR;
+ IRO_NonAssignmentOp[EPREDEC] = MAXEXPR;
+ IRO_NonAssignmentOp[EINDIRECT] = MAXEXPR;
+ IRO_NonAssignmentOp[EMONMIN] = MAXEXPR;
+ IRO_NonAssignmentOp[EBINNOT] = MAXEXPR;
+ IRO_NonAssignmentOp[ELOGNOT] = MAXEXPR;
+ IRO_NonAssignmentOp[EFORCELOAD] = MAXEXPR;
+ IRO_NonAssignmentOp[EMUL] = MAXEXPR;
+ IRO_NonAssignmentOp[EMULV] = MAXEXPR;
+ IRO_NonAssignmentOp[EDIV] = MAXEXPR;
+ IRO_NonAssignmentOp[EMODULO] = MAXEXPR;
+ IRO_NonAssignmentOp[EADDV] = MAXEXPR;
+ IRO_NonAssignmentOp[ESUBV] = MAXEXPR;
+ IRO_NonAssignmentOp[EADD] = MAXEXPR;
+ IRO_NonAssignmentOp[ESUB] = MAXEXPR;
+ IRO_NonAssignmentOp[ESHL] = MAXEXPR;
+ IRO_NonAssignmentOp[ESHR] = MAXEXPR;
+ IRO_NonAssignmentOp[ELESS] = MAXEXPR;
+ IRO_NonAssignmentOp[EGREATER] = MAXEXPR;
+ IRO_NonAssignmentOp[ELESSEQU] = MAXEXPR;
+ IRO_NonAssignmentOp[EGREATEREQU] = MAXEXPR;
+ IRO_NonAssignmentOp[EEQU] = MAXEXPR;
+ IRO_NonAssignmentOp[ENOTEQU] = MAXEXPR;
+ IRO_NonAssignmentOp[EAND] = MAXEXPR;
+ IRO_NonAssignmentOp[EXOR] = MAXEXPR;
+ IRO_NonAssignmentOp[EOR] = MAXEXPR;
+ IRO_NonAssignmentOp[ELAND] = MAXEXPR;
+ IRO_NonAssignmentOp[ELOR] = MAXEXPR;
+ IRO_NonAssignmentOp[EASS] = MAXEXPR;
+ IRO_NonAssignmentOp[EMULASS] = EMUL;
+ IRO_NonAssignmentOp[EDIVASS] = EDIV;
+ IRO_NonAssignmentOp[EMODASS] = EMODULO;
+ IRO_NonAssignmentOp[EADDASS] = EADD;
+ IRO_NonAssignmentOp[ESUBASS] = ESUB;
+ IRO_NonAssignmentOp[ESHLASS] = ESHL;
+ IRO_NonAssignmentOp[ESHRASS] = ESHR;
+ IRO_NonAssignmentOp[EANDASS] = EAND;
+ IRO_NonAssignmentOp[EXORASS] = EXOR;
+ IRO_NonAssignmentOp[EORASS] = EOR;
+ IRO_NonAssignmentOp[ECOMMA] = MAXEXPR;
+ IRO_NonAssignmentOp[EPMODULO] = MAXEXPR;
+ IRO_NonAssignmentOp[EROTL] = MAXEXPR;
+ IRO_NonAssignmentOp[EROTR] = MAXEXPR;
+ IRO_NonAssignmentOp[EBCLR] = MAXEXPR;
+ IRO_NonAssignmentOp[EBTST] = MAXEXPR;
+ IRO_NonAssignmentOp[EBSET] = MAXEXPR;
+ IRO_NonAssignmentOp[ETYPCON] = MAXEXPR;
+ IRO_NonAssignmentOp[EBITFIELD] = MAXEXPR;
+ IRO_NonAssignmentOp[EINTCONST] = MAXEXPR;
+ IRO_NonAssignmentOp[EFLOATCONST] = MAXEXPR;
+ IRO_NonAssignmentOp[ESTRINGCONST] = MAXEXPR;
+ IRO_NonAssignmentOp[ECOND] = MAXEXPR;
+ IRO_NonAssignmentOp[EFUNCCALL] = MAXEXPR;
+ IRO_NonAssignmentOp[EFUNCCALLP] = MAXEXPR;
+ IRO_NonAssignmentOp[EOBJREF] = MAXEXPR;
+ IRO_NonAssignmentOp[EMFPOINTER] = MAXEXPR;
+ IRO_NonAssignmentOp[ENULLCHECK] = MAXEXPR;
+ IRO_NonAssignmentOp[EPRECOMP] = MAXEXPR;
+ IRO_NonAssignmentOp[ETEMP] = MAXEXPR;
+ IRO_NonAssignmentOp[EARGOBJ] = MAXEXPR;
+ IRO_NonAssignmentOp[ELOCOBJ] = MAXEXPR;
+ IRO_NonAssignmentOp[ELABEL] = MAXEXPR;
+ IRO_NonAssignmentOp[ESETCONST] = MAXEXPR;
+ IRO_NonAssignmentOp[ENEWEXCEPTION] = MAXEXPR;
+ IRO_NonAssignmentOp[ENEWEXCEPTIONARRAY] = MAXEXPR;
+ IRO_NonAssignmentOp[EOBJLIST] = MAXEXPR;
+ IRO_NonAssignmentOp[EMEMBER] = MAXEXPR;
+ IRO_NonAssignmentOp[ETEMPLDEP] = MAXEXPR;
+ IRO_NonAssignmentOp[EINSTRUCTION] = MAXEXPR;
+ IRO_NonAssignmentOp[EDEFINE] = MAXEXPR;
+ IRO_NonAssignmentOp[EREUSE] = MAXEXPR;
+ IRO_NonAssignmentOp[EASSBLK] = MAXEXPR;
+ IRO_NonAssignmentOp[EVECTOR128CONST] = MAXEXPR;
+ IRO_NonAssignmentOp[ECONDASS] = MAXEXPR;
+}
+
+void IRO_InitializeAssignmentFoldingFunctionArray(void) {
+ int i;
+
+ for (i = 0; i < MAXEXPR; i++)
+ AssignmentFoldingFunction[i] = NULL;
+
+ AssignmentFoldingFunction[EPOSTINC] = NULL;
+ AssignmentFoldingFunction[EPOSTDEC] = NULL;
+ AssignmentFoldingFunction[EPREINC] = NULL;
+ AssignmentFoldingFunction[EPREDEC] = NULL;
+ AssignmentFoldingFunction[EINDIRECT] = NULL;
+ AssignmentFoldingFunction[EMONMIN] = NULL;
+ AssignmentFoldingFunction[EBINNOT] = NULL;
+ AssignmentFoldingFunction[ELOGNOT] = NULL;
+ AssignmentFoldingFunction[EFORCELOAD] = NULL;
+ AssignmentFoldingFunction[EMUL] = NULL;
+ AssignmentFoldingFunction[EMULV] = NULL;
+ AssignmentFoldingFunction[EDIV] = NULL;
+ AssignmentFoldingFunction[EMODULO] = NULL;
+ AssignmentFoldingFunction[EADDV] = NULL;
+ AssignmentFoldingFunction[ESUBV] = NULL;
+ AssignmentFoldingFunction[EADD] = NULL;
+ AssignmentFoldingFunction[ESUB] = NULL;
+ AssignmentFoldingFunction[ESHL] = NULL;
+ AssignmentFoldingFunction[ESHR] = NULL;
+ AssignmentFoldingFunction[ELESS] = NULL;
+ AssignmentFoldingFunction[EGREATER] = NULL;
+ AssignmentFoldingFunction[ELESSEQU] = NULL;
+ AssignmentFoldingFunction[EGREATEREQU] = NULL;
+ AssignmentFoldingFunction[EEQU] = NULL;
+ AssignmentFoldingFunction[ENOTEQU] = NULL;
+ AssignmentFoldingFunction[EAND] = NULL;
+ AssignmentFoldingFunction[EXOR] = NULL;
+ AssignmentFoldingFunction[EOR] = NULL;
+ AssignmentFoldingFunction[ELAND] = NULL;
+ AssignmentFoldingFunction[ELOR] = NULL;
+ AssignmentFoldingFunction[EASS] = NULL;
+ AssignmentFoldingFunction[EMULASS] = CInt64_Mul;
+ AssignmentFoldingFunction[EDIVASS] = CInt64_Mul;
+ AssignmentFoldingFunction[EMODASS] = NULL;
+ AssignmentFoldingFunction[EADDASS] = CInt64_Add;
+ AssignmentFoldingFunction[ESUBASS] = CInt64_Add;
+ AssignmentFoldingFunction[ESHLASS] = CInt64_Add;
+ AssignmentFoldingFunction[ESHRASS] = CInt64_Add;
+ AssignmentFoldingFunction[EANDASS] = CInt64_And;
+ AssignmentFoldingFunction[EXORASS] = CInt64_Xor;
+ AssignmentFoldingFunction[EORASS] = CInt64_Or;
+ AssignmentFoldingFunction[ECOMMA] = NULL;
+ AssignmentFoldingFunction[EPMODULO] = NULL;
+ AssignmentFoldingFunction[EROTL] = NULL;
+ AssignmentFoldingFunction[EROTR] = NULL;
+ AssignmentFoldingFunction[EBCLR] = NULL;
+ AssignmentFoldingFunction[EBTST] = NULL;
+ AssignmentFoldingFunction[EBSET] = NULL;
+ AssignmentFoldingFunction[ETYPCON] = NULL;
+ AssignmentFoldingFunction[EBITFIELD] = NULL;
+ AssignmentFoldingFunction[EINTCONST] = NULL;
+ AssignmentFoldingFunction[EFLOATCONST] = NULL;
+ AssignmentFoldingFunction[ESTRINGCONST] = NULL;
+ AssignmentFoldingFunction[ECOND] = NULL;
+ AssignmentFoldingFunction[EFUNCCALL] = NULL;
+ AssignmentFoldingFunction[EFUNCCALLP] = NULL;
+ AssignmentFoldingFunction[EOBJREF] = NULL;
+ AssignmentFoldingFunction[EMFPOINTER] = NULL;
+ AssignmentFoldingFunction[ENULLCHECK] = NULL;
+ AssignmentFoldingFunction[EPRECOMP] = NULL;
+ AssignmentFoldingFunction[ETEMP] = NULL;
+ AssignmentFoldingFunction[EARGOBJ] = NULL;
+ AssignmentFoldingFunction[ELOCOBJ] = NULL;
+ AssignmentFoldingFunction[ELABEL] = NULL;
+ AssignmentFoldingFunction[ESETCONST] = NULL;
+ AssignmentFoldingFunction[ENEWEXCEPTION] = NULL;
+ AssignmentFoldingFunction[ENEWEXCEPTIONARRAY] = NULL;
+ AssignmentFoldingFunction[EOBJLIST] = NULL;
+ AssignmentFoldingFunction[EMEMBER] = NULL;
+ AssignmentFoldingFunction[ETEMPLDEP] = NULL;
+ AssignmentFoldingFunction[EINSTRUCTION] = NULL;
+ AssignmentFoldingFunction[EDEFINE] = NULL;
+ AssignmentFoldingFunction[EREUSE] = NULL;
+ AssignmentFoldingFunction[EASSBLK] = NULL;
+ AssignmentFoldingFunction[EVECTOR128CONST] = NULL;
+ AssignmentFoldingFunction[ECONDASS] = NULL;
+}
+
+static void UpdateUseForOtherSelfAssignment(IROLinear *a, IROLinear *b, Type *type) {
+ CInt64 val;
+ IROLinear *father;
+ IROLinear *repl;
+ IROLinear *newdiadic;
+
+ val = IRO_GetSelfAssignmentVal(b);
+ if ((father = IRO_LocateFather(a)) && father->type == IROLinearOp2Arg && IRO_IsIntConstant(father->u.diadic.right)) {
+ CInt64 var_30 = father->u.diadic.right->u.node->data.intval;
+ if (AssignmentFoldingFunction[b->nodetype] && ((father->nodetype == b->nodetype) || (father->nodetype == IRO_NonAssignmentOp[b->nodetype]))) {
+ CInt64 v;
+ CInt64 folded;
+ CInt64_SetLong(&v, b->rtype->size * 8);
+ folded = AssignmentFoldingFunction[b->nodetype](var_30, val);
+ if (b->nodetype == ESHRASS && !is_unsigned(b->rtype)) {
+ if (CInt64_LessU(var_30, v) && CInt64_LessU(val, v)) {
+ if (CInt64_GreaterEqualU(folded, v))
+ folded = CInt64_Sub(v, cint64_one);
+ father->u.diadic.right->u.node->data.intval = folded;
+ return;
+ }
+ } else {
+ father->u.diadic.right->u.node->data.intval = folded;
+ return;
+ }
+ } else {
+ switch (b->nodetype) {
+ case EMULASS:
+ if (father->nodetype == ESHL || father->nodetype == ESHLASS) {
+ SInt32 powvalue;
+ if (IRO_IsPow2(b->u.diadic.right, &powvalue)) {
+ if (powvalue > 0) {
+ CInt64 v;
+ CInt64_SetLong(&v, powvalue);
+ father->u.diadic.right->u.node->data.intval = CInt64_Add(v, var_30);
+ }
+ } else {
+ father->nodetype = (father->nodetype == ESHL) ? EMUL : EMULASS;
+ var_30 = CInt64_Shl(cint64_one, var_30);
+ father->u.diadic.right->u.node->data.intval = CInt64_Mul(var_30, val);
+ }
+ return;
+ }
+ break;
+ case EDIVASS:
+ if ((father->nodetype == ESHR || father->nodetype == ESHRASS) && is_unsigned(father->rtype)) {
+ SInt32 powvalue;
+ if (IRO_IsPow2(b->u.diadic.right, &powvalue)) {
+ if (powvalue > 0) {
+ CInt64 v;
+ CInt64_SetLong(&v, powvalue);
+ father->u.diadic.right->u.node->data.intval = CInt64_Add(v, var_30);
+ }
+ } else {
+ father->nodetype = (father->nodetype == ESHR) ? EDIV : EDIVASS;
+ var_30 = CInt64_Shl(cint64_one, var_30);
+ father->u.diadic.right->u.node->data.intval = CInt64_Mul(var_30, val);
+ }
+ return;
+ }
+ break;
+ case ESHLASS:
+ if (father->nodetype == EMUL || father->nodetype == EMULASS) {
+ SInt32 powvalue;
+ if (IRO_IsPow2(father->u.diadic.right, &powvalue)) {
+ if (powvalue > 0) {
+ CInt64 v;
+ father->nodetype = (father->nodetype == EMUL) ? ESHL : ESHLASS;
+ CInt64_SetLong(&v, powvalue);
+ father->u.diadic.right->u.node->data.intval = CInt64_Add(v, val);
+ }
+ } else {
+ val = CInt64_Shl(cint64_one, val);
+ father->u.diadic.right->u.node->data.intval = CInt64_Mul(var_30, val);
+ }
+ return;
+ } else if (father->nodetype == ESHR || father->nodetype == ESHRASS) {
+ if (CInt64_Equal(var_30, val) && is_unsigned(father->rtype)) {
+ father->nodetype = (father->nodetype == ESHR) ? EAND : EANDASS;
+ if (father->rtype->size < 8) {
+ CInt64 v;
+ CInt64_SetLong(&v, 64 - (father->rtype->size * 8));
+ val = CInt64_Add(val, v);
+ }
+ father->u.diadic.right->u.node->data.intval = CInt64_ShrU(cint64_negone, val);
+ return;
+ }
+ }
+ break;
+ case ESHRASS:
+ if ((father->nodetype == EDIV || father->nodetype == EDIVASS) && is_unsigned(father->rtype)) {
+ SInt32 powvalue;
+ if (IRO_IsPow2(father->u.diadic.right, &powvalue)) {
+ if (powvalue > 0) {
+ CInt64 v;
+ father->nodetype = (father->nodetype == EDIV) ? ESHR : ESHRASS;
+ CInt64_SetLong(&v, powvalue);
+ father->u.diadic.right->u.node->data.intval = CInt64_Add(v, val);
+ }
+ } else {
+ val = CInt64_Shl(cint64_one, val);
+ father->u.diadic.right->u.node->data.intval = CInt64_Mul(var_30, val);
+ }
+ return;
+ } else if (father->nodetype == ESHL || father->nodetype == ESHLASS) {
+ if (CInt64_Equal(var_30, val)) {
+ father->nodetype = (father->nodetype == ESHL) ? EAND : EANDASS;
+ father->u.diadic.right->u.node->data.intval = CInt64_Shl(cint64_negone, val);
+ return;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ repl = IRO_NewIntConst(val, type);
+ newdiadic = IRO_NewLinear(IROLinearOp2Arg);
+ newdiadic->index = ++IRO_NumLinear;
+ newdiadic->nodetype = IRO_NonAssignmentOp[b->nodetype];
+ newdiadic->u.diadic.left = a;
+ newdiadic->u.diadic.right = repl;
+ newdiadic->rtype = a->rtype;
+ repl->next = newdiadic;
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(a, newdiadic);
+ IRO_PasteAfter(repl, newdiadic, a);
+}
+
+static Boolean PropagateIncsAndDecs(void) {
+ IRODef *def;
+ Boolean result;
+
+ result = 0;
+ def = FirstDef;
+ while (def) {
+ if (
+ def->linear &&
+ def->x1C &&
+ IsIncOrDec(def->linear) &&
+ !(def->linear->flags & IROLF_Reffed) &&
+ (IS_TYPE_INT_OR_ENUM(def->linear->rtype) || IS_TYPE_POINTER_ONLY(def->linear->rtype)) &&
+ IRO_TypesEqual(def->linear->rtype, def->var->object->type) &&
+ !is_volatile_object(def->var->object)
+ ) {
+ IROUse *use;
+ IROUse *use2;
+ IROLinear *father;
+ CInt64 val;
+ SInt32 i;
+ Type *type;
+
+ for (use = def->var->uses, i = 0; use; use = use->varnext) {
+ if (Bv_IsBitSet(def->index, use->x18)) {
+ if (
+ use->x1C == 1 &&
+ use->linear->type == IROLinearOperand &&
+ (father = IRO_LocateFather(use->linear)) &&
+ IRO_IsVariable(father) &&
+ IRO_TypesEqual(def->linear->rtype, father->rtype)
+ ) {
+ if (use->linear->flags & IROLF_Assigned) {
+ if (!((father = IRO_LocateFather(father)) && IsIncOrDec(father) && !(father->flags & IROLF_Reffed)))
+ goto nextDef;
+ }
+ i++;
+ } else {
+ goto nextDef;
+ }
+ }
+ }
+
+ if (i == def->x18) {
+ for (use = def->var->uses; use; use = use->varnext) {
+ if (Bv_IsBitSet(def->index, use->x18)) {
+ IRO_Dump("Propagating inc/dec from %d to %d\n", def->linear->index, use->linear->index);
+ father = IRO_LocateFather(use->linear);
+ val = IRO_GetSelfAssignmentVal(def->linear);
+ type = def->linear->rtype;
+ if (IS_TYPE_POINTER_ONLY(def->linear->rtype))
+ type = TYPE(&stunsignedlong);
+ UpdateUse(father, val, type);
+
+ result = 1;
+ for (use2 = def->var->uses; use2; use2 = use2->varnext) {
+ if (use2->linear == def->linear->u.monadic->u.diadic.left) {
+ use->x1C = use2->x1C;
+ Bv_Copy(use2->x18, use->x18);
+ break;
+ }
+ }
+ }
+ }
+ def->x18 = 0;
+ IRO_NopNonSideEffects(def->linear, -1);
+ def->linear->type = IROLinearNop;
+ IRO_Dump("Removing deadddd assignment %d\n", def->linear->index);
+ }
+ }
+ nextDef:
+ def = def->globalnext;
+ }
+
+ return result;
+}
+
+static Boolean PropagateOtherSelfAssignments(void) {
+ IRODef *def;
+ Boolean result;
+
+ result = 0;
+
+ def = FirstDef;
+ while (def) {
+ if (
+ def->linear &&
+ def->x1C &&
+ IsOtherSelfAssignment(def->linear) &&
+ !(def->linear->flags & IROLF_Reffed) &&
+ IS_TYPE_INT_OR_ENUM(def->linear->rtype) &&
+ IRO_TypesEqual(def->linear->rtype, def->var->object->type) &&
+ !is_volatile_object(def->var->object)
+ )
+ {
+ IROUse *use;
+ IROUse *use2;
+ IROLinear *father;
+ SInt32 i;
+ Type *type;
+
+ for (use = def->var->uses, i = 0; use; use = use->varnext) {
+ if (Bv_IsBitSet(def->index, use->x18)) {
+ if (
+ use->x1C == 1 &&
+ use->linear->type == IROLinearOperand &&
+ (father = IRO_LocateFather(use->linear)) &&
+ IRO_IsVariable(father) &&
+ IRO_TypesEqual(def->linear->rtype, father->rtype)
+ ) {
+ if (use->linear->flags & IROLF_Assigned) {
+ if (!((father = IRO_LocateFather(father)) && IsOtherSelfAssignment(father) && (father->nodetype == def->linear->nodetype) && !(father->flags & IROLF_Reffed)))
+ goto nextDef;
+ }
+ i++;
+ } else {
+ goto nextDef;
+ }
+ }
+ }
+
+ if (i == def->x18) {
+ for (use = def->var->uses; use; use = use->varnext) {
+ if (Bv_IsBitSet(def->index, use->x18)) {
+ IRO_Dump("Propagating self assignment from %d to %d\n", def->linear->index, use->linear->index);
+ father = IRO_LocateFather(use->linear);
+ UpdateUseForOtherSelfAssignment(father, def->linear, def->linear->rtype);
+
+ result = 1;
+ for (use2 = def->var->uses; use2; use2 = use2->varnext) {
+ if (use2->linear == def->linear->u.monadic->u.diadic.left) {
+ use->x1C = use2->x1C;
+ Bv_Copy(use2->x18, use->x18);
+ break;
+ }
+ }
+ }
+ }
+ def->x18 = 0;
+ IRO_NopNonSideEffects(def->linear, -1);
+ def->linear->type = IROLinearNop;
+ IRO_Dump("Removing deadddd assignment %d\n", def->linear->index);
+ }
+ }
+ nextDef:
+ def = def->globalnext;
+ }
+
+ return result;
+}
+
+static void MarkUsesByIndirect(IROLinear *linear, BitVector *a, BitVector *b) {
+ IROListNode *list;
+ IROLinear *nd;
+ Object *obj;
+ VarRecord *var;
+ Boolean foundObjRef;
+ IROListNode *scan;
+ IRODef *def;
+ Boolean found;
+
+ found = 0;
+
+ if (linear && copts.opt_pointer_analysis && linear->pointsToFunction && FunctionName) {
+ IROListNode *resultList;
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, linear, &resultList);
+ if ((list = resultList)) {
+ for (scan = list; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ found = 1;
+ break;
+ }
+
+ foundObjRef = 0;
+ for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) {
+ if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
+ foundObjRef = 1;
+ break;
+ }
+ }
+
+ if (!foundObjRef) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ while (list) {
+ for (nd = list->list.head; nd != list->list.tail->next; nd = nd->next) {
+ if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
+ obj = nd->u.node->data.objref;
+ CError_ASSERT(1422, obj != NULL);
+ var = IRO_FindVar(obj, 1, 1);
+ CError_ASSERT(1424, var != NULL);
+
+ for (def = var->defs; def; def = def->varnext) {
+ if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches))) {
+ def->x18++;
+ Bv_SetBit(def->index, MightReachAnyUse);
+ }
+ }
+ }
+ }
+ list = list->nextList;
+ }
+ }
+
+ while (resultList) {
+ IROListNode *next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ found = 1;
+ }
+ } else {
+ found = 1;
+ }
+
+ if (found) {
+ Bv_Copy(Reaches, a);
+ Bv_And(b, a);
+ Bv_Or(a, MightReachAnyUse);
+ for (def = FirstDef; def; def = def->globalnext) {
+ if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches)))
+ def->x18++;
+ }
+ }
+}
+
+static void MarkUsesByFunctionCall(IROLinear *linear, BitVector *a, BitVector *b) {
+ ObjectList *olist;
+ IROLinear *funcnd;
+ IROListNode *list;
+ IROLinear *nd;
+ Object *obj;
+ VarRecord *var;
+ Boolean foundObjRef;
+ IROListNode *scan;
+ IRODef *def;
+ Boolean found;
+
+ found = 0;
+
+ if ((funcnd = linear->u.funccall.linear8) && copts.opt_pointer_analysis && funcnd->pointsToFunction && FunctionName) {
+ IROListNode *resultList;
+ ObjectList *depsList;
+
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, funcnd, &resultList);
+ if (resultList) {
+ for (scan = resultList; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ found = 1;
+ break;
+ }
+
+ foundObjRef = 0;
+ for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) {
+ if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
+ foundObjRef = 1;
+ obj = nd->u.node->data.objref;
+ CError_ASSERT(1522, obj != NULL);
+
+ depsList = NULL;
+ PointerAnalysis_GetFunctionDependencies(obj, linear, &depsList);
+ for (olist = depsList; olist; olist = olist->next) {
+ if (!olist->object) {
+ found = 1;
+ break;
+ }
+ }
+
+ while (depsList) {
+ olist = depsList->next;
+ IRO_free(depsList);
+ depsList = olist;
+ }
+
+ if (found)
+ break;
+ }
+ }
+
+ if (!foundObjRef)
+ found = 1;
+ if (found)
+ break;
+ }
+
+ if (!found) {
+ for (list = resultList; list; list = list->nextList) {
+ for (nd = list->list.head; nd != list->list.tail->next; nd = nd->next) {
+ if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
+ obj = nd->u.node->data.objref;
+ depsList = NULL;
+ PointerAnalysis_GetFunctionDependencies(obj, linear, &depsList);
+
+ for (olist = depsList; olist; olist = olist->next) {
+ var = IRO_FindVar(olist->object, 1, 1);
+ CError_ASSERT(1573, var != NULL);
+
+ for (def = var->defs; def; def = def->varnext) {
+ if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches))) {
+ def->x18++;
+ Bv_SetBit(def->index, MightReachAnyUse);
+ }
+ }
+ }
+
+ while (depsList) {
+ olist = depsList->next;
+ IRO_free(depsList);
+ depsList = olist;
+ }
+ }
+ }
+ }
+ }
+
+ while (resultList) {
+ IROListNode *next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ found = 1;
+ }
+ } else {
+ found = 1;
+ }
+
+ if (found) {
+ Bv_Copy(Reaches, a);
+ Bv_And(b, a);
+ Bv_Or(a, MightReachAnyUse);
+ for (def = FirstDef; def; def = def->globalnext) {
+ if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches)))
+ def->x18++;
+ }
+ }
+
+ if (linear->stmt && IRO_FunctionCallMightThrowException(linear))
+ IRO_WalkExcActions(linear->stmt->dobjstack, MarkUses);
+}
+
+static Boolean UseOfVarIsInsideASimpleDefOfVar(IROUse *use) {
+ VarRecord *var;
+ VarRecord *varAss;
+ IROLinear *nd;
+ IROLinear *nd2;
+
+ if ((var = use->var)) {
+ if ((nd = use->linear) && (nd->flags & IROLF_4000))
+ return 0;
+
+ while (nd && (nd->flags & IROLF_Reffed))
+ nd = nd->next;
+
+ if (
+ nd &&
+ IRO_IsAssignment(nd) &&
+ (varAss = IRO_FindAssigned(nd)) &&
+ varAss == var &&
+ !IRO_HasSideEffect((nd->type == IROLinearOp1Arg) ? nd->u.monadic : nd->u.diadic.left) &&
+ (!(nd2 = (nd->type == IROLinearOp1Arg) ? NULL : nd->u.diadic.right) || !IRO_HasSideEffect(nd2))
+ ) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static Boolean AllLoopDefUsesAreInSimpleLoopDefs(IRODef *def) {
+ VarRecord *var;
+ IRODef *scan;
+ IROUse *use;
+
+ if ((var = def->var)) {
+ for (scan = var->defs; scan; scan = scan->varnext) {
+ if (scan->node && scan->node->loopdepth) {
+ for (use = var->uses; use; use = use->varnext) {
+ if (Bv_IsBitSet(scan->index, use->x18)) {
+ if (!use->node || !use->node->loopdepth || !UseOfVarIsInsideASimpleDefOfVar(use))
+ return 0;
+ }
+ }
+ }
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void MarkRemovableLoopDefs(void) {
+ IRODef *def;
+ IRODef *scan;
+
+ for (def = FirstDef; def; def = def->globalnext) {
+ if (!def->x1A && !def->x1B && def->node && def->node->loopdepth && !def->x1D &&
+ AllLoopDefUsesAreInSimpleLoopDefs(def) && def->var) {
+ for (scan = def->var->defs; scan; scan = scan->varnext) {
+ if (scan->node && scan->node->loopdepth)
+ scan->x1D = 1;
+ }
+ }
+ }
+}
+
+static Boolean EliminateReffedDeadStore(IRODef *def) {
+ Boolean isPostIncOrDec;
+ IROLinear *nd;
+ Boolean result;
+
+ nd = def->linear;
+ isPostIncOrDec = (nd->type == IROLinearOp1Arg) && (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC);
+
+ result = IRO_LocateFather(nd) != NULL;
+ if (result && IRO_IsAssignment(nd) && IRO_IsModifyOp[nd->nodetype])
+ result = IRO_TransformSelfAssignmentToAssignment(nd);
+ result = result && (nd->type == IROLinearOp2Arg) && (nd->nodetype == EASS);
+
+ if (result) {
+ def->x18 = 0;
+ IRO_Dump("Removing referenced dead assignment %d\n", nd->index);
+
+ if (isPostIncOrDec) {
+ IRO_NopNonSideEffects(nd->u.diadic.right, 0);
+ nd->type = IROLinearNop;
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, nd->u.diadic.left);
+ } else {
+ IRO_NopNonSideEffects(nd->u.diadic.left, 0);
+ nd->type = IROLinearNop;
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, nd->u.diadic.right);
+ }
+ }
+
+ return result;
+}
+
+Boolean IRO_UseDef(Boolean optDeadAssignments, Boolean optPropagation) {
+ Boolean result;
+ IRODef *gdef;
+ IROUse *guse;
+ IRODef *def;
+ IROUse *use;
+ IRONode *node;
+ IROLinear *nd;
+ VarRecord *var;
+ Boolean flag;
+ BitVector *bv3;
+ BitVector *bv2;
+ BitVector *bv;
+ int i;
+
+ FindDefsAndUses();
+
+ IRO_CheckForUserBreak();
+
+ for (use = IRO_FirstVarUse; use; use = use->globalnext)
+ Bv_AllocVector(&use->x18, NumDefs);
+ Bv_AllocVector(&MightReachAnyUse, NumDefs);
+ Bv_AllocVector(&bv, NumDefs);
+
+ IRO_CheckForUserBreak();
+
+ for (def = FirstDef; def; def = def->globalnext) {
+ if (def->x1A || def->x1B)
+ Bv_SetBit(def->index, bv);
+ }
+
+ Bv_AllocVector(&bv2, NumDefs);
+ gdef = FirstDef;
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ Bv_AllocVector(&node->x16, NumDefs);
+ Bv_AllocVector(&node->x1E, NumDefs);
+ Bv_AllocVector(&node->x22, NumDefs);
+ Bv_AllocVector(&node->x1A, NumDefs);
+
+ for (nd = node->first; nd; nd = nd->next) {
+ while (gdef && gdef->linear == nd) {
+ Bv_SetBit(gdef->index, node->x1E);
+ if (gdef->x1C) {
+ for (def = gdef->var->defs; def; def = def->varnext) {
+ if (def != gdef) {
+ Bv_SetBit(def->index, node->x22);
+ Bv_ClearBit(def->index, node->x1E);
+ }
+ }
+ }
+ gdef = gdef->globalnext;
+ }
+ if (nd == node->last)
+ break;
+ }
+
+ if (node->numpred)
+ Bv_Set(node->x16);
+ Bv_Copy(node->x1E, node->x1A);
+ IRO_CheckForUserBreak();
+ }
+
+ Bv_AllocVector(&bv3, NumDefs);
+
+ do {
+ flag = 0;
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ Bv_Clear(node->x16);
+ if (node->numpred) {
+ for (i = 0; i < node->numpred; i++)
+ Bv_Or(IRO_NodeTable[node->pred[i]]->x1A, node->x16);
+ } else if (node == IRO_FirstNode) {
+ for (var = IRO_FirstVar; var; var = var->next)
+ Bv_SetBit(var->defs->index, node->x16);
+ }
+ Bv_Copy(node->x16, bv3);
+ Bv_Minus(node->x22, bv3);
+ Bv_Or(node->x1E, bv3);
+ if (!Bv_Compare(bv3, node->x1A)) {
+ Bv_Copy(bv3, node->x1A);
+ flag = 1;
+ }
+ }
+
+ IRO_CheckForUserBreak();
+ } while (flag);
+
+ gdef = FirstDef;
+ guse = IRO_FirstVarUse;
+ Bv_AllocVector(&Reaches, NumDefs);
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ Bv_Copy(node->x16, Reaches);
+ nd = node->first;
+ while (1) {
+ while (guse && guse->linear == nd) {
+ for (def = guse->var->defs; def; def = def->varnext) {
+ if (Bv_IsBitSet(def->index, Reaches)) {
+ Bv_SetBit(def->index, guse->x18);
+ Bv_SetBit(def->index, MightReachAnyUse);
+ def->x18++;
+ guse->x1C++;
+ }
+ }
+ guse = guse->globalnext;
+ }
+
+ if (nd->type == IROLinearFunccall) {
+ MarkUsesByFunctionCall(nd, bv2, bv);
+ } else if (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT && !IRO_IsVariable(nd)) {
+ MarkUsesByIndirect(nd, bv2, bv);
+ } else if ((nd->type == IROLinearFunccall) ||
+ (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT && !IRO_IsVariable(nd))) {
+ Bv_Copy(Reaches, bv2);
+ Bv_And(bv, bv2);
+ Bv_Or(bv2, MightReachAnyUse);
+ for (def = FirstDef; def; def = def->globalnext) {
+ if (def->x1A || (def->x1B && Bv_IsBitSet(def->index, Reaches)))
+ def->x18++;
+ }
+ if (nd->type == IROLinearFunccall && nd->stmt && IRO_FunctionCallMightThrowException(nd))
+ IRO_WalkExcActions(nd->stmt->dobjstack, MarkUses);
+ }
+
+ if (nd->type == IROLinearAsm) {
+ IAEffects effects;
+ CodeGen_GetAsmEffects(nd->u.asm_stmt, &effects);
+ if (effects.x2) {
+ Bv_Copy(Reaches, bv2);
+ Bv_And(bv, bv2);
+ Bv_Or(bv2, MightReachAnyUse);
+ }
+ }
+
+ if (nd->type == IROLinearReturn || nd->type == IROLinearEnd) {
+ for (def = FirstDef; def; def = def->globalnext) {
+ if (def->x1A && Bv_IsBitSet(def->index, Reaches)) {
+ Bv_SetBit(def->index, MightReachAnyUse);
+ def->x18++;
+ }
+ }
+ }
+
+ while (gdef && gdef->linear == nd) {
+ if (gdef->x1C) {
+ for (def = gdef->var->defs; def; def = def->varnext)
+ Bv_ClearBit(def->index, Reaches);
+ }
+ Bv_SetBit(gdef->index, Reaches);
+ gdef = gdef->globalnext;
+ }
+
+ if (nd == node->last)
+ break;
+ nd = nd->next;
+ }
+ }
+
+ IRO_CheckForUserBreak();
+
+ result = 0;
+
+ if (optDeadAssignments) {
+ MarkRemovableLoopDefs();
+ for (def = FirstDef; def; def = def->globalnext) {
+ if (def->linear &&
+ (!Bv_IsBitSet(def->index, MightReachAnyUse) || def->x1D) &&
+ (copts.opt_pointer_analysis || !def->x1B) &&
+ def->linear->type != IROLinearAsm &&
+ (!def->linear->rtype || !CParser_IsVolatile(def->linear->rtype, def->linear->nodeflags & ENODE_FLAG_QUALS)) &&
+ !is_volatile_object(def->var->object)
+ ) {
+ if (!(def->linear->flags & IROLF_Reffed)) {
+ def->x18 = 0;
+ IRO_NopNonSideEffects(def->linear, -1);
+ def->linear->type = IROLinearNop;
+ IRO_Dump("Removing dead assignment %d\n", def->linear->index);
+ result = 1;
+ } else {
+ result = EliminateReffedDeadStore(def);
+ }
+ }
+ }
+ }
+
+ IRO_CheckForUserBreak();
+
+ if (optPropagation) {
+ while (1) {
+ if (PropagateIncsAndDecs() || PropagateOtherSelfAssignments())
+ result = 1;
+ else
+ break;
+ }
+ }
+
+ IRO_CheckForUserBreak();
+
+ return result;
+}
+
+static IROLinear *GetOperand(IROLinear *nd) {
+ IROLinear *inner;
+
+ if (nd->type == IROLinearOperand)
+ return nd;
+
+ if (nd->type == IROLinearOp2Arg && nd->nodetype == EADD) {
+ inner = GetOperand(nd->u.diadic.left);
+ if (!inner)
+ inner = GetOperand(nd->u.diadic.right);
+ return inner;
+ }
+
+ return NULL;
+}
+
+static IROLinear *GetAssigned(IROLinear *nd) {
+ if (!nd)
+ return NULL;
+
+ if (nd->type == IROLinearOp2Arg)
+ nd = nd->u.diadic.left;
+ else if (nd->type == IROLinearOp1Arg)
+ nd = nd->u.monadic;
+ else
+ CError_FATAL(2338);
+
+ if (nd->type != IROLinearOp1Arg || nd->nodetype != EINDIRECT)
+ CError_FATAL(2351);
+
+ nd = nd->u.monadic;
+
+ if (nd->type == IROLinearOp2Arg && nd->nodetype == EADD)
+ nd = GetOperand(nd);
+
+ return nd;
+}
+
+static void AddUseToRange(IROUse *use) {
+ IRODef *def;
+
+ Bv_SetBit(use->index, useset);
+ Bv_ClearBit(use->index, alluses);
+
+ for (def = use->var->defs; def; def = def->varnext) {
+ if (Bv_IsBitSet(def->index, alldefs) && (Bv_IsBitSet(def->index, use->x18) || GetAssigned(def->linear) == use->linear))
+ AddDefToRange(def);
+ }
+}
+
+static void AddDefToRange(IRODef *def) {
+ IROUse *use;
+ IROLinear *assigned;
+
+ Bv_SetBit(def->index, defset);
+ Bv_ClearBit(def->index, alldefs);
+
+ for (use = def->var->uses, assigned = GetAssigned(def->linear); use; use = use->varnext) {
+ if (Bv_IsBitSet(use->index, alluses) && (Bv_IsBitSet(def->index, use->x18) || assigned == use->linear))
+ AddUseToRange(use);
+ }
+}
+
+static void ReplaceAssigned(IROLinear *nd, Object *from, Object *to) {
+ IROLinear *assigned;
+
+ if (
+ !(assigned = GetAssigned(nd)) ||
+ assigned->type != IROLinearOperand ||
+ assigned->u.node->type != EOBJREF ||
+ assigned->u.node->data.objref != from
+ )
+ CError_FATAL(2459);
+
+ assigned->u.node->data.objref = to;
+}
+
+static void ReplaceUsed(IROLinear *nd, Object *from, Object *to) {
+ CError_ASSERT(2482, nd->type == IROLinearOperand && nd->u.node->type == EOBJREF);
+
+ if (nd->u.node->data.objref == from)
+ nd->u.node->data.objref = to;
+ else if (nd->u.node->data.objref != to)
+ CError_FATAL(2494);
+}
+
+static void SplitOffRange(VarRecord *var) {
+ Object *newObj;
+ IRODef *def;
+ IROUse *use;
+
+ IRO_Dump("Splitting range for variable: %d\n", var->index);
+ IRO_DumpBits("Def set: ", defset);
+ IRO_DumpBits("Use set: ", useset);
+ IRO_DumpBits("All defs: ", alldefs);
+ IRO_DumpBits("All uses: ", alluses);
+
+ newObj = create_temp_object(var->object->type);
+ IRO_FindVar(newObj, 1, 1);
+
+ for (def = var->defs; def; def = def->varnext) {
+ if (Bv_IsBitSet(def->index, defset) && def->linear)
+ ReplaceAssigned(def->linear, var->object, newObj);
+ }
+
+ for (use = var->uses; use; use = use->varnext) {
+ if (Bv_IsBitSet(use->index, useset))
+ ReplaceUsed(use->linear, var->object, newObj);
+ }
+}
+
+void IRO_SplitLifetimes(void) {
+ VarRecord *var;
+ SInt32 numVars;
+ IRODef *def;
+ IROUse *use;
+ Boolean flag;
+
+ Bv_AllocVector(&alldefs, NumDefs);
+ Bv_AllocVector(&alluses, NumUses);
+ Bv_AllocVector(&defset, NumDefs);
+ Bv_AllocVector(&useset, NumUses);
+
+ var = IRO_FirstVar;
+ numVars = IRO_NumVars;
+
+ while (var && var->index <= numVars) {
+ if (var->object->datatype == DLOCAL && !is_volatile_object(var->object) && !var->xC && !var->xB && !var->x1E) {
+ Bv_Clear(alldefs);
+ Bv_Clear(alluses);
+
+ for (def = var->defs; def; def = def->varnext) {
+ if (def->linear && def->linear->type == IROLinearAsm)
+ goto skipThisVar;
+ Bv_SetBit(def->index, alldefs);
+ }
+
+ for (use = var->uses; use; use = use->varnext) {
+ if (use->linear && use->linear->type == IROLinearAsm)
+ goto skipThisVar;
+ Bv_SetBit(use->index, alluses);
+ }
+
+ flag = 1;
+ while (1) {
+ Bv_Clear(defset);
+ Bv_Clear(useset);
+
+ def = var->defs;
+ while (def && !Bv_IsBitSet(def->index, alldefs))
+ def = def->varnext;
+
+ if (!def)
+ break;
+
+ AddDefToRange(def);
+ if (Bv_IsEmpty(alldefs))
+ break;
+
+ if (!flag)
+ SplitOffRange(var);
+ flag = 0;
+ }
+ }
+
+ skipThisVar:
+ var = var->next;
+ }
+
+ IRO_CheckForUserBreak();
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IROUseDef.h b/compiler_and_linker/FrontEnd/Optimizer/IROUseDef.h
new file mode 100644
index 0000000..03d3f9b
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IROUseDef.h
@@ -0,0 +1,48 @@
+#ifndef COMPILER_IROUSEDEF_H
+#define COMPILER_IROUSEDEF_H
+
+#include "IrOptimizer.h"
+#include "BitVector.h"
+#include "compiler/enode.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+struct IROUse {
+ SInt32 index;
+ IRONode *node;
+ IROLinear *linear;
+ VarRecord *var;
+ IROUse *globalnext;
+ IROUse *varnext;
+ BitVector *x18;
+ UInt16 x1C;
+};
+struct IRODef {
+ SInt32 index;
+ IRONode *node;
+ IROLinear *linear;
+ VarRecord *var;
+ IRODef *globalnext;
+ IRODef *varnext;
+ UInt16 x18;
+ Boolean x1A;
+ Boolean x1B;
+ Boolean x1C;
+ Boolean x1D;
+};
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+extern ENodeType IRO_NonAssignmentOp[MAXEXPR];
+extern IROUse *IRO_FirstVarUse;
+extern IROUse *IRO_LastVarUse;
+
+extern CInt64 IRO_GetSelfAssignmentVal(IROLinear *linear);
+extern void IRO_InitializeNonAssignmentOpArray(void);
+extern void IRO_InitializeAssignmentFoldingFunctionArray(void);
+extern Boolean IRO_UseDef(Boolean optDeadAssignments, Boolean optPropagation);
+extern void IRO_SplitLifetimes(void);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.c b/compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.c
new file mode 100644
index 0000000..59bb368
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.c
@@ -0,0 +1,400 @@
+#include "IrOptimizer.h"
+#include "compiler/CError.h"
+#include "compiler/CParser.h"
+#include "compiler/InlineAsmPPC.h"
+#include "IroCSE.h"
+#include "IroDump.h"
+#include "IroEval.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroSubable.h"
+#include "IroTransform.h"
+#include "IROUseDef.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/objects.h"
+#include "IroPropagate.h"
+#include "IroPointerAnalysis.h"
+#include "IroJump.h"
+#include "IroRangePropagation.h"
+#include "IroEmptyLoop.h"
+#include "IroUnrollLoop.h"
+#include "IroLoop.h"
+#include "IroExprRegeneration.h"
+
+Boolean DoScalarize;
+Boolean DoLinearize;
+Boolean EarlyReturn;
+Boolean IRO_CPFirstTime;
+Boolean VectorPhaseCalledFromUnroll;
+Boolean IRO_Log;
+static Boolean stIsSetup;
+
+static void CountRefToObject(Object *object, int depth) {
+ static unsigned short LoopUsage[] = {1, 4, 16, 64};
+
+ if (depth > 3)
+ depth = 3;
+
+ object->u.var.info->usage += LoopUsage[depth];
+ object->u.var.info->used = 1;
+}
+
+static void CountARef(IROLinear *node, int depth) {
+ Object *object;
+
+ object = node->u.node->data.objref;
+ CError_ASSERT(78, object->datatype != DALIAS);
+
+ if (object->datatype == DLOCAL && object->u.var.info) {
+ CountRefToObject(object, depth);
+ if ((node->flags & IROLF_Used) && (node->flags & IROLF_Assigned))
+ CountRefToObject(object, depth);
+
+ if (!(node->flags & IROLF_Immind) && !object->u.var.info->noregister)
+ object->u.var.info->noregister = 2;
+ }
+}
+
+static void CountDoubleInd(IROLinear *node, int depth) {
+ if (IRO_IsVariable(node)) {
+ CountARef(node->u.monadic, depth);
+ } else if (node->type == IROLinearOp2Arg) {
+ if (node->nodetype == EADD) {
+ CountDoubleInd(node->u.diadic.left, depth);
+ CountDoubleInd(node->u.diadic.right, depth);
+ } else if (IRO_IsAddressMultiply(node)) {
+ if (IRO_IsVariable(node->u.diadic.left))
+ CountARef(node->u.diadic.left->u.monadic, depth);
+ }
+ }
+}
+
+static void CountUsage(void) {
+ IRONode *fnode = IRO_FirstNode;
+ IROLinear *node;
+
+ if (IRO_FirstNode) {
+ for (; fnode; fnode = fnode->nextnode) {
+ for (node = fnode->first; node; node = node->next) {
+ if (IS_LINEAR_ENODE(node, EOBJREF))
+ CountARef(node, fnode->loopdepth);
+ else if (IS_LINEAR_MONADIC(node, EINDIRECT))
+ CountDoubleInd(node->u.monadic, fnode->loopdepth);
+
+ if (node->type == IROLinearAsm) {
+ IAEffects effects;
+ int i;
+
+ CodeGen_GetAsmEffects(node->u.asm_stmt, &effects);
+ for (i = 0; i < effects.numoperands; i++) {
+ Object *object = effects.operands[i].object;
+ if (object->datatype == DLOCAL && object->u.var.info) {
+ CountRefToObject(object, fnode->loopdepth);
+ if (effects.operands[i].type == IAOpnd_3 && !object->u.var.info->noregister)
+ object->u.var.info->noregister = 2;
+ }
+ }
+ }
+
+ if (node == fnode->last)
+ break;
+ }
+ }
+ } else {
+ for (node = IRO_FirstLinear; node; node = node->next) {
+ if (IS_LINEAR_ENODE(node, EOBJREF))
+ CountARef(node, 0);
+ else if (IS_LINEAR_MONADIC(node, EINDIRECT))
+ CountDoubleInd(node->u.monadic, 0);
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+Statement *IRO_Optimizer(Object *func, Statement *statements) {
+ Boolean changed;
+ int pass;
+ int passCount;
+
+ CError_ASSERT(234, stIsSetup);
+
+#ifdef CW_ENABLE_IRO_DEBUG
+ if (copts.debuglisting)
+ IRO_Log = 1;
+#endif
+
+ DisableDueToAsm = 0;
+ FunctionName = func;
+ DoScalarize = 1;
+ DoLinearize = 1;
+ EarlyReturn = 0;
+ IRO_Depends = NULL;
+ LoopOptimizerRun = 0;
+ IRO_IsLeafFunction = 1;
+ IRO_FunctionHasReturn = 0;
+
+ IRO_SetupForUserBreakChecking();
+
+ IRO_Dump("Starting function %s\n", func ? func->name->name : "Init-code");
+ IRO_Dump("--------------------------------------------------------------------------------\n");
+
+ if (DoLinearize)
+ IRO_PreLinearize(statements);
+ if (copts.optimizationlevel > 0)
+ IRO_TransformTree(statements);
+
+ VectorPhaseCalledFromUnroll = 0;
+
+ IRO_Linearize(statements);
+
+ CurStat = NULL;
+
+ IRO_FirstExpr = NULL;
+ IRO_LastExpr = NULL;
+ IRO_FirstAssign = NULL;
+ IRO_LastAssign = NULL;
+ IRO_FirstVarUse = NULL;
+ IRO_LastVarUse = NULL;
+ IRO_FirstNode = NULL;
+ IRO_LastNode = NULL;
+
+ if (copts.optimizationlevel > 0)
+ IRO_DoTransformations();
+
+ IRO_BuildFlowgraph(IRO_FirstLinear);
+ IRO_DumpAfterPhase("IRO_BuildflowGraph", 0);
+
+ IRO_FindAllVars();
+ IRO_CheckInit();
+
+ if (!DisableDueToAsm && copts.optimizationlevel > 0 && copts.opt_pointer_analysis && func) {
+ IRO_AnalyzePointers(func);
+ if (copts.propagation && IRO_EvaluateDefinitePointers(func)) {
+ IRO_UpdateFlagsOnInts();
+ IRO_UpdateVars();
+ IRO_DumpAfterPhase("IRO_EvaluateDefinitePointers", 0);
+ }
+ }
+
+ if (copts.optimizationlevel > 0) {
+ changed = IRO_EvaluateConditionals();
+
+ if (!DisableDueToAsm) {
+ changed |= IRO_RemoveUnreachable();
+ IRO_DumpAfterPhase("IRO_RemoveUnreachable", 0);
+ }
+
+ changed |= IRO_RemoveRedundantJumps();
+ IRO_DumpAfterPhase("IRO_RemoveRedundantJumps", 0);
+
+ if (!DisableDueToAsm) {
+ changed |= IRO_RemoveLabels();
+ IRO_DumpAfterPhase("IRO_RemoveLabels()", 0);
+ }
+
+ if (changed) {
+ IRO_BuildFlowgraph(IRO_FirstLinear);
+ IRO_DumpAfterPhase("IRO_BuildflowGraph--1", 0);
+ }
+ }
+
+ if (!DisableDueToAsm && copts.optimizationlevel > 0) {
+ passCount = copts.multiplepasses ? 2 : 1;
+ IRO_CPFirstTime = 1;
+ for (pass = 0; pass < passCount; pass++) {
+ IRO_Dump("*****************\n");
+ IRO_Dump("Dumps for pass=%d\n", pass);
+ IRO_Dump("*****************\n");
+
+ if (DoScalarize)
+ IRO_ScalarizeClassDataMembers();
+ IRO_DumpAfterPhase("IRO_ScalarizeClassDataMembers", 0);
+
+ if (copts.propagation) {
+ IRO_CopyAndConstantPropagation();
+ IRO_CPFirstTime = 0;
+ IRO_ExpressionPropagation();
+ IRO_DumpAfterPhase("Copy and constant propagation", 0);
+
+ IRO_RangePropagateInFNode();
+ IRO_DumpAfterPhase("IRO_RangePropagateInFNode", 0);
+ IRO_UpdateFlagsOnInts();
+ }
+
+ IRO_DumpAfterPhase("IRO_ExpressionPropagation", 0);
+
+ if (copts.deadstore || copts.propagation)
+ IRO_UseDef(copts.deadstore, copts.propagation);
+ IRO_DumpAfterPhase("after IRO_UseDef", 0);
+
+ IRO_UpdateVars();
+ IRO_ConstantFolding();
+ IRO_DumpAfterPhase("IRO_ConstantFolding", 0);
+
+ IRO_EvaluateConditionals();
+ IRO_RemoveUnreachable();
+ IRO_SimplifyConditionals();
+
+ if (pass == 1 && copts.optimizationlevel > 2) {
+ IRO_RenumberInts();
+ IRO_DumpAfterPhase("Before IRO_FindEmptyLoops", 0);
+ IRO_FindEmptyLoops();
+ IRO_DumpAfterPhase("After IRO_FindEmptyLoops", 0);
+ IRO_RenumberInts();
+ }
+
+ if (copts.unrolling && !copts.optimizesize && pass == 0) {
+ IRO_DumpAfterPhase("Before IRO_LoopUnroller", 0);
+ IRO_LoopUnroller();
+ IRO_DumpAfterPhase("After IRO_LoopUnroller", 0);
+ IRO_RenumberInts();
+ }
+
+ VectorPhaseCalledFromUnroll = 0;
+
+ if (pass == 0 && (copts.loopinvariants || copts.strengthreduction)) {
+ IRO_DumpAfterPhase("Before IRO_FindLoops", 0);
+ IRO_FindLoops();
+ LoopOptimizerRun = 1;
+ IRO_SetLoopDepth();
+ }
+ IRO_DumpAfterPhase("After IRO_FindLoops", 0);
+
+ if (copts.propagation) {
+ IRO_CopyAndConstantPropagation();
+ IRO_ConstantFolding();
+ IRO_EvaluateConditionals();
+ }
+
+ IRO_DumpAfterPhase("Second pass:IRO_CopyAndConstantPropagation, IRO_ConstantFolding, IRO_EvaluateConditionals", 0);
+
+ if (copts.commonsubs)
+ IRO_FindExpressions(NULL, 0);
+
+ if (copts.commonsubs) {
+ IRO_ComputeAvail();
+ IRO_CommonSubs();
+ }
+ IRO_DumpAfterPhase("IRO_CommonSubs", 0);
+
+ IRO_UpdateFlagsOnInts();
+ IRO_UpdateVars();
+ IRO_DoTransformations();
+ IRO_ConstantFolding();
+
+ do {
+ IRO_UpdateFlagsOnInts();
+
+ if (copts.deadcode)
+ IRO_RemoveUnreachable();
+ IRO_DumpAfterPhase("IRO_RemoveUnreachable", 0);
+
+ changed = IRO_RemoveRedundantJumps();
+ IRO_DumpAfterPhase("IRO_RemoveRedundantJumps", 0);
+
+ changed |= IRO_RemoveLabels();
+ IRO_DumpAfterPhase("IRO_RemoveLabels", 0);
+
+ changed |= IRO_DoJumpChaining();
+ IRO_DumpAfterPhase("IRO_DoJumpChaining", 0);
+
+ if (copts.propagation) {
+ IRO_RenumberInts();
+ IRO_DumpAfterPhase("Before IRO_CopyAndConstantPropagation", 0);
+ changed |= IRO_CopyAndConstantPropagation();
+ IRO_DumpAfterPhase("After IRO_CopyAndConstantPropagation", 0);
+ IRO_ConstantFolding();
+ }
+
+ if (copts.deadstore || copts.propagation)
+ changed |= IRO_UseDef(copts.deadstore, copts.propagation);
+ IRO_DumpAfterPhase("IRO_UseDef", 0);
+
+ changed |= IRO_EvaluateConditionals();
+ IRO_DumpAfterPhase("IRO_EvaluateConditionals", 0);
+ } while (changed);
+ }
+
+ if (copts.lifetimes) {
+ IRO_UseDef(0, 0);
+ IRO_SplitLifetimes();
+ }
+
+ IRO_DoTransformations();
+ IRO_DumpAfterPhase("Before RebuildCondExpressions", 0);
+ }
+
+ IRO_RenumberInts();
+ IRO_DumpAfterPhase("before IRO_RewriteBitFieldTemps", 0);
+ IRO_RewriteBitFieldTemps();
+ IRO_DumpAfterPhase("After IRO_RewriteBitFieldTemps", 0);
+
+ CountUsage();
+
+ if (!DisableDueToAsm) {
+ IRO_RegenerateExpressions();
+ IRO_DumpAfterPhase("IRO_RegenerateExpressions", 0);
+ }
+
+ IRO_DumpAfterPhase("After IRO_Optimizer", 0);
+
+ statements = IRO_Delinearize(IRO_FirstNode, NULL);
+
+ IRO_ZapVarPtrs();
+ freeoheap();
+ return statements;
+}
+
+void IRO_Setup(void) {
+ static Boolean ENodeArraysHaveBeenInitialized;
+
+ if (!stIsSetup) {
+ IRO_Log = 0;
+ IRO_SetupDump();
+ if (!ENodeArraysHaveBeenInitialized) {
+ IRO_InitializeNodeNamesArray();
+ IRO_InitializeIsAssociativeENodeTypeArray();
+ IRO_InitializeIsSubableOpArray();
+ IRO_InitializeAssignmentOpArray();
+ IRO_InitializeComplementaryOpArray();
+ IRO_InitializeComplementaryOpLogicalArray();
+ IRO_InitializeNonAssignmentOpArray();
+ IRO_InitializeAssignmentFoldingFunctionArray();
+ IRO_InitializeIRO_IsModifyOpArray();
+ IRO_InitializeIRO_IsAssignOpArray();
+ ENodeArraysHaveBeenInitialized = 1;
+ }
+ stIsSetup = 1;
+ }
+}
+
+void IRO_Cleanup(void) {
+ if (stIsSetup) {
+ IRO_CleanupDump();
+ stIsSetup = 0;
+ }
+}
+
+void CodeGen_UpdateOptimizerOptions(void) {
+ Boolean flag;
+
+ flag = copts.optimizationlevel >= 1;
+ copts.deadcode = flag;
+
+ flag = copts.optimizationlevel >= 2;
+ copts.propagation = flag;
+ copts.commonsubs = flag;
+
+ flag = copts.optimizationlevel >= 3;
+ copts.vectorizeloops = flag;
+ copts.unrolling = flag;
+ copts.deadstore = flag;
+ copts.lifetimes = flag;
+ copts.strengthreduction = flag;
+ copts.loopinvariants = flag;
+
+ flag = copts.optimizationlevel >= 4;
+ copts.multiplepasses = flag;
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.h b/compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.h
new file mode 100644
index 0000000..287e279
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IrOptimizer.h
@@ -0,0 +1,30 @@
+#ifndef COMPILER_IROPTIMIZER_H
+#define COMPILER_IROPTIMIZER_H
+
+#include "compiler/common.h"
+
+typedef struct IROAddrRecord IROAddrRecord;
+typedef struct IROAssign IROAssign;
+typedef struct IRODef IRODef;
+typedef struct IROElmList IROElmList;
+typedef struct IROExpr IROExpr;
+typedef struct IROLinear IROLinear;
+typedef struct IROList IROList;
+typedef struct IROListNode IROListNode;
+typedef struct IROLoop IROLoop;
+typedef struct IRONode IRONode;
+typedef struct IROUse IROUse;
+
+extern Boolean DoScalarize;
+extern Boolean DoLinearize;
+extern Boolean EarlyReturn;
+extern Boolean IRO_CPFirstTime;
+extern Boolean VectorPhaseCalledFromUnroll;
+extern Boolean IRO_Log;
+
+extern Statement *IRO_Optimizer(Object *func, Statement *statements);
+extern void IRO_Setup(void);
+extern void IRO_Cleanup(void);
+extern void CodeGen_UpdateOptimizerOptions(void);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroBitVect.c b/compiler_and_linker/FrontEnd/Optimizer/IroBitVect.c
new file mode 100644
index 0000000..873b1ca
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroBitVect.c
@@ -0,0 +1,112 @@
+#include "BitVector.h"
+#include "compiler/CompilerTools.h"
+
+void Bv_AllocVector(BitVector **bv, UInt32 size) {
+ UInt32 long_size = (size / 32) + 1;
+ *bv = oalloc(sizeof(BitVector) + sizeof(UInt32) * long_size);
+ (*bv)->size = long_size;
+ Bv_Clear(*bv);
+}
+
+void Bv_AllocVectorLocal(BitVector **bv, UInt32 size) {
+ UInt32 long_size = (size / 32) + 1;
+ *bv = lalloc(sizeof(BitVector) + sizeof(UInt32) * long_size);
+ (*bv)->size = long_size;
+ Bv_Clear(*bv);
+}
+
+void Bv_ClearBit(UInt32 bit, BitVector *bv) {
+ if ((bit / 32) < bv->size)
+ bv->data[bit / 32] &= ~(1 << (bit & 31));
+ else
+ CError_FATAL(73);
+}
+
+void Bv_And(const BitVector *a, BitVector *b) {
+ UInt32 i;
+ for (i = 0; i < b->size; i++)
+ b->data[i] &= a->data[i];
+}
+
+void Bv_Or(const BitVector *a, BitVector *b) {
+ UInt32 i, len;
+
+ len = a->size;
+ if (b->size < len)
+ len = b->size;
+
+ for (i = 0; i < len; i++) {
+ b->data[i] |= a->data[i];
+ }
+}
+
+Boolean Bv_BitsInCommon(const BitVector *a, const BitVector *b) {
+ UInt32 len;
+ UInt32 i;
+
+ len = a->size;
+ if (b->size < len)
+ len = b->size;
+
+ for (i = 0; i < len; i++) {
+ if (a->data[i] & b->data[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+Boolean Bv_Compare(const BitVector *a, const BitVector *b) {
+ UInt32 i;
+ for (i = 0; i < a->size; i++) {
+ if (a->data[i] != b->data[i])
+ return 0;
+ }
+
+ return 1;
+}
+
+void Bv_Minus(const BitVector *a, BitVector *b) {
+ UInt32 i;
+ for (i = 0; i < b->size; i++)
+ b->data[i] &= ~a->data[i];
+}
+
+void Bv_Copy(const BitVector *src, BitVector *dst) {
+ memcpy(dst->data, src->data, sizeof(UInt32) * dst->size);
+}
+
+void Bv_Clear(BitVector *bv) {
+ memset(bv->data, 0, sizeof(UInt32) * bv->size);
+}
+
+void Bv_Set(BitVector *bv) {
+ memset(bv->data, 0xFF, sizeof(UInt32) * bv->size);
+}
+
+Boolean Bv_IsSubset(const BitVector *a, const BitVector *b) {
+ UInt32 i;
+
+ for (i = 0; i < a->size; i++) {
+ if (b->size < i) {
+ if (a->data[i])
+ return 0;
+ } else {
+ if (a->data[i] & ~(b->data[i]))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+Boolean Bv_IsEmpty(const BitVector *bv) {
+ UInt32 i;
+
+ for (i = 0; i < bv->size; i++) {
+ if (bv->data[i])
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroCSE.c b/compiler_and_linker/FrontEnd/Optimizer/IroCSE.c
new file mode 100644
index 0000000..7bc4866
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroCSE.c
@@ -0,0 +1,1038 @@
+#include "IroCSE.h"
+#include "IroDump.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroMalloc.h"
+#include "IroPointerAnalysis.h"
+#include "IroSubable.h"
+#include "IROUseDef.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CInt64.h"
+#include "compiler/CParser.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/objects.h"
+
+BitVector *IRO_Depends;
+Boolean IRO_NotSubable;
+Boolean IRO_IsVolatile;
+Boolean IRO_CouldError;
+IROExpr *IRO_FirstExpr;
+IROExpr *IRO_LastExpr;
+SInt32 IRO_NumExprs;
+static Boolean HasVectorOperand;
+
+// forward decls
+static void IRO_DependsOnForDataFlow(IROLinear *linear, Boolean flag);
+
+static void GetDependsOfIndirect(IROLinear *nd) {
+ IROListNode *resultList;
+ IROListNode *next;
+ IROListNode *list;
+ IROListNode *scan;
+ IROLinear *scannd;
+ Object *obj;
+ VarRecord *var;
+ int index;
+ Boolean result;
+ Boolean foundObjRef;
+
+ result = 0;
+
+ if (nd && copts.opt_pointer_analysis && nd->pointsToFunction && FunctionName) {
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, nd, &resultList);
+ if ((list = resultList)) {
+ for (scan = list; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ result = 1;
+ break;
+ }
+
+ foundObjRef = 0;
+ for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ foundObjRef = 1;
+ break;
+ }
+ }
+
+ if (!foundObjRef) {
+ result = 1;
+ break;
+ }
+ }
+
+ if (!result) {
+ while (list) {
+ for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ obj = scannd->u.node->data.objref;
+ CError_ASSERT(119, obj != NULL);
+ var = IRO_FindVar(obj, 1, 1);
+ CError_ASSERT(121, var != NULL);
+ index = var->index;
+ CError_ASSERT(123, index != 0);
+
+ if (is_volatile_object(obj)) {
+ IRO_IsVolatile = 1;
+ IRO_NotSubable = 1;
+ }
+ Bv_SetBit(index, IRO_Depends);
+ }
+ }
+ list = list->nextList;
+ }
+ }
+
+ while (resultList) {
+ next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ result = 1;
+ }
+ } else {
+ result = 1;
+ }
+
+ if (result) {
+ nd = nd->u.monadic;
+ if (nd->type == IROLinearOp1Arg && nd->nodetype == EBITFIELD)
+ nd = nd->u.monadic;
+
+ if (nd->type == IROLinearOp2Arg && nd->nodetype == EADD) {
+ IRO_BaseTerms = 0;
+ IRO_VarTerms = 0;
+ IRO_DecomposeAddressExpression_Cheap(nd);
+ if (IRO_BaseTerms != 1) {
+ IRO_CouldError = 1;
+ Bv_SetBit(0, IRO_Depends);
+ Bv_Or(IRO_FuncKills, IRO_Depends);
+ }
+ if (IRO_VarTerms)
+ IRO_CouldError = 1;
+ } else {
+ IRO_CouldError = 1;
+ Bv_SetBit(0, IRO_Depends);
+ Bv_Or(IRO_FuncKills, IRO_Depends);
+ }
+ }
+}
+
+static void GetDependsOfFunctionCallForDataFlow(IROLinear *nd) {
+ IROLinear *innernd;
+ IROListNode *resultList;
+ IROListNode *next;
+ IROListNode *list;
+ IROListNode *scan;
+ IROLinear *scannd;
+ Object *obj;
+ VarRecord *var;
+ int index;
+ Boolean result;
+ Boolean foundObjRef;
+ ObjectList *olist;
+ ObjectList *depsList;
+
+ result = 0;
+ innernd = nd->u.funccall.linear8;
+
+ if (innernd && copts.opt_pointer_analysis && innernd->pointsToFunction && FunctionName) {
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, innernd, &resultList);
+ if ((list = resultList)) {
+ for (scan = list; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ result = 1;
+ break;
+ }
+
+ foundObjRef = 0;
+ for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ foundObjRef = 1;
+ obj = scannd->u.node->data.objref;
+ CError_ASSERT(234, obj != NULL);
+
+ depsList = NULL;
+ PointerAnalysis_GetFunctionDependencies(obj, nd, &depsList);
+
+ for (olist = depsList; olist; olist = olist->next) {
+ if (!olist->object) {
+ result = 1;
+ break;
+ }
+ }
+
+ while (depsList) {
+ olist = depsList->next;
+ IRO_free(depsList);
+ depsList = olist;
+ }
+
+ if (result)
+ break;
+ }
+ }
+
+ if (!foundObjRef)
+ result = 1;
+ if (result)
+ break;
+ }
+
+ if (!result) {
+ for (list = resultList; list; list = list->nextList) {
+ for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ obj = scannd->u.node->data.objref;
+
+ depsList = NULL;
+ PointerAnalysis_GetFunctionDependencies(obj, nd, &depsList);
+
+ for (olist = depsList; olist; olist = olist->next) {
+ var = IRO_FindVar(olist->object, 1, 1);
+ CError_ASSERT(285, var != NULL);
+ index = var->index;
+ CError_ASSERT(287, index != 0);
+
+ if (is_volatile_object(olist->object)) {
+ IRO_IsVolatile = 1;
+ IRO_NotSubable = 1;
+ }
+ Bv_SetBit(index, IRO_Depends);
+ }
+
+ while (depsList) {
+ olist = depsList->next;
+ IRO_free(depsList);
+ depsList = olist;
+ }
+ }
+ }
+ }
+ }
+
+ while (resultList) {
+ next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ result = 1;
+ }
+ } else {
+ result = 1;
+ }
+
+ if (result) {
+ IRO_DependsOnForDataFlow(nd->u.funccall.linear8, 0);
+ Bv_Or(IRO_FuncKills, IRO_Depends);
+
+ for (index = nd->u.funccall.argCount - 1; index >= 0; index--)
+ IRO_DependsOnForDataFlow(nd->u.funccall.args[index], 0);
+ }
+}
+
+static void IRO_DependsOn(IROLinear *linear, Boolean flag) {
+ VarRecord *var;
+ IROLinear *inner;
+
+ if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) {
+ IRO_IsVolatile = 1;
+ IRO_NotSubable = 1;
+ }
+
+ if (!IRO_NotSubable) {
+ switch (linear->type) {
+ case IROLinearOperand:
+ if (flag && linear->u.node->type == EOBJREF) {
+ if ((var = IRO_FindVar(linear->u.node->data.objref, 0, 1))) {
+ if (is_volatile_object(var->object)) {
+ IRO_IsVolatile = 1;
+ IRO_NotSubable = 1;
+ }
+ Bv_SetBit(var->index, IRO_Depends);
+ } else {
+ IRO_NotSubable = 1;
+ }
+ }
+ break;
+ case IROLinearOp1Arg:
+ if (IRO_IsAssignOp[linear->nodetype]) {
+ IRO_NotSubable = 1;
+ } else {
+ inner = linear->u.monadic;
+ if (linear->nodetype == EINDIRECT) {
+ if (inner->type == IROLinearOp1Arg && inner->nodetype == EBITFIELD)
+ inner = inner->u.monadic;
+ if (inner->type != IROLinearOperand || inner->u.node->type != EOBJREF)
+ GetDependsOfIndirect(linear);
+ }
+
+ IRO_DependsOn(inner, linear->nodetype == EINDIRECT);
+ }
+ break;
+ case IROLinearOp2Arg:
+ if (IRO_IsAssignOp[linear->nodetype]) {
+ IRO_NotSubable = 1;
+ } else {
+ if (linear->nodetype == EDIV || linear->nodetype == EMODULO) {
+ if (IRO_IsIntConstant(linear->u.diadic.right)) {
+ if (CInt64_Equal(linear->u.diadic.right->u.node->data.intval, cint64_zero))
+ IRO_CouldError = 1;
+ } else {
+ IRO_CouldError = 1;
+ }
+ }
+
+ IRO_DependsOn(linear->u.diadic.left, flag);
+ IRO_DependsOn(linear->u.diadic.right, flag);
+ }
+ break;
+ case IROLinearOp3Arg:
+ if (IRO_IsAssignOp[linear->nodetype]) {
+ IRO_NotSubable = 1;
+ } else {
+ IRO_DependsOn(linear->u.args3.a, flag);
+ IRO_DependsOn(linear->u.args3.b, flag);
+ IRO_DependsOn(linear->u.args3.c, flag);
+ }
+ break;
+ case IROLinearFunccall:
+ IRO_NotSubable = 1;
+ break;
+ default:
+ CError_FATAL(479);
+ }
+ }
+}
+
+static void IRO_DependsOnForDataFlow(IROLinear *linear, Boolean flag) {
+ VarRecord *var;
+ IROLinear *inner;
+
+ if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) {
+ IRO_IsVolatile = 1;
+ IRO_NotSubable = 1;
+ }
+
+ switch (linear->type) {
+ case IROLinearOperand:
+ if (flag && linear->u.node->type == EOBJREF) {
+ if ((var = IRO_FindVar(linear->u.node->data.objref, 0, 1))) {
+ if (is_volatile_object(var->object)) {
+ IRO_IsVolatile = 1;
+ IRO_NotSubable = 1;
+ }
+ Bv_SetBit(var->index, IRO_Depends);
+ } else {
+ IRO_NotSubable = 1;
+ }
+ }
+ break;
+ case IROLinearOp1Arg:
+ if (IRO_IsAssignOp[linear->nodetype])
+ IRO_NotSubable = 1;
+
+ inner = linear->u.monadic;
+ if (linear->nodetype == EINDIRECT) {
+ if (inner->type == IROLinearOp1Arg && inner->nodetype == EBITFIELD)
+ inner = inner->u.monadic;
+ if (inner->type != IROLinearOperand || inner->u.node->type != EOBJREF)
+ GetDependsOfIndirect(linear);
+ }
+
+ IRO_DependsOnForDataFlow(inner, linear->nodetype == EINDIRECT);
+ break;
+ case IROLinearOp2Arg:
+ if (IRO_IsAssignOp[linear->nodetype])
+ IRO_NotSubable = 1;
+
+ if (linear->nodetype == EDIV || linear->nodetype == EMODULO) {
+ if (IRO_IsIntConstant(linear->u.diadic.right)) {
+ if (CInt64_Equal(linear->u.diadic.right->u.node->data.intval, cint64_zero))
+ IRO_CouldError = 1;
+ } else {
+ IRO_CouldError = 1;
+ }
+ }
+
+ IRO_DependsOnForDataFlow(linear->u.diadic.left, flag);
+ IRO_DependsOnForDataFlow(linear->u.diadic.right, flag);
+ break;
+ case IROLinearOp3Arg:
+ if (IRO_IsAssignOp[linear->nodetype])
+ IRO_NotSubable = 1;
+
+ IRO_DependsOnForDataFlow(linear->u.args3.a, flag);
+ IRO_DependsOnForDataFlow(linear->u.args3.b, flag);
+ IRO_DependsOnForDataFlow(linear->u.args3.c, flag);
+ break;
+ case IROLinearFunccall:
+ IRO_NotSubable = 1;
+ GetDependsOfFunctionCallForDataFlow(linear);
+ break;
+ default:
+ CError_FATAL(650);
+ }
+}
+
+void IRO_FindDepends_NoAlloc(IROLinear *linear) {
+ Bv_Clear(IRO_Depends);
+ IRO_CouldError = 0;
+ IRO_NotSubable = 0;
+ IRO_IsVolatile = 0;
+ IRO_DependsOnForDataFlow(linear, 0);
+}
+
+void IRO_FindDepends(IROLinear *linear) {
+ Bv_AllocVector(&IRO_Depends, IRO_NumVars + 1);
+ IRO_CouldError = 0;
+ IRO_NotSubable = 0;
+ IRO_DependsOn(linear, 0);
+}
+
+static void VecAct(IROLinear *linear, Boolean isFirst) {
+ if (!isFirst && (linear->flags & IROLF_VecOpBase))
+ HasVectorOperand = 1;
+}
+
+static Boolean IRO_DoesNotHaveVectorOperand(IROLinear *linear) {
+ HasVectorOperand = 0;
+ IRO_WalkTree(linear, VecAct);
+ return HasVectorOperand == 0;
+}
+
+static void IRO_AddExpression(IROLinear *linear, IRONode *node, Boolean flag) {
+ IROExpr *expr;
+
+ if ((linear->flags & IROLF_Reffed) && IRO_IsSubableExpression(linear) && IRO_DoesNotHaveVectorOperand(linear)) {
+ expr = oalloc(sizeof(IROExpr));
+ expr->x0 = 0;
+ expr->index = ++IRO_NumExprs;
+ expr->linear = linear;
+ expr->x8 = NULL;
+ expr->node = node;
+ IRO_FindDepends(linear);
+ expr->depends = IRO_Depends;
+ expr->notSubable = IRO_NotSubable;
+ expr->couldError = IRO_CouldError;
+ expr->next = NULL;
+ expr->x14 = NULL;
+ if (IRO_FirstExpr)
+ IRO_LastExpr->next = expr;
+ else
+ IRO_FirstExpr = expr;
+ IRO_LastExpr = expr;
+ linear->expr = expr;
+ }
+}
+
+void IRO_FindExpressions(BitVector *bv, Boolean flag) {
+ IROLinear *nd;
+ IRONode *fnode;
+
+ IRO_FirstExpr = IRO_LastExpr = NULL;
+ IRO_NumExprs = 0;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ if (!bv || Bv_IsBitSet(fnode->index, bv)) {
+ for (nd = fnode->first; nd; nd = nd->next) {
+ nd->expr = NULL;
+ IRO_AddExpression(nd, fnode, flag);
+ if (nd == fnode->last)
+ break;
+ }
+ } else {
+ for (nd = fnode->first; nd; nd = nd->next) {
+ nd->expr = NULL;
+ if (nd == fnode->last)
+ break;
+ }
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+void IRO_RemoveExpr(IROExpr *expr) {
+ IROExpr *prev;
+ IROExpr *scan;
+
+ scan = IRO_FirstExpr;
+ prev = NULL;
+ while (scan != expr) {
+ prev = scan;
+ scan = scan->next;
+ CError_ASSERT(809, scan);
+ }
+
+ expr->linear->expr = NULL;
+ if (prev)
+ prev->next = expr->next;
+ else
+ IRO_FirstExpr = expr->next;
+}
+
+static void GetExprKillsByIndirectAssignment(IROLinear *linear) {
+ IROLinear *inner;
+ IROListNode *resultList;
+ IROListNode *next;
+ IROListNode *list;
+ IROListNode *scan;
+ IROLinear *scannd;
+ Object *obj;
+ VarRecord *var;
+ int index;
+ Boolean result;
+ Boolean foundObjRef;
+ IROExpr *expr;
+
+ result = 0;
+ if (linear->type == IROLinearOp2Arg)
+ linear = linear->u.diadic.left;
+ else
+ linear = linear->u.monadic;
+
+ if (
+ linear &&
+ linear->type == IROLinearOp1Arg &&
+ linear->nodetype == EINDIRECT &&
+ (inner = linear->u.monadic) &&
+ copts.opt_pointer_analysis &&
+ inner->pointsToFunction &&
+ FunctionName
+ ) {
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, inner, &resultList);
+ if ((list = resultList)) {
+ for (scan = list; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ result = 1;
+ break;
+ }
+
+ foundObjRef = 0;
+ for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ foundObjRef = 1;
+ break;
+ }
+ }
+
+ if (!foundObjRef) {
+ result = 1;
+ break;
+ }
+ }
+
+ if (!result) {
+ while (list) {
+ for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ obj = scannd->u.node->data.objref;
+ CError_ASSERT(893, obj != NULL);
+ var = IRO_FindVar(obj, 1, 1);
+ CError_ASSERT(895, var != NULL);
+ index = var->index;
+
+ for (expr = IRO_FirstExpr; expr; expr = expr->next) {
+ if (Bv_IsBitSet(index, expr->depends))
+ Bv_SetBit(expr->index, IRO_ExprKills);
+ }
+ }
+ }
+ list = list->nextList;
+ }
+ }
+
+ while (resultList) {
+ next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ result = 1;
+ }
+ } else {
+ result = 1;
+ }
+
+ if (result) {
+ for (expr = IRO_FirstExpr; expr; expr = expr->next) {
+ if (Bv_BitsInCommon(expr->depends, IRO_FuncKills))
+ Bv_SetBit(expr->index, IRO_ExprKills);
+ }
+ }
+}
+
+static void GetExprKillsByFunctionCall(IROLinear *funccall) {
+ IROLinear *innernd;
+ IROListNode *resultList;
+ IROListNode *next;
+ IROListNode *list;
+ IROListNode *scan;
+ IROLinear *scannd;
+ Object *obj;
+ VarRecord *var;
+ int index;
+ Boolean result;
+ Boolean foundObjRef;
+ ObjectList *olist;
+ ObjectList *depsList;
+ IROExpr *expr;
+
+ result = 0;
+ innernd = funccall->u.funccall.linear8;
+
+ if (innernd && copts.opt_pointer_analysis && innernd->pointsToFunction && FunctionName) {
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, innernd, &resultList);
+ if ((list = resultList)) {
+ for (scan = list; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ result = 1;
+ break;
+ }
+
+ foundObjRef = 0;
+ for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ foundObjRef = 1;
+ obj = scannd->u.node->data.objref;
+ CError_ASSERT(991, obj != NULL);
+
+ depsList = NULL;
+ PointerAnalysis_GetFunctionKills(obj, funccall, &depsList);
+
+ for (olist = depsList; olist; olist = olist->next) {
+ if (!olist->object) {
+ result = 1;
+ break;
+ }
+ }
+
+ while (depsList) {
+ olist = depsList->next;
+ IRO_free(depsList);
+ depsList = olist;
+ }
+
+ if (result)
+ break;
+ }
+ }
+
+ if (!foundObjRef)
+ result = 1;
+ if (result)
+ break;
+ }
+
+ if (!result) {
+ for (list = resultList; list; list = list->nextList) {
+ for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ obj = scannd->u.node->data.objref;
+
+ depsList = NULL;
+ PointerAnalysis_GetFunctionKills(obj, funccall, &depsList);
+
+ for (olist = depsList; olist; olist = olist->next) {
+ var = IRO_FindVar(olist->object, 1, 1);
+ CError_ASSERT(1042, var != NULL);
+ index = var->index;
+ CError_ASSERT(1044, index != 0);
+
+ for (expr = IRO_FirstExpr; expr; expr = expr->next) {
+ if (Bv_IsBitSet(index, expr->depends))
+ Bv_SetBit(expr->index, IRO_ExprKills);
+ }
+ }
+
+ while (depsList) {
+ olist = depsList->next;
+ IRO_free(depsList);
+ depsList = olist;
+ }
+ }
+ }
+ }
+ }
+
+ while (resultList) {
+ next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ result = 1;
+ }
+ } else {
+ result = 1;
+ }
+
+ if (result) {
+ for (expr = IRO_FirstExpr; expr; expr = expr->next) {
+ if (Bv_BitsInCommon(expr->depends, IRO_FuncKills))
+ Bv_SetBit(expr->index, IRO_ExprKills);
+ }
+ }
+}
+
+static void IRO_GetExprKills(IROLinear *linear) {
+ Bv_Clear(IRO_ExprKills);
+ switch (linear->type) {
+ case IROLinearOp1Arg:
+ case IROLinearOp2Arg:
+ if (IRO_IsAssignOp[linear->nodetype]) {
+ VarRecord *var;
+ int index;
+
+ var = IRO_FindAssigned(linear);
+ index = 0;
+ if (var)
+ index = var->index;
+ if (!index) {
+ GetExprKillsByIndirectAssignment(linear);
+ } else {
+ IROExpr *expr;
+ for (expr = IRO_FirstExpr; expr; expr = expr->next) {
+ if (Bv_IsBitSet(index, expr->depends))
+ Bv_SetBit(expr->index, IRO_ExprKills);
+ }
+ }
+ }
+ break;
+ case IROLinearAsm: {
+ IROExpr *expr;
+ IRO_GetKills(linear);
+ for (expr = IRO_FirstExpr; expr; expr = expr->next) {
+ if (Bv_BitsInCommon(expr->depends, IRO_VarKills))
+ Bv_SetBit(expr->index, IRO_ExprKills);
+ }
+ break;
+ }
+ case IROLinearFunccall:
+ GetExprKillsByFunctionCall(linear);
+ break;
+ }
+}
+
+void IRO_ComputeAvail(void) {
+ IRONode *node;
+ IROLinear *linear;
+ SInt32 counter;
+ BitVector *bv;
+ Boolean flag;
+
+ counter = 0;
+ node = IRO_FirstNode;
+ Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
+ Bv_AllocVector(&IRO_ExprKills, IRO_NumExprs + 1);
+
+ while (node) {
+ Bv_AllocVector(&node->x16, IRO_NumExprs);
+ if (node->numpred)
+ Bv_Set(node->x16);
+ Bv_AllocVector(&node->x22, IRO_NumExprs);
+ Bv_AllocVector(&node->x1E, IRO_NumExprs);
+ Bv_AllocVector(&node->x1A, IRO_NumExprs);
+
+ for (linear = node->first; linear; linear = linear->next) {
+ if (linear->expr)
+ Bv_SetBit(linear->expr->index, node->x1E);
+ IRO_GetExprKills(linear);
+ Bv_Or(IRO_ExprKills, node->x22);
+ Bv_Minus(IRO_ExprKills, node->x1E);
+ if (linear == node->last)
+ break;
+
+ if (counter > 250) {
+ IRO_CheckForUserBreak();
+ counter = 0;
+ } else {
+ counter++;
+ }
+ }
+
+ Bv_Copy(node->x16, node->x1A);
+ Bv_Minus(node->x22, node->x1A);
+ Bv_Or(node->x1E, node->x1A);
+ node = node->nextnode;
+ }
+
+ IRO_CheckForUserBreak();
+
+ Bv_AllocVector(&bv, IRO_NumExprs);
+ do {
+ flag = 0;
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (!node->numpred) {
+ Bv_Clear(bv);
+ } else {
+ UInt16 i;
+ Bv_Set(bv);
+ for (i = 0; i < node->numpred; i++)
+ Bv_And(IRO_NodeTable[node->pred[i]]->x1A, bv);
+ }
+
+ if (!Bv_Compare(bv, node->x16)) {
+ flag = 1;
+ Bv_Copy(bv, node->x16);
+ }
+
+ Bv_Copy(node->x16, node->x1A);
+ Bv_Minus(node->x22, node->x1A);
+ Bv_Or(node->x1E, node->x1A);
+ }
+ IRO_CheckForUserBreak();
+ } while (flag);
+}
+
+static void IRO_MakeReplacementEmbedded(IROExpr *expr) {
+ IROLinear *opnd;
+ IROLinear *ind;
+ IROLinear *ass;
+
+ IRO_GetTemp(expr);
+
+ opnd = IRO_NewLinear(IROLinearOperand);
+ opnd->u.node = create_objectrefnode(expr->x8);
+ opnd->rtype = opnd->u.node->data.objref->type;
+ opnd->index = ++IRO_NumLinear;
+ opnd->flags |= IROLF_Reffed | IROLF_Assigned | IROLF_Ind;
+
+ ind = IRO_NewLinear(IROLinearOp1Arg);
+ ind->nodetype = EINDIRECT;
+ ind->rtype = expr->linear->rtype;
+ ind->u.monadic = opnd;
+ ind->index = ++IRO_NumLinear;
+ ind->flags |= IROLF_Reffed | IROLF_Assigned;
+
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->nodetype = EASS;
+ ass->u.diadic.left = ind;
+ ass->u.diadic.right = expr->linear;
+ ass->rtype = expr->linear->rtype;
+ ass->index = ++IRO_NumLinear;
+
+ opnd->next = ind;
+ ind->next = ass;
+ IRO_ReplaceReferenceWithNode(expr->linear, ass);
+ IRO_PasteAfter(opnd, ass, expr->linear);
+}
+
+static void IRO_ActUnmarkSubExpressions(IROLinear *linear, Boolean isFirst) {
+ if (isFirst)
+ linear->flags &= ~IROLF_8;
+}
+
+static void CheckCommonSub(IROLinear *linear) {
+ IROExpr *expr;
+
+ for (expr = IRO_FirstExpr; expr; expr = expr->next) {
+ if (expr->linear != linear && !expr->x14) {
+ if (Bv_IsBitSet(expr->index, IRO_Avail) && !expr->notSubable && IRO_ExprsSame(linear, expr->linear)) {
+ IRO_WalkTree(linear, IRO_ActUnmarkSubExpressions);
+ linear->flags |= IROLF_8;
+ linear->expr->x14 = expr;
+ break;
+ }
+ }
+ }
+}
+
+static void MoveCommonSub(IROExpr *expr) {
+ SInt32 best;
+ SInt32 sz1;
+ SInt32 sz2;
+ SInt32 i1;
+ SInt32 i2;
+ IROLinear *scan;
+ IROLinear *array1[64];
+ IROLinear *array2[64];
+ IROExpr *scanexpr;
+
+ sz1 = 0;
+ scan = expr->linear;
+ do {
+ scan = IRO_LocateFather(scan);
+ if (scan) {
+ if (sz1 == 64)
+ return;
+ array1[sz1++] = scan;
+ }
+ } while (scan);
+
+ best = -1;
+ for (scanexpr = IRO_FirstExpr; scanexpr; scanexpr = scanexpr->next) {
+ if (scanexpr->x14 == expr) {
+ sz2 = 0;
+ scan = scanexpr->linear;
+ do {
+ scan = IRO_LocateFather(scan);
+ if (scan) {
+ if (sz2 == 64)
+ return;
+ array2[sz2++] = scan;
+ }
+ } while (scan);
+
+ i1 = sz1;
+ i2 = sz2;
+ while (i1 && i2 && array1[i1 - 1] == array2[i2 - 1]) {
+ i1--;
+ i2--;
+ }
+
+ if (i1 != sz1 && i1 > best)
+ best = i1;
+ }
+ }
+
+ if (best < 0) {
+ IRO_MakeReplacementEmbedded(expr);
+ } else {
+ IROLinear *start;
+ IROLinear *comma;
+ IRO_Dump("Moving common sub from node %d to %d\n", expr->linear->index, array1[best]->index);
+ start = IRO_FindStart(array1[best]);
+ IRO_GetTemp(expr);
+ IRO_ReplaceReference(expr->linear, expr->x8, expr->linear);
+ IRO_MoveExpression(expr, start);
+
+ comma = IRO_NewLinear(IROLinearOp2Arg);
+ comma->nodetype = ECOMMA;
+ comma->rtype = array1[best]->rtype;
+ comma->u.diadic.left = IRO_AssignToTemp(expr);
+ comma->u.diadic.right = array1[best];
+ comma->stmt = array1[best]->stmt;
+ IRO_ReplaceReferenceWithNode(array1[best], comma);
+ IRO_PasteAfter(comma, comma, array1[best]);
+ }
+}
+
+static void ReplaceCommonSub(IROLinear *linear) {
+ IROExpr *expr = linear->expr->x14;
+ if (!expr->x8) {
+ MoveCommonSub(expr);
+ if (!expr->x8)
+ return;
+ }
+
+ IRO_Dump("Replacing common sub at %d with %d\n", linear->index, expr->linear->index);
+ IRO_ReplaceReference(linear, expr->x8, linear);
+ IRO_RemoveExpr(linear->expr);
+ IRO_NopOut(linear);
+}
+
+void IRO_CommonSubs(void) {
+ IRONode *node;
+ IROLinear *linear;
+ SInt32 counter;
+
+ counter = 0;
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ IRO_Avail = node->x16;
+ linear = node->first;
+ while (1) {
+ if (!linear)
+ break;
+ if (linear->expr && !linear->expr->notSubable)
+ CheckCommonSub(linear);
+ if (linear->expr)
+ Bv_SetBit(linear->expr->index, IRO_Avail);
+ IRO_GetExprKills(linear);
+ Bv_Minus(IRO_ExprKills, IRO_Avail);
+ if (linear == node->last)
+ break;
+ if (counter > 250) {
+ IRO_CheckForUserBreak();
+ counter = 0;
+ } else {
+ counter++;
+ }
+ linear = linear->next;
+ }
+ }
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ for (linear = node->first; linear; linear = linear->next) {
+ if (linear->expr && (linear->flags & IROLF_8) && !IRO_HasSideEffect(linear))
+ ReplaceCommonSub(linear);
+ if (linear == node->last)
+ break;
+ if (counter > 250) {
+ IRO_CheckForUserBreak();
+ counter = 0;
+ } else {
+ counter++;
+ }
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+static Boolean CountThisSubableOperandUse(IROUse *use) {
+ return use->x1C != 0;
+}
+
+static int GetSubableOperandUseCount(VarRecord *var) {
+ int count = 0;
+ IROUse *use;
+
+ if (var->uses) {
+ for (use = var->uses; use; use = use->varnext) {
+ if (CountThisSubableOperandUse(use))
+ count++;
+ }
+ }
+
+ return count;
+}
+
+static void IRO_MakeTopLevelExprForSubableOperand(IROLinear *linear) {
+ IROLinear *copy = IRO_NewLinear(IROLinearOperand);
+ memcpy(copy, linear, sizeof(IROLinear));
+ copy->index = ++IRO_NumLinear;
+
+ if (IRO_FirstLinear && IRO_FirstLinear->type == IROLinearNop)
+ IRO_PasteAfter(copy, copy, IRO_FirstLinear);
+ else
+ IRO_Paste(copy, copy, IRO_FirstLinear);
+}
+
+void IRO_GenerateTopLevelExprsForSubableOperands(void) {
+ IROLinear *nd;
+ IRONode *fnode;
+ VarRecord *var;
+ BitVector *bv;
+
+ Bv_AllocVector(&bv, IRO_NumVars + 1);
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ for (nd = fnode->first; nd; nd = nd->next) {
+ nd->expr = NULL;
+ if ((nd->flags & IROLF_Reffed) && IRO_IsSubableExpression(nd) && IRO_DoesNotHaveVectorOperand(nd)) {
+ if (nd->type == IROLinearOperand && nd->u.node && nd->u.node->type == EOBJREF) {
+ if ((var = IRO_FindVar(nd->u.node->data.objref, 0, 1))) {
+ if (!Bv_IsBitSet(var->index, bv)) {
+ IRO_MakeTopLevelExprForSubableOperand(nd);
+ Bv_SetBit(var->index, bv);
+ }
+ }
+ }
+ }
+
+ if (nd == fnode->last)
+ break;
+ }
+ }
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroCSE.h b/compiler_and_linker/FrontEnd/Optimizer/IroCSE.h
new file mode 100644
index 0000000..c1e166c
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroCSE.h
@@ -0,0 +1,45 @@
+#ifndef COMPILER_IROCSE_H
+#define COMPILER_IROCSE_H
+
+#include "IrOptimizer.h"
+#include "BitVector.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+struct IROExpr {
+ Boolean x0;
+ UInt16 index;
+ IROLinear *linear;
+ Object *x8;
+ IRONode *node;
+ BitVector *depends;
+ IROExpr *x14;
+ Boolean couldError;
+ Boolean notSubable;
+ IROLinear *x1A;
+ VarRecord *x1E;
+ IROLinear *x22;
+ IROExpr *next;
+};
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+extern BitVector *IRO_Depends;
+extern Boolean IRO_NotSubable;
+extern Boolean IRO_IsVolatile;
+extern Boolean IRO_CouldError;
+extern IROExpr *IRO_FirstExpr;
+extern IROExpr *IRO_LastExpr;
+extern SInt32 IRO_NumExprs;
+
+extern void IRO_FindDepends_NoAlloc(IROLinear *linear);
+extern void IRO_FindDepends(IROLinear *linear);
+extern void IRO_FindExpressions(BitVector *bv, Boolean flag);
+extern void IRO_RemoveExpr(IROExpr *expr);
+extern void IRO_ComputeAvail(void);
+extern void IRO_CommonSubs(void);
+extern void IRO_GenerateTopLevelExprsForSubableOperands(void);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroDump.c b/compiler_and_linker/FrontEnd/Optimizer/IroDump.c
new file mode 100644
index 0000000..d21496f
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroDump.c
@@ -0,0 +1,660 @@
+#include "IroDump.h"
+#include "IroCSE.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroPropagate.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInt64.h"
+#include "compiler/CParser.h"
+#include "compiler/objects.h"
+
+static FILE *DumpFile;
+static char *nodenames[MAXEXPR];
+
+char *IRO_NodeName(ENodeType nodetype) {
+ return nodenames[nodetype];
+}
+
+void IRO_InitializeNodeNamesArray(void) {
+ int i;
+ for (i = 0; i < MAXEXPR; i++)
+ nodenames[i] = "";
+
+ nodenames[EPOSTINC] = "EPOSTINC";
+ nodenames[EPOSTDEC] = "EPOSTDEC";
+ nodenames[EPREINC] = "EPREINC";
+ nodenames[EPREDEC] = "EPREDEC";
+ nodenames[EINDIRECT] = "EINDIRECT";
+ nodenames[EMONMIN] = "EMONMIN";
+ nodenames[EBINNOT] = "EBINNOT";
+ nodenames[ELOGNOT] = "ELOGNOT";
+ nodenames[EFORCELOAD] = "EFORCELOAD";
+ nodenames[EMUL] = "EMUL";
+ nodenames[EMULV] = "EMULV";
+ nodenames[EDIV] = "EDIV";
+ nodenames[EMODULO] = "EMODULO";
+ nodenames[EADDV] = "EADDV";
+ nodenames[ESUBV] = "ESUBV";
+ nodenames[EADD] = "EADD";
+ nodenames[ESUB] = "ESUB";
+ nodenames[ESHL] = "ESHL";
+ nodenames[ESHR] = "ESHR";
+ nodenames[ELESS] = "ELESS";
+ nodenames[EGREATER] = "EGREATER";
+ nodenames[ELESSEQU] = "ELESSEQU";
+ nodenames[EGREATEREQU] = "EGREATEREQU";
+ nodenames[EEQU] = "EEQU";
+ nodenames[ENOTEQU] = "ENOTEQU";
+ nodenames[EAND] = "EAND";
+ nodenames[EXOR] = "EXOR";
+ nodenames[EOR] = "EOR";
+ nodenames[ELAND] = "ELAND";
+ nodenames[ELOR] = "ELOR";
+ nodenames[EASS] = "EASS";
+ nodenames[EMULASS] = "EMULASS";
+ nodenames[EDIVASS] = "EDIVASS";
+ nodenames[EMODASS] = "EMODASS";
+ nodenames[EADDASS] = "EADDASS";
+ nodenames[ESUBASS] = "ESUBASS";
+ nodenames[ESHLASS] = "ESHLASS";
+ nodenames[ESHRASS] = "ESHRASS";
+ nodenames[EANDASS] = "EANDASS";
+ nodenames[EXORASS] = "EXORASS";
+ nodenames[EORASS] = "EORASS";
+ nodenames[ECOMMA] = "ECOMMA";
+ nodenames[EPMODULO] = "EPMODULO";
+ nodenames[EROTL] = "EROTL";
+ nodenames[EROTR] = "EROTR";
+ nodenames[EBCLR] = "EBCLR";
+ nodenames[EBTST] = "EBTST";
+ nodenames[EBSET] = "EBSET";
+ nodenames[ETYPCON] = "ETYPCON";
+ nodenames[EBITFIELD] = "EBITFIELD";
+ nodenames[EINTCONST] = "EINTCONST";
+ nodenames[EFLOATCONST] = "EFLOATCONST";
+ nodenames[ESTRINGCONST] = "ESTRINGCONST";
+ nodenames[ECOND] = "ECOND";
+ nodenames[EFUNCCALL] = "EFUNCCALL";
+ nodenames[EFUNCCALLP] = "EFUNCCALLP";
+ nodenames[EOBJREF] = "EOBJREF";
+ nodenames[EMFPOINTER] = "EMFPOINTER";
+ nodenames[ENULLCHECK] = "ENULLCHECK";
+ nodenames[EPRECOMP] = "EPRECOMP";
+ nodenames[ETEMP] = "ETEMP";
+ nodenames[EARGOBJ] = "EARGOBJ";
+ nodenames[ELOCOBJ] = "ELOCOBJ";
+ nodenames[ELABEL] = "ELABEL";
+ nodenames[ESETCONST] = "ESETCONST";
+ nodenames[ENEWEXCEPTION] = "ENEWEXCEPTION";
+ nodenames[ENEWEXCEPTIONARRAY] = "ENEWEXCEPTIONARRAY";
+ nodenames[EOBJLIST] = "EOBJLIST";
+ nodenames[EMEMBER] = "EMEMBER";
+ nodenames[ETEMPLDEP] = "ETEMPLDEP";
+ nodenames[EINSTRUCTION] = "EINSTRUCTION";
+ nodenames[EDEFINE] = "EDEFINE";
+ nodenames[EREUSE] = "EREUSE";
+ nodenames[EASSBLK] = "EASSBLK";
+ nodenames[EVECTOR128CONST] = "EVECTOR128CONST";
+ nodenames[ECONDASS] = "ECONDASS";
+}
+
+static void DumpENode(ENode *enode) {
+ char buf[64];
+
+ if (IRO_Log) {
+ switch (enode->type) {
+ case EOBJREF:
+ fprintf(DumpFile, "%s", enode->data.objref->name->name);
+ break;
+ case EINTCONST:
+ CInt64_PrintDec(buf, enode->data.intval);
+ fprintf(DumpFile, "%s", buf);
+ break;
+ case EFLOATCONST:
+ fprintf(DumpFile, "%g", enode->data.floatval.value);
+ break;
+ case EVECTOR128CONST:
+ fprintf(DumpFile, "%.8lX%.8lX%.8lX%.8lX",
+ enode->data.vector128val.ul[0],
+ enode->data.vector128val.ul[1],
+ enode->data.vector128val.ul[2],
+ enode->data.vector128val.ul[3]
+ );
+ break;
+ }
+ }
+}
+
+static void DumpLinearNode(IROLinear *linear) {
+ int i;
+
+ if (IRO_Log) {
+ fprintf(DumpFile, "%4d: ", linear->index);
+ switch (linear->type) {
+ case IROLinearNop:
+ fprintf(DumpFile, "Nop");
+ break;
+ case IROLinearOperand:
+ fprintf(DumpFile, "Operand ");
+ DumpENode(linear->u.node);
+ break;
+ case IROLinearOp1Arg:
+ fprintf(DumpFile, "%s %d", nodenames[linear->nodetype], linear->u.monadic->index);
+ break;
+ case IROLinearOp2Arg:
+ fprintf(DumpFile, "%s %d %d", nodenames[linear->nodetype], linear->u.diadic.left->index, linear->u.diadic.right->index);
+ break;
+ case IROLinearGoto:
+ fprintf(DumpFile, "Goto %s", linear->u.label.label->name->name);
+ break;
+ case IROLinearIf:
+ fprintf(DumpFile, "If %d %s", linear->u.label.x4->index, linear->u.label.label->name->name);
+ break;
+ case IROLinearIfNot:
+ fprintf(DumpFile, "IfNot %d %s", linear->u.label.x4->index, linear->u.label.label->name->name);
+ break;
+ case IROLinearReturn:
+ fprintf(DumpFile, "Return ");
+ if (linear->u.monadic)
+ fprintf(DumpFile, "%d", linear->u.monadic->index);
+ break;
+ case IROLinearLabel:
+ fprintf(DumpFile, "Label %s", linear->u.label.label->name->name);
+ break;
+ case IROLinearSwitch:
+ fprintf(DumpFile, "Switch %d", linear->u.swtch.x4->index);
+ break;
+ case IROLinearOp3Arg:
+ fprintf(DumpFile, "%s %d %d %d",
+ nodenames[linear->nodetype],
+ linear->u.args3.a->index,
+ linear->u.args3.b->index,
+ linear->u.args3.c->index);
+ break;
+ case IROLinearFunccall:
+ fprintf(DumpFile, "Funccall %d(", linear->u.funccall.linear8->index);
+ for (i = 0; i < linear->u.funccall.argCount; i++) {
+ fprintf(DumpFile, "%d", linear->u.funccall.args[i]->index);
+ if (i < (linear->u.funccall.argCount - 1))
+ fprintf(DumpFile, ",");
+ }
+ fprintf(DumpFile, ")");
+ break;
+ case IROLinearBeginCatch:
+ fprintf(DumpFile, "BeginCatch %d", linear->u.ctch.linear->index);
+ break;
+ case IROLinearEndCatch:
+ fprintf(DumpFile, "EndCatch %d", linear->u.monadic->index);
+ break;
+ case IROLinearEndCatchDtor:
+ fprintf(DumpFile, "EndCatchDtor %d", linear->u.monadic->index);
+ break;
+ case IROLinearEnd:
+ fprintf(DumpFile, "End");
+ break;
+ }
+
+ if (linear->flags & IROLF_Assigned) fprintf(DumpFile, " <assigned>");
+ if (linear->flags & IROLF_Used) fprintf(DumpFile, " <used>");
+ if (linear->flags & IROLF_Ind) fprintf(DumpFile, " <ind>");
+ if (linear->flags & IROLF_Subs) fprintf(DumpFile, " <subs>");
+ if (linear->flags & IROLF_LoopInvariant) fprintf(DumpFile, " <loop invariant>");
+ if (linear->flags & IROLF_BeginLoop) fprintf(DumpFile, " <begin loop>");
+ if (linear->flags & IROLF_EndLoop) fprintf(DumpFile, " <end loop>");
+ if (linear->flags & IROLF_Ris) fprintf(DumpFile, " <ris>");
+ if (linear->flags & IROLF_Immind) fprintf(DumpFile, " <immind>");
+ if (linear->flags & IROLF_Reffed) fprintf(DumpFile, " <reffed>");
+ if (linear->flags & IROLF_VecOp) fprintf(DumpFile, " <vec op>");
+ if (linear->flags & IROLF_VecOpBase) fprintf(DumpFile, " <vec op_base>");
+ if (linear->flags & IROLF_CounterLoop) fprintf(DumpFile, " <counter loop>");
+ if (linear->flags & IROLF_BitfieldIndirect) fprintf(DumpFile, " <bitfield_indirect>");
+ if (linear->flags & IROLF_CouldError) fprintf(DumpFile, " <could_error>");
+
+ if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS))
+ fprintf(DumpFile, " <volatile>");
+
+ if (IS_LINEAR_ENODE(linear, EOBJREF)) {
+ VarRecord *var = IRO_FindVar(linear->u.node->data.objref, 0, 1);
+ if (var && is_volatile_object(var->object))
+ fprintf(DumpFile, " <volatile obj>");
+ }
+
+ fprintf(DumpFile, "\n");
+ }
+}
+
+static void DumpAct(IROLinear *linear, Boolean isFirst) {
+ if (!isFirst)
+ DumpLinearNode(linear);
+}
+
+void IRO_DumpIntTree(IROLinear *linear) {
+ IRO_WalkTree(linear, DumpAct);
+}
+
+void IRO_DumpLinearList(IROLinear *linear) {
+ if (!IRO_Log)
+ return;
+
+ while (linear) {
+ DumpLinearNode(linear);
+ linear = linear->next;
+ }
+ fprintf(DumpFile, "\n");
+}
+
+static void DumpList(int num, UInt16 *list) {
+ int i;
+
+ if (IRO_Log) {
+ for (i = 0; i < num; i++)
+ fprintf(DumpFile, "%d ", list[i]);
+ fprintf(DumpFile, "\n");
+ }
+}
+
+void IRO_DumpBits(char *name, BitVector *bv) {
+ SInt32 i;
+ SInt32 rangeStart;
+ Boolean inRange = 0;
+ Boolean isFirst = 1;
+
+ if (!IRO_Log)
+ return;
+
+ fprintf(DumpFile, name);
+ if (!bv) {
+ fprintf(DumpFile, "NULL");
+ } else {
+ for (i = 0; i < (bv->size * 32); i++) {
+ if (Bv_IsBitSet(i, bv)) {
+ if (!inRange) {
+ if (!isFirst)
+ fputc(',', DumpFile);
+ isFirst = 0;
+ fprintf(DumpFile, "%d", i);
+ inRange = 1;
+ rangeStart = i;
+ }
+ } else {
+ if (inRange) {
+ inRange = 0;
+ if (i != (rangeStart + 1))
+ fprintf(DumpFile, "-%d", i - 1);
+ }
+ }
+ }
+
+ if (inRange && i != (rangeStart + 1))
+ fprintf(DumpFile, "-%d", i - 1);
+ }
+
+ fprintf(DumpFile, "\n");
+}
+
+void IRO_DumpAfterPhase(char *str, Boolean flag) {
+#ifdef CW_ENABLE_IRO_DEBUG
+ if (copts.debuglisting)
+ flag = 1;
+#endif
+ if (flag) {
+ IRO_Dump("Dumping function %s after %s \n", FunctionName ? FunctionName->name->name : "Init-code", str);
+ IRO_Dump("--------------------------------------------------------------------------------\n");
+ IRO_DumpFlowgraph();
+ }
+}
+
+void IRO_LogForFunction(char *name) {
+ if (FunctionName) {
+ if (!strcmp(FunctionName->name->name, name))
+ IRO_Log = 1;
+ else
+ IRO_Log = 0;
+ }
+}
+
+void IRO_DumpFlowgraph(void) {
+ IRONode *node;
+ IROLinear *linear;
+
+ if (IRO_Log && DumpFile) {
+ fprintf(DumpFile, "\nFlowgraph\n");
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ fprintf(DumpFile, "Flowgraph node %d First=%d, Last=%d\n", node->index, node->first->index, node->last->index);
+
+ fprintf(DumpFile, "Succ = ");
+ DumpList(node->numsucc, node->succ);
+ fprintf(DumpFile, "Pred = ");
+ DumpList(node->numpred, node->pred);
+
+ fprintf(DumpFile, "MustReach = %d, MustReach1=%d\n", node->mustreach, node->mustreach1);
+ fprintf(DumpFile, "LoopDepth = %d\n", node->loopdepth);
+
+ IRO_DumpBits("Dom: ", node->dom);
+ if ((linear = node->first)) {
+ while (1) {
+ DumpLinearNode(linear);
+ if (linear == node->last)
+ break;
+ linear = linear->next;
+ }
+ }
+
+ fprintf(DumpFile, "\n\n");
+ }
+ fprintf(DumpFile, "\n");
+ fflush(DumpFile);
+ }
+}
+
+void IRO_DumpNode(IRONode *node) {
+ IROLinear *linear;
+
+ if (IRO_Log) {
+ if (!DumpFile)
+ return;
+
+ while (node) {
+ fprintf(DumpFile, "Flowgraph node %d First=%d, Last=%d\n", node->index, node->first->index,
+ node->last->index);
+
+ fprintf(DumpFile, "Succ = ");
+ DumpList(node->numsucc, node->succ);
+ fprintf(DumpFile, "Pred = ");
+ DumpList(node->numpred, node->pred);
+
+ fprintf(DumpFile, "MustReach = %d MustReach1 = %d\n", node->mustreach, node->mustreach1);
+ fprintf(DumpFile, "LoopDepth = %d\n", node->loopdepth);
+
+ IRO_DumpBits("Dom: ", node->dom);
+ if ((linear = node->first)) {
+ while (1) {
+ DumpLinearNode(linear);
+ if (linear == node->last)
+ break;
+ linear = linear->next;
+ }
+ }
+
+ fprintf(DumpFile, "\n\n");
+ node = node->nextnode;
+ }
+
+ fprintf(DumpFile, "\n");
+ fflush(DumpFile);
+ }
+}
+
+void IRO_DumpAssignments(void) {
+ IROAssign *assign;
+
+ if (IRO_Log) {
+ fprintf(DumpFile, "\nAssignments\n\n");
+ for (assign = IRO_FirstAssign; assign; assign = assign->next) {
+ fprintf(DumpFile, "%5d ", assign->index);
+ DumpLinearNode(assign->linear);
+ fprintf(DumpFile, "\n");
+ }
+ fprintf(DumpFile, "\n");
+ }
+}
+
+void IRO_DumpVars(void) {
+ VarRecord *var;
+
+ if (IRO_Log) {
+ fprintf(DumpFile, "\nVariables\n");
+ for (var = IRO_FirstVar; var; var = var->next) {
+ fprintf(DumpFile, "%5d %s %s\n", var->index, var->object->name->name, var->xB ? "<addressed>" : "");
+ }
+ fprintf(DumpFile, "\n");
+ }
+}
+
+void IRO_DumpDf(void) {
+ IRONode *node;
+
+ if (IRO_Log) {
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ fprintf(DumpFile, "Node %d\n", node->index);
+ if (node->x16) IRO_DumpBits("In: ", node->x16);
+ if (node->x1E) IRO_DumpBits("Gen: ", node->x1E);
+ if (node->x22) IRO_DumpBits("Kill: ", node->x22);
+ if (node->x1A) IRO_DumpBits("Out: ", node->x1A);
+ if (node->x2A) IRO_DumpBits("AA: ", node->x2A);
+ fprintf(DumpFile, "\n");
+ }
+ fprintf(DumpFile, "\n");
+ }
+}
+
+void IRO_DumpExprs(void) {
+ IROExpr *expr;
+
+ if (IRO_Log) {
+ fprintf(DumpFile, "Expressions\n\n");
+ for (expr = IRO_FirstExpr; expr; expr = expr->next) {
+ fprintf(DumpFile, "%4d: %d FN:%d CE:%d NS:%d ", expr->index, expr->linear->index, expr->node->index, expr->couldError, expr->notSubable);
+ IRO_DumpBits("Depends: ", expr->depends);
+ fprintf(DumpFile, "\n");
+ }
+ fprintf(DumpFile, "\n");
+ }
+}
+
+void IRO_SetupDump(void) {
+#ifdef CW_ENABLE_IRO_DEBUG
+ IRO_Log = 1;
+#endif
+
+ if (IRO_Log) {
+ if ((DumpFile = fopen("OPT.LOG", "wt")) == NULL)
+ IRO_Log = 0;
+ }
+}
+
+void IRO_CleanupDump(void) {
+ if (DumpFile)
+ fclose(DumpFile);
+}
+
+void IRO_Dump(char *format, ...) {
+ va_list va;
+ if (IRO_Log) {
+ va_start(va, format);
+ vfprintf(DumpFile, format, va);
+ va_end(va);
+ }
+}
+
+void IRO_DumpAddr(IROAddrRecord *rec) {
+ IROElmList *list;
+
+ if (IRO_Log && DumpFile) {
+ fprintf(DumpFile, "\n");
+ fprintf(DumpFile, "Address :\n");
+ IRO_DumpIntTree(rec->linear);
+ fprintf(DumpFile, "\n");
+ fprintf(DumpFile, "BaseTerms:\n");
+ for (list = rec->objRefs; list; list = list->next) {
+ IRO_DumpIntTree(list->element);
+ fprintf(DumpFile, "\n");
+ }
+ fprintf(DumpFile, "VarTerms:\n");
+ for (list = rec->misc; list; list = list->next) {
+ IRO_DumpIntTree(list->element);
+ fprintf(DumpFile, "\n");
+ }
+ fprintf(DumpFile, "ConstTerms:\n");
+ for (list = rec->ints; list; list = list->next) {
+ IRO_DumpIntTree(list->element);
+ fprintf(DumpFile, "\n");
+ }
+ }
+}
+
+static void IRO_DumpType(Type *type) {
+ char buf[256];
+ IRO_SpellType(type, buf);
+ fprintf(DumpFile, " (%s)", buf);
+}
+
+void IRO_SpellType(Type *type, char *buf) {
+ char mybuf[256];
+ char mybuf2[256];
+
+ switch (type->type) {
+ case TYPEVOID:
+ strcpy(buf, "void");
+ break;
+ case TYPEINT:
+ switch (TYPE_INTEGRAL(type)->integral) {
+ case IT_BOOL:
+ strcpy(buf, "bool");
+ break;
+ case IT_CHAR:
+ strcpy(buf, "char");
+ break;
+ case IT_WCHAR_T:
+ strcpy(buf, "wchar_t");
+ break;
+ case IT_SCHAR:
+ strcpy(buf, "signed char");
+ break;
+ case IT_UCHAR:
+ strcpy(buf, "unsigned char");
+ break;
+ case IT_SHORT:
+ strcpy(buf, "short");
+ break;
+ case IT_USHORT:
+ strcpy(buf, "unsigned short");
+ break;
+ case IT_INT:
+ strcpy(buf, "int");
+ break;
+ case IT_UINT:
+ strcpy(buf, "unsigned int");
+ break;
+ case IT_LONG:
+ strcpy(buf, "long");
+ break;
+ case IT_ULONG:
+ strcpy(buf, "unsigned long");
+ break;
+ case IT_LONGLONG:
+ strcpy(buf, "long long");
+ break;
+ case IT_ULONGLONG:
+ strcpy(buf, "unsigned long long");
+ break;
+ }
+ break;
+ case TYPEFLOAT:
+ switch (TYPE_INTEGRAL(type)->integral) {
+ case IT_FLOAT:
+ strcpy(buf, "float");
+ break;
+ case IT_SHORTDOUBLE:
+ strcpy(buf, "short double");
+ break;
+ case IT_DOUBLE:
+ strcpy(buf, "double");
+ break;
+ case IT_LONGDOUBLE:
+ strcpy(buf, "long double");
+ break;
+ }
+ break;
+ case TYPEENUM:
+ strcpy(buf, "enum ");
+ if (TYPE_ENUM(type)->enumname)
+ strcat(buf, TYPE_ENUM(type)->enumname->name);
+ break;
+ case TYPESTRUCT:
+ if (IS_TYPESTRUCT_VECTOR(TYPE_STRUCT(type))) {
+ switch (TYPE_STRUCT(type)->stype) {
+ case STRUCT_VECTOR_UCHAR:
+ strcpy(buf, "vector unsigned char ");
+ break;
+ case STRUCT_VECTOR_SCHAR:
+ strcpy(buf, "vector signed char ");
+ break;
+ case STRUCT_VECTOR_BCHAR:
+ strcpy(buf, "vector bool char ");
+ break;
+ case STRUCT_VECTOR_USHORT:
+ strcpy(buf, "vector unsigned short ");
+ break;
+ case STRUCT_VECTOR_SSHORT:
+ strcpy(buf, "vector signed short ");
+ break;
+ case STRUCT_VECTOR_BSHORT:
+ strcpy(buf, "vector bool short ");
+ break;
+ case STRUCT_VECTOR_UINT:
+ strcpy(buf, "vector unsigned long ");
+ break;
+ case STRUCT_VECTOR_SINT:
+ strcpy(buf, "vector signed long ");
+ break;
+ case STRUCT_VECTOR_BINT:
+ strcpy(buf, "vector bool long ");
+ break;
+ case STRUCT_VECTOR_FLOAT:
+ strcpy(buf, "vector float ");
+ break;
+ case STRUCT_VECTOR_PIXEL:
+ strcpy(buf, "vector pixel ");
+ break;
+ }
+ } else {
+ strcpy(buf, "struct ");
+ }
+ if (TYPE_STRUCT(type)->name)
+ strcat(buf, TYPE_STRUCT(type)->name->name);
+ break;
+ case TYPECLASS:
+ strcpy(buf, "class ");
+ if (TYPE_CLASS(type)->classname)
+ strcat(buf, TYPE_CLASS(type)->classname->name);
+ break;
+ case TYPEFUNC:
+ IRO_SpellType(TYPE_FUNC(type)->functype, mybuf);
+ strcpy(buf, "freturns(");
+ strcat(buf, mybuf);
+ strcat(buf, ")");
+ break;
+ case TYPEBITFIELD:
+ IRO_SpellType(TYPE_BITFIELD(type)->bitfieldtype, mybuf);
+ sprintf(buf, "bitfield(%s){%d:%d}", mybuf, TYPE_BITFIELD(type)->offset, TYPE_BITFIELD(type)->bitlength);
+ break;
+ case TYPELABEL:
+ strcpy(buf, "label");
+ break;
+ case TYPEPOINTER:
+ IRO_SpellType(TPTR_TARGET(type), mybuf);
+ strcpy(buf, "pointer(");
+ strcat(buf, mybuf);
+ strcat(buf, ")");
+ break;
+ case TYPEARRAY:
+ IRO_SpellType(TPTR_TARGET(type), mybuf);
+ strcpy(buf, "array(");
+ strcat(buf, mybuf);
+ strcat(buf, ")");
+ break;
+ case TYPEMEMBERPOINTER:
+ IRO_SpellType(TYPE_MEMBER_POINTER(type)->ty2, mybuf);
+ IRO_SpellType(TYPE_MEMBER_POINTER(type)->ty1, mybuf2);
+ strcpy(buf, "memberpointer(");
+ strcat(buf, mybuf);
+ strcat(buf, ",");
+ strcat(buf, mybuf2);
+ strcat(buf, ")");
+ break;
+ }
+}
+
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroDump.h b/compiler_and_linker/FrontEnd/Optimizer/IroDump.h
new file mode 100644
index 0000000..ad8c039
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroDump.h
@@ -0,0 +1,27 @@
+#ifndef COMPILER_IRODUMP_H
+#define COMPILER_IRODUMP_H
+
+#include "IrOptimizer.h"
+#include "BitVector.h"
+#include "compiler/enode.h"
+
+extern char *IRO_NodeName(ENodeType nodetype);
+extern void IRO_InitializeNodeNamesArray(void);
+extern void IRO_DumpIntTree(IROLinear *linear);
+extern void IRO_DumpLinearList(IROLinear *linear);
+extern void IRO_DumpBits(char *name, BitVector *bv);
+extern void IRO_DumpAfterPhase(char *str, Boolean flag);
+extern void IRO_LogForFunction(char *name);
+extern void IRO_DumpFlowgraph(void);
+extern void IRO_DumpNode(IRONode *node);
+extern void IRO_DumpAssignments(void);
+extern void IRO_DumpVars(void);
+extern void IRO_DumpDf(void);
+extern void IRO_DumpExprs(void);
+extern void IRO_SetupDump(void);
+extern void IRO_CleanupDump(void);
+extern void IRO_Dump(char *format, ...);
+extern void IRO_DumpAddr(IROAddrRecord *rec);
+extern void IRO_SpellType(Type *type, char *buf);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c b/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c
new file mode 100644
index 0000000..23d5d4a
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.c
@@ -0,0 +1,560 @@
+#include "IroEmptyLoop.h"
+#include "IroDump.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroLoop.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/CInt64.h"
+
+// forward decls
+static Boolean EmptyLoop(IRONode *fnode);
+static int CanRemoveRedundantLoop(IROLoop *loop);
+static int CanRemoveRedundantLoop1(IROLoop *loop);
+static int RedundantLoopCheck(IROLoop *loop);
+static int CheckStepOverFlow1_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2);
+static int CheckStepOverFlow2_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2);
+
+void IRO_FindEmptyLoops(void) {
+ IRONode *fnode;
+ IRONode *pred;
+ UInt16 i;
+ UInt16 x;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ x = 0;
+ for (i = 0; i < fnode->numpred; i++) {
+ pred = IRO_NodeTable[fnode->pred[i]];
+ if (Bv_IsBitSet(fnode->index, pred->dom)) {
+ if (!x) {
+ Bv_AllocVector(&InLoop, IRO_NumNodes + 1);
+ Bv_Clear(InLoop);
+ Bv_SetBit(fnode->index, InLoop);
+ }
+ x = 1;
+ Bv_SetBit(pred->index, InLoop);
+ if (pred != fnode)
+ AddPreds(pred);
+ }
+ }
+
+ if (x) {
+ IRO_Dump("IRO_FindEmptyLoops:Found loop with header %d\n", fnode->index);
+ IRO_DumpBits("Loop includes: ", InLoop);
+ EmptyLoop(fnode);
+ IRO_UpdateFlagsOnInts();
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+static Boolean EmptyLoop(IRONode *fnode) {
+ VarRecord *var;
+ IRONode *bestpred;
+ IRONode *pred;
+ UInt16 i;
+ int flag2;
+ IRONode *r24;
+ Boolean flag;
+ int counter;
+ int j;
+ IRONode *succ;
+ IRONode *bestsucc;
+ int counter2;
+ UInt32 counter3;
+ IROLoop *loop;
+ IRONode *r21;
+ IRONode *r20;
+ IROLinear *constnd;
+ Type *type20;
+ ENode *enode;
+ IROLinear *save;
+
+ flag = 0;
+ counter = 0;
+ LoopNode = fnode;
+ FindMustReach();
+
+ for (var = IRO_FirstVar; var; var = var->next)
+ var->xA = 1;
+
+ ComputeLoopKills();
+ ComputeLoopInvariance();
+ ComputeLoopInduction();
+
+ LoopNode = fnode;
+ ConditionalHeaderAtBottom = 0;
+
+ bestpred = NULL;
+ flag2 = 0;
+ for (i = 0; i < LoopNode->numpred; i++) {
+ pred = IRO_NodeTable[LoopNode->pred[i]];
+ if (!Bv_IsBitSet(pred->index, InLoop)) {
+ flag2 = 1;
+ if (pred->nextnode == fnode) {
+ CError_ASSERT(173, !bestpred || pred == bestpred);
+ bestpred = pred;
+ }
+ }
+ }
+
+ if (!flag2) {
+ IRO_Dump("No predecessor outside the loop\n");
+ return 0;
+ }
+
+ bestsucc = NULL;
+ for (i = 0; i < LoopNode->numsucc; i++) {
+ succ = IRO_NodeTable[LoopNode->succ[i]];
+ if (Bv_IsBitSet(succ->index, InLoop)) {
+ bestsucc = succ;
+ counter++;
+ }
+ }
+
+ if (LoopNode == bestsucc && counter == 1)
+ flag = 1;
+
+ if (LoopNode->last->type != IROLinearIf || LoopNode->last->type != IROLinearIfNot || flag) {
+ counter2 = 0;
+ for (j = 0; j < LoopNode->numpred; j++) {
+ if (Bv_IsBitSet(IRO_NodeTable[LoopNode->pred[j]]->index, InLoop)) {
+ r21 = IRO_NodeTable[LoopNode->pred[j]];
+ counter2++;
+ }
+ }
+
+ r24 = NULL;
+ counter3 = 0;
+ for (j = 0; j < LoopNode->numpred; j++) {
+ if (!Bv_IsBitSet(IRO_NodeTable[LoopNode->pred[j]]->index, InLoop)) {
+ r24 = IRO_NodeTable[LoopNode->pred[j]];
+ counter3++;
+ }
+ }
+
+ if (counter2 == 1 && counter3 == 1) {
+ if (r21->last->type == IROLinearIf) {
+ if ((Bv_IsBitSet(LoopNode->nextnode->index, InLoop) && !Bv_IsBitSet(r21->nextnode->index, InLoop)) || flag) {
+ IRO_Dump("Standard while loop layout\n");
+ loop = ExtractLoopInfo(r21);
+ if (flag)
+ loop->flags |= LoopFlags_20000;
+ FindAssignmenttoInductionVar(loop, r24);
+ r20 = r24;
+ while (r20 && !loop->nd14 && r20->numpred == 1 && IRO_NodeTable[r20->pred[0]]->numsucc == 1) {
+ FindAssignmenttoInductionVar(loop, IRO_NodeTable[r20->pred[0]]);
+ r20 = IRO_NodeTable[r20->pred[0]];
+ }
+
+ if (CanRemoveRedundantLoop(loop)) {
+ IRO_Dump("EmptyLoop: # of iterations =%" PRId32 ", FinalStoreVal=%" PRId32 "\n", CInt64_GetULong(&loop->x28), CInt64_GetULong(&loop->x30));
+ IRO_NopOut(r21->last->u.label.x4);
+ r21->last->type = IROLinearNop;
+ type20 = loop->induction->nd->rtype;
+ constnd = IRO_NewLinear(IROLinearOperand);
+ constnd->index = ++IRO_NumLinear;
+ enode = IRO_NewENode(EINTCONST);
+ enode->rtype = type20;
+ enode->data.intval = loop->x30;
+ constnd->u.node = enode;
+ constnd->rtype = type20;
+
+ if (loop->induction->nd->type == IROLinearOp1Arg) {
+ save = loop->induction->nd->u.monadic;
+ loop->induction->nd->type = IROLinearOp2Arg;
+ loop->induction->nd->nodetype = EASS;
+ loop->induction->nd->u.diadic.left = save;
+ loop->induction->nd->u.diadic.right = constnd;
+ IRO_Paste(constnd, constnd, loop->induction->nd);
+ } else if (loop->induction->nd->type == IROLinearOp2Arg) {
+ loop->induction->nd->nodetype = EASS;
+ IRO_NopOut(loop->induction->nd->u.diadic.right);
+ loop->induction->nd->u.diadic.right = constnd;
+ IRO_Paste(constnd, constnd, loop->induction->nd);
+ }
+ } else if (CanRemoveRedundantLoop1(loop)) {
+ IRO_Dump("EmptyLoop: self recursive dowhile(--n ) loop\n");
+
+ r21->last->type = IROLinearNop;
+ type20 = loop->induction->nd->rtype;
+ constnd = IRO_NewLinear(IROLinearOperand);
+ constnd->index = ++IRO_NumLinear;
+ enode = IRO_NewENode(EINTCONST);
+ enode->rtype = type20;
+ enode->data.intval = cint64_zero;
+ constnd->u.node = enode;
+ constnd->rtype = type20;
+
+ save = loop->induction->nd->u.monadic;
+ loop->induction->nd->type = IROLinearOp2Arg;
+ loop->induction->nd->nodetype = EASS;
+ loop->induction->nd->u.diadic.left = save;
+ loop->induction->nd->u.diadic.right = constnd;
+ IRO_Paste(constnd, constnd, loop->induction->nd);
+ }
+ } else {
+ IRO_Dump("NonStandard while loop layout\n");
+ }
+ } else {
+ IRO_Dump("NonStandard while loop layout\n");
+ }
+ } else {
+ IRO_Dump("Cannot handle Do While Loop with multiple tails\n");
+ }
+ }
+
+ return 0;
+}
+
+static int CanRemoveRedundantLoop(IROLoop *loop) {
+ IROLinear *inner;
+
+ if (loop->flags & LoopFlags_10000) {
+ IRO_Dump("CanRemoveRedundantLoop:No because detection of dowhile(n--) loop not supported\n");
+ return 0;
+ }
+
+ if (loop->flags & LP_LOOP_HAS_ASM) {
+ IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HAS_ASM \n");
+ return 0;
+ }
+
+ if (loop->flags & LP_IFEXPR_NON_CANONICAL) {
+ IRO_Dump("CanRemoveRedundantLoop:No due to LP_IFEXPR_NON_CANONICAL \n");
+ return 0;
+ }
+
+ if (loop->flags & LP_LOOP_HAS_CALLS) {
+ IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HAS_CALLS \n");
+ return 0;
+ }
+
+ if (loop->flags & LP_LOOP_HAS_CNTRLFLOW) {
+ IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HAS_CNTRLFLOW \n");
+ return 0;
+ }
+
+ if (loop->flags & LP_INDUCTION_NOT_FOUND) {
+ IRO_Dump("CanRemoveRedundantLoop:No due to LP_INDUCTION_NOT_FOUND \n");
+ return 0;
+ }
+
+ if (loop->flags & LP_HAS_MULTIPLE_INDUCTIONS) {
+ IRO_Dump("CanRemoveRedundantLoop:No due to LP_HAS_MULTIPLE_INDUCTIONS \n");
+ return 0;
+ }
+
+ if (loop->flags & LP_LOOP_HDR_HAS_SIDEEFFECTS) {
+ IRO_Dump("CanRemoveRedundantLoop:No due to LP_LOOP_HDR_HAS_SIDEEFFECTS \n");
+ return 0;
+ }
+
+ if (!(loop->flags & LoopFlags_200)) {
+ IRO_Dump("CanRemoveRedundantLoop:No because header does not follow induction update \n");
+ return 0;
+ }
+
+ if (!(loop->flags & LoopFlags_10000)) {
+ inner = loop->nd18->u.diadic.right;
+ if (!IRO_IsIntConstant(inner) && !(inner->flags & IROLF_LoopInvariant)) {
+ IRO_Dump("CanRemoveRedundantLoop:No because Loop Upper Bound is Variant in the loop\n");
+ return 0;
+ }
+
+ if (!loop->nd14) {
+ IRO_Dump("CanRemoveRedundantLoop:No because there is no initialization of loop index in PreHeader\n");
+ return 0;
+ }
+
+ if (!IRO_IsVariable(loop->nd14->u.diadic.left)) {
+ IRO_Dump("CanRemoveRedundantLoop:No because initial value of induction stored thru pointer\n");
+ return 0;
+ }
+
+ if (!IRO_IsUnsignedType(loop->nd14->rtype)) {
+ if (IRO_IsIntConstant(loop->nd14->u.diadic.right)) {
+ if (!CInt64_GreaterEqual(loop->nd14->u.diadic.right->u.node->data.intval, cint64_zero)) {
+ IRO_Dump("CanRemoveRedundantLoop:No because initial value of induction is signed but < 0\n");
+ return 0;
+ }
+ } else {
+ IRO_Dump("CanRemoveRedundantLoop:No because initial value of induction is signed and not constant\n");
+ return 0;
+ }
+ }
+
+ if (!(loop->flags & LP_LOOP_STEP_ISPOS) && !(loop->flags & LP_LOOP_STEP_ISNEG)) {
+ IRO_Dump("CanRemoveRedundantLoop:No because LP_LOOP_STEP_ISPOS/LP_LOOP_STEP_ISNEG is not set\n");
+ return 0;
+ }
+
+ if ((loop->flags & LP_LOOP_STEP_ISPOS) && CheckStepOverFlow1_EmptyLoop(loop, &loop->x28, &loop->x30)) {
+ IRO_Dump("CanRemoveRedundantLoop:No because Final Value of indution will overflow\n");
+ return 0;
+ }
+
+ if ((loop->flags & LP_LOOP_STEP_ISNEG) && CheckStepOverFlow2_EmptyLoop(loop, &loop->x28, &loop->x30)) {
+ IRO_Dump("CanRemoveRedundantLoop:No because Final Value of indution will overflow\n");
+ return 0;
+ }
+ }
+
+ return RedundantLoopCheck(loop) != 0;
+}
+
+static int CanRemoveRedundantLoop1(IROLoop *loop) {
+ if ((loop->flags & LoopFlags_10000) && (loop->flags & LoopFlags_20000)) {
+ if (loop->flags & LP_LOOP_HAS_ASM) {
+ IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HAS_ASM \n");
+ return 0;
+ }
+
+ if (loop->flags & LP_IFEXPR_NON_CANONICAL) {
+ IRO_Dump("CanRemoveRedundantLoop1:No due to LP_IFEXPR_NON_CANONICAL \n");
+ return 0;
+ }
+
+ if (loop->flags & LP_LOOP_HAS_CALLS) {
+ IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HAS_CALLS \n");
+ return 0;
+ }
+
+ if (loop->flags & LP_LOOP_HAS_CNTRLFLOW) {
+ IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HAS_CNTRLFLOW \n");
+ return 0;
+ }
+
+ if (loop->flags & LP_INDUCTION_NOT_FOUND) {
+ IRO_Dump("CanRemoveRedundantLoop1:No due to LP_INDUCTION_NOT_FOUND \n");
+ return 0;
+ }
+
+ if (loop->flags & LP_HAS_MULTIPLE_INDUCTIONS) {
+ IRO_Dump("CanRemoveRedundantLoop1:No due to LP_HAS_MULTIPLE_INDUCTIONS \n");
+ return 0;
+ }
+
+ if (loop->flags & LP_LOOP_HDR_HAS_SIDEEFFECTS) {
+ IRO_Dump("CanRemoveRedundantLoop1:No due to LP_LOOP_HDR_HAS_SIDEEFFECTS \n");
+ return 0;
+ }
+
+ if (!(loop->flags & LoopFlags_200)) {
+ IRO_Dump("CanRemoveRedundantLoop1:No because header does not follow induction update \n");
+ return 0;
+ }
+
+ if (loop->induction->nd->type == IROLinearOp1Arg && loop->induction->nd->nodetype == EPREDEC) {
+ if (IRO_IsUnsignedType(loop->induction->nd->rtype))
+ return 1;
+ IRO_Dump("CanRemoveRedundantLoop1:No because induction not of the right type \n");
+ return 0;
+ }
+
+ IRO_Dump("CanRemoveRedundantLoop1:No because induction operator not a predec \n");
+ return 0;
+ } else {
+ return 0;
+ }
+}
+
+static int RedundantLoopCheck(IROLoop *loop) {
+ IRONode *fnode;
+ IROLinear *nd;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ if (Bv_IsBitSet(fnode->index, InLoop) && fnode != loop->fnode && (nd = fnode->first)) {
+ while (1) {
+ if ((nd->index < loop->index20 || nd->index > loop->index24) && nd->type != IROLinearNop && nd->type != IROLinearLabel) {
+ if (IS_LINEAR_DIADIC(nd, EASS)) {
+ if (!(nd->flags & IROLF_Reffed)) {
+ if (IS_LINEAR_MONADIC(nd->u.diadic.left, EINDIRECT)) {
+ if (nd->u.diadic.left->rtype && CParser_IsVolatile(nd->u.diadic.left->rtype, nd->u.diadic.left->nodeflags & ENODE_FLAG_QUALS)) {
+ IRO_Dump(" EASS at %d fail as store to volatile memory \n", nd->index);
+ return 0;
+ }
+
+ if ((nd->u.diadic.left->u.monadic->flags & IROLF_LoopInvariant) && (nd->u.diadic.right->flags & IROLF_LoopInvariant)) {
+ IRO_Dump(" EASS at %d pass\n", nd->index);
+ } else {
+ IRO_Dump(" EASS at %d fail, either LHS address or RHS is variant \n", nd->index);
+ return 0;
+ }
+ } else {
+ IRO_Dump("Found EASS nodes whose lhs root is not a EINDIRECT node\n");
+ return 0;
+ }
+ } else {
+ IRO_Dump("Found EASS node that is referenced i.e embedded assignment\n");
+ return 0;
+ }
+ } else {
+ if (!(nd->flags & IROLF_Reffed)) {
+ IRO_Dump("Found non EASS top level node in the loop\n");
+ return 0;
+ }
+ }
+ }
+
+ if (nd == fnode->last)
+ break;
+ nd = nd->next;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int CheckStepOverFlow1_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2) {
+ Boolean isUnsigned;
+ IROLinear *nd2;
+ IROLinear *nd1;
+ CInt64 nd2value;
+ CInt64 nd1value;
+ CInt64 addConst;
+ CInt64 work;
+ CInt64 neg1;
+
+ nd2 = loop->nd14->u.diadic.right;
+ nd1 = loop->nd18->u.diadic.right;
+ isUnsigned = IRO_IsUnsignedType(loop->nd18->u.diadic.right->rtype);
+
+ if (IRO_IsIntConstant(nd2) && IRO_IsIntConstant(nd1)) {
+ nd2value = nd2->u.node->data.intval;
+ nd1value = nd1->u.node->data.intval;
+ if (isUnsigned) {
+ if (CInt64_LessEqualU(nd1value, nd2value))
+ return 1;
+ } else {
+ if (CInt64_LessEqual(nd1value, nd2value))
+ return 1;
+ }
+
+ CInt64_SetLong(&addConst, loop->induction->addConst);
+ CInt64_SetLong(&neg1, -1);
+ *val1 = CInt64_Sub(nd1value, nd2value);
+ *val1 = CInt64_Add(*val1, addConst);
+ if (IS_LINEAR_DIADIC(loop->nd18, ELESS))
+ *val1 = CInt64_Add(*val1, neg1);
+
+ CError_ASSERT(855, !CInt64_IsZero(&addConst));
+
+ if (isUnsigned)
+ *val1 = CInt64_DivU(*val1, addConst);
+ else
+ *val1 = CInt64_Div(*val1, addConst);
+
+ if (CInt64_Equal(*val1, cint64_zero))
+ return 1;
+
+ if (isUnsigned) {
+ if (CInt64_LessEqualU(*val1, cint64_zero))
+ CError_FATAL(877);
+ } else {
+ if (CInt64_LessEqual(*val1, cint64_zero))
+ CError_FATAL(886);
+ }
+
+ if (isUnsigned) {
+ *val2 = CInt64_MulU(*val1, addConst);
+ *val2 = CInt64_Add(*val2, nd2value);
+ } else {
+ *val2 = CInt64_Mul(*val1, addConst);
+ *val2 = CInt64_Add(*val2, nd2value);
+ }
+ } else {
+ return 1;
+ }
+
+ CInt64_SetLong(&addConst, loop->induction->addConst);
+ work = CInt64_Add(nd1value, addConst);
+
+ if (isUnsigned) {
+ if (CInt64_LessU(work, nd1value))
+ return 1;
+ } else {
+ if (CInt64_Less(work, nd1value))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int CheckStepOverFlow2_EmptyLoop(IROLoop *loop, CInt64 *val1, CInt64 *val2) {
+ Boolean isUnsigned;
+ IROLinear *nd2;
+ IROLinear *nd1;
+ CInt64 nd2value;
+ CInt64 nd1value;
+ CInt64 addConst;
+ CInt64 work;
+ CInt64 neg1;
+
+ nd1 = loop->nd14->u.diadic.right;
+ nd2 = loop->nd18->u.diadic.right;
+ isUnsigned = IRO_IsUnsignedType(loop->nd18->u.diadic.right->rtype);
+
+ if (IRO_IsIntConstant(nd2) && IRO_IsIntConstant(nd1)) {
+ nd2value = nd2->u.node->data.intval;
+ nd1value = nd1->u.node->data.intval;
+ if (isUnsigned) {
+ if (CInt64_LessEqualU(nd1value, nd2value))
+ return 1;
+ } else {
+ if (CInt64_LessEqual(nd1value, nd2value))
+ return 1;
+ }
+
+ CInt64_SetLong(&addConst, loop->induction->addConst);
+ CInt64_SetLong(&neg1, -1);
+ *val1 = CInt64_Sub(nd1value, nd2value);
+ *val1 = CInt64_Add(*val1, addConst);
+ if (IS_LINEAR_DIADIC(loop->nd18, EGREATER))
+ *val1 = CInt64_Add(*val1, neg1);
+
+ CError_ASSERT(995, !CInt64_IsZero(&addConst));
+
+ if (isUnsigned)
+ *val1 = CInt64_DivU(*val1, addConst);
+ else
+ *val1 = CInt64_Div(*val1, addConst);
+
+ if (CInt64_Equal(*val1, cint64_zero))
+ return 1;
+
+ if (isUnsigned) {
+ if (CInt64_LessEqualU(*val1, cint64_zero))
+ return 0;
+ } else {
+ if (CInt64_LessEqual(*val1, cint64_zero))
+ return 0;
+ }
+
+ if (isUnsigned) {
+ *val2 = CInt64_MulU(*val1, addConst);
+ *val2 = CInt64_Sub(nd1value, *val2);
+ } else {
+ *val2 = CInt64_Mul(*val1, addConst);
+ *val2 = CInt64_Sub(nd1value, *val2);
+ }
+ } else {
+ return 1;
+ }
+
+ CInt64_SetLong(&addConst, loop->induction->addConst);
+ work = CInt64_Sub(nd2value, addConst);
+
+ if (isUnsigned) {
+ if (CInt64_GreaterU(work, nd2value))
+ return 1;
+ } else {
+ if (CInt64_Greater(work, nd1value))
+ return 1;
+ }
+
+ return 0;
+}
+
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.h b/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.h
new file mode 100644
index 0000000..c5597e6
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroEmptyLoop.h
@@ -0,0 +1,8 @@
+#ifndef COMPILER_IROEMPTYLOOP_H
+#define COMPILER_IROEMPTYLOOP_H
+
+#include "IrOptimizer.h"
+
+extern void IRO_FindEmptyLoops(void);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroEval.c b/compiler_and_linker/FrontEnd/Optimizer/IroEval.c
new file mode 100644
index 0000000..aba64e1
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroEval.c
@@ -0,0 +1,914 @@
+#include "IroEval.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroMalloc.h"
+#include "IroPointerAnalysis.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/enode.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+static Boolean IsAssociativeENodeType[MAXEXPR];
+
+void IRO_InitializeIsAssociativeENodeTypeArray(void) {
+ int i;
+
+ for (i = 0; i < MAXEXPR; i++)
+ IsAssociativeENodeType[i] = 0;
+
+ IsAssociativeENodeType[EPOSTINC] = 0;
+ IsAssociativeENodeType[EPOSTDEC] = 0;
+ IsAssociativeENodeType[EPREINC] = 0;
+ IsAssociativeENodeType[EPREDEC] = 0;
+ IsAssociativeENodeType[EINDIRECT] = 0;
+ IsAssociativeENodeType[EMONMIN] = 0;
+ IsAssociativeENodeType[EBINNOT] = 0;
+ IsAssociativeENodeType[ELOGNOT] = 0;
+ IsAssociativeENodeType[EFORCELOAD] = 0;
+ IsAssociativeENodeType[EMUL] = 1;
+ IsAssociativeENodeType[EMULV] = 1;
+ IsAssociativeENodeType[EDIV] = 0;
+ IsAssociativeENodeType[EMODULO] = 0;
+ IsAssociativeENodeType[EADDV] = 1;
+ IsAssociativeENodeType[ESUBV] = 0;
+ IsAssociativeENodeType[EADD] = 1;
+ IsAssociativeENodeType[ESUB] = 0;
+ IsAssociativeENodeType[ESHL] = 0;
+ IsAssociativeENodeType[ESHR] = 0;
+ IsAssociativeENodeType[ELESS] = 0;
+ IsAssociativeENodeType[EGREATER] = 0;
+ IsAssociativeENodeType[ELESSEQU] = 0;
+ IsAssociativeENodeType[EGREATEREQU] = 0;
+ IsAssociativeENodeType[EEQU] = 0;
+ IsAssociativeENodeType[ENOTEQU] = 0;
+ IsAssociativeENodeType[EAND] = 1;
+ IsAssociativeENodeType[EXOR] = 1;
+ IsAssociativeENodeType[EOR] = 1;
+ IsAssociativeENodeType[ELAND] = 0;
+ IsAssociativeENodeType[ELOR] = 0;
+ IsAssociativeENodeType[EASS] = 0;
+ IsAssociativeENodeType[EMULASS] = 0;
+ IsAssociativeENodeType[EDIVASS] = 0;
+ IsAssociativeENodeType[EMODASS] = 0;
+ IsAssociativeENodeType[EADDASS] = 0;
+ IsAssociativeENodeType[ESUBASS] = 0;
+ IsAssociativeENodeType[ESHLASS] = 0;
+ IsAssociativeENodeType[ESHRASS] = 0;
+ IsAssociativeENodeType[EANDASS] = 0;
+ IsAssociativeENodeType[EXORASS] = 0;
+ IsAssociativeENodeType[EORASS] = 0;
+ IsAssociativeENodeType[ECOMMA] = 0;
+ IsAssociativeENodeType[EPMODULO] = 0;
+ IsAssociativeENodeType[EROTL] = 0;
+ IsAssociativeENodeType[EROTR] = 0;
+ IsAssociativeENodeType[EBCLR] = 0;
+ IsAssociativeENodeType[EBTST] = 0;
+ IsAssociativeENodeType[EBSET] = 0;
+ IsAssociativeENodeType[ETYPCON] = 0;
+ IsAssociativeENodeType[EBITFIELD] = 0;
+ IsAssociativeENodeType[EINTCONST] = 0;
+ IsAssociativeENodeType[EFLOATCONST] = 0;
+ IsAssociativeENodeType[ESTRINGCONST] = 0;
+ IsAssociativeENodeType[ECOND] = 0;
+ IsAssociativeENodeType[EFUNCCALL] = 0;
+ IsAssociativeENodeType[EFUNCCALLP] = 0;
+ IsAssociativeENodeType[EOBJREF] = 0;
+ IsAssociativeENodeType[EMFPOINTER] = 0;
+ IsAssociativeENodeType[ENULLCHECK] = 0;
+ IsAssociativeENodeType[EPRECOMP] = 0;
+ IsAssociativeENodeType[ETEMP] = 0;
+ IsAssociativeENodeType[EARGOBJ] = 0;
+ IsAssociativeENodeType[ELOCOBJ] = 0;
+ IsAssociativeENodeType[ELABEL] = 0;
+ IsAssociativeENodeType[ESETCONST] = 0;
+ IsAssociativeENodeType[ENEWEXCEPTION] = 0;
+ IsAssociativeENodeType[ENEWEXCEPTIONARRAY] = 0;
+ IsAssociativeENodeType[EOBJLIST] = 0;
+ IsAssociativeENodeType[EMEMBER] = 0;
+ IsAssociativeENodeType[ETEMPLDEP] = 0;
+ IsAssociativeENodeType[EINSTRUCTION] = 0;
+ IsAssociativeENodeType[EDEFINE] = 0;
+ IsAssociativeENodeType[EREUSE] = 0;
+ IsAssociativeENodeType[EASSBLK] = 0;
+ IsAssociativeENodeType[EVECTOR128CONST] = 0;
+ IsAssociativeENodeType[ECONDASS] = 0;
+}
+
+void IRO_TruncateValueToType(CInt64 *val, Type *type) {
+ if (IRO_IsUnsignedType(type)) {
+ switch (type->size) {
+ case 1:
+ CInt64_ConvertUInt8(val);
+ break;
+ case 2:
+ CInt64_ConvertUInt16(val);
+ break;
+ case 4:
+ CInt64_ConvertUInt32(val);
+ break;
+ }
+ } else {
+ switch (type->size) {
+ case 1:
+ CInt64_ConvertInt8(val);
+ break;
+ case 2:
+ CInt64_ConvertInt16(val);
+ break;
+ case 4:
+ CInt64_ConvertInt32(val);
+ break;
+ }
+ }
+}
+
+void IRO_TruncateBitfieldValueToType(CInt64 *val, Type *type, Type *type2) {
+ UInt32 limit;
+ UInt32 i;
+ UInt32 j;
+ CInt64 work;
+
+ work = cint64_zero;
+ limit = TYPE_BITFIELD(type2)->bitlength;
+ for (i = 0; i < limit; i++)
+ work = CInt64_Or(work, CInt64_Shl(cint64_one, IRO_MakeULong(i)));
+ *val = CInt64_And(*val, work);
+
+ if (!IRO_IsUnsignedType(type)) {
+ work = cint64_zero;
+ for (j = 0; j <= (i - 1); j++) {
+ if (j == (i - 1))
+ work = CInt64_Or(work, CInt64_Shl(cint64_one, IRO_MakeULong(j)));
+ }
+ if (CInt64_NotEqual(CInt64_And(work, *val), cint64_zero)) {
+ for (j = i - 1; j < 64; j++)
+ *val = CInt64_Or(*val, CInt64_Shl(cint64_one, IRO_MakeULong(j)));
+ }
+ }
+
+ IRO_TruncateValueToType(val, type);
+}
+
+void IRO_ConstantFolding(void) {
+ IROLinear *nd;
+ ENode *expr;
+ int isCompare;
+ int flag;
+ CInt64 val;
+
+ for (nd = IRO_FirstLinear; nd; nd = nd->next) {
+ switch (nd->type) {
+ case IROLinearOp1Arg:
+ if (IRO_IsIntConstant(nd->u.monadic)) {
+ expr = NULL;
+ flag = 0;
+ val = nd->u.monadic->u.node->data.intval;
+ if (nd->nodetype == ETYPCON && IS_TYPE_FLOAT(nd->rtype)) {
+ expr = IRO_NewENode(EFLOATCONST);
+ if (!IRO_IsUnsignedType(nd->u.monadic->rtype))
+ expr->data.floatval.value = CInt64_ConvertToLongDouble(&val);
+ else
+ expr->data.floatval.value = CInt64_ConvertUToLongDouble(&val);
+ expr->rtype = nd->rtype;
+ } else {
+ switch (nd->nodetype) {
+ case ETYPCON:
+ flag = 1;
+ break;
+ case ELOGNOT:
+ val = CInt64_Not(val);
+ flag = 1;
+ break;
+ case EBINNOT:
+ val = CInt64_Inv(val);
+ flag = 1;
+ break;
+ case EMONMIN:
+ val = CInt64_Neg(val);
+ flag = 1;
+ break;
+ }
+
+ if (flag) {
+ IRO_TruncateValueToType(&val, nd->rtype);
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = nd->rtype;
+ expr->data.intval = val;
+ }
+ }
+
+ if (expr) {
+ nd->u.monadic->type = IROLinearNop;
+ nd->type = IROLinearOperand;
+ nd->u.node = expr;
+ }
+ }
+ break;
+
+ case IROLinearOp2Arg:
+ if (IRO_IsIntConstant(nd->u.diadic.left) && !IRO_IsIntConstant(nd->u.diadic.right) && IsAssociativeENodeType[nd->nodetype]) {
+ IROLinear *tmp = nd->u.diadic.right;
+ nd->u.diadic.right = nd->u.diadic.left;
+ nd->u.diadic.left = tmp;
+ }
+
+ if (IRO_IsIntConstant(nd->u.diadic.right) && nd->nodetype == ESUB) {
+ nd->nodetype = EADD;
+ if (IRO_IsIntConstant(nd->u.diadic.right)) {
+ CInt64 v;
+ v = CInt64_Neg(nd->u.diadic.right->u.node->data.intval);
+ nd->u.diadic.right->u.node->data.intval = v;
+ } else {
+ Float f;
+ f = CMach_CalcFloatMonadic(
+ nd->u.diadic.right->rtype,
+ '-',
+ nd->u.diadic.right->u.node->data.floatval);
+ nd->u.diadic.right->u.node->data.floatval = f;
+ }
+ }
+
+ if (
+ IRO_IsIntConstant(nd->u.diadic.right) &&
+ IsAssociativeENodeType[nd->nodetype] &&
+ nd->u.diadic.left->type == IROLinearOp2Arg &&
+ nd->u.diadic.left->nodetype == nd->nodetype &&
+ nd->u.diadic.left->rtype == nd->rtype &&
+ IRO_IsIntConstant(nd->u.diadic.left->u.diadic.right) &&
+ nd->u.diadic.left->u.diadic.right->rtype == nd->u.diadic.right->rtype
+ )
+ {
+ IROLinear *tmp = nd->u.diadic.left;
+ nd->u.diadic.left = tmp->u.diadic.left;
+ tmp->u.diadic.left = tmp->u.diadic.right;
+ tmp->u.diadic.right = nd->u.diadic.right;
+ tmp->rtype = tmp->u.diadic.left->rtype;
+ nd->u.diadic.right = tmp;
+ nd = tmp;
+ }
+
+ if (IRO_IsIntConstant(nd->u.diadic.left) && IRO_IsIntConstant(nd->u.diadic.right)) {
+ CInt64 val1 = nd->u.diadic.left->u.node->data.intval;
+ CInt64 val2 = nd->u.diadic.right->u.node->data.intval;
+ flag = 0;
+ switch (nd->nodetype) {
+ case EADD:
+ val = CInt64_Add(val1, val2);
+ flag = 1;
+ break;
+ case ESUB:
+ val = CInt64_Sub(val1, val2);
+ flag = 1;
+ break;
+ case EMUL:
+ if (IRO_IsUnsignedType(nd->rtype))
+ val = CInt64_MulU(val1, val2);
+ else
+ val = CInt64_Mul(val1, val2);
+ flag = 1;
+ break;
+ case EDIV:
+ if (!CInt64_IsZero(&val2)) {
+ if (IRO_IsUnsignedType(nd->rtype))
+ val = CInt64_DivU(val1, val2);
+ else
+ val = CInt64_Div(val1, val2);
+ flag = 1;
+ }
+ break;
+ case EMODULO:
+ if (!CInt64_IsZero(&val2)) {
+ if (IRO_IsUnsignedType(nd->rtype))
+ val = CInt64_ModU(val1, val2);
+ else
+ val = CInt64_Mod(val1, val2);
+ flag = 1;
+ }
+ break;
+ case ESHL:
+ val = CInt64_Shl(val1, val2);
+ flag = 1;
+ break;
+ case ESHR:
+ if (IRO_IsUnsignedType(nd->rtype))
+ val = CInt64_ShrU(val1, val2);
+ else
+ val = CInt64_Shr(val1, val2);
+ flag = 1;
+ break;
+ case EAND:
+ val = CInt64_And(val1, val2);
+ flag = 1;
+ break;
+ case EOR:
+ val = CInt64_Or(val1, val2);
+ flag = 1;
+ break;
+ case EXOR:
+ val = CInt64_Xor(val1, val2);
+ flag = 1;
+ break;
+ case ELESS:
+ if (IRO_IsUnsignedType(nd->u.diadic.left->rtype))
+ CInt64_SetULong(&val, CInt64_LessU(val1, val2));
+ else
+ CInt64_SetULong(&val, CInt64_Less(val1, val2));
+ flag = 1;
+ break;
+ case EGREATER:
+ if (IRO_IsUnsignedType(nd->u.diadic.left->rtype))
+ CInt64_SetULong(&val, CInt64_GreaterU(val1, val2));
+ else
+ CInt64_SetULong(&val, CInt64_Greater(val1, val2));
+ flag = 1;
+ break;
+ case ELESSEQU:
+ if (IRO_IsUnsignedType(nd->u.diadic.left->rtype))
+ CInt64_SetULong(&val, CInt64_LessEqualU(val1, val2));
+ else
+ CInt64_SetULong(&val, CInt64_LessEqual(val1, val2));
+ flag = 1;
+ break;
+ case EGREATEREQU:
+ if (IRO_IsUnsignedType(nd->u.diadic.left->rtype))
+ CInt64_SetULong(&val, CInt64_GreaterEqualU(val1, val2));
+ else
+ CInt64_SetULong(&val, CInt64_GreaterEqual(val1, val2));
+ flag = 1;
+ break;
+ case EEQU:
+ CInt64_SetULong(&val, CInt64_Equal(val1, val2));
+ flag = 1;
+ break;
+ case ENOTEQU:
+ CInt64_SetULong(&val, CInt64_NotEqual(val1, val2));
+ flag = 1;
+ break;
+ }
+
+ if (flag) {
+ IRO_TruncateValueToType(&val, nd->rtype);
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = nd->rtype;
+ expr->data.intval = val;
+ nd->u.diadic.left->type = IROLinearNop;
+ nd->u.diadic.right->type = IROLinearNop;
+ nd->type = IROLinearOperand;
+ nd->u.node = expr;
+ }
+ }
+
+ if (IRO_IsFloatConstant(nd->u.diadic.left) && IRO_IsFloatConstant(nd->u.diadic.right)) {
+ Float fval1 = nd->u.diadic.left->u.node->data.floatval;
+ Float fval2 = nd->u.diadic.right->u.node->data.floatval;
+ Float fval;
+ flag = 0;
+ isCompare = 0;
+ switch (nd->nodetype) {
+ case EADD:
+ fval = CMach_CalcFloatDiadic(nd->rtype, fval1, '+', fval2);
+ flag = 1;
+ break;
+ case ESUB:
+ fval = CMach_CalcFloatDiadic(nd->rtype, fval1, '-', fval2);
+ flag = 1;
+ break;
+ case EMUL:
+ fval = CMach_CalcFloatDiadic(nd->rtype, fval1, '*', fval2);
+ flag = 1;
+ break;
+ case EDIV:
+ fval = CMach_CalcFloatDiadic(nd->rtype, fval1, '/', fval2);
+ flag = 1;
+ break;
+ case ELESS:
+ CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, '<', fval2));
+ flag = 1;
+ isCompare = 1;
+ break;
+ case EGREATER:
+ CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, '>', fval2));
+ flag = 1;
+ isCompare = 1;
+ break;
+ case ELESSEQU:
+ CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, TK_LESS_EQUAL, fval2));
+ flag = 1;
+ isCompare = 1;
+ break;
+ case EGREATEREQU:
+ CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, TK_GREATER_EQUAL, fval2));
+ flag = 1;
+ isCompare = 1;
+ break;
+ case EEQU:
+ CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, TK_LOGICAL_EQ, fval2));
+ flag = 1;
+ isCompare = 1;
+ break;
+ case ENOTEQU:
+ CInt64_SetULong(&val, CMach_CalcFloatDiadicBool(nd->rtype, fval1, TK_LOGICAL_NE, fval2));
+ flag = 1;
+ isCompare = 1;
+ break;
+ }
+
+ if (flag) {
+ if (isCompare) {
+ IRO_TruncateValueToType(&val, nd->rtype);
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = nd->rtype;
+ expr->data.intval = val;
+ nd->u.diadic.left->type = IROLinearNop;
+ nd->u.diadic.right->type = IROLinearNop;
+ nd->type = IROLinearOperand;
+ nd->u.node = expr;
+ } else {
+ expr = IRO_NewENode(EFLOATCONST);
+ expr->rtype = nd->rtype;
+ expr->data.floatval = fval;
+ nd->u.diadic.left->type = IROLinearNop;
+ nd->u.diadic.right->type = IROLinearNop;
+ nd->type = IROLinearOperand;
+ nd->u.node = expr;
+ }
+ }
+ }
+
+ break;
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+Boolean IRO_EvaluateConditionals(void) {
+ IRONode *fnode;
+ IROLinear *nd;
+ Boolean changed = 0;
+ SwitchInfo *switchInfo;
+ SwitchCase *swcase;
+ char found;
+ CInt64 val;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ nd = fnode->last;
+ switch (nd->type) {
+ case IROLinearIf:
+ case IROLinearIfNot:
+ if (IRO_IsIntConstant(nd->u.label.x4)) {
+ Boolean isZero = CInt64_IsZero(&nd->u.label.x4->u.node->data.intval);
+ IRO_NopOut(nd->u.label.x4);
+ if ((isZero == 0) == (nd->type == IROLinearIf))
+ nd->type = IROLinearGoto;
+ else
+ nd->type = IROLinearNop;
+ changed = 1;
+ }
+ break;
+
+ case IROLinearSwitch:
+ if (IRO_IsIntConstant(nd->u.swtch.x4)) {
+ val = nd->u.swtch.x4->u.node->data.intval;
+ switchInfo = nd->u.swtch.info;
+ swcase = switchInfo->cases;
+
+ IRO_NopOut(nd->u.swtch.x4);
+ nd->type = IROLinearGoto;
+
+ found = 0;
+ while (swcase) {
+ if (CInt64_GreaterEqual(val, swcase->min) && CInt64_LessEqual(val, swcase->max)) {
+ found = 1;
+ nd->u.label.label = swcase->label;
+ break;
+ }
+ swcase = swcase->next;
+ }
+
+ if (!found)
+ nd->u.label.label = switchInfo->defaultlabel;
+ changed = 1;
+ }
+ break;
+ }
+ }
+
+ if (changed) {
+ IRO_ComputeSuccPred();
+ IRO_ComputeDom();
+ }
+ IRO_CheckForUserBreak();
+
+ return changed;
+}
+
+static int EEquConst(IROLinear *nd) {
+ return nd && (nd->nodetype == EEQU) && IRO_IsIntConstant(nd->u.diadic.right);
+}
+
+static Object *VEquConst(IROLinear *nd) {
+ if (EEquConst(nd))
+ return IRO_IsVariable(nd->u.diadic.left);
+ else
+ return NULL;
+}
+
+static int IsConsecutive(CInt64 a, CInt64 b) {
+ CInt64 diff;
+
+ if (!CInt64_Equal(a, cint64_min) && !CInt64_Equal(b, cint64_min)) {
+ diff = CInt64_Sub(b, a);
+ return CInt64_Equal(diff, cint64_one) || CInt64_Equal(diff, cint64_negone);
+ }
+
+ return 0;
+}
+
+static IROLinear *findLabel(CLabel *label) {
+ IROLinear *nd;
+
+ for (nd = IRO_FirstLinear; nd; nd = nd->next) {
+ if (nd->type == IROLinearLabel && nd->u.label.label == label)
+ break;
+ }
+
+ return nd;
+}
+
+static IROLinear *leftLeaveOf(IROLinear *nd) {
+ switch (nd->type) {
+ case IROLinearOp1Arg:
+ return leftLeaveOf(nd->u.monadic);
+ case IROLinearOp2Arg:
+ return leftLeaveOf(nd->u.diadic.left);
+ case IROLinearOperand:
+ return nd;
+ default:
+ return NULL;
+ }
+}
+
+static int checkNode(IRONode *fnode) {
+ IROLinear *nd;
+
+ if (fnode->numpred <= 1) {
+ nd = fnode->first;
+ while (nd != fnode->last && (nd->type == IROLinearNop || nd->type == IROLinearLabel))
+ nd = nd->next;
+
+ if (nd == leftLeaveOf(fnode->last->u.label.x4))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int checkLabel(CLabel *label, IRONode *fnode) {
+ switch (fnode->last->type) {
+ case IROLinearIf:
+ if (label == fnode->last->u.label.label)
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+
+static Object *checkExpr(Object *a, IROLinear *nd) {
+ Object *b = VEquConst(nd);
+
+ if ((!a || a == b) && !IRO_HasSideEffect(nd))
+ return b;
+
+ return NULL;
+}
+
+static int checkStruct(IRONode *fnode1, IRONode *fnode2) {
+ CLabel *label;
+ Object *var;
+
+ if (fnode1 == fnode2)
+ return (int) checkExpr(NULL, fnode1->last->u.label.x4);
+
+ label = fnode1->last->u.label.label;
+ var = IRO_IsVariable(fnode1->last->u.label.x4->u.monadic);
+ return checkNode(fnode2) && checkLabel(label, fnode2) && checkExpr(var, fnode2->last->u.label.x4);
+}
+
+typedef struct ReduceInfo {
+ int x0;
+ int x4;
+ Object *x8;
+ IRONode *fnode;
+ struct ReduceInfo *next;
+ CInt64 val;
+} ReduceInfo;
+
+static int MarkPattern1(ReduceInfo *info1, ReduceInfo *info2, CInt64 *val) {
+ ReduceInfo *scan;
+
+ if (!info2)
+ return 0;
+
+ if (info2->x0)
+ return MarkPattern1(info1, info2->next, val);
+
+ for (scan = info1; scan; scan = scan->next) {
+ if (scan->x0 == 2) {
+ if (CInt64_Equal(info2->val, scan->val)) {
+ IRO_NopOut(scan->fnode->last);
+ IRO_NopOut(scan->fnode->last->u.label.x4); // right union?
+ scan->x0 = -1;
+ return MarkPattern1(info1, info2->next, val);
+ }
+
+ if (IsConsecutive(info2->val, scan->val)) {
+ info2->x0 = 2;
+ if (CInt64_Greater(*val, scan->val))
+ *val = scan->val;
+ if (CInt64_Greater(*val, info2->val))
+ *val = info2->val;
+ MarkPattern1(scan->next, info2, val);
+ MarkPattern1(info1, info1->next, val);
+ return 1;
+ }
+ }
+ }
+
+ return MarkPattern1(info1, info2->next, val);
+}
+
+static int DoReducible1(ReduceInfo *info, CInt64 val) {
+ ReduceInfo *last;
+ ReduceInfo *scan;
+ IROLinear *right;
+ IROLinear *left;
+ IROLinear *typconRight;
+ IROLinear *typconLeft;
+ IROLinear *cond;
+ int count;
+
+ count = 0;
+ for (scan = info; scan; scan = scan->next) {
+ if (scan->x0 == 2) {
+ last = scan;
+ count++;
+ }
+ }
+
+ if (!count)
+ return 0;
+
+ for (scan = info; scan != last; scan = scan->next) {
+ if (scan->x0 == 2) {
+ scan->x0 = -1;
+ IRO_NopOut(scan->fnode->last);
+ IRO_NopOut(scan->fnode->last->u.label.x4);
+ }
+ }
+
+ last->x0 = -1;
+
+ cond = last->fnode->last;
+ cond->u.label.x4->nodetype = ELESSEQU;
+ CInt64_SetULong(&cond->u.label.x4->u.diadic.right->u.node->data.intval, count - 1);
+
+ typconLeft = IRO_NewLinear(IROLinearOp1Arg);
+ typconLeft->nodetype = ETYPCON;
+ typconLeft->rtype = IRO_UnsignedType(cond->u.label.x4->u.diadic.left->rtype);
+ typconLeft->index = ++IRO_NumLinear;
+
+ typconRight = IRO_NewLinear(IROLinearOp1Arg);
+ *typconRight = *typconLeft;
+ typconRight->index = ++IRO_NumLinear;
+
+ left = IRO_NewLinear(IROLinearOp2Arg);
+ left->nodetype = EADD;
+ left->rtype = cond->u.label.x4->u.diadic.left->rtype;
+ left->index = ++IRO_NumLinear;
+
+ right = IRO_NewLinear(IROLinearOperand);
+ right->nodetype = EINTCONST;
+ right->rtype = cond->u.label.x4->u.diadic.left->rtype;
+ right->index = ++IRO_NumLinear;
+ right->u.node = IRO_NewENode(EINTCONST);
+ right->u.node->data.intval = CInt64_Neg(val);
+ right->u.node->rtype = right->rtype;
+
+ typconLeft->next = cond->u.label.x4->u.diadic.left->next;
+ cond->u.label.x4->u.diadic.left->next = right;
+ right->next = left;
+ left->next = typconLeft;
+
+ typconRight->next = cond->u.label.x4->u.diadic.right->next;
+ cond->u.label.x4->u.diadic.right->next = typconRight;
+
+ typconLeft->u.monadic = left;
+ left->u.diadic.left = cond->u.label.x4->u.diadic.left;
+ left->u.diadic.right = right;
+ cond->u.label.x4->u.diadic.left = typconLeft;
+ typconRight->u.monadic = cond->u.label.x4->u.diadic.right;
+ cond->u.label.x4->u.diadic.right = typconRight;
+
+ return count;
+};
+
+static int ReducePattern1(IRONode *startnode, IRONode *endnode) {
+ ReduceInfo *infos;
+ ReduceInfo *info;
+ int changed = 0;
+ int count;
+ IRONode *fnode;
+ int i;
+ int j;
+ CInt64 val;
+
+ if (startnode == endnode)
+ return 0;
+
+ count = 0;
+ for (fnode = startnode; fnode != endnode; fnode = fnode->nextnode)
+ count++;
+
+ infos = oalloc(sizeof(ReduceInfo) * ++count);
+
+ fnode = startnode;
+ for (i = 0; i < count; i++) {
+ infos[i].x0 = 0;
+ infos[i].x4 = 0;
+ infos[i].fnode = fnode;
+ infos[i].next = NULL;
+ infos[i].x8 = VEquConst(fnode->last->u.label.x4);
+ if (infos[i].x8) {
+ infos[i].val = fnode->last->u.label.x4->u.diadic.right->u.node->data.intval;
+ infos[i].x4 = 1;
+ }
+ fnode = fnode->nextnode;
+ }
+
+ for (j = 0; j < count; j++) {
+ if (infos[j].x4 == 1 && infos[j].x8) {
+ infos[j].x4 = -1;
+ info = &infos[j];
+ for (i = j + 1; i < count; i++) {
+ if (infos[j].x8 == infos[i].x8) {
+ info->next = &infos[i];
+ info = &infos[i];
+ infos[i].x4 = 0;
+ }
+ }
+ }
+ }
+
+ for (j = 0; j < count; j++) {
+ if (infos[j].x4 == -1) {
+ for (info = &infos[j]; info; info = info->next) {
+ if (info->x0 == 0) {
+ info->x0 = 2;
+ val = info->val;
+ if (MarkPattern1(&infos[j], info->next, &val)) {
+ changed = 1;
+ DoReducible1(&infos[j], val);
+ } else {
+ info->x0 = -1;
+ }
+ }
+ }
+ }
+ }
+
+ return changed;
+}
+
+static int ReduceConsecutiveIf(IRONode *startnode, IRONode *endnode) {
+ IRONode *node31;
+ IRONode *node30;
+ int changed = 0;
+
+ while (startnode != endnode) {
+ if (checkStruct(startnode, startnode))
+ break;
+ startnode = startnode->nextnode;
+ }
+
+ node31 = startnode;
+ if (startnode != endnode) {
+ node30 = startnode;
+ node31 = startnode->nextnode;
+ while (node31 != endnode) {
+ if (checkStruct(startnode, node31)) {
+ node30 = node31;
+ node31 = node31->nextnode;
+ } else {
+ node31 = node30;
+ break;
+ }
+ }
+
+ if (node31 == endnode && !checkStruct(startnode, node31))
+ node31 = node30;
+
+ if (startnode != node31 && ReducePattern1(startnode, node31))
+ changed = 1;
+
+ if (node31 != endnode)
+ node31 = node31->nextnode;
+ }
+
+ if (node31 != endnode && ReduceConsecutiveIf(node31, endnode))
+ changed = 1;
+
+ return changed;
+}
+
+int IRO_SimplifyConditionals(void) {
+ IRONode *fnode;
+ IRONode *start;
+ IRONode *end;
+ int changed = 0;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ if (fnode->last->type == IROLinearIf) {
+ start = end = fnode;
+ while (fnode->nextnode && fnode->nextnode->last->type == IROLinearIf) {
+ end = fnode = fnode->nextnode;
+ }
+ if (start != end && ReduceConsecutiveIf(start, end))
+ changed = 1;
+ }
+ }
+
+ if (changed) {
+ IRO_ComputeSuccPred();
+ IRO_ComputeDom();
+ }
+ IRO_CheckForUserBreak();
+ return changed;
+}
+
+Boolean IRO_EvaluateDefinitePointers(Object *func) {
+ IROLinear *nd;
+ Boolean result; // r29
+ Boolean changed; // r28
+ Boolean changed2; // r26
+ IROLinear *nd2; // r25
+ IROListNode *scan; // r25
+ IROListNode *list;
+
+ if (!copts.opt_pointer_analysis)
+ return 0;
+
+ result = 0;
+
+ do {
+ changed = 0;
+
+ for (nd = IRO_FirstLinear; nd; nd = nd->next) {
+ if (
+ nd->type == IROLinearOp1Arg &&
+ nd->nodetype == EINDIRECT &&
+ !(nd->flags & IROLF_Assigned) &&
+ nd->pointsToFunction &&
+ !IRO_HasSideEffect(nd) &&
+ PointerAnalysis_IsLinearNodePointerExprDefinite(func, nd)
+ )
+ {
+ list = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(func, nd, &list);
+ if (list) {
+ if (list->list.head && list->list.tail && !list->nextList) {
+ changed2 = IRO_LocateFather_Cut_And_Paste(nd, list->list.tail) != NULL;
+ if (changed2) {
+ IRO_PasteAfter(list->list.head, list->list.tail, nd);
+ for (nd2 = list->list.head; nd2 != list->list.tail->next; nd2 = nd2->next) {
+ if (nd2->type == IROLinearOperand && nd2->u.node->type == EOBJREF) {
+ if (nd2->u.node->data.objref->datatype == DDATA || nd2->u.node->data.objref->datatype == DLOCAL)
+ IRO_FindVar(nd2->u.node->data.objref, 1, 1);
+ else
+ nd2->u.node->data.objref->varptr = NULL;
+ }
+ }
+ }
+ changed |= changed2;
+ }
+
+ while (list) {
+ scan = list->nextList;
+ IRO_free(list);
+ list = scan;
+ }
+ }
+ }
+ }
+
+ result |= changed;
+ IRO_CheckForUserBreak();
+ } while (changed);
+
+ return result;
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroEval.h b/compiler_and_linker/FrontEnd/Optimizer/IroEval.h
new file mode 100644
index 0000000..3b91f21
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroEval.h
@@ -0,0 +1,14 @@
+#ifndef COMPILER_IROEVAL_H
+#define COMPILER_IROEVAL_H
+
+#include "IrOptimizer.h"
+
+extern void IRO_InitializeIsAssociativeENodeTypeArray(void);
+extern void IRO_TruncateValueToType(CInt64 *val, Type *type);
+extern void IRO_TruncateBitfieldValueToType(CInt64 *val, Type *type, Type *type2);
+extern void IRO_ConstantFolding(void);
+extern Boolean IRO_EvaluateConditionals(void);
+extern int IRO_SimplifyConditionals(void);
+extern Boolean IRO_EvaluateDefinitePointers(Object *func);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.c b/compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.c
new file mode 100644
index 0000000..c56beae
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.c
@@ -0,0 +1,1531 @@
+#include "IroExprRegeneration.h"
+#include "IroCSE.h"
+#include "IroDump.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroSubable.h"
+#include "IroTransform.h"
+#include "IROUseDef.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/CDecl.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/objects.h"
+
+// forward decls
+static void GetExprUses(IROLinear *linear, Boolean isEntry);
+static void RebuildPossibleCondExpression(IRONode *fnode);
+static void AddNodeAndSuccessorsRecursively(IRONodes *nodes, IRONode *fnode1, IRONode *fnode2);
+
+static Boolean FindFlowgraphNodeThatStartsWithLabel(CLabel *label, IRONode **result1, IRONode **result2) {
+ IRONode *prev;
+ IRONode *iter;
+
+ prev = IRO_FirstNode;
+ if (prev != NULL)
+ iter = prev->nextnode;
+
+ while (iter) {
+ if (iter->first->type == IROLinearLabel && iter->first->u.label.label == label) {
+ *result1 = iter;
+ *result2 = prev;
+ return 1;
+ }
+
+ prev = iter;
+ iter = iter->nextnode;
+ }
+
+ return 0;
+}
+
+static IROLinear *FindLastDiadicTopLevelAssignmentInFlowgraphNode(IRONode *fnode) {
+ IROLinear *scan;
+ IROLinear *result;
+
+ result = NULL;
+
+ for (scan = fnode->first; scan != fnode->last->next; scan = scan->next) {
+ if (scan->type == IROLinearOp2Arg && scan->nodetype == EASS && !(scan->flags & IROLF_Reffed))
+ result = scan;
+ }
+
+ return result;
+}
+
+static Boolean RewriteUse(IROUse *use, ENode *enode, IROLinear *nd, Boolean flag) {
+ IROLinear *father;
+ IROLinear *father2;
+
+ if (
+ use &&
+ use->x1C &&
+ use->linear &&
+ use->linear->type == IROLinearOperand &&
+ use->linear->u.node->type == EOBJREF &&
+ use->linear->u.node->data.objref == enode->data.objref &&
+ (father = IRO_LocateFather(use->linear)) &&
+ father->type == IROLinearOp1Arg &&
+ father->nodetype == EINDIRECT &&
+ father->rtype == nd->rtype &&
+ (father2 = IRO_LocateFather(father)) &&
+ ((father2->type != IROLinearOp1Arg && father2->type != IROLinearOp2Arg) || !IRO_IsModifyOp[father2->nodetype])
+ ) {
+ if (flag)
+ IRO_LocateFather_Cut_And_Paste(father, nd);
+ return 1;
+ }
+
+ return 0;
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+static struct {
+ jmp_buf buf;
+ UInt16 index;
+ Boolean flag;
+} scuai;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void StatementContainsUseAction(IROLinear *linear, Boolean isFirst) {
+ if (isFirst && linear->index == scuai.index) {
+ scuai.flag = 1;
+ longjmp(scuai.buf, 1);
+ }
+}
+
+static Boolean StatementContainsUse(IROLinear *a, IROLinear *b) {
+ memset(&scuai, 0, sizeof(scuai));
+ scuai.index = b->index;
+ scuai.flag = 0;
+
+ if (!setjmp(scuai.buf))
+ IRO_WalkInts(a, a, StatementContainsUseAction);
+
+ return scuai.flag;
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+static struct {
+ jmp_buf buf;
+ Boolean flag;
+} scseai;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void StatementContainsSideEffectAction(IROLinear *linear, Boolean isFirst) {
+ if (isFirst) {
+ switch (linear->type) {
+ case IROLinearOperand:
+ case IROLinearOp1Arg:
+ case IROLinearOp2Arg:
+ case IROLinearOp3Arg:
+ case IROLinearFunccall:
+ case IROLinearAsm:
+ if (IRO_HasSideEffect(linear)) {
+ scseai.flag = 1;
+ longjmp(scseai.buf, 1);
+ }
+ break;
+ }
+ }
+}
+
+static Boolean StatementContainsSideEffect(IROLinear *linear) {
+ memset(&scseai, 0, sizeof(scseai));
+ scseai.flag = 0;
+
+ if (!setjmp(scseai.buf))
+ IRO_WalkInts(linear, linear, StatementContainsSideEffectAction);
+
+ return scseai.flag;
+}
+
+static Boolean HasSideEffectsBeforeUse(IRONode *fnode1, IRONode *fnode2, IRONode *fnode3, IROLinear *nd, Boolean flag) {
+ IRONode *fnode;
+ IROLinear *scannd;
+ UInt16 i;
+
+ if (fnode1 != fnode3) {
+ if (flag) {
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode)
+ fnode->x3C = 0;
+ } else if (fnode1->x3C) {
+ return 0;
+ }
+ fnode1->x3C = 1;
+ }
+
+ for (scannd = fnode1->first; scannd && scannd != fnode1->last->next; scannd = scannd->next) {
+ if (!(scannd->flags & IROLF_Reffed)) {
+ if (StatementContainsUse(scannd, nd))
+ return 0;
+ if (StatementContainsSideEffect(scannd))
+ return 1;
+ }
+ }
+
+ if (fnode1 != fnode3) {
+ for (i = 0; i < fnode1->numsucc; i++) {
+ if (HasSideEffectsBeforeUse(IRO_NodeTable[fnode1->succ[i]], fnode2, fnode3, nd, 0))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static Boolean UsesAKilledVarBeforeUse(IRONode *fnode1, IRONode *fnode2, IRONode *fnode3, IROLinear *nd, BitVector *bv, Boolean flag) {
+ IRONode *fnode;
+ UInt16 i;
+ IROLinear *scannd;
+
+ if (fnode1 != fnode3) {
+ if (flag) {
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode)
+ fnode->x3C = 0;
+ } else if (fnode1->x3C) {
+ return 0;
+ }
+ fnode1->x3C = 1;
+ }
+
+ for (scannd = fnode1->first; scannd && scannd != fnode1->last->next; scannd = scannd->next) {
+ if (!(scannd->flags & IROLF_Reffed)) {
+ if (StatementContainsUse(scannd, nd))
+ return 0;
+ Bv_Clear(IRO_VarKills);
+ IRO_WalkInts(scannd, scannd, GetExprUses);
+ if (Bv_BitsInCommon(bv, IRO_VarKills))
+ return 1;
+ }
+ }
+
+ if (fnode1 != fnode3) {
+ for (i = 0; i < fnode1->numsucc; i++) {
+ if (UsesAKilledVarBeforeUse(IRO_NodeTable[fnode1->succ[i]], fnode2, fnode3, nd, bv, 0))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void GetExprUses(IROLinear *linear, Boolean isEntry) {
+ Object *obj;
+ VarRecord *var;
+
+ if (isEntry) {
+ if (linear->type == IROLinearOperand && linear->u.node->type == EOBJREF) {
+ obj = linear->u.node->data.objref;
+ if ((linear->flags & IROLF_Ind) && (!(linear->flags & IROLF_Assigned) || (linear->flags & IROLF_Used))) {
+ if ((var = IRO_FindVar(obj, 0, 1)))
+ Bv_SetBit(var->index, IRO_VarKills);
+ }
+ }
+ }
+}
+
+static void GetExprKills(IROLinear *linear, Boolean isEntry) {
+ if (isEntry)
+ IRO_GetKills(linear);
+}
+
+static void CheckUnorderedRegionForSideEffectsAndUses(IROLinear *nd, BitVector *bv1, BitVector *bv2, Boolean *result) {
+ if (IRO_HasSideEffect(nd)) {
+ *result = 1;
+ } else {
+ Bv_Clear(bv2);
+ Bv_Clear(IRO_VarKills);
+ IRO_WalkTree(nd, GetExprUses);
+ Bv_Or(IRO_VarKills, bv2);
+
+ if (Bv_BitsInCommon(bv1, bv2))
+ *result = 1;
+ }
+}
+
+static void CheckUnorderedRegionsForSideEffectsAndUses(IROLinear *nd1, IROLinear *nd2, BitVector *bv1, BitVector *bv2, Boolean *result) {
+ int i;
+
+ switch (nd1->type) {
+ case IROLinearOp2Arg:
+ if (nd1->nodetype != ELAND && nd1->nodetype != ELOR && nd1->nodetype != ECOMMA) {
+ if (nd1->u.diadic.left != nd2)
+ CheckUnorderedRegionForSideEffectsAndUses(nd1->u.diadic.left, bv1, bv2, result);
+ if (nd1->u.diadic.right != nd2)
+ CheckUnorderedRegionForSideEffectsAndUses(nd1->u.diadic.right, bv1, bv2, result);
+ }
+ break;
+ case IROLinearFunccall:
+ if (nd1->u.funccall.linear8 != nd2)
+ CheckUnorderedRegionForSideEffectsAndUses(nd1->u.funccall.linear8, bv1, bv2, result);
+ for (i = 0; !*result && i < nd1->u.funccall.argCount; i++) {
+ if (nd1->u.funccall.args[i] != nd2)
+ CheckUnorderedRegionForSideEffectsAndUses(nd1->u.funccall.args[i], bv1, bv2, result);
+ }
+ break;
+ }
+}
+
+static Boolean CheckThenOrElseBranch(IRONode *fnode1, IRONode *fnode2, IROLinear *nd, Boolean flag) {
+ IRONode *fnode;
+ IROLinear *scannd;
+ IRONodes nodes;
+ Boolean result;
+
+ IROFlowgraph_sub_4C2140(&nodes);
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode)
+ fnode->x3C = 0;
+ AddNodeAndSuccessorsRecursively(&nodes, fnode1, fnode2);
+
+ while (IROFlowgraph_sub_4C2040(&nodes)) {
+ fnode = IRO_NodeTable[IROFlowgraph_sub_4C2100(&nodes)];
+ if (fnode) {
+ if (!Bv_IsBitSet(fnode1->index, fnode->dom)) {
+ result = 0;
+ goto done;
+ }
+
+ for (scannd = fnode->first; scannd && scannd != fnode->last->next; scannd = scannd->next) {
+ if (!nd || scannd != nd) {
+ if (!flag || (scannd->type != IROLinearReturn)) {
+ if (fnode->numpred == 2 && scannd->type == IROLinearLabel)
+ RebuildPossibleCondExpression(fnode);
+
+ if (scannd->type != IROLinearNop &&
+ scannd->type != IROLinearLabel &&
+ scannd->type != IROLinearGoto &&
+ !(scannd->flags & IROLF_Reffed)) {
+ result = 0;
+ goto done;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = 1;
+done:
+ IROFlowgraph_sub_4C20E0(&nodes);
+ return result;
+}
+
+static void RebuildPossibleCondExpression(IRONode *fnode) {
+ IRONode *pred1;
+ IRONode *pred2;
+ IRONode *r30;
+ IROLinear *leftAss;
+ IROLinear *rightAss;
+ IROLinear *r27;
+ IROLinear *r13;
+ IROLinear *var_58;
+ IRONode *left;
+ IRONode *right;
+ IRONode *r24;
+ ENode *r23;
+ IRODef *r22;
+ IRODef *r21;
+ IRODef *def;
+ IROUse *use;
+ UInt32 r20;
+ UInt32 r19;
+ Boolean r18;
+ Boolean r17;
+ UInt32 i;
+ Boolean compareType;
+ Type *var_60;
+ IROLinear copy1;
+ IROLinear copy2;
+ IROLinear copy3;
+
+ if (
+ !fnode ||
+ fnode->numpred != 2 ||
+ !fnode->first ||
+ fnode->first->type != IROLinearLabel
+ )
+ return;
+
+ pred1 = IRO_NodeTable[fnode->pred[0]];
+ pred2 = IRO_NodeTable[fnode->pred[1]];
+ if (
+ !pred1 || !pred2 ||
+ pred1->numsucc != 1 || pred2->numsucc != 1
+ )
+ return;
+
+ r24 = NULL;
+ for (i = 0; i < IRO_NumNodes; i++) {
+ if (
+ Bv_IsBitSet(i, fnode->dom) &&
+ (r24 = IRO_NodeTable[i]) &&
+ r24->last &&
+ (r24->last->type == IROLinearIf || r24->last->type == IROLinearIfNot) &&
+ r24->last->u.label.label &&
+ r24->numsucc == 2
+ ) {
+ if (Bv_IsBitSet(r24->succ[0], pred1->dom) &&
+ !Bv_IsBitSet(r24->succ[0], pred2->dom) &&
+ Bv_IsBitSet(r24->succ[1], pred2->dom) &&
+ !Bv_IsBitSet(r24->succ[1], pred1->dom))
+ break;
+
+ if (Bv_IsBitSet(r24->succ[0], pred2->dom) &&
+ !Bv_IsBitSet(r24->succ[0], pred1->dom) &&
+ Bv_IsBitSet(r24->succ[1], pred1->dom) &&
+ !Bv_IsBitSet(r24->succ[1], pred2->dom))
+ break;
+ }
+ }
+
+ if (i >= IRO_NumNodes)
+ return;
+
+ /*if (
+ (r30 = IRO_NodeTable[r24->succ[0]]) &&
+ r30->numpred == 1 &&
+ r30->first &&
+ r30->first->type == IROLinearLabel &&
+ r30->first->u.label.label == r24->last->u.label.label
+ ) {
+ goto ok;
+ } else if (
+ (r30 = IRO_NodeTable[r24->succ[1]]) &&
+ r30->numpred == 1 &&
+ r30->first &&
+ r30->first->type == IROLinearLabel &&
+ r30->first->u.label.label == r24->last->u.label.label
+ ) {
+ goto ok;
+ } else {
+ return;
+ }*/
+ /*if (
+ (!(r30 = IRO_NodeTable[r24->succ[0]]) ||
+ r30->numpred != 1 ||
+ !r30->first ||
+ r30->first->type != IROLinearLabel ||
+ r30->first->u.label.label != r24->last->u.label.label)
+ &&
+ (!(r30 = IRO_NodeTable[r24->succ[1]]) ||
+ r30->numpred != 1 ||
+ !r30->first ||
+ r30->first->type != IROLinearLabel ||
+ r30->first->u.label.label != r24->last->u.label.label)
+ )
+ return;*/
+ r30 = IRO_NodeTable[r24->succ[0]];
+ if (
+ r30 &&
+ r30->numpred == 1 &&
+ r30->first &&
+ r30->first->type == IROLinearLabel &&
+ r30->first->u.label.label == r24->last->u.label.label
+ ) {
+ (void)0;
+ } else {
+ r30 = IRO_NodeTable[r24->succ[1]];
+ if (
+ r30 &&
+ r30->numpred == 1 &&
+ r30->first &&
+ r30->first->type == IROLinearLabel &&
+ r30->first->u.label.label == r24->last->u.label.label
+ ) {
+ } else {
+ return;
+ }
+ }
+
+ok:
+ if (Bv_IsBitSet(r30->index, pred1->dom)) {
+ left = pred2;
+ right = pred1;
+ } else {
+ left = pred1;
+ right = pred2;
+ }
+
+ leftAss = FindLastDiadicTopLevelAssignmentInFlowgraphNode(left);
+ if (
+ !leftAss ||
+ leftAss->type != IROLinearOp2Arg ||
+ !leftAss->u.diadic.left ||
+ leftAss->u.diadic.left->type != IROLinearOp1Arg ||
+ leftAss->u.diadic.left->nodetype != EINDIRECT ||
+ !leftAss->u.diadic.left->u.monadic ||
+ leftAss->u.diadic.left->u.monadic->type != IROLinearOperand ||
+ !(r23 = leftAss->u.diadic.left->u.monadic->u.node) ||
+ !r23->rtype ||
+ !IS_TYPE_POINTER_ONLY(r23->rtype) ||
+ !r23->data.objref ||
+ is_volatile_object(r23->data.objref) ||
+ r23->data.objref->datatype != DLOCAL
+ )
+ r23 = NULL;
+
+ if (r23) {
+ rightAss = FindLastDiadicTopLevelAssignmentInFlowgraphNode(right);
+ if (
+ !rightAss ||
+ rightAss->type != IROLinearOp2Arg ||
+ !rightAss->u.diadic.left ||
+ rightAss->u.diadic.left->type != IROLinearOp1Arg ||
+ rightAss->u.diadic.left->nodetype != EINDIRECT ||
+ !rightAss->u.diadic.left->u.monadic ||
+ rightAss->u.diadic.left->u.monadic->type != IROLinearOperand ||
+ !rightAss->u.diadic.left->u.monadic->u.node ||
+ !rightAss->u.diadic.left->u.monadic->u.node->rtype ||
+ !IS_TYPE_POINTER_ONLY(rightAss->u.diadic.left->u.monadic->u.node->rtype) ||
+ rightAss->u.diadic.left->u.monadic->u.node->type != EOBJREF ||
+ rightAss->u.diadic.left->u.monadic->u.node->data.objref != r23->data.objref ||
+ rightAss->rtype != leftAss->rtype
+ )
+ r23 = NULL;
+ }
+
+ if (r23) {
+ if (!CheckThenOrElseBranch(r24->nextnode, left, leftAss, 0) || !CheckThenOrElseBranch(r30, right, rightAss, 0))
+ return;
+
+ r19 = 0;
+ r20 = 0;
+ r18 = 0;
+ r17 = 0;
+ if (!r23->data.objref->varptr || !r23->data.objref->varptr->uses || !r23->data.objref->varptr->defs) {
+ r23 = NULL;
+ } else {
+ r21 = NULL;
+ r22 = NULL;
+ for (def = r23->data.objref->varptr->defs; def && (!r22 || !r21); def = def->varnext) {
+ if (def->x18 && def->linear == leftAss)
+ r22 = def;
+ else if (def->x18 && def->linear == rightAss)
+ r21 = def;
+ }
+
+ if (!r22 || !r21) {
+ r23 = NULL;
+ } else {
+ for (use = r23->data.objref->varptr->uses; r23 && use; use = use->varnext) {
+ if (use->x1C) {
+ r20++;
+ if (Bv_IsBitSet(r22->index, use->x18) && Bv_IsBitSet(r21->index, use->x18)) {
+ for (i = 0; r23 && i < use->x18->size; i++) {
+ if (i != r22->index && i != r21->index && Bv_IsBitSet(i, use->x18))
+ r23 = NULL;
+ }
+
+ if (r23 && !Bv_IsBitSet(fnode->index, use->node->dom))
+ r23 = NULL;
+
+ if (r23) {
+ if (RewriteUse(use, r23, rightAss, 0))
+ r19++;
+ else
+ r23 = NULL;
+ }
+
+ if (r23 && !r17)
+ r17 = HasSideEffectsBeforeUse(fnode, fnode, use->node, use->linear, 1);
+
+ if (r23 && !r18 && (IRO_HasSideEffect(r24->last->u.label.x4) || IRO_HasSideEffect(leftAss->u.label.x4) ||
+ IRO_HasSideEffect(rightAss->u.label.x4)))
+ r18 = 1;
+ } else if (Bv_IsBitSet(r22->index, use->x18) || Bv_IsBitSet(r21->index, use->x18)) {
+ r23 = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!r23)
+ return;
+
+ compareType = r24->last->type == IROLinearIf;
+ r27 = r24->last->u.label.x4;
+ r13 = leftAss->u.label.x4;
+ var_58 = rightAss->u.label.x4;
+ var_60 = rightAss->rtype;
+ memcpy(&copy1, r13, sizeof(IROLinear));
+ memcpy(&copy2, rightAss, sizeof(IROLinear));
+
+ r24->last->type = IROLinearNop;
+ r24->last->expr = NULL;
+ r30->first->type = IROLinearNop;
+ r30->first->expr = NULL;
+ fnode->first->type = IROLinearNop;
+ fnode->first->expr = NULL;
+ if (left->last->type == IROLinearGoto) {
+ left->last->type = IROLinearNop;
+ left->last->expr = NULL;
+ }
+ if (right->last->type == IROLinearGoto) {
+ right->last->type = IROLinearNop;
+ right->last->expr = NULL;
+ }
+
+ if (r23) {
+ IRO_NopOut(leftAss->u.diadic.left);
+ leftAss->type = IROLinearNop;
+ leftAss->expr = NULL;
+ }
+
+ memcpy(rightAss, &copy1, sizeof(IROLinear));
+ rightAss->type = IROLinearOp3Arg;
+ rightAss->nodetype = ECOND;
+ rightAss->index = copy2.index;
+ rightAss->u.args3.a = r27;
+ rightAss->rtype = var_60;
+ rightAss->next = copy2.next;
+ if (compareType) {
+ rightAss->u.args3.b = var_58;
+ rightAss->u.args3.c = r13;
+ } else {
+ rightAss->u.args3.b = r13;
+ rightAss->u.args3.c = var_58;
+ }
+ rightAss->flags |= IROLF_Reffed;
+
+ if (r19 == 1 && !r17 && !r18 && !r23->data.objref->varptr->xB) {
+ for (use = r23->data.objref->varptr->uses; use; use = use->varnext) {
+ if (use->x1C && Bv_IsBitSet(r22->index, use->x18) && Bv_IsBitSet(r21->index, use->x18)) {
+ RewriteUse(use, r23, rightAss, 1);
+ if ((r18 = (use->linear->flags & IROLF_4000) && IRO_HasSideEffect(r27))) {
+ IROLinear *tmp;
+ Object *obj;
+
+ tmp = IRO_NewLinear(IROLinearOperand);
+ memcpy(tmp, copy2.u.diadic.left->u.monadic, sizeof(IROLinear));
+ tmp->index = IRO_NumLinear++;
+ tmp->rtype = r27->rtype;
+ if (r20 == 1) {
+ tmp->u.node->data.objref->type = r27->rtype;
+ tmp->u.node->rtype = CDecl_NewPointerType(r27->rtype);
+ } else {
+ obj = create_temp_object(tmp->rtype);
+ IRO_FindVar(obj, 1, 1);
+ tmp->u.node = create_objectrefnode(obj);
+ }
+ IRO_PasteAfter(tmp, tmp, r27);
+
+ tmp = IRO_NewLinear(IROLinearOp1Arg);
+ memcpy(tmp, copy2.u.diadic.left, sizeof(IROLinear));
+ tmp->index = IRO_NumLinear++;
+ tmp->u.monadic = r27->next;
+ tmp->rtype = r27->rtype;
+ IRO_PasteAfter(tmp, tmp, r27->next);
+
+ tmp = IRO_NewLinear(IROLinearOp2Arg);
+ memcpy(tmp, &copy2, sizeof(IROLinear));
+ tmp->index = IRO_NumLinear++;
+ tmp->u.diadic.right = r27;
+ tmp->u.diadic.left = r27->next->next;
+ tmp->rtype = r27->rtype;
+ IRO_PasteAfter(tmp, tmp, r27->next->next);
+
+ if (r20 != 1) {
+ tmp = copy2.u.diadic.left->u.monadic;
+ tmp->u.node = create_objectrefnode(obj);
+ }
+
+ rightAss->u.args3.a = copy2.u.diadic.left;
+ rightAss->u.args3.a->rtype = r27->rtype;
+
+ if (r20 == 1) {
+ r21->linear = r27->next->next;
+ if (Bv_IsBitSet(r21->index, right->x1A)) {
+ Bv_ClearBit(r21->index, right->x1A);
+ Bv_SetBit(r21->index, r24->x1A);
+ }
+ if (Bv_IsBitSet(r21->index, right->x1E)) {
+ Bv_ClearBit(r21->index, right->x1E);
+ Bv_SetBit(r21->index, r24->x1E);
+ }
+ if (Bv_IsBitSet(r21->index, right->x22)) {
+ Bv_ClearBit(r21->index, right->x22);
+ Bv_SetBit(r21->index, r24->x22);
+ }
+ }
+ }
+ }
+ }
+
+ if (!r18) {
+ if (r20 == 1 && r23->data.objref->u.var.info) {
+ r23->data.objref->u.var.info->usage = 0;
+ r23->data.objref->u.var.info->used = 0;
+ }
+ r22->x18 = 0;
+ IRO_NopOut(copy2.u.diadic.left);
+ r21->x18 = 0;
+ }
+ } else {
+ memcpy(&copy3, fnode->first, sizeof(IROLinear));
+ memcpy(fnode->first, &copy2, sizeof(IROLinear));
+
+ fnode->first->index = copy3.index;
+ fnode->first->u.diadic.right = rightAss;
+ fnode->first->next = copy3.next;
+ r22->x18 = 0;
+ r21->linear = fnode->first;
+ if (Bv_IsBitSet(r21->index, right->x1A)) {
+ Bv_ClearBit(r21->index, right->x1A);
+ Bv_SetBit(r21->index, fnode->x1A);
+ }
+ if (Bv_IsBitSet(r21->index, right->x1E)) {
+ Bv_ClearBit(r21->index, right->x1E);
+ Bv_SetBit(r21->index, fnode->x1E);
+ }
+ if (Bv_IsBitSet(r21->index, right->x22)) {
+ Bv_ClearBit(r21->index, right->x22);
+ Bv_SetBit(r21->index, fnode->x22);
+ }
+ }
+}
+
+static void RebuildPossibleReturnCondExpression(IRONode *fnode) {
+ IRONode *succ1;
+ IRONode *succ2;
+ IROLinear *node1;
+ IROLinear *node2;
+ IROLinear *node3;
+ IRONode *r27;
+ Boolean isIf;
+ Type *type;
+ IROList list;
+
+ if (
+ !fnode ||
+ fnode->numsucc != 2 ||
+ !fnode->last ||
+ (fnode->last->type != IROLinearIf && fnode->last->type != IROLinearIfNot)
+ )
+ return;
+
+ succ1 = IRO_NodeTable[fnode->succ[0]];
+ succ2 = IRO_NodeTable[fnode->succ[1]];
+ if (
+ !succ1 || !succ2 ||
+ succ1->numsucc != 0 || succ1->numpred != 1 ||
+ succ2->numsucc != 0 || succ2->numpred != 1
+ )
+ return;
+
+ if (succ1->first && succ1->first->type == IROLinearLabel && succ1->first->u.label.label == fnode->last->u.label.label) {
+ r27 = succ1;
+ } else if (succ2->first && succ2->first->type == IROLinearLabel && succ2->first->u.label.label == fnode->last->u.label.label) {
+ r27 = succ2;
+ } else {
+ return;
+ }
+
+ if (r27->numpred != 1)
+ return;
+
+ if (!CheckThenOrElseBranch(fnode->nextnode, fnode->nextnode, NULL, 1) || !CheckThenOrElseBranch(r27, r27, NULL, 1))
+ return;
+
+ if (
+ !fnode->nextnode->last ||
+ fnode->nextnode->last->type != IROLinearReturn ||
+ !fnode->nextnode->last->u.monadic ||
+ !r27->last ||
+ r27->last->type != IROLinearReturn ||
+ !r27->last->u.monadic ||
+ !IRO_TypesEqual(fnode->nextnode->last->u.monadic->rtype, r27->last->u.monadic->rtype)
+ )
+ return;
+
+ isIf = fnode->last->type == IROLinearIf;
+ node1 = fnode->last->u.diadic.right;
+ node2 = fnode->nextnode->last->u.diadic.left;
+ node3 = r27->last->u.diadic.left;
+ type = node2->rtype;
+
+ fnode->last->type = IROLinearNop;
+ fnode->last->expr = NULL;
+ r27->last->type = IROLinearNop;
+ r27->last->expr = NULL;
+ r27->first->type = IROLinearNop;
+ r27->first->expr = NULL;
+
+ if (IRO_IsIntConstant(node2) && IRO_IsIntConstant(node3) &&
+ ((IRO_IsConstantOne(node2) && IRO_IsConstantZero(node3)) ||
+ (IRO_IsConstantZero(node2) && IRO_IsConstantOne(node3)))) {
+ if (!(node1->type == IROLinearOp1Arg && node1->nodetype == ELOGNOT && node1->rtype == type)) {
+ IROLinear *tmp1;
+ IROLinear *tmp2;
+
+ tmp1 = IRO_NewLinear(IROLinearOp1Arg);
+ memcpy(tmp1, node2, sizeof(IROLinear));
+ tmp1->type = IROLinearOp1Arg;
+ tmp1->nodetype = ELOGNOT;
+ tmp1->index = IRO_NumLinear++;
+ tmp1->u.monadic = node1;
+
+ tmp1->next = tmp2 = IRO_NewLinear(IROLinearOp1Arg);
+ memcpy(tmp2, node2, sizeof(IROLinear));
+ tmp2->type = IROLinearOp1Arg;
+ tmp2->nodetype = ELOGNOT;
+ tmp2->index = IRO_NumLinear++;
+ tmp2->u.monadic = tmp1;
+
+ IRO_PasteAfter(tmp1, tmp2, node1);
+ node1 = tmp2;
+ }
+
+ if ((IRO_IsConstantZero(node2) && !isIf) || (IRO_IsConstantOne(node2) && isIf)) {
+ if (node1->type == IROLinearOp1Arg && node1->nodetype == ELOGNOT && node1->rtype == node1->u.monadic->rtype) {
+ IROLinear *tmp = node1;
+ node1 = node1->u.monadic;
+ tmp->type = IROLinearNop;
+ tmp->expr = NULL;
+ } else {
+ IROLinear *tmp = IRO_NewLinear(IROLinearOp1Arg);
+ memcpy(tmp, node2, sizeof(IROLinear));
+ tmp->type = IROLinearOp1Arg;
+ tmp->nodetype = ELOGNOT;
+ tmp->index = IRO_NumLinear++;
+ tmp->u.monadic = node1;
+ IRO_PasteAfter(tmp, tmp, node1);
+ node1 = tmp;
+ }
+ }
+
+ node2->type = IROLinearNop;
+ node2->expr = NULL;
+ node3->type = IROLinearNop;
+ node3->expr = NULL;
+ fnode->nextnode->last->u.monadic = node1;
+ } else {
+ IROLinear *tmp1;
+ IROLinear *tmp2;
+
+ IRO_InitList(&list);
+ tmp1 = IRO_DuplicateExpr(node3, &list);
+ IRO_NopOut(node3);
+ IRO_Paste(list.head, list.tail, fnode->nextnode->last);
+
+ tmp2 = IRO_NewLinear(IROLinearOp3Arg);
+ memcpy(tmp2, node2, sizeof(IROLinear));
+ tmp2->type = IROLinearOp3Arg;
+ tmp2->nodetype = ECOND;
+ tmp2->index = IRO_NumLinear++;
+ tmp2->u.args3.a = node1;
+ tmp2->rtype = type;
+ IRO_Paste(tmp2, tmp2, fnode->nextnode->last);
+
+ if (isIf) {
+ tmp2->u.args3.b = tmp1;
+ tmp2->u.args3.c = node2;
+ } else {
+ tmp2->u.args3.b = node2;
+ tmp2->u.args3.c = tmp1;
+ }
+
+ fnode->nextnode->last->u.monadic = tmp2;
+ }
+}
+
+static void RebuildCondExpressions(void) {
+ IRONode *fnode;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ if (fnode->numpred == 2) {
+ if (fnode->first && fnode->first->type == IROLinearLabel)
+ RebuildPossibleCondExpression(fnode);
+ } else if (fnode->numsucc == 2) {
+ if (fnode->last && (fnode->last->type == IROLinearIf || fnode->last->type == IROLinearIfNot))
+ RebuildPossibleReturnCondExpression(fnode);
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+static Boolean IsLogicalExpressionAssign(IROLinear *nd) {
+ IROLinear *right;
+ IROLinear *left;
+
+ return (
+ nd->type == IROLinearOp2Arg &&
+ nd->nodetype == EASS &&
+ (left = nd->u.diadic.left) &&
+ (right = nd->u.diadic.right) &&
+ right->type == IROLinearOperand &&
+ right->u.node &&
+ right->u.node->type == EINTCONST &&
+ (CInt64_Equal(right->u.node->data.intval, cint64_one) || CInt64_Equal(right->u.node->data.intval, cint64_zero)) &&
+ left->type == IROLinearOp1Arg &&
+ left->nodetype == EINDIRECT &&
+ left->u.monadic &&
+ IS_TYPE_POINTER_ONLY(left->u.monadic->rtype) &&
+ left->u.monadic->type == IROLinearOperand &&
+ left->u.monadic->u.node &&
+ left->u.monadic->u.node->type == EOBJREF &&
+ left->u.monadic->u.node->data.objref &&
+ left->u.monadic->u.node->data.objref->datatype == DLOCAL);
+}
+
+static Boolean IsPossibleLogicalExpressionStart(IRONode *fnode, IROLinear *nd) {
+ return
+ fnode->numsucc == 2 &&
+ fnode->last &&
+ (fnode->last->type == IROLinearIf || fnode->last->type == IROLinearIfNot) &&
+ IsLogicalExpressionAssign(nd);
+}
+
+static Boolean CheckForTopLevelExpressions(IRONode *fnode1, IRONode *fnode2, IRONode *fnode3, IROLinear *nd1, IROLinear *nd2, Boolean flag) {
+ IRONode *fnode;
+ IROLinear *nd;
+ UInt16 i;
+
+ if (fnode1 != fnode3) {
+ if (!Bv_IsBitSet(fnode2->index, fnode1->dom))
+ return 0;
+
+ if (flag) {
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode)
+ fnode->x3C = 0;
+ } else if (fnode1->x3C) {
+ return 1;
+ }
+ fnode1->x3C = 1;
+
+ for (i = 0; i < fnode1->numsucc; i++) {
+ fnode = IRO_NodeTable[fnode1->succ[i]];
+ if (!CheckForTopLevelExpressions(fnode, fnode2, fnode3, fnode->first, nd2, 0))
+ return 0;
+ }
+ }
+
+ for (nd = nd1; nd && nd != fnode1->last->next; nd = nd->next) {
+ if (nd == nd2)
+ return 1;
+
+ if (nd->type != IROLinearNop && nd->type != IROLinearLabel && !(nd->flags & IROLF_Reffed))
+ return 0;
+ }
+
+ return 1;
+}
+
+static void AddNodeAndSuccessorsRecursively(IRONodes *nodes, IRONode *fnode1, IRONode *fnode2) {
+ UInt16 i;
+
+ if (fnode1 && !fnode1->x3C) {
+ fnode1->x3C = 1;
+ IROFlowgraph_sub_4C3880(nodes, fnode1->index);
+ if (fnode1 != fnode2) {
+ for (i = 0; i < fnode1->numsucc; i++)
+ AddNodeAndSuccessorsRecursively(nodes, IRO_NodeTable[fnode1->succ[i]], fnode2);
+ }
+ }
+}
+
+static Boolean RebuildPossibleLogicalExpression(IRONode *fnode, IROLinear *nd) {
+ IROUse *use;
+ IROLinear *nd2;
+ IROLinear *left;
+ IROLinear *right;
+ IRONode *r25;
+ IRONode *r24;
+ ENode *objnode;
+ IRODef *def1;
+ IRODef *def2;
+ UInt32 useCount;
+ UInt32 rewrittenUseCount;
+ Boolean sideEffectFlag;
+ IROLinearType compareType;
+ CLabel *somelab;
+ IRONode *var_68;
+ IRONode *var_6C;
+ CInt64 compareVal;
+ Boolean killedFlag;
+ BitVector *bv1;
+ BitVector *bv2;
+
+ IROLinear *father;
+ IROLinear *iter;
+ IRODef *def;
+ UInt32 i;
+ IROLinear *newlin;
+
+ objnode = nd->u.diadic.left->u.monadic->u.node;
+ if (!objnode->data.objref->varptr)
+ return 0;
+
+ if (CInt64_Equal(nd->u.diadic.right->u.node->data.intval, cint64_zero)) {
+ compareType = IROLinearIfNot;
+ compareVal = cint64_one;
+ } else {
+ compareType = IROLinearIf;
+ compareVal = cint64_zero;
+ }
+
+ var_68 = NULL;
+ def1 = NULL;
+ for (def = objnode->data.objref->varptr->defs; def && !def1; def = def->varnext) {
+ if (def->x18 && def->linear == nd)
+ def1 = def;
+ }
+
+ if (def1) {
+ for (use = objnode->data.objref->varptr->uses; use; use = use->varnext) {
+ if (use->x1C == 2 && Bv_IsBitSet(def1->index, use->x18)) {
+ if (!var_68) {
+ var_68 = use->node;
+ } else if (Bv_IsBitSet(use->node->index, var_68->dom)) {
+ var_68 = use->node;
+ }
+ }
+ }
+
+ if (var_68) {
+ for (use = objnode->data.objref->varptr->uses; use; use = use->varnext) {
+ if (use->node != var_68 && use->x1C == 2 && Bv_IsBitSet(def1->index, use->x18) && !Bv_IsBitSet(var_68->index, use->node->dom)) {
+ var_68 = NULL;
+ break;
+ }
+ }
+ }
+ }
+
+ if (
+ !var_68 ||
+ !var_68->first ||
+ var_68->first->type != IROLinearLabel ||
+ !(somelab = var_68->first->u.label.label) ||
+ var_68->numpred != 3
+ )
+ return 0;
+
+ r25 = IRO_NodeTable[var_68->pred[0]];
+ if (Bv_IsBitSet(IRO_NodeTable[var_68->pred[1]]->index, r25->dom)) {
+ r25 = IRO_NodeTable[var_68->pred[1]];
+ } else if (!Bv_IsBitSet(r25->index, IRO_NodeTable[var_68->pred[1]]->dom)) {
+ return 0;
+ }
+
+ if (Bv_IsBitSet(IRO_NodeTable[var_68->pred[2]]->index, r25->dom)) {
+ r25 = IRO_NodeTable[var_68->pred[2]];
+ } else if (!Bv_IsBitSet(r25->index, IRO_NodeTable[var_68->pred[2]]->dom)) {
+ return 0;
+ }
+
+ if (
+ !r25 ||
+ !(left = r25->last) ||
+ left->type != compareType ||
+ left->u.label.label != somelab
+ )
+ return 0;
+
+ if (
+ !FindFlowgraphNodeThatStartsWithLabel(left->u.label.label, &var_68, &var_6C) ||
+ !var_6C ||
+ var_6C->numpred != 1 ||
+ !(r24 = IRO_NodeTable[var_6C->pred[0]]) ||
+ !(right = r24->last) ||
+ right->type != compareType ||
+ right->u.label.label != left->u.label.label ||
+ !(nd2 = FindLastDiadicTopLevelAssignmentInFlowgraphNode(var_6C)) ||
+ !IsLogicalExpressionAssign(nd2) ||
+ nd2->u.diadic.left->u.monadic->u.node->data.objref != objnode->data.objref ||
+ !CInt64_Equal(compareVal, nd2->u.diadic.right->u.node->data.intval) ||
+ nd2->rtype != nd->rtype
+ )
+ return 0;
+
+ if (
+ !CheckForTopLevelExpressions(fnode, fnode, r25, nd->next, left, 1) ||
+ !CheckForTopLevelExpressions(r25->nextnode, r25->nextnode, r24, r25->nextnode->first, right, 1) ||
+ !CheckForTopLevelExpressions(r24->nextnode, r24->nextnode, var_6C, right->next, nd2, 1) ||
+ !CheckForTopLevelExpressions(var_6C, var_6C, var_6C, nd2->next, var_68->first, 1)
+ )
+ return 0;
+
+ rewrittenUseCount = 0;
+ useCount = 0;
+ killedFlag = 0;
+ sideEffectFlag = 0;
+ if (!objnode->data.objref->varptr || !(objnode->data.objref->varptr->uses) || !(objnode->data.objref->varptr->defs)) {
+ objnode = NULL;
+ } else {
+ def1 = def2 = NULL;
+ for (def = objnode->data.objref->varptr->defs; def && (!def1 || !def2); def = def->varnext) {
+ if (def->x18 && def->linear == nd)
+ def1 = def;
+ else if (def->x18 && def->linear == nd2)
+ def2 = def;
+ }
+
+ if (!def1 || !def2) {
+ objnode = NULL;
+ } else {
+ for (use = objnode->data.objref->varptr->uses; objnode && use; use = use->varnext) {
+ if (use->x1C) {
+ useCount++;
+ if (Bv_IsBitSet(def1->index, use->x18) && Bv_IsBitSet(def2->index, use->x18)) {
+ for (i = 0; objnode && i < use->x18->size; i++) {
+ if (i != def1->index && i != def2->index && Bv_IsBitSet(i, use->x18))
+ objnode = NULL;
+ }
+
+ if (objnode && !Bv_IsBitSet(var_68->index, use->node->dom))
+ objnode = NULL;
+
+ if (objnode) {
+ if (RewriteUse(use, objnode, nd2, 0))
+ rewrittenUseCount++;
+ else
+ objnode = NULL;
+ }
+
+ if (objnode) {
+ if (!sideEffectFlag)
+ sideEffectFlag = HasSideEffectsBeforeUse(var_68, var_68, use->node, use->linear, 1);
+
+ if (!killedFlag && (IRO_HasSideEffect(left->u.label.x4) || IRO_HasSideEffect(right->u.label.x4))) {
+ iter = use->linear;
+ if ((father = IRO_LocateFather(use->linear))) {
+ Bv_AllocVector(&bv1, IRO_NumVars + 1);
+ Bv_AllocVector(&bv2, IRO_NumVars + 1);
+ Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
+ IRO_WalkTree(left->u.label.x4, GetExprKills);
+ IRO_WalkTree(right->u.label.x4, GetExprKills);
+ Bv_Or(IRO_VarKills, bv1);
+ while (father && !killedFlag) {
+ CheckUnorderedRegionsForSideEffectsAndUses(father, iter, bv1, bv2, &killedFlag);
+ iter = father;
+ father = IRO_LocateFather(father);
+ }
+ }
+
+ if (!killedFlag)
+ killedFlag = UsesAKilledVarBeforeUse(var_68, var_68, use->node, use->linear, bv1, 1);
+ }
+ }
+ } else if (Bv_IsBitSet(def1->index, use->x18) || Bv_IsBitSet(def2->index, use->x18))
+ objnode = NULL;
+ }
+ }
+ }
+ }
+
+ if (!objnode)
+ return 0;
+
+ left->type = right->type = IROLinearNop;
+ left->expr = right->expr = NULL;
+
+ IRO_NopOut(nd);
+
+ newlin = IRO_NewLinear(IROLinearOp2Arg);
+ memcpy(newlin, nd2, sizeof(IROLinear));
+ newlin->nodetype = (compareType == IROLinearIf) ? ELOR : ELAND;
+ newlin->index = IRO_NumLinear++;
+ newlin->u.diadic.left = left->u.label.x4;
+ newlin->u.diadic.right = right->u.label.x4;
+ newlin->flags |= IROLF_Reffed;
+ IRO_Paste(newlin, newlin, nd2);
+
+ if (rewrittenUseCount == 1 && !sideEffectFlag && !killedFlag && !objnode->data.objref->varptr->xB) {
+ for (use = objnode->data.objref->varptr->uses; use; use = use->varnext) {
+ if (use->x1C && Bv_IsBitSet(def1->index, use->x18) && Bv_IsBitSet(def2->index, use->x18))
+ RewriteUse(use, objnode, newlin, 1);
+ }
+
+ if (useCount == 1 && objnode->data.objref->u.var.info) {
+ objnode->data.objref->u.var.info->usage = 0;
+ objnode->data.objref->u.var.info->used = 0;
+ }
+ IRO_NopOut(nd2);
+ def1->x18 = 0;
+ def2->x18 = 0;
+ } else {
+ IRO_NopOut(nd2->u.label.x4);
+ nd2->u.label.x4 = newlin;
+ def1->x18 = 0;
+ }
+
+ if (r24->numpred == 1 && IRO_NodeTable[r24->pred[0]] == r25 && IRO_MergeFlowGraphNodes(r25, r24))
+ r24 = r25;
+ if (var_6C->numpred == 1 && IRO_NodeTable[var_6C->pred[0]] == r24 && IRO_MergeFlowGraphNodes(r24, var_6C))
+ var_6C = r24;
+ if (var_68->numpred == 1 && r24 == r25 && var_6C == r24)
+ IRO_MergeFlowGraphNodes(var_6C, var_68);
+ return 1;
+}
+
+static void RebuildLogicalExpressions(void) {
+ IRONode *fnode;
+ IROLinear *nd;
+ Boolean flag;
+
+ flag = 1;
+ while (flag) {
+ flag = 0;
+ for (fnode = IRO_FirstNode; fnode && fnode->last; fnode = fnode->nextnode) {
+ for (nd = fnode->first; nd && nd != fnode->last->next; nd = nd->next) {
+ if (IsPossibleLogicalExpressionStart(fnode, nd) && RebuildPossibleLogicalExpression(fnode, nd))
+ flag = 1;
+ }
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+static Boolean IsPossibleCondAssStart(IRONode *fnode) {
+ return (fnode->numsucc == 2) && fnode->last && (fnode->last->type == IROLinearIf || fnode->last->type == IROLinearIfNot);
+}
+
+static Type *logicalType(void) {
+ if (copts.cplusplus && copts.booltruefalse)
+ return TYPE(&stbool);
+ else
+ return TYPE(&stsignedint);
+}
+
+static Boolean GeneratePossibleCondAss(IRONode *fnode) {
+ IROLinear *r31;
+ IRONode *node2;
+ IRONode *r29;
+ Boolean r28;
+ IRONode *node1;
+ IROLinear *r24;
+ Boolean r23;
+ IROLinear *r19;
+ Boolean r18;
+ IROLinear *r20;
+ Boolean r19flag;
+ IROLinear *r18nd;
+ IROLinear *ass;
+ IROLinear *cond;
+ IROLinear *r16;
+ IROLinear *r15;
+ BitVector *saveVarKills;
+ IROList list;
+ Object *obj;
+ IROLinear *r14;
+
+ if (!fnode || fnode->numsucc != 2 || !fnode->last || (fnode->last->type != IROLinearIf && fnode->last->type != IROLinearIfNot))
+ return 0;
+
+ if (IRO_NodeTable[fnode->succ[0]] &&
+ IRO_NodeTable[fnode->succ[0]]->first &&
+ IRO_NodeTable[fnode->succ[0]]->first->type == IROLinearLabel &&
+ IRO_NodeTable[fnode->succ[0]]->first->u.label.label == fnode->last->u.label.label) {
+ node1 = IRO_NodeTable[fnode->succ[0]];
+ node2 = IRO_NodeTable[fnode->succ[1]];
+ } else {
+ node1 = IRO_NodeTable[fnode->succ[1]];
+ if (node1 && node1->first && node1->first->type == IROLinearLabel && node1->first->u.label.label == fnode->last->u.label.label) {
+ node2 = IRO_NodeTable[fnode->succ[0]];
+ } else {
+ return 0;
+ }
+ }
+
+ if (!node2 || node2->numpred != 1 || node2->numsucc != 1 || node2->last->next != node1->first)
+ return 0;
+
+ if (IRO_NodeTable[node2->succ[0]] == node1 && Bv_IsBitSet(fnode->index, node1->dom)) {
+ r28 = 0;
+ } else if (
+ node1->numpred == 1 && node1->numsucc == 1 &&
+ node2->succ[0] == node1->succ[0] &&
+ (r29 = IRO_NodeTable[node2->succ[0]]) &&
+ Bv_IsBitSet(fnode->index, r29->dom) &&
+ node1->last->next == r29->first
+ ) {
+ r28 = 1;
+ } else {
+ return 0;
+ }
+
+ r24 = NULL;
+ if (node2->last) {
+ for (r19 = node2->first; r19 && r19 != node2->last->next; r19 = r19->next) {
+ if (IRO_IsAssignment(r19) && !(r19->flags & IROLF_Reffed) && !r24) {
+ r24 = r19;
+ } else if (r19->type != IROLinearNop && r19->type != IROLinearLabel && r19->type != IROLinearGoto && !(r19->flags & IROLF_Reffed)) {
+ return 0;
+ }
+ }
+ }
+
+ if (
+ !r24 ||
+ (r24->nodetype != EASS && !IRO_TransformSelfAssignmentToAssignment(r24)) ||
+ !r24->u.diadic.left ||
+ r24->u.diadic.left->type != IROLinearOp1Arg ||
+ r24->u.diadic.left->nodetype != EINDIRECT ||
+ !r24->u.diadic.left->u.monadic ||
+ r24->u.diadic.left->u.monadic->type != IROLinearOperand ||
+ !r24->u.diadic.left->u.monadic->u.node ||
+ !r24->u.diadic.left->u.monadic->u.node->rtype ||
+ !IS_TYPE_POINTER_ONLY(r24->u.diadic.left->u.monadic->u.node->rtype) ||
+ !r24->u.diadic.left->u.monadic->u.node->data.monadic
+ )
+ return 0;
+
+ if (r28) {
+ r31 = NULL;
+ if (node1->last) {
+ for (r19 = node1->first; r19 && r19 != node1->last->next; r19 = r19->next) {
+ if (IRO_IsAssignment(r19) && !(r19->flags & IROLF_Reffed) && !r31) {
+ r31 = r19;
+ } else if (r19->type != IROLinearNop && r19->type != IROLinearLabel && r19->type != IROLinearGoto && !(r19->flags & IROLF_Reffed)) {
+ return 0;
+ }
+ }
+ }
+
+ if (
+ !r31 ||
+ (r31->nodetype != EASS && !IRO_TransformSelfAssignmentToAssignment(r31)) ||
+ !r31->u.diadic.left ||
+ r31->u.diadic.left->type != IROLinearOp1Arg ||
+ r31->u.diadic.left->nodetype != EINDIRECT ||
+ !r31->u.diadic.left->u.monadic ||
+ r31->u.diadic.left->u.monadic->type != IROLinearOperand ||
+ !r31->u.diadic.left->u.monadic->u.node ||
+ !r31->u.diadic.left->u.monadic->u.node->rtype ||
+ !IS_TYPE_POINTER_ONLY(r31->u.diadic.left->u.monadic->u.node->rtype) ||
+ !r31->u.diadic.left->u.monadic->u.node->data.monadic
+ )
+ return 0;
+
+ r18 = IRO_ExprsSame(r24->u.diadic.left, r31->u.diadic.left);
+ }
+
+ r23 = fnode->last->type == IROLinearIf;
+ r20 = fnode->last->u.diadic.right;
+ r19flag = 0;
+ if (r28 && copts.commonsubs && IRO_IsSubableExpression(r20))
+ r19flag = 1;
+
+ if (r19flag) {
+ IRO_FindDepends(r20);
+ r19flag = !IRO_NotSubable;
+ }
+
+ if (r28) {
+ if (r18) {
+ r19flag = 0;
+ } else if (IRO_HasSideEffect(r20)) {
+ r19flag = 1;
+ } else {
+ Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
+ IRO_WalkTree(r20, GetExprUses);
+ saveVarKills = IRO_VarKills;
+ Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
+ IRO_WalkTree(r20, GetExprKills);
+ if (Bv_BitsInCommon(IRO_VarKills, saveVarKills))
+ r19flag = 1;
+ }
+
+ if (r19flag && !copts.commonsubs)
+ return 0;
+ }
+
+ if (r19flag) {
+ IRO_InitList(&list);
+ obj = create_temp_object(r20->rtype);
+ IRO_FindVar(obj, 1, 1);
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->u.diadic.left = IRO_TempReference(obj, &list);
+ ass->rtype = r20->rtype;
+ ass->nodetype = EASS;
+ ass->index = ++IRO_NumLinear;
+ ass->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned;
+ ass->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned;
+ ass->u.diadic.right = r20;
+ IRO_AddToList(ass, &list);
+ IRO_PasteAfter(list.head, list.tail, r20);
+ }
+
+ r16 = r24->u.diadic.left;
+ r15 = r24->u.diadic.right;
+ fnode->last->type = IROLinearNop;
+ fnode->last->expr = NULL;
+ if (node2->last->type == IROLinearGoto) {
+ node2->last->type = IROLinearNop;
+ node2->last->expr = NULL;
+ }
+ if (r28 || node1->numpred == 2) {
+ node1->first->type = IROLinearNop;
+ node1->first->expr = NULL;
+ }
+
+ if (r28 && r18) {
+ if (node1->last->type == IROLinearGoto) {
+ node1->last->type = IROLinearNop;
+ node1->last->expr = NULL;
+ }
+ if (r29->numpred == 2) {
+ r29->first->type = IROLinearNop;
+ r29->first->expr = NULL;
+ }
+
+ cond = IRO_NewLinear(IROLinearOp3Arg);
+ memcpy(cond, r24, sizeof(IROLinear));
+ cond->type = IROLinearOp3Arg;
+ cond->nodetype = ECOND;
+ cond->index = ++IRO_NumLinear;
+ cond->rtype = r16->rtype;
+ cond->flags |= IROLF_Reffed;
+ if (r19flag) {
+ IRO_InitList(&list);
+ r14 = IRO_TempReference(obj, &list);
+ IRO_Paste(list.head, list.tail, r31);
+ } else {
+ r14 = r20;
+ }
+ cond->u.args3.a = r14;
+
+ if (r23) {
+ cond->u.args3.b = r31->u.diadic.right;
+ cond->u.args3.c = r15;
+ } else {
+ cond->u.args3.b = r15;
+ cond->u.args3.c = r31->u.diadic.right;
+ }
+
+ r24->type = IROLinearNop;
+ r24->expr = NULL;
+ IRO_NopOut(r24->u.diadic.left);
+ IRO_Paste(cond, cond, r31);
+ r31->u.diadic.right = cond;
+ } else {
+ r24->type = IROLinearOp3Arg;
+ r24->nodetype = ECONDASS;
+ if (r19flag) {
+ IRO_InitList(&list);
+ r20 = IRO_TempReference(obj, &list);
+ IRO_Paste(list.head, list.tail, r24);
+ }
+ cond = r20;
+ if (r23) {
+ r18nd = IRO_NewLinear(IROLinearOp1Arg);
+ memcpy(r18nd, r20, sizeof(IROLinear));
+ r18nd->type = IROLinearOp1Arg;
+ r18nd->nodetype = ELOGNOT;
+ r18nd->index = ++IRO_NumLinear;
+ r18nd->rtype = logicalType();
+ r18nd->u.monadic = r20;
+ r18nd->flags |= IROLF_Reffed;
+ IRO_Paste(r18nd, r18nd, r24);
+ r20 = r18nd;
+ }
+ r24->u.args3.a = r20;
+ r24->u.args3.b = r16;
+ r24->u.args3.c = r15;
+ if (r28) {
+ r15 = r31->u.diadic.left;
+ r16 = r31->u.diadic.right;
+ if (node1->last->type == IROLinearGoto) {
+ node1->last->type = IROLinearNop;
+ node1->last->expr = NULL;
+ }
+ if (r29->numpred == 2) {
+ r29->first->type = IROLinearNop;
+ r29->first->expr = NULL;
+ }
+ r31->type = IROLinearOp3Arg;
+ r31->nodetype = ECONDASS;
+ if (r19flag) {
+ IRO_InitList(&list);
+ cond = IRO_TempReference(obj, &list);
+ IRO_Paste(list.head, list.tail, r31);
+ } else {
+ IRO_InitList(&list);
+ cond = IRO_DuplicateExpr(cond, &list);
+ IRO_Paste(list.head, list.tail, r31);
+ }
+ if (!r23) {
+ r14 = IRO_NewLinear(IROLinearOp1Arg);
+ memcpy(r14, cond, sizeof(IROLinear));
+ r14->type = IROLinearOp1Arg;
+ r14->nodetype = ELOGNOT;
+ r14->index = ++IRO_NumLinear;
+ r14->rtype = logicalType();
+ r14->u.monadic = cond;
+ r14->flags |= IROLF_Reffed;
+ IRO_Paste(r14, r14, r31);
+ cond = r14;
+ }
+ r31->u.args3.a = cond;
+ r31->u.args3.b = r15;
+ r31->u.args3.c = r16;
+ }
+ }
+
+ if (IRO_MergeFlowGraphNodes(fnode, node2))
+ node2 = fnode;
+ if ((r28 || node1->numpred == 1) && IRO_MergeFlowGraphNodes(node2, node1))
+ node1 = node2;
+ if (r28 && r29->numpred == 1)
+ IRO_MergeFlowGraphNodes(node1, r29);
+ return 1;
+}
+
+static void GenerateCondAssignments(void) {
+ IRONode *fnode;
+
+ fnode = IRO_FirstNode;
+ while (fnode && fnode->last) {
+ if (IsPossibleCondAssStart(fnode)) {
+ if (!GeneratePossibleCondAss(fnode))
+ fnode = fnode->nextnode;
+ } else {
+ fnode = fnode->nextnode;
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+void IRO_RegenerateExpressions(void) {
+ IRO_UpdateFlagsOnInts();
+ IRO_ComputeSuccPred();
+ IRO_ComputeDom();
+ IRO_UseDef(0, 0);
+
+ if (copts.optimizationlevel > 0) {
+ IRO_Dump("Rebuilding ELORs and ELANDs\n");
+ RebuildLogicalExpressions();
+ IRO_DumpAfterPhase("RebuildLogicalExpressions", 0);
+ }
+
+ if (copts.optimizationlevel > 0) {
+ IRO_Dump("Rebuilding ECONDs\n");
+ RebuildCondExpressions();
+ IRO_DumpAfterPhase("RebuildCondExpressions", 0);
+ }
+
+ if (copts.optimizationlevel > 0) {
+ IRO_Dump("Generating ECONDASSes\n");
+ GenerateCondAssignments();
+ IRO_DumpAfterPhase("GenerateCondAssignments", 0);
+ }
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.h b/compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.h
new file mode 100644
index 0000000..c74f95f
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroExprRegeneration.h
@@ -0,0 +1,8 @@
+#ifndef COMPILER_IROEXPRREGENERATION_H
+#define COMPILER_IROEXPRREGENERATION_H
+
+#include "IrOptimizer.h"
+
+extern void IRO_RegenerateExpressions(void);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.c b/compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.c
new file mode 100644
index 0000000..2fa9875
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.c
@@ -0,0 +1,439 @@
+#include "IroFlowgraph.h"
+#include "IroCSE.h"
+#include "IroLinearForm.h"
+#include "IroPropagate.h"
+#include "IROUseDef.h"
+#include "IroUtil.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/Exceptions.h"
+#include "compiler/InlineAsmPPC.h"
+
+UInt16 IRO_NumNodes;
+IRONode *IRO_FirstNode;
+IRONode *IRO_LastNode;
+IRONode *IRO_EndNode;
+IRONode **IRO_NodeTable;
+BitVector *IRO_VarKills;
+BitVector *IRO_Avail;
+BitVector *IRO_FuncKills;
+BitVector *IRO_ExprKills;
+
+static IRONode *StartNode(IROLinear *linear) {
+ IRONode *node = oalloc(sizeof(IRONode));
+
+ node->index = IRO_NumNodes;
+ node->numsucc = 0;
+ node->succ = NULL;
+ node->numpred = 0;
+ node->pred = NULL;
+ node->first = linear;
+ node->last = linear;
+ node->x16 = NULL;
+ node->x1A = NULL;
+ node->x1E = NULL;
+ node->x22 = NULL;
+ node->x26 = 0;
+ node->x2A = NULL;
+ node->dom = NULL;
+ node->nextnode = NULL;
+ node->x36 = 0;
+ node->x37 = 0;
+ node->mustreach = 0;
+ node->x39 = 0;
+ node->loopdepth = 0;
+ node->x3C = 0;
+ node->addressed = NULL;
+
+ IRO_NumNodes++;
+ if (!IRO_FirstNode)
+ IRO_FirstNode = node;
+ else
+ IRO_LastNode->nextnode = node;
+ IRO_LastNode = node;
+ return node;
+}
+
+static void AddSucc(IRONode *a, IRONode *b) {
+ a->succ[a->numsucc++] = b->index;
+ b->numpred++;
+}
+
+static void AddLabelSucc(IRONode *node, CLabel *label) {
+ IRONode *targetnode = (IRONode *) label->stmt;
+ if (targetnode) {
+ AddSucc(node, targetnode);
+ targetnode->x39 = 1;
+ } else {
+ CError_FATAL(126);
+ }
+}
+
+static void AddSwitchSucc(IRONode *node) {
+ SwitchInfo *info = node->last->u.swtch.info;
+ SwitchCase *curcase = info->cases;
+ SInt32 i = 1;
+
+ while (curcase) {
+ curcase = curcase->next;
+ i++;
+ }
+
+ node->succ = oalloc(sizeof(UInt16) * i);
+ for (curcase = info->cases; curcase; curcase = curcase->next)
+ AddLabelSucc(node, curcase->label);
+ AddLabelSucc(node, info->defaultlabel);
+}
+
+static void AddPred(UInt32 a, UInt16 b) {
+ IRONode *node = IRO_NodeTable[a];
+ node->pred[node->numpred++] = b;
+}
+
+void IRO_ComputeSuccPred(void) {
+ CLabel *label;
+ IRONode *node;
+ SInt32 count;
+ IROLinear *linear;
+ ExceptionAction *action;
+ IAEffects effects;
+ UInt16 i;
+
+ for (label = Labels; label; label = label->next)
+ label->stmt = NULL;
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ node->x39 = 0;
+ node->numsucc = 0;
+ node->numpred = 0;
+ node->x36 = 0;
+ node->x37 = 0;
+ if (node->first && node->first->type == IROLinearLabel)
+ node->first->u.label.label->stmt = (Statement *) node;
+ }
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (!node->first) {
+ if (node->nextnode) {
+ node->succ = oalloc(sizeof(UInt16));
+ AddSucc(node, node->nextnode);
+ }
+ } else {
+ linear = node->last;
+ next_linear:
+ switch (linear->type) {
+ case IROLinearReturn:
+ case IROLinearEnd:
+ break;
+ case IROLinearGoto:
+ node->succ = oalloc(sizeof(UInt16));
+ AddLabelSucc(node, linear->u.label.label);
+ break;
+ case IROLinearIf:
+ case IROLinearIfNot:
+ node->succ = oalloc(sizeof(UInt16) * 2);
+ AddSucc(node, node->nextnode);
+ AddLabelSucc(node, linear->u.label.label);
+ break;
+ case IROLinearSwitch:
+ AddSwitchSucc(node);
+ break;
+ case IROLinearFunccall:
+ count = 1;
+ if (IRO_FunctionCallMightThrowException(linear)) {
+ for (action = linear->stmt->dobjstack; action; action = action->prev) {
+ if (action->type == EAT_CATCHBLOCK || action->type == EAT_SPECIFICATION)
+ count++;
+ }
+ }
+ node->succ = oalloc(sizeof(UInt16) * count);
+ AddSucc(node, node->nextnode);
+ if (IRO_FunctionCallMightThrowException(linear)) {
+ for (action = linear->stmt->dobjstack; action; action = action->prev) {
+ if (action->type == EAT_CATCHBLOCK)
+ AddLabelSucc(node, action->data.catch_block.catch_label);
+ else if (action->type == EAT_SPECIFICATION)
+ AddLabelSucc(node, action->data.specification.unexp_label);
+ }
+ }
+ break;
+ case IROLinearAsm:
+ CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects);
+ node->succ = oalloc(sizeof(UInt16) * (!effects.x5 + effects.numlabels));
+ if (!effects.x5)
+ AddSucc(node, node->nextnode);
+ for (i = 0; i < effects.numlabels; i++)
+ AddLabelSucc(node, effects.labels[i]);
+ break;
+ case IROLinearOp2Arg:
+ if (linear->nodetype == ECOMMA) {
+ linear = linear->u.diadic.right;
+ goto next_linear;
+ }
+ default:
+ if (node->nextnode) {
+ node->succ = oalloc(sizeof(UInt16));
+ AddSucc(node, node->nextnode);
+ }
+ }
+ }
+ }
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (node->numpred)
+ node->pred = oalloc(sizeof(UInt16) * node->numpred);
+ else
+ node->pred = NULL;
+ node->numpred = 0;
+ }
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ for (i = 0; i < node->numsucc; i++)
+ AddPred(node->succ[i], node->index);
+ }
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (node->first && node->first->type == IROLinearLabel) {
+ IROLinear *linear = node->first;
+ do {
+ if (linear->type == IROLinearBeginCatch || linear->type == IROLinearEndCatch || linear->type == IROLinearEndCatchDtor) {
+ node->x39 = 1;
+ break;
+ }
+ } while (linear != node->last && (linear = linear->next));
+ }
+ }
+}
+
+void IRO_ComputeDom(void) {
+ IRONode *node;
+ BitVector *bv;
+ SInt32 i;
+ int repeat;
+
+ Bv_AllocVector(&IRO_FirstNode->dom, IRO_NumNodes);
+ Bv_SetBit(IRO_FirstNode->index, IRO_FirstNode->dom);
+ for (node = IRO_FirstNode->nextnode; node; node = node->nextnode) {
+ Bv_AllocVector(&node->dom, IRO_NumNodes);
+ Bv_Set(node->dom);
+ }
+
+ Bv_AllocVector(&bv, IRO_NumNodes);
+
+ do {
+ repeat = 0;
+ for (node = IRO_FirstNode->nextnode; node; node = node->nextnode) {
+ if (node->numpred) {
+ Bv_Set(bv);
+ for (i = 0; i < node->numpred; i++) {
+ Bv_And(IRO_NodeTable[node->pred[i]]->dom, bv);
+ }
+ Bv_SetBit(node->index, bv);
+ } else {
+ Bv_Clear(bv);
+ Bv_SetBit(node->index, bv);
+ }
+
+ if (!Bv_Compare(bv, node->dom)) {
+ Bv_Copy(bv, node->dom);
+ repeat = 1;
+ }
+ }
+ } while (repeat);
+}
+
+void IRO_BuildFlowgraph(IROLinear *linear) {
+ IROLinear *scan;
+ CLabel *label;
+ ExceptionAction *action;
+ IAEffects effects;
+ IRONode *node;
+ SInt32 i;
+ int flag;
+
+ for (label = Labels; label; label = label->next)
+ label->stmt = NULL;
+
+ scan = linear;
+ IRO_NumNodes = 0;
+ IRO_FirstNode = IRO_LastNode = IRO_EndNode = NULL;
+ while (scan) {
+ StartNode(scan);
+ if (scan->type == IROLinearLabel)
+ scan->u.label.label->stmt = (Statement *) IRO_LastNode;
+
+ flag = 0;
+ while (!flag && scan->next && !(scan->next->flags & IROLF_1)) {
+ switch (scan->type) {
+ case IROLinearGoto:
+ case IROLinearReturn:
+ case IROLinearEntry:
+ case IROLinearExit:
+ case IROLinearEnd:
+ flag = 1;
+ break;
+ case IROLinearIf:
+ case IROLinearIfNot:
+ case IROLinearSwitch:
+ flag = 1;
+ skip:
+ if (scan->next->type == IROLinearLabel) {
+ IROLinear *nw = IRO_NewLinear(IROLinearNop);
+ nw->index = ++IRO_NumLinear;
+ nw->next = scan->next;
+ scan->next = nw;
+ }
+ break;
+ case IROLinearFunccall:
+ if (IRO_FunctionCallMightThrowException(scan)) {
+ for (action = scan->stmt->dobjstack; action; action = action->prev) {
+ if (action->type == EAT_CATCHBLOCK || action->type == EAT_SPECIFICATION) {
+ flag = 1;
+ goto skip;
+ }
+ }
+ }
+ break;
+ case IROLinearAsm:
+ CodeGen_GetAsmEffects(scan->u.asm_stmt, &effects);
+ if (effects.numlabels)
+ flag = 1;
+ break;
+ }
+ if (!flag)
+ scan = scan->next;
+ }
+
+ if (scan->type == IROLinearEnd)
+ IRO_EndNode = IRO_LastNode;
+ IRO_LastNode->last = scan;
+ scan = scan->next;
+ }
+
+ IRO_NodeTable = oalloc(IRO_NumNodes * sizeof(IRONode *));
+ memset(IRO_NodeTable, 0, IRO_NumNodes * sizeof(IRONode *));
+ for (node = IRO_FirstNode, i = 0; node; node = node->nextnode)
+ IRO_NodeTable[i++] = node;
+
+ IRO_ComputeSuccPred();
+ IRO_ComputeDom();
+ IRO_CheckForUserBreak();
+}
+
+IRONode *IRO_NewFlowGraphNode(void) {
+ IRONode *node = oalloc(sizeof(IRONode));
+ memset(node, 0, sizeof(IRONode));
+ node->index = IRO_NumNodes;
+ IRO_NumNodes++;
+ node->nextnode = NULL;
+ return node;
+}
+
+IRONode *IRO_MergeFlowGraphNodes(IRONode *a, IRONode *b) {
+ IRONode *succ;
+ Boolean found;
+ UInt32 i;
+ UInt32 j;
+ UInt32 k;
+
+ if (a->nextnode == b && a->last && b->first && a->last->next == b->first) {
+ if (b->first->type == IROLinearLabel)
+ IRO_NopOut(b->first);
+
+ a->nextnode = b->nextnode;
+ a->last = b->last;
+
+ for (i = 0; i < a->numsucc; i++) {
+ if (b->index == a->succ[i]) {
+ for (j = i; j < a->numsucc; j++) {
+ if ((j + 1) < a->numsucc)
+ a->succ[j] = a->succ[j + 1];
+ else
+ a->succ[j] = 0;
+ }
+ a->numsucc--;
+ break;
+ }
+ }
+
+ for (i = 0; i < b->numsucc; i++) {
+ succ = IRO_NodeTable[b->succ[i]];
+ for (j = 0; j < a->numsucc; j++) {
+ if (b->succ[i] == a->succ[j])
+ break;
+ }
+
+ if (j == a->numsucc) {
+ AddSucc(a, IRO_NodeTable[b->succ[i]]);
+ succ->numpred--;
+ }
+
+ found = 0;
+ for (j = 0; j < succ->numpred; j++) {
+ if (a->index == succ->pred[j]) {
+ found = 1;
+ break;
+ }
+ }
+
+ for (j = 0; j < succ->numpred; j++) {
+ if (b->index == succ->pred[j]) {
+ if (!found) {
+ succ->pred[j] = a->index;
+ } else {
+ for (k = j; k < succ->numpred; k++) {
+ if ((k + 1) < succ->numpred)
+ succ->pred[k] = succ->pred[k + 1];
+ else
+ succ->pred[k] = 0;
+ }
+ succ->numpred--;
+ }
+ break;
+ }
+ }
+ }
+
+ b->numsucc = b->numpred = 0;
+ b->first = b->last = NULL;
+ b->nextnode = NULL;
+ b->x36 = 0;
+ b->x37 = 0;
+ b->mustreach = 0;
+ b->x39 = 0;
+ b->loopdepth = 0;
+
+ if (IRO_LastNode == b)
+ IRO_LastNode = a;
+
+ if (IRO_FirstExpr && IRO_LastExpr) {
+ IROExpr *expr;
+ for (expr = IRO_FirstExpr; expr && expr != IRO_LastExpr->next; expr = expr->next) {
+ if (expr->node == b)
+ expr->node = a;
+ }
+ }
+
+ if (IRO_FirstAssign && IRO_LastAssign) {
+ IROAssign *assign;
+ for (assign = IRO_FirstAssign; assign && assign != IRO_LastAssign->next; assign = assign->next) {
+ if (assign->node == b)
+ assign->node = a;
+ }
+ }
+
+ if (IRO_FirstVarUse && IRO_LastVarUse) {
+ IROUse *use;
+ for (use = IRO_FirstVarUse; use && use != IRO_LastVarUse->globalnext; use = use->globalnext) {
+ if (use->node == b)
+ use->node = a;
+ }
+ }
+
+ IRO_NodeTable[b->index] = NULL;
+ return a;
+ }
+
+ return NULL;
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.h b/compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.h
new file mode 100644
index 0000000..13ddce9
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroFlowgraph.h
@@ -0,0 +1,97 @@
+#ifndef COMPILER_IROFLOWGRAPH_H
+#define COMPILER_IROFLOWGRAPH_H
+
+#include "IrOptimizer.h"
+#include "BitVector.h"
+#include "compiler/CError.h"
+#include "compiler/CompilerTools.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+
+struct IRONode {
+ UInt16 index;
+ UInt16 numsucc;
+ UInt16 *succ;
+ UInt16 numpred;
+ UInt16 *pred;
+ IROLinear *first;
+ IROLinear *last;
+ BitVector *x16; // In
+ BitVector *x1A; // Out
+ BitVector *x1E; // Gen
+ BitVector *x22; // Kill
+ UInt32 x26;
+ BitVector *x2A; // AA
+ BitVector *dom;
+ IRONode *nextnode;
+ Boolean x36;
+ Boolean x37;
+ Boolean mustreach;
+ Boolean x39;
+ UInt16 loopdepth;
+ Boolean x3C;
+ struct ObjectSet *addressed;
+ Boolean mustreach1;
+};
+
+typedef struct IRONodes {
+ UInt16 *indices;
+ UInt16 num;
+ UInt16 base;
+} IRONodes;
+
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+extern UInt16 IRO_NumNodes;
+extern IRONode *IRO_FirstNode;
+extern IRONode *IRO_LastNode;
+extern IRONode *IRO_EndNode;
+extern IRONode **IRO_NodeTable;
+extern BitVector *IRO_VarKills;
+extern BitVector *IRO_Avail;
+extern BitVector *IRO_FuncKills;
+extern BitVector *IRO_ExprKills;
+
+extern void IRO_ComputeSuccPred(void);
+extern void IRO_ComputeDom(void);
+extern void IRO_BuildFlowgraph(IROLinear *linear);
+extern IRONode *IRO_NewFlowGraphNode(void);
+extern IRONode *IRO_MergeFlowGraphNodes(IRONode *a, IRONode *b);
+
+CW_INLINE void IROFlowgraph_sub_4C2140(IRONodes *nodes) {
+ nodes->indices = oalloc(sizeof(UInt16) * IRO_NumNodes);
+ nodes->num = 0;
+ nodes->base = 0;
+}
+
+CW_INLINE void IROFlowgraph_sub_4C20E0(IRONodes *nodes) {
+}
+
+CW_INLINE UInt16 IROFlowgraph_sub_4C2040(IRONodes *nodes) {
+ return nodes->num;
+}
+
+CW_INLINE UInt16 IROFlowgraph_sub_4C2100(IRONodes *nodes) {
+ UInt16 result = -1;
+ if (nodes->num) {
+ result = nodes->indices[nodes->base];
+ nodes->base = (nodes->base + 1) % IRO_NumNodes;
+ nodes->num--;
+ }
+ return result;
+}
+
+CW_INLINE void IROFlowgraph_sub_4C3880(IRONodes *nodes, UInt16 index) {
+ if (nodes->num < IRO_NumNodes) {
+ nodes->indices[(nodes->base + nodes->num) % IRO_NumNodes] = index;
+ nodes->num++;
+ } else {
+ CError_FATAL(93);
+ }
+}
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroJump.c b/compiler_and_linker/FrontEnd/Optimizer/IroJump.c
new file mode 100644
index 0000000..9af248e
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroJump.c
@@ -0,0 +1,267 @@
+#include "IroJump.h"
+#include "IroDump.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroUtil.h"
+#include "compiler/CFunc.h"
+#include "compiler/Exceptions.h"
+
+static Boolean CheckChain(CLabel **labelptr) {
+ IRONode *node;
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (node->first && node->first->type == IROLinearLabel && node->first->u.label.label == *labelptr) {
+ IROLinear *linear;
+ CLabel *lab;
+ for (linear = node->first->next, lab = NULL; linear && (linear->type == IROLinearLabel || linear->type == IROLinearNop); linear = linear->next) {
+ if (linear->type == IROLinearLabel)
+ lab = linear->u.label.label;
+ }
+
+ if (linear->type == IROLinearGoto && *labelptr != linear->u.label.label) {
+ *labelptr = linear->u.label.label;
+ IRO_Dump("Chaining goto at %d\n", linear->index);
+ return 1;
+ }
+
+ if (lab && *labelptr != lab)
+ *labelptr = lab;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+Boolean IRO_DoJumpChaining(void) {
+ IRONode *node;
+ IROLinear *linear;
+ Boolean flag;
+ SwitchInfo *info;
+ SwitchCase *curcase;
+ Boolean result;
+
+ result = 0;
+ do {
+ flag = 0;
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (node->first) {
+ linear = node->last;
+ switch (linear->type) {
+ case IROLinearGoto:
+ if (CheckChain(&linear->u.label.label))
+ flag = 1;
+ break;
+ case IROLinearIf:
+ case IROLinearIfNot:
+ if (CheckChain(&linear->u.label.label))
+ flag = 1;
+ break;
+ case IROLinearSwitch:
+ info = linear->u.swtch.info;
+ for (curcase = info->cases; curcase; curcase = curcase->next) {
+ if (CheckChain(&curcase->label))
+ flag = 1;
+ }
+ if (CheckChain(&info->defaultlabel))
+ flag = 1;
+ break;
+ }
+ }
+ }
+ result |= flag;
+ IRO_CheckForUserBreak();
+ } while (flag);
+
+ return result;
+}
+
+void IRO_MakeReachable(IRONode *node) {
+ UInt16 i;
+ Boolean flag;
+
+ node->x36 = 1;
+ do {
+ flag = 0;
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (node->x36 && !node->x37) {
+ for (i = 0; i < node->numsucc; i++) {
+ if (!IRO_NodeTable[node->succ[i]]->x36) {
+ flag = 1;
+ IRO_NodeTable[node->succ[i]]->x36 = 1;
+ }
+ }
+ node->x37 = 1;
+ }
+ }
+ } while (flag);
+}
+
+Boolean IRO_RemoveUnreachable(void) {
+ IRONode *node2;
+ IRONode *node1;
+ IROLinear *scan;
+ IROLinear *linear;
+ Boolean result;
+ ExceptionAction **actptr;
+ ExceptionAction *act;
+
+ result = 0;
+ IRO_ComputeSuccPred();
+ IRO_MakeReachable(IRO_FirstNode);
+ node1 = IRO_FirstNode;
+ for (node2 = IRO_FirstNode->nextnode; node2; node2 = node2->nextnode) {
+ if (node2->first && !node2->x36) {
+ IRO_Dump("Removing unreachable code at: %d\n", node2->index);
+ node1->nextnode = node2->nextnode;
+ node1->last->next = node2->last->next;
+ result = 1;
+ for (linear = node2->first; linear && linear->type == IROLinearLabel && linear != node2->last->next; linear = linear->next) {
+ for (scan = IRO_FirstLinear; scan; scan = scan->next) {
+ if (scan->stmt)
+ scan->stmt->marked = 0;
+ }
+
+ for (scan = IRO_FirstLinear; scan; scan = scan->next) {
+ if (scan->stmt && !scan->stmt->marked) {
+ scan->stmt->marked = 1;
+ for (actptr = &scan->stmt->dobjstack; (act = *actptr); actptr = &act->prev) {
+ if (
+ (act->type == EAT_CATCHBLOCK && act->data.catch_block.catch_label == linear->u.label.label) ||
+ (act->type == EAT_SPECIFICATION && act->data.specification.unexp_label == linear->u.label.label)) {
+ *actptr = act->prev;
+ }
+ }
+ }
+ }
+ }
+ if (node2 == IRO_LastNode)
+ IRO_LastNode = node1;
+ } else {
+ node1 = node2;
+ }
+ }
+
+ if (result) {
+ IRO_ComputeSuccPred();
+ IRO_ComputeDom();
+ }
+
+ IRO_CheckForUserBreak();
+ return result;
+}
+
+Boolean IRO_RemoveRedundantJumps(void) {
+ IRONode *node;
+ IROLinear *linear;
+ IROLinear *scan;
+ IROLinear *scan2;
+ SwitchInfo *info;
+ SwitchCase *curcase;
+ Boolean result;
+
+ result = 0;
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (node->first) {
+ linear = node->last;
+ switch (linear->type) {
+ case IROLinearGoto:
+ scan = linear->next;
+ while (scan && ((scan->type == IROLinearNop) || (scan->type == IROLinearLabel && scan->u.label.label != linear->u.label.label)))
+ scan = scan->next;
+ while (1) {
+ if (!scan) break;
+ if (scan->type != IROLinearLabel) break;
+ if (scan->u.label.label == linear->u.label.label) {
+ IRO_Dump("Removing goto next at %d\n", linear->index);
+ linear->type = IROLinearNop;
+ result = 1;
+ break;
+ }
+ scan = scan->next;
+ }
+ break;
+
+ case IROLinearIf:
+ case IROLinearIfNot:
+ scan = linear->next;
+ while (scan && scan->type == IROLinearNop)
+ scan = scan->next;
+ if (scan && scan->type == IROLinearGoto) {
+ scan2 = scan->next;
+ while (scan2 && ((scan2->type == IROLinearNop) || (scan2->type == IROLinearLabel && scan2->u.label.label != linear->u.label.label)))
+ scan2 = scan2->next;
+
+ if (scan2 && scan2->type == IROLinearLabel && scan2->u.label.label == linear->u.label.label) {
+ if (linear->type == IROLinearIf)
+ linear->type = IROLinearIfNot;
+ else
+ linear->type = IROLinearIf;
+
+ linear->u.label.label = scan->u.label.label;
+ scan->type = IROLinearNop;
+ IRO_Dump("Removing branch around goto at %d\n", linear->index);
+ result = 1;
+ }
+ }
+
+ scan2 = linear->next;
+ while (scan2 && ((scan2->type == IROLinearNop) || (scan2->type == IROLinearLabel && scan2->u.label.label != linear->u.label.label)))
+ scan2 = scan2->next;
+ while (1) {
+ if (!scan2) break;
+ if (scan2->type != IROLinearLabel) break;
+ if (scan2->u.label.label == linear->u.label.label) {
+ IRO_Dump("Removing If/IfNot_Goto next at %d\n", linear->index);
+ linear->type = IROLinearNop;
+ IRO_CheckSideEffect(linear->u.label.x4);
+ result = 1;
+ break;
+ }
+ scan2 = scan2->next;
+ }
+ break;
+
+ case IROLinearSwitch:
+ info = linear->u.swtch.info;
+ curcase = info->cases;
+ while (curcase && curcase->label == info->defaultlabel)
+ curcase = curcase->next;
+ if (!curcase) {
+ IRO_Dump("Removing Switch next at %d\n", linear->index);
+ IRO_CheckSideEffect(linear->u.swtch.x4);
+ linear->type = IROLinearGoto;
+ linear->u.label.label = info->defaultlabel;
+ result = 1;
+ }
+ break;
+ }
+ }
+ }
+
+ if (result) {
+ IRO_ComputeSuccPred();
+ IRO_ComputeDom();
+ }
+
+ IRO_CheckForUserBreak();
+ return result;
+}
+
+Boolean IRO_RemoveLabels(void) {
+ Boolean result;
+ IRONode *node;
+
+ result = 0;
+ IRO_ComputeSuccPred();
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (node->first && node->first->type == IROLinearLabel && !node->x39) {
+ node->first->type = IROLinearNop;
+ node->first->flags &= ~IROLF_1;
+ result = 1;
+ }
+ }
+
+ IRO_CheckForUserBreak();
+ return result;
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroJump.h b/compiler_and_linker/FrontEnd/Optimizer/IroJump.h
new file mode 100644
index 0000000..62b7be6
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroJump.h
@@ -0,0 +1,12 @@
+#ifndef COMPILER_IROJUMP_H
+#define COMPILER_IROJUMP_H
+
+#include "IrOptimizer.h"
+
+extern Boolean IRO_DoJumpChaining(void);
+extern void IRO_MakeReachable(IRONode *node);
+extern Boolean IRO_RemoveUnreachable(void);
+extern Boolean IRO_RemoveRedundantJumps(void);
+extern Boolean IRO_RemoveLabels(void);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.c b/compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.c
new file mode 100644
index 0000000..8c5b0d8
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.c
@@ -0,0 +1,1797 @@
+#include "IroLinearForm.h"
+#include "IroDump.h"
+#include "IroFlowgraph.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInt64.h"
+#include "compiler/CParser.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/InlineAsmPPC.h"
+#include "compiler/types.h"
+
+typedef struct NullCheckListNode {
+ SInt32 precompid;
+ Object *tempobj;
+ struct NullCheckListNode *next;
+} NullCheckListNode;
+
+IROLinear *IRO_FirstLinear;
+IROLinear *IRO_LastLinear;
+UInt32 IRO_NumLinear;
+Statement *CurStat;
+static NullCheckListNode *NullCheckList;
+static Statement *CurrStmt;
+static Statement *PrevStmt;
+
+static void LinkLinear(IROLinear *linear) {
+ linear->index = IRO_NumLinear++;
+ if (IRO_FirstLinear)
+ IRO_LastLinear->next = linear;
+ else
+ IRO_FirstLinear = linear;
+ IRO_LastLinear = linear;
+}
+
+IROLinear *IRO_NewLinear(IROLinearType type) {
+ IROLinear *linear = oalloc(sizeof(IROLinear));
+ memset(linear, 0, sizeof(IROLinear));
+ linear->stmt = CurStat;
+ linear->nodetype = EPOSTINC;
+ linear->next = NULL;
+ linear->type = type;
+ linear->rtype = NULL;
+ linear->flags = 0;
+ linear->nodeflags = 0;
+ linear->expr = NULL;
+ linear->x16 = 0;
+ return linear;
+}
+
+static void MarkAssigned(IROLinear *linear, Boolean flag) {
+ IROLinear *inner;
+ IROAddrRecord *rec;
+
+ if (IS_LINEAR_MONADIC(linear, EINDIRECT) && IS_LINEAR_MONADIC(linear->u.monadic, EBITFIELD)) {
+ linear->flags |= IROLF_Assigned;
+ inner = linear->u.monadic->u.monadic;
+ if (inner->type == IROLinearOperand) {
+ inner->flags |= IROLF_Assigned;
+ if (flag) {
+ linear->flags |= IROLF_Used;
+ inner->flags |= IROLF_Used;
+ }
+ }
+
+ if (IS_LINEAR_DIADIC(inner, EADD)) {
+ if (IS_LINEAR_ENODE(inner->u.diadic.left, EOBJREF)) {
+ if (IS_LINEAR_ENODE(inner->u.diadic.right, EINTCONST))
+ inner->u.diadic.left->flags |= IROLF_Assigned;
+ if (flag) {
+ linear->flags |= IROLF_Used;
+ inner->u.diadic.left->flags |= IROLF_Used;
+ }
+ }
+
+ rec = IRO_InitAddrRecordPointer(inner);
+ IRO_DecomposeAddressExpression(inner, rec);
+ if (rec->numObjRefs == 1 && IS_LINEAR_ENODE(inner->u.diadic.left, EOBJREF)) {
+ ((IROLinear *) rec->objRefs->element)->flags |= IROLF_Assigned;
+ if (flag) {
+ linear->flags |= IROLF_Used;
+ ((IROLinear *) rec->objRefs->element)->flags |= IROLF_Used;
+ }
+ }
+ }
+ }
+
+ if (IS_LINEAR_MONADIC(linear, EINDIRECT)) {
+ linear->flags |= IROLF_Assigned;
+ if (linear->u.monadic->type == IROLinearOperand) {
+ linear->u.monadic->flags |= IROLF_Assigned;
+ if (flag) {
+ linear->flags |= IROLF_Used;
+ linear->u.monadic->flags |= IROLF_Used;
+ }
+ }
+ }
+
+ if (IS_LINEAR_MONADIC(linear, EINDIRECT)) {
+ linear->flags |= IROLF_Assigned;
+ inner = linear->u.monadic;
+
+ if (IS_LINEAR_DIADIC(inner, EADD)) {
+ if (IS_LINEAR_ENODE(inner->u.diadic.left, EOBJREF)) {
+ if (IS_LINEAR_ENODE(inner->u.diadic.right, EINTCONST))
+ inner->u.diadic.left->flags |= IROLF_Assigned;
+ if (flag) {
+ linear->flags |= IROLF_Used;
+ inner->u.diadic.left->flags |= IROLF_Used;
+ }
+ }
+
+ rec = IRO_InitAddrRecordPointer(inner);
+ IRO_DecomposeAddressExpression(inner, rec);
+ if (rec->numObjRefs == 1 && IS_LINEAR_ENODE(inner->u.diadic.left, EOBJREF)) {
+ ((IROLinear *) rec->objRefs->element)->flags |= IROLF_Assigned;
+ if (flag) {
+ linear->flags |= IROLF_Used;
+ ((IROLinear *) rec->objRefs->element)->flags |= IROLF_Used;
+ }
+ }
+ }
+ }
+}
+
+static void MarkSubscript(IROLinear *linear) {
+ linear->flags |= IROLF_Subs;
+ if (IS_LINEAR_DIADIC(linear, EADD)) {
+ if (IRO_IsAddressMultiply(linear->u.diadic.left) || IS_LINEAR_MONADIC(linear->u.diadic.left, EINDIRECT))
+ linear->u.diadic.left->flags |= IROLF_Subs;
+ if (IRO_IsAddressMultiply(linear->u.diadic.right) || IS_LINEAR_MONADIC(linear->u.diadic.right, EINDIRECT))
+ linear->u.diadic.right->flags |= IROLF_Subs;
+
+ if (IS_LINEAR_DIADIC(linear->u.diadic.left, EADD))
+ MarkSubscript(linear->u.diadic.left);
+ if (IS_LINEAR_DIADIC(linear->u.diadic.right, EADD))
+ MarkSubscript(linear->u.diadic.right);
+ }
+}
+
+static void MarkArgs(IROLinear *linear) {
+ int i;
+ linear->flags |= IROLF_4000;
+
+ switch (linear->type) {
+ case IROLinearEnd:
+ break;
+ case IROLinearOp1Arg:
+ case IROLinearBeginCatch:
+ case IROLinearEndCatch:
+ case IROLinearEndCatchDtor:
+ MarkArgs(linear->u.monadic);
+ break;
+ case IROLinearOp2Arg:
+ MarkArgs(linear->u.diadic.left);
+ MarkArgs(linear->u.diadic.right);
+ break;
+ case IROLinearIf:
+ case IROLinearIfNot:
+ MarkArgs(linear->u.label.x4);
+ break;
+ case IROLinearReturn:
+ if (linear->u.monadic)
+ MarkArgs(linear->u.monadic);
+ break;
+ case IROLinearSwitch:
+ MarkArgs(linear->u.swtch.x4);
+ break;
+ case IROLinearOp3Arg:
+ MarkArgs(linear->u.args3.a);
+ MarkArgs(linear->u.args3.b);
+ MarkArgs(linear->u.args3.c);
+ break;
+ case IROLinearFunccall:
+ MarkArgs(linear->u.funccall.linear8);
+ for (i = 0; i < linear->u.funccall.argCount; i++)
+ MarkArgs(linear->u.funccall.args[i]);
+ break;
+ }
+}
+
+// assumed name, position
+CW_INLINE void MarkSubExpr(IROLinear *linear) {
+ int i;
+
+ switch (linear->type) {
+ case IROLinearNop:
+ case IROLinearOperand:
+ case IROLinearGoto:
+ case IROLinearLabel:
+ case IROLinearEntry:
+ case IROLinearExit:
+ case IROLinearAsm:
+ case IROLinearEnd:
+ break;
+ case IROLinearOp1Arg:
+ case IROLinearBeginCatch:
+ case IROLinearEndCatch:
+ case IROLinearEndCatchDtor:
+ linear->u.monadic->flags |= IROLF_Reffed;
+ break;
+ case IROLinearOp2Arg:
+ linear->u.diadic.left->flags |= IROLF_Reffed;
+ linear->u.diadic.right->flags |= IROLF_Reffed;
+ break;
+ case IROLinearIf:
+ case IROLinearIfNot:
+ linear->u.label.x4->flags |= IROLF_Reffed;
+ break;
+ case IROLinearReturn:
+ if (linear->u.monadic)
+ linear->u.monadic->flags |= IROLF_Reffed;
+ break;
+ case IROLinearSwitch:
+ linear->u.swtch.x4->flags |= IROLF_Reffed;
+ break;
+ case IROLinearOp3Arg:
+ linear->u.args3.a->flags |= IROLF_Reffed;
+ linear->u.args3.b->flags |= IROLF_Reffed;
+ linear->u.args3.c->flags |= IROLF_Reffed;
+ break;
+ case IROLinearFunccall:
+ linear->u.funccall.linear8->flags |= IROLF_Reffed;
+ for (i = 0; i < linear->u.funccall.argCount; i++)
+ linear->u.funccall.args[i]->flags |= IROLF_Reffed;
+ break;
+ default:
+ CError_FATAL(368);
+ }
+}
+
+static void MarkSubs1(IROLinear *linear) {
+ IROAddrRecord *rec;
+
+ if (IS_LINEAR_MONADIC(linear, EBITFIELD)) {
+ linear = linear->u.monadic;
+ if (IS_LINEAR_ENODE(linear, EOBJREF))
+ linear->flags |= IROLF_Ind;
+ }
+
+ if (IS_LINEAR_DIADIC(linear, EADD)) {
+ if (IS_LINEAR_ENODE(linear->u.diadic.left, EOBJREF) && IS_LINEAR_ENODE(linear->u.diadic.right, EINTCONST))
+ linear->u.diadic.left->flags |= IROLF_Ind;
+
+ rec = IRO_InitAddrRecordPointer(linear);
+ IRO_DecomposeAddressExpression(linear, rec);
+ if (rec->numObjRefs == 1 && IS_LINEAR_ENODE(linear->u.diadic.left, EOBJREF))
+ ((IROLinear *) rec->objRefs->element)->flags |= IROLF_Ind;
+ }
+}
+
+static void MakeLeftChildAsAssignment(ENode *enode) {
+ Statement *stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = enode->data.diadic.left;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void AssignCommaRToTemp(ENode *enode, Boolean flag) {
+ Statement *stmt;
+
+ if (!IS_TYPE_VOID(enode->rtype) && !flag) {
+ Object *obj = create_temp_object(enode->rtype);
+ ENode *indnode = IRO_NewENode(EINDIRECT);
+ indnode->data.monadic = create_objectrefnode(obj);
+
+ if (!IS_TYPE_VOID(enode->rtype))
+ indnode->rtype = enode->rtype;
+ else
+ CError_FATAL(548);
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = IRO_NewENode(EASS);
+ stmt->expr->data.diadic.left = indnode;
+ stmt->expr->data.diadic.right = enode->data.diadic.right;
+ stmt->expr->rtype = enode->rtype;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+
+ enode->type = EINDIRECT;
+ enode->data.monadic = create_objectrefnode(obj);
+ CError_ASSERT(580, !IS_TYPE_VOID(enode->rtype));
+ } else {
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = enode->data.diadic.right;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+
+ enode->type = EINTCONST;
+ enode->data.intval = cint64_zero;
+ }
+}
+
+static void AssignDangerousArgumentToTemp(ENode *enode) {
+ Statement *stmt;
+ Object *obj;
+ ENode *indnode;
+ ENode *rightnode;
+
+ obj = create_temp_object(enode->rtype);
+ indnode = IRO_NewENode(EINDIRECT);
+ indnode->data.monadic = create_objectrefnode(obj);
+
+ if (!IS_TYPE_VOID(enode->rtype))
+ indnode->rtype = enode->rtype;
+ else
+ CError_FATAL(627);
+
+ rightnode = IRO_NewENode(enode->type);
+ memcpy(rightnode, enode, sizeof(ENode));
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = IRO_NewENode(EASS);
+ stmt->expr->data.diadic.left = indnode;
+ stmt->expr->data.diadic.right = rightnode;
+ stmt->expr->rtype = enode->rtype;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+
+ enode->type = EINDIRECT;
+ enode->data.monadic = create_objectrefnode(obj);
+}
+
+static void CreateTempAssignmentToZero(ENode *enode, Object **objptr) {
+ Statement *stmt;
+ ENode *indnode;
+ ENode *rightnode;
+
+ *objptr = create_temp_object(enode->rtype);
+ indnode = IRO_NewENode(EINDIRECT);
+ indnode->data.monadic = create_objectrefnode(*objptr);
+ if (!IS_TYPE_VOID(enode->rtype))
+ indnode->rtype = enode->rtype;
+ else
+ CError_FATAL(678);
+
+ rightnode = IRO_NewENode(EINTCONST);
+ rightnode->data.intval = cint64_zero;
+ rightnode->rtype = enode->rtype;
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = IRO_NewENode(EASS);
+ stmt->expr->data.diadic.left = indnode;
+ stmt->expr->data.diadic.right = rightnode;
+ stmt->expr->rtype = enode->rtype;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void CreateTempAssignmentToOne(ENode *enode, Object **objptr) {
+ Statement *stmt;
+ ENode *indnode;
+ ENode *rightnode;
+
+ *objptr = create_temp_object(enode->rtype);
+ indnode = IRO_NewENode(EINDIRECT);
+ indnode->data.monadic = create_objectrefnode(*objptr);
+ if (!IS_TYPE_VOID(enode->rtype))
+ indnode->rtype = enode->rtype;
+ else
+ CError_FATAL(720);
+
+ rightnode = IRO_NewENode(EINTCONST);
+ rightnode->data.intval = cint64_one;
+ rightnode->rtype = enode->rtype;
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = IRO_NewENode(EASS);
+ stmt->expr->data.diadic.left = indnode;
+ stmt->expr->data.diadic.right = rightnode;
+ stmt->expr->rtype = enode->rtype;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void GenerateCondExpression(ENode *enode, CLabel **label) {
+ Statement *stmt;
+
+ *label = IRO_NewLabel();
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_IFNGOTO;
+ stmt->expr = enode->data.cond.cond;
+ stmt->label = *label;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void GenerateGoToStmt(ENode *enode, CLabel **label) {
+ Statement *stmt;
+
+ *label = IRO_NewLabel();
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_GOTO;
+ stmt->label = *label;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void PutTempOnNullCheckList(ENode *expr, Object *obj) {
+ NullCheckListNode *n = lalloc(sizeof(NullCheckListNode));
+ n->precompid = expr->data.nullcheck.precompid;
+ n->tempobj = obj;
+ n->next = NULL;
+ if (NullCheckList) {
+ n->next = NullCheckList;
+ NullCheckList = n;
+ } else {
+ NullCheckList = n;
+ }
+}
+
+static Object *GetTempFromtheList(ENode *expr) {
+ NullCheckListNode *n;
+
+ for (n = NullCheckList; n; n = n->next) {
+ if (n->precompid == expr->data.precompid)
+ break;
+ }
+
+ CError_ASSERT(839, n);
+ return n->tempobj;
+}
+
+static void GenerateNullcheckExprTempAssignment(ENode *enode, Object **objptr) {
+ Statement *stmt;
+ ENode *indnode;
+
+ if (!IS_TYPE_VOID(enode->rtype))
+ *objptr = create_temp_object(enode->rtype);
+ else
+ *objptr = create_temp_object(enode->data.nullcheck.nullcheckexpr->rtype);
+
+ PutTempOnNullCheckList(enode, *objptr);
+
+ indnode = IRO_NewENode(EINDIRECT);
+ indnode->data.monadic = create_objectrefnode(*objptr);
+ if (!IS_TYPE_VOID(enode->rtype))
+ indnode->rtype = enode->rtype;
+ else
+ indnode->rtype = enode->data.nullcheck.nullcheckexpr->rtype;
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = IRO_NewENode(EASS);
+ stmt->expr->data.diadic.left = indnode;
+ stmt->expr->data.diadic.right = enode->data.nullcheck.nullcheckexpr;
+ if (!IS_TYPE_VOID(enode->rtype))
+ stmt->expr->rtype = enode->rtype;
+ else
+ stmt->expr->rtype = enode->data.nullcheck.nullcheckexpr->rtype;
+
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void GenerateExpr1TempAssignment(ENode *enode, Object **objptr) {
+ Statement *stmt;
+ ENode *indnode;
+
+ if (!IS_TYPE_VOID(enode->rtype)) {
+ *objptr = create_temp_object(enode->rtype);
+ indnode = IRO_NewENode(EINDIRECT);
+ indnode->data.monadic = create_objectrefnode(*objptr);
+ indnode->rtype = enode->rtype;
+ CError_ASSERT(905, !IS_TYPE_VOID(enode->rtype));
+ }
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_EXPRESSION;
+ if (!IS_TYPE_VOID(enode->rtype)) {
+ stmt->expr = IRO_NewENode(EASS);
+ stmt->expr->data.diadic.left = indnode;
+ stmt->expr->data.diadic.right = enode->data.cond.expr1;
+ stmt->expr->rtype = enode->rtype;
+ } else {
+ stmt->expr = enode->data.cond.expr1;
+ }
+
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void GenerateExpr2TempAssignment(ENode *enode, Object **objptr) {
+ Statement *stmt;
+ ENode *indnode;
+
+ if (!IS_TYPE_VOID(enode->rtype)) {
+ indnode = IRO_NewENode(EINDIRECT);
+ indnode->data.monadic = create_objectrefnode(*objptr);
+ indnode->rtype = enode->rtype;
+ CError_ASSERT(953, !IS_TYPE_VOID(enode->rtype));
+ }
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_EXPRESSION;
+ if (!IS_TYPE_VOID(enode->rtype)) {
+ stmt->expr = IRO_NewENode(EASS);
+ stmt->expr->data.diadic.left = indnode;
+ stmt->expr->data.diadic.right = enode->data.cond.expr2;
+ stmt->expr->rtype = enode->rtype;
+ } else {
+ stmt->expr = enode->data.cond.expr2;
+ }
+
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void GenerateForceLoadTempAssignment(ENode *enode, Object **objptr) {
+ Statement *stmt;
+ ENode *indnode;
+
+ if (!IS_TYPE_VOID(enode->rtype)) {
+ *objptr = create_temp_object(enode->rtype);
+ indnode = IRO_NewENode(EINDIRECT);
+ indnode->data.monadic = create_objectrefnode(*objptr);
+ indnode->rtype = enode->rtype;
+ CError_ASSERT(1003, !IS_TYPE_VOID(enode->rtype));
+ }
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_EXPRESSION;
+ if (!IS_TYPE_VOID(enode->rtype)) {
+ stmt->expr = IRO_NewENode(EASS);
+ stmt->expr->data.diadic.left = indnode;
+ stmt->expr->data.diadic.right = enode->data.monadic;
+ stmt->expr->rtype = enode->rtype;
+ } else {
+ stmt->expr = enode->data.monadic;
+ }
+
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void GenerateLabel(CLabel **labelptr) {
+ Statement *stmt;
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_LABEL;
+ stmt->label = *labelptr;
+ stmt->label->stmt = stmt;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void GenerateIfNotTemp(ENode *enode, Object **objptr, CLabel **labelptr) {
+ Statement *stmt;
+ ENode *indnode;
+
+ indnode = IRO_NewENode(EINDIRECT);
+ indnode->data.monadic = create_objectrefnode(*objptr);
+ if (!IS_TYPE_VOID(enode->rtype))
+ indnode->rtype = enode->rtype;
+ else
+ indnode->rtype = enode->data.monadic->rtype;
+
+ *labelptr = IRO_NewLabel();
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_IFNGOTO;
+ stmt->expr = indnode;
+ stmt->label = *labelptr;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void GenerateNullcheckCondExpr(ENode *enode, Object **objptr) {
+ Statement *stmt;
+ ENode *indnode;
+
+ indnode = IRO_NewENode(EINDIRECT);
+ indnode->data.monadic = create_objectrefnode(*objptr);
+ if (!IS_TYPE_VOID(enode->rtype))
+ indnode->rtype = enode->rtype;
+ else
+ indnode->rtype = enode->data.nullcheck.nullcheckexpr->rtype;
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = IRO_NewENode(EASS);
+ stmt->expr->data.diadic.left = indnode;
+ stmt->expr->data.diadic.right = enode->data.nullcheck.condexpr;
+ if (!IS_TYPE_VOID(enode->rtype))
+ stmt->expr->rtype = enode->rtype;
+ else
+ stmt->expr->rtype = enode->data.nullcheck.nullcheckexpr->rtype;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void TransformLogicalAndLHS(ENode *enode, Object **objptr, CLabel **labelptr) {
+ Statement *stmt;
+
+ *labelptr = IRO_NewLabel();
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_IFNGOTO;
+ stmt->expr = enode->data.diadic.left;
+ stmt->label = *labelptr;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void TransformLogicalAndRHS(ENode *enode, Object **objptr, CLabel **labelptr) {
+ Statement *stmt;
+ ENode *indnode;
+ ENode *rightnode;
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_IFNGOTO;
+ stmt->expr = enode->data.diadic.right;
+ stmt->label = *labelptr;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+
+ indnode = IRO_NewENode(EINDIRECT);
+ indnode->data.monadic = create_objectrefnode(*objptr);
+ if (!IS_TYPE_VOID(enode->rtype))
+ indnode->rtype = enode->rtype;
+ else
+ CError_FATAL(1225);
+
+ rightnode = IRO_NewENode(EINTCONST);
+ rightnode->data.intval = cint64_one;
+ rightnode->rtype = enode->rtype;
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = IRO_NewENode(EASS);
+ stmt->expr->data.diadic.left = indnode;
+ stmt->expr->data.diadic.right = rightnode;
+ stmt->expr->rtype = enode->rtype;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_LABEL;
+ stmt->label = *labelptr;
+ stmt->label->stmt = stmt;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+
+ enode->type = EINDIRECT;
+ enode->data.monadic = create_objectrefnode(*objptr);
+ CError_ASSERT(1276, !IS_TYPE_VOID(enode->rtype));
+}
+
+static void TransformLogicalOrLHS(ENode *enode, Object **objptr, CLabel **labelptr) {
+ Statement *stmt;
+
+ *labelptr = IRO_NewLabel();
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_IFGOTO;
+ stmt->expr = enode->data.diadic.left;
+ stmt->label = *labelptr;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+}
+
+static void TransformLogicalOrRHS(ENode *enode, Object **objptr, CLabel **labelptr) {
+ Statement *stmt;
+ ENode *indnode;
+ ENode *rightnode;
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_IFGOTO;
+ stmt->expr = enode->data.diadic.right;
+ stmt->label = *labelptr;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+
+ indnode = IRO_NewENode(EINDIRECT);
+ indnode->data.monadic = create_objectrefnode(*objptr);
+ if (!IS_TYPE_VOID(enode->rtype))
+ indnode->rtype = enode->rtype;
+ else
+ CError_FATAL(1354);
+
+ rightnode = IRO_NewENode(EINTCONST);
+ rightnode->data.intval = cint64_zero;
+ rightnode->rtype = enode->rtype;
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_EXPRESSION;
+ stmt->expr = IRO_NewENode(EASS);
+ stmt->expr->data.diadic.left = indnode;
+ stmt->expr->data.diadic.right = rightnode;
+ stmt->expr->rtype = enode->rtype;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+
+ stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = ST_LABEL;
+ stmt->label = *labelptr;
+ stmt->label->stmt = stmt;
+ stmt->dobjstack = CurrStmt->dobjstack;
+ stmt->sourceoffset = CurrStmt->sourceoffset;
+ stmt->sourcefilepath = CurrStmt->sourcefilepath;
+ stmt->value = CurrStmt->value;
+ stmt->flags = CurrStmt->flags;
+
+ if (PrevStmt) {
+ stmt->next = PrevStmt->next;
+ PrevStmt->next = stmt;
+ } else {
+ stmt->next = NULL;
+ }
+ PrevStmt = stmt;
+
+ enode->type = EINDIRECT;
+ enode->data.monadic = create_objectrefnode(*objptr);
+ CError_ASSERT(1405, !IS_TYPE_VOID(enode->rtype));
+}
+
+static void LinearizeExpr1(ENode *a, ENode *b, Boolean flag, Boolean flag2) {
+ switch (a->type) {
+ ENODE_CASE_MONADIC:
+ LinearizeExpr1(a->data.monadic, a, 0, 0);
+ if (a->type == EFORCELOAD) {
+ Object *obj;
+ GenerateForceLoadTempAssignment(a, &obj);
+ a->type = EINDIRECT;
+ a->data.monadic = create_objectrefnode(obj);
+ CError_ASSERT(1428, !IS_TYPE_VOID(a->rtype));
+ }
+ break;
+ ENODE_CASE_DIADIC_1:
+ case ECOMMA:
+ case EPMODULO:
+ case EROTL:
+ case EROTR:
+ case EBTST:
+ if (a->type == ECOMMA) {
+ LinearizeExpr1(a->data.diadic.left, a, 1, 0);
+ MakeLeftChildAsAssignment(a);
+ LinearizeExpr1(a->data.diadic.right, a, 0, 0);
+ AssignCommaRToTemp(a, flag);
+ } else if (a->data.diadic.right->cost >= a->data.diadic.left->cost) {
+ LinearizeExpr1(a->data.diadic.right, a, 0, 0);
+ LinearizeExpr1(a->data.diadic.left, a, 0, 0);
+ } else {
+ LinearizeExpr1(a->data.diadic.left, a, 0, 0);
+ LinearizeExpr1(a->data.diadic.right, a, 0, 0);
+ }
+ break;
+ ENODE_CASE_ASSIGN:
+ LinearizeExpr1(a->data.diadic.right, a, 0, 0);
+ LinearizeExpr1(a->data.diadic.left, a, 0, 0);
+ break;
+ case ELAND:
+ case ELOR:
+ if (a->type == ELAND) {
+ CLabel *label;
+ Object *obj;
+ CreateTempAssignmentToZero(a, &obj);
+ LinearizeExpr1(a->data.diadic.left, a, 0, 0);
+ TransformLogicalAndLHS(a, &obj, &label);
+ LinearizeExpr1(a->data.diadic.right, a, 0, 0);
+ TransformLogicalAndRHS(a, &obj, &label);
+ } else if (a->type == ELOR) {
+ CLabel *label;
+ Object *obj;
+ CreateTempAssignmentToOne(a, &obj);
+ LinearizeExpr1(a->data.diadic.left, a, 0, 0);
+ TransformLogicalOrLHS(a, &obj, &label);
+ LinearizeExpr1(a->data.diadic.right, a, 0, 0);
+ TransformLogicalOrRHS(a, &obj, &label);
+ }
+ break;
+ case ECOND: {
+ CLabel *label1, *label2;
+ Object *obj;
+ LinearizeExpr1(a->data.cond.cond, a, 0, 0);
+ GenerateCondExpression(a, &label1);
+ LinearizeExpr1(a->data.cond.expr1, a, 0, 0);
+ GenerateExpr1TempAssignment(a, &obj);
+ GenerateGoToStmt(a, &label2);
+ GenerateLabel(&label1);
+ LinearizeExpr1(a->data.cond.expr2, a, 0, 0);
+ GenerateExpr2TempAssignment(a, &obj);
+ GenerateLabel(&label2);
+ if (!IS_TYPE_VOID(a->rtype)) {
+ a->type = EINDIRECT;
+ a->data.monadic = create_objectrefnode(obj);
+ CError_ASSERT(1596, !IS_TYPE_VOID(a->rtype));
+ } else {
+ a->type = EINTCONST;
+ a->data.intval = cint64_zero;
+ }
+ break;
+ }
+ case EPRECOMP: {
+ Object *temp = GetTempFromtheList(a);
+ a->type = EINDIRECT;
+ a->data.monadic = create_objectrefnode(temp);
+ CError_ASSERT(1614, !IS_TYPE_VOID(a->rtype));
+ break;
+ }
+ case ENULLCHECK: {
+ CLabel *label;
+ Object *obj;
+ LinearizeExpr1(a->data.nullcheck.nullcheckexpr, a, 0, 0);
+ GenerateNullcheckExprTempAssignment(a, &obj);
+ GenerateIfNotTemp(a, &obj, &label);
+ LinearizeExpr1(a->data.nullcheck.condexpr, a, 0, 0);
+ GenerateNullcheckCondExpr(a, &obj);
+ GenerateLabel(&label);
+ if (!IS_TYPE_VOID(a->rtype)) {
+ a->type = EINDIRECT;
+ a->data.monadic = create_objectrefnode(obj);
+ CError_ASSERT(1639, !IS_TYPE_VOID(a->rtype));
+ } else {
+ a->type = EINTCONST;
+ a->data.intval = cint64_zero;
+ }
+ break;
+ }
+ case EFUNCCALL:
+ case EFUNCCALLP: {
+ SInt32 count;
+ SInt32 i;
+ ENodeList *list;
+ ENode **arr;
+ SInt16 *arr2;
+
+ IRO_IsLeafFunction = 0;
+
+ list = a->data.funccall.args;
+ count = 0;
+ while (list) {
+ list = list->next;
+ count++;
+ }
+
+ if (count) {
+ arr = oalloc(sizeof(ENode *) * count);
+ list = a->data.funccall.args;
+ count = 0;
+ while (list) {
+ arr[count] = list->node;
+ list = list->next;
+ count++;
+ }
+
+ arr2 = oalloc(sizeof(SInt16) * count);
+ for (i = 0; i < count; i++)
+ arr2[i] = count - i - 1;
+
+ for (i = 0; i < count; i++)
+ LinearizeExpr1(arr[arr2[i]], a, 0, 0);
+ }
+
+ LinearizeExpr1(a->data.funccall.funcref, a, 0, 0);
+ break;
+ }
+
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case ESETCONST:
+ case EVECTOR128CONST:
+ break;
+
+ default:
+ CError_FATAL(1723);
+ }
+}
+
+static IROLinear *LinearizeExpr(ENode *enode) {
+ IROLinear *linear = NULL;
+
+ switch (enode->type) {
+ ENODE_CASE_MONADIC:
+ linear = IRO_NewLinear(IROLinearOp1Arg);
+ linear->u.monadic = LinearizeExpr(enode->data.monadic);
+ linear->nodetype = enode->type;
+ linear->rtype = enode->rtype;
+ linear->nodeflags = enode->flags;
+ if (IRO_IsAssignOp[linear->nodetype])
+ MarkAssigned(linear->u.monadic, 1);
+ if (linear->nodetype == EINDIRECT) {
+ MarkSubs1(linear->u.monadic);
+ linear->u.monadic->flags |= IROLF_Immind | IROLF_Ind;
+ if (IS_LINEAR_DIADIC(linear->u.monadic, EADD))
+ MarkSubscript(linear->u.monadic);
+ }
+ break;
+ ENODE_CASE_DIADIC_1:
+ case ECOMMA:
+ case EPMODULO:
+ case EROTL:
+ case EROTR:
+ case EBTST:
+ linear = IRO_NewLinear(IROLinearOp2Arg);
+ linear->nodeflags = enode->flags;
+ if (!ENODE_IS(enode, ECOMMA) && enode->data.diadic.right->cost >= enode->data.diadic.left->cost) {
+ linear->u.diadic.right = LinearizeExpr(enode->data.diadic.right);
+ linear->u.diadic.left = LinearizeExpr(enode->data.diadic.left);
+ linear->flags |= IROLF_8000;
+ } else {
+ linear->u.diadic.left = LinearizeExpr(enode->data.diadic.left);
+ linear->u.diadic.right = LinearizeExpr(enode->data.diadic.right);
+ }
+ linear->nodetype = enode->type;
+ linear->rtype = enode->rtype;
+ if (IRO_IsAssignOp[linear->nodetype])
+ MarkAssigned(linear->u.diadic.left, IRO_IsModifyOp[linear->nodetype]);
+ break;
+ ENODE_CASE_ASSIGN:
+ linear = IRO_NewLinear(IROLinearOp2Arg);
+ linear->nodeflags = enode->flags;
+ linear->u.diadic.right = LinearizeExpr(enode->data.diadic.right);
+ linear->u.diadic.left = LinearizeExpr(enode->data.diadic.left);
+ linear->flags |= IROLF_8000;
+ linear->nodetype = enode->type;
+ linear->rtype = enode->rtype;
+ MarkAssigned(linear->u.diadic.left, IRO_IsModifyOp[linear->nodetype]);
+ break;
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EVECTOR128CONST:
+ linear = IRO_NewLinear(IROLinearOperand);
+ linear->nodeflags = enode->flags;
+ linear->u.node = enode;
+ linear->rtype = enode->rtype;
+ break;
+ case EFUNCCALL:
+ case EFUNCCALLP: {
+ SInt32 count;
+ SInt32 i;
+ ENodeList *list;
+ ENode **arr;
+ SInt16 *arr2;
+
+ linear = IRO_NewLinear(IROLinearFunccall);
+ linear->nodeflags = enode->flags;
+ linear->u.funccall.ispascal = enode->type == EFUNCCALLP;
+
+ list = enode->data.funccall.args;
+ count = 0;
+ while (list) {
+ list = list->next;
+ count++;
+ }
+
+ arr = NULL;
+ if (count) {
+ arr = oalloc(sizeof(ENode *) * count);
+ list = enode->data.funccall.args;
+ count = 0;
+ while (list) {
+ arr[count] = list->node;
+ list = list->next;
+ count++;
+ }
+
+ arr2 = oalloc(sizeof(SInt16) * count);
+ for (i = 0; i < count; i++)
+ arr2[i] = count - i - 1;
+
+ for (i = 0; i < count; i++) {
+ arr[arr2[i]] = (ENode *) LinearizeExpr(arr[arr2[i]]);
+ MarkArgs((IROLinear *) arr[arr2[i]]);
+ }
+ }
+
+ linear->u.funccall.argCount = count;
+ linear->u.funccall.args = (IROLinear **) arr;
+ linear->u.funccall.linear8 = LinearizeExpr(enode->data.funccall.funcref);
+ linear->u.funccall.functype = enode->data.funccall.functype;
+ linear->rtype = enode->rtype;
+ break;
+ }
+ default:
+ CError_FATAL(1943);
+ }
+
+ if (linear)
+ LinkLinear(linear);
+ return linear;
+}
+
+void IRO_PreLinearize(Statement *stmt) {
+ IRO_FirstLinear = IRO_LastLinear = NULL;
+ IRO_NumLinear = 0;
+ CurrStmt = PrevStmt = NULL;
+
+ while (stmt) {
+ CurStat = stmt;
+ CurrStmt = stmt;
+ NullCheckList = NULL;
+
+ switch (stmt->type) {
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_GOTO:
+ break;
+ case ST_OVF:
+ CError_FATAL(1989);
+ case ST_EXPRESSION:
+ LinearizeExpr1(stmt->expr, NULL, 0, 0);
+ break;
+ case ST_SWITCH:
+ LinearizeExpr1(stmt->expr, NULL, 0, 0);
+ break;
+ case ST_IFGOTO:
+ LinearizeExpr1(stmt->expr, NULL, 0, 0);
+ break;
+ case ST_IFNGOTO:
+ LinearizeExpr1(stmt->expr, NULL, 0, 0);
+ break;
+ case ST_RETURN:
+ if (stmt->expr)
+ LinearizeExpr1(stmt->expr, NULL, 0, 0);
+ break;
+ case ST_BEGINCATCH:
+ LinearizeExpr1(stmt->expr, NULL, 0, 0);
+ break;
+ case ST_ENDCATCH:
+ LinearizeExpr1(stmt->expr, NULL, 0, 0);
+ break;
+ case ST_ENDCATCHDTOR:
+ LinearizeExpr1(stmt->expr, NULL, 0, 0);
+ break;
+
+ case ST_EXIT:
+ case ST_ENTRY:
+ case ST_ASM:
+ break;
+
+ default:
+ CError_FATAL(2038);
+ }
+
+ PrevStmt = stmt;
+ stmt = stmt->next;
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+static void MarkAllSubExprs(IROLinear *linear) {
+ IROLinear *scan;
+ int i;
+
+ for (scan = linear; scan; scan = scan->next)
+ scan->flags &= ~IROLF_Reffed;
+
+ for (scan = linear; scan; scan = scan->next)
+ MarkSubExpr(scan);
+}
+
+void IRO_Linearize(Statement *stmt) {
+ IROLinear *linear;
+
+ IRO_FirstLinear = IRO_LastLinear = NULL;
+ IRO_NumLinear = 0;
+
+ while (stmt) {
+ CurStat = stmt;
+ linear = NULL;
+
+ switch (stmt->type) {
+ case ST_NOP:
+ linear = IRO_NewLinear(IROLinearNop);
+ break;
+ case ST_LABEL:
+ linear = IRO_NewLinear(IROLinearLabel);
+ linear->u.label.label = stmt->label;
+ linear->flags |= IROLF_1;
+ break;
+ case ST_GOTO:
+ linear = IRO_NewLinear(IROLinearGoto);
+ linear->u.label.label = stmt->label;
+ break;
+ case ST_EXPRESSION:
+ LinearizeExpr(stmt->expr);
+ break;
+ case ST_SWITCH:
+ linear = IRO_NewLinear(IROLinearSwitch);
+ linear->u.swtch.x4 = LinearizeExpr(stmt->expr);
+ linear->u.swtch.info = (SwitchInfo *) stmt->label;
+ break;
+ case ST_IFGOTO:
+ linear = IRO_NewLinear(IROLinearIf);
+ linear->u.label.x4 = LinearizeExpr(stmt->expr);
+ linear->u.label.label = stmt->label;
+ break;
+ case ST_IFNGOTO:
+ linear = IRO_NewLinear(IROLinearIfNot);
+ linear->u.label.x4 = LinearizeExpr(stmt->expr);
+ linear->u.label.label = stmt->label;
+ break;
+ case ST_RETURN:
+ IRO_FunctionHasReturn = 1;
+ linear = IRO_NewLinear(IROLinearReturn);
+ if (stmt->expr)
+ linear->u.monadic = LinearizeExpr(stmt->expr);
+ else
+ linear->u.monadic = NULL;
+ break;
+ case ST_OVF:
+ CError_FATAL(2143);
+ break;
+ case ST_EXIT:
+ linear = IRO_NewLinear(IROLinearExit);
+ linear->u.label.label = stmt->label;
+ break;
+ case ST_ENTRY:
+ linear = IRO_NewLinear(IROLinearEntry);
+ linear->u.label.label = stmt->label;
+ linear->flags |= IROLF_1;
+ break;
+ case ST_BEGINCATCH:
+ linear = IRO_NewLinear(IROLinearBeginCatch);
+ linear->u.ctch.linear = LinearizeExpr(stmt->expr);
+ linear->u.ctch.x4 = 0;
+ linear->u.ctch.x8 = 0;
+ break;
+ case ST_ENDCATCH:
+ linear = IRO_NewLinear(IROLinearEndCatch);
+ linear->u.monadic = LinearizeExpr(stmt->expr);
+ break;
+ case ST_ENDCATCHDTOR:
+ linear = IRO_NewLinear(IROLinearEndCatchDtor);
+ linear->u.monadic = LinearizeExpr(stmt->expr);
+ break;
+ case ST_ASM:
+ linear = IRO_NewLinear(IROLinearAsm);
+ linear->u.asm_stmt = stmt;
+ if (copts.optimizewithasm) {
+ IAEffects effects;
+ CodeGen_GetAsmEffects(stmt, &effects);
+ if (effects.x0 || effects.x3)
+ DisableDueToAsm = 1;
+ } else {
+ DisableDueToAsm = 1;
+ }
+ break;
+ default:
+ CError_FATAL(2194);
+ }
+
+ if (linear)
+ LinkLinear(linear);
+ stmt = stmt->next;
+ }
+
+ linear = IRO_NewLinear(IROLinearEnd);
+ linear->flags |= IROLF_1;
+ LinkLinear(linear);
+
+ MarkAllSubExprs(IRO_FirstLinear);
+ IRO_CheckForUserBreak();
+}
+
+static Statement *NewStatement(IROLinear *linear, StatementType sttype) {
+ Statement *stmt = lalloc(sizeof(Statement));
+ memset(stmt, 0, sizeof(Statement));
+ stmt->type = sttype;
+ stmt->value = 1;
+ if (linear->stmt) {
+ stmt->dobjstack = linear->stmt->dobjstack;
+ stmt->sourceoffset = linear->stmt->sourceoffset;
+ stmt->sourcefilepath = linear->stmt->sourcefilepath;
+ stmt->value = linear->stmt->value;
+ stmt->flags = linear->stmt->flags;
+ } else {
+ stmt->sourceoffset = -1;
+ stmt->sourcefilepath = NULL;
+ }
+ return stmt;
+}
+
+ENode *IRO_NewENode(ENodeType nodetype) {
+ ENode *enode = lalloc(sizeof(ENode));
+ memset(enode, 0, sizeof(ENode));
+ enode->type = nodetype;
+ return enode;
+}
+
+static ENode *BuildExpr(IROLinear *linear) {
+ ENode *enode;
+
+ switch (linear->type) {
+ case IROLinearOperand:
+ enode = IRO_NewENode(linear->u.node->type);
+ enode->flags = linear->nodeflags;
+ *enode = *linear->u.node;
+ break;
+ case IROLinearOp1Arg:
+ enode = IRO_NewENode(linear->nodetype);
+ enode->flags = linear->nodeflags;
+ enode->data.monadic = BuildExpr(linear->u.monadic);
+ enode->rtype = linear->rtype;
+ enode->cost = enode->data.monadic->cost;
+ if (!enode->cost)
+ enode->cost = 1;
+ break;
+ case IROLinearOp2Arg:
+ enode = IRO_NewENode(linear->nodetype);
+ enode->flags = linear->nodeflags;
+ enode->data.diadic.left = BuildExpr(linear->u.diadic.left);
+ enode->data.diadic.right = BuildExpr(linear->u.diadic.right);
+
+ enode->cost = enode->data.diadic.left->cost;
+ if (enode->data.diadic.right->cost > enode->cost)
+ enode->cost = enode->data.diadic.right->cost;
+ else if (enode->data.diadic.right->cost == enode->cost)
+ enode->cost += 1;
+
+ if (ENODE_IS4(enode, ESHL, ESHR, EDIV, EMODULO))
+ enode->cost += 2;
+ if (enode->cost > 200)
+ enode->cost = 200;
+
+ enode->rtype = linear->rtype;
+ break;
+ case IROLinearOp3Arg:
+ enode = IRO_NewENode(linear->nodetype);
+ enode->flags = linear->nodeflags;
+ enode->data.cond.cond = BuildExpr(linear->u.args3.a);
+ enode->data.cond.expr1 = BuildExpr(linear->u.args3.b);
+ enode->data.cond.expr2 = BuildExpr(linear->u.args3.c);
+ enode->rtype = linear->rtype;
+
+ enode->cost = enode->data.cond.cond->cost;
+ if (enode->data.cond.expr1->cost > enode->cost)
+ enode->cost = enode->data.cond.expr1->cost;
+ if (enode->data.cond.expr2->cost > enode->cost)
+ enode->cost = enode->data.cond.expr2->cost;
+ enode->cost += 1;
+
+ if (enode->cost > 200)
+ enode->cost = 200;
+
+ break;
+
+ case IROLinearFunccall: {
+ int i;
+ enode = IRO_NewENode(linear->u.funccall.ispascal ? EFUNCCALLP : EFUNCCALL);
+ enode->flags = linear->nodeflags;
+ enode->data.funccall.funcref = BuildExpr(linear->u.funccall.linear8);
+ enode->data.funccall.functype = linear->u.funccall.functype;
+ enode->data.funccall.args = NULL;
+ enode->cost = 200;
+ for (i = linear->u.funccall.argCount - 1; i >= 0; i--) {
+ ENodeList *list = lalloc(sizeof(ENodeList));
+ list->node = BuildExpr(linear->u.funccall.args[i]);
+ list->next = enode->data.funccall.args;
+ enode->data.funccall.args = list;
+ }
+ enode->rtype = linear->rtype;
+ break;
+ }
+
+ default:
+ IRO_Dump("Oh, oh, bad expression type in BuildExpr at: %d\n", linear->index);
+ CError_FATAL(2390);
+ }
+
+ enode->pointsTo = linear->pointsToFunction;
+ return enode;
+}
+
+Statement *IRO_Delinearize(IRONode *node, IROLinear *linear) {
+ IROLinear *scanlin;
+ Statement *firstStmt;
+ Statement *lastStmt;
+ IRONode *scan;
+ Statement *stmt;
+ IRONode mynode;
+
+ firstStmt = lastStmt = NULL;
+
+ if (node) {
+ scan = node;
+ MarkAllSubExprs(IRO_FirstLinear);
+ } else {
+ memset(&mynode, 0, sizeof(IRONode));
+ mynode.first = linear;
+ scan = &mynode;
+ MarkAllSubExprs(linear);
+ }
+
+ while (scan) {
+ for (scanlin = scan->first; scanlin; scanlin = scanlin->next) {
+ stmt = NULL;
+ if (!(scanlin->flags & IROLF_Reffed)) {
+ switch (scanlin->type) {
+ case IROLinearNop:
+ if (scan == node)
+ stmt = NewStatement(scanlin, ST_NOP);
+ else
+ stmt = NULL;
+ break;
+ case IROLinearOperand:
+ case IROLinearOp1Arg:
+ case IROLinearOp2Arg:
+ case IROLinearOp3Arg:
+ case IROLinearFunccall:
+ stmt = NewStatement(scanlin, ST_EXPRESSION);
+ stmt->expr = BuildExpr(scanlin);
+ break;
+ case IROLinearGoto:
+ stmt = NewStatement(scanlin, ST_GOTO);
+ stmt->label = scanlin->u.label.label;
+ break;
+ case IROLinearExit:
+ stmt = NewStatement(scanlin, ST_EXIT);
+ stmt->label = scanlin->u.label.label;
+ break;
+ case IROLinearIf:
+ case IROLinearIfNot:
+ stmt = NewStatement(scanlin, (scanlin->type == IROLinearIf) ? ST_IFGOTO : ST_IFNGOTO);
+ stmt->label = scanlin->u.label.label;
+ stmt->expr = BuildExpr(scanlin->u.label.x4);
+ break;
+ case IROLinearReturn:
+ stmt = NewStatement(scanlin, ST_RETURN);
+ if (scanlin->u.monadic)
+ stmt->expr = BuildExpr(scanlin->u.monadic);
+ break;
+ case IROLinearLabel:
+ stmt = NewStatement(scanlin, ST_LABEL);
+ stmt->label = scanlin->u.label.label;
+ stmt->label->stmt = stmt;
+ break;
+ case IROLinearEntry:
+ stmt = NewStatement(scanlin, ST_ENTRY);
+ stmt->label = scanlin->u.label.label;
+ stmt->label->stmt = stmt;
+ break;
+ case IROLinearSwitch:
+ stmt = NewStatement(scanlin, ST_SWITCH);
+ stmt->expr = BuildExpr(scanlin->u.swtch.x4);
+ stmt->label = (CLabel *) scanlin->u.swtch.info;
+ break;
+ case IROLinearBeginCatch:
+ stmt = NewStatement(scanlin, ST_BEGINCATCH);
+ stmt->expr = BuildExpr(scanlin->u.ctch.linear);
+ break;
+ case IROLinearEndCatch:
+ stmt = NewStatement(scanlin, ST_ENDCATCH);
+ stmt->expr = BuildExpr(scanlin->u.monadic);
+ break;
+ case IROLinearEndCatchDtor:
+ stmt = NewStatement(scanlin, ST_ENDCATCHDTOR);
+ stmt->expr = BuildExpr(scanlin->u.monadic);
+ break;
+ case IROLinearAsm:
+ stmt = scanlin->u.asm_stmt;
+ break;
+ case IROLinearEnd:
+ stmt = NULL;
+ break;
+ default:
+ CError_FATAL(2685);
+ }
+
+ if (stmt) {
+ if (LoopOptimizerRun) {
+ SInt32 i;
+ SInt32 value = 1;
+ for (i = 0; i < scan->loopdepth; i++) {
+ value = (value < 4096) ? (value * 8) : (value + 1);
+ }
+ stmt->value = value;
+ }
+ if (firstStmt)
+ lastStmt->next = stmt;
+ else
+ firstStmt = stmt;
+ lastStmt = stmt;
+ }
+ }
+ if (scanlin == scan->last)
+ break;
+ }
+ scan = scan->nextnode;
+ }
+
+ return firstStmt;
+}
+
+void IRO_RenumberInts(void) {
+ IROLinear *linear = IRO_FirstLinear;
+ IRO_NumLinear = 0;
+ while (linear) {
+ linear->index = IRO_NumLinear++;
+ linear = linear->next;
+ }
+}
+
+static void TravExprToUpdateFlags(IROLinear *linear) {
+ int i;
+
+ linear->flags &= ~(IROLF_Assigned | IROLF_8 | IROLF_Used | IROLF_Ind | IROLF_Subs | IROLF_LoopInvariant | IROLF_Ris | IROLF_Immind | IROLF_CouldError);
+ switch (linear->type) {
+ case IROLinearNop:
+ case IROLinearOperand:
+ break;
+ case IROLinearOp1Arg:
+ TravExprToUpdateFlags(linear->u.monadic);
+ if (IRO_IsAssignOp[linear->nodetype])
+ MarkAssigned(linear->u.monadic, 1);
+ if (linear->nodetype == EINDIRECT) {
+ MarkSubs1(linear->u.monadic);
+ linear->u.monadic->flags |= IROLF_Immind | IROLF_Ind;
+ if (IS_LINEAR_DIADIC(linear->u.monadic, EADD))
+ MarkSubscript(linear->u.monadic);
+ }
+ break;
+ case IROLinearOp2Arg:
+ TravExprToUpdateFlags(linear->u.diadic.left);
+ TravExprToUpdateFlags(linear->u.diadic.right);
+ if (IRO_IsAssignOp[linear->nodetype])
+ MarkAssigned(linear->u.diadic.left, IRO_IsModifyOp[linear->nodetype]);
+ break;
+ case IROLinearOp3Arg:
+ TravExprToUpdateFlags(linear->u.args3.a);
+ TravExprToUpdateFlags(linear->u.args3.b);
+ TravExprToUpdateFlags(linear->u.args3.c);
+ break;
+ case IROLinearFunccall:
+ TravExprToUpdateFlags(linear->u.funccall.linear8);
+ for (i = linear->u.funccall.argCount - 1; i >= 0; i--)
+ TravExprToUpdateFlags(linear->u.funccall.args[i]);
+ break;
+ default:
+ IRO_Dump("Oh, oh, bad expression type in TravExprToUpdateFlags at: %d\n", linear->index);
+ CError_FATAL(2853);
+ }
+}
+
+void IRO_UpdateFlagsOnInts(void) {
+ IROLinear *linear;
+ IRONode *node;
+
+ MarkAllSubExprs(IRO_FirstLinear);
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ for (linear = node->first; linear; linear = linear->next) {
+ if (!(linear->flags & IROLF_Reffed)) {
+ switch (linear->type) {
+ case IROLinearOperand:
+ case IROLinearOp1Arg:
+ case IROLinearOp2Arg:
+ case IROLinearOp3Arg:
+ case IROLinearFunccall:
+ TravExprToUpdateFlags(linear);
+ break;
+ case IROLinearIf:
+ case IROLinearIfNot:
+ TravExprToUpdateFlags(linear->u.label.x4);
+ break;
+ case IROLinearReturn:
+ if (linear->u.monadic)
+ TravExprToUpdateFlags(linear->u.monadic);
+ break;
+ case IROLinearSwitch:
+ TravExprToUpdateFlags(linear->u.swtch.x4);
+ break;
+ case IROLinearBeginCatch:
+ TravExprToUpdateFlags(linear->u.ctch.linear);
+ break;
+ case IROLinearEndCatch:
+ TravExprToUpdateFlags(linear->u.monadic);
+ break;
+ case IROLinearEndCatchDtor:
+ TravExprToUpdateFlags(linear->u.monadic);
+ break;
+ case IROLinearNop:
+ case IROLinearGoto:
+ case IROLinearLabel:
+ case IROLinearEntry:
+ case IROLinearExit:
+ case IROLinearAsm:
+ case IROLinearEnd:
+ break;
+ default:
+ CError_FATAL(2931);
+ }
+ }
+ if (linear == node->last)
+ break;
+ }
+ }
+}
+
+void IRO_SaveLinearIR(IROLinearIRSave *save) {
+ save->firstLinear = IRO_FirstLinear;
+ save->lastLinear = IRO_LastLinear;
+ save->numLinear = IRO_NumLinear;
+ save->curStat = CurStat;
+ save->disableDueToAsm = DisableDueToAsm;
+ save->isLeafFunction = IRO_IsLeafFunction;
+ save->functionHasReturn = IRO_FunctionHasReturn;
+ save->nullCheckList = NullCheckList;
+ save->currStmt = CurrStmt;
+ save->prevStmt = PrevStmt;
+}
+
+void IRO_RestoreLinearIR(IROLinearIRSave *save) {
+ IRO_FirstLinear = save->firstLinear;
+ IRO_LastLinear = save->lastLinear;
+ IRO_NumLinear = save->numLinear;
+ CurStat = save->curStat;
+ DisableDueToAsm = save->disableDueToAsm;
+ IRO_IsLeafFunction = save->isLeafFunction;
+ IRO_FunctionHasReturn = save->functionHasReturn;
+ NullCheckList = save->nullCheckList;
+ CurrStmt = save->currStmt;
+ PrevStmt = save->prevStmt;
+}
+
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.h b/compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.h
new file mode 100644
index 0000000..c0b2d17
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroLinearForm.h
@@ -0,0 +1,165 @@
+#ifndef COMPILER_IROLINEARFORM_H
+#define COMPILER_IROLINEARFORM_H
+
+#include "IrOptimizer.h"
+#include "compiler/Switch.h"
+#include "compiler/enode.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+
+typedef struct IROLinearIRSave {
+ IROLinear *firstLinear;
+ IROLinear *lastLinear;
+ UInt32 numLinear;
+ Statement *curStat;
+ Boolean disableDueToAsm;
+ Boolean isLeafFunction;
+ Boolean functionHasReturn;
+ void *nullCheckList;
+ Statement *currStmt;
+ Statement *prevStmt;
+} IROLinearIRSave;
+
+typedef enum IROLinearType {
+ IROLinearNop,
+ IROLinearOperand,
+ IROLinearOp1Arg,
+ IROLinearOp2Arg,
+ IROLinearGoto,
+ IROLinearIf,
+ IROLinearIfNot,
+ IROLinearReturn,
+ IROLinearLabel,
+ IROLinearSwitch,
+ IROLinearOp3Arg,
+ IROLinearFunccall,
+ IROLinearEntry,
+ IROLinearExit,
+ IROLinearBeginCatch,
+ IROLinearEndCatch,
+ IROLinearEndCatchDtor,
+ IROLinearAsm,
+ IROLinear18,
+ IROLinear19,
+ IROLinearEnd
+} IROLinearType;
+
+enum {
+ IROLF_1 = 0x1,
+ IROLF_Reffed = 0x2,
+ IROLF_Assigned = 0x4,
+ IROLF_8 = 0x8,
+ IROLF_Used = 0x10,
+ IROLF_Ind = 0x20,
+ IROLF_Subs = 0x40,
+ IROLF_80 = 0x80,
+ IROLF_LoopInvariant = 0x100,
+ IROLF_BeginLoop = 0x200,
+ IROLF_EndLoop = 0x400,
+ IROLF_Ris = 0x800,
+ IROLF_Immind = 0x1000,
+ IROLF_VecOp = 0x2000,
+ IROLF_4000 = 0x4000,
+ IROLF_8000 = 0x8000,
+ IROLF_VecOpBase = 0x10000,
+ IROLF_20000 = 0x20000,
+ IROLF_CounterLoop = 0x40000,
+ IROLF_BitfieldIndirect = 0x80000,
+ IROLF_CouldError = 0x100000
+};
+
+// actual name is LinearNode as per mwccppc v8
+struct IROLinear {
+ IROLinearType type;
+ ENodeType nodetype;
+ SInt32 flags;
+ UInt16 nodeflags;
+ unsigned short index;
+ Statement *stmt;
+ Type *rtype;
+ IROExpr *expr;
+ struct ERange *x16;
+ PointsToFunction *pointsToFunction;
+ Boolean x1E;
+ union {
+ struct {
+ void *data1;
+ void *data2;
+ void *data3;
+ void *data4;
+ void *data5;
+ } idk;
+ // Operand
+ ENode *node;
+ // Op1Arg
+ IROLinear *monadic;
+ // Op2Arg
+ struct {
+ IROLinear *left;
+ IROLinear *right;
+ } diadic;
+ // Op3Arg
+ struct {
+ IROLinear *a;
+ IROLinear *b;
+ IROLinear *c;
+ } args3;
+ // Funccall
+ struct {
+ char ispascal;
+ short argCount;
+ IROLinear **args;
+ IROLinear *linear8; // funcref
+ TypeFunc *functype;
+ struct LocationSetSet *returnedLocs;
+ } funccall;
+ // Asm
+ Statement *asm_stmt;
+ // If, IfNot, Goto, Label
+ struct {
+ CLabel *label;
+ IROLinear *x4; // if,ifnot only??
+ } label;
+ struct {
+ SwitchInfo *info;
+ IROLinear *x4;
+ } swtch;
+ // BeginCatch, EndCatch, EndCatchDtor
+ struct {
+ IROLinear *linear;
+ int x4;
+ int x8;
+ } ctch;
+ } u;
+ IROLinear *next;
+};
+
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+extern IROLinear *IRO_FirstLinear;
+extern IROLinear *IRO_LastLinear;
+extern UInt32 IRO_NumLinear;
+extern Statement *CurStat;
+
+extern IROLinear *IRO_NewLinear(IROLinearType type);
+extern void IRO_PreLinearize(Statement *stmt);
+extern void IRO_Linearize(Statement *stmt);
+extern ENode *IRO_NewENode(ENodeType nodetype);
+extern Statement *IRO_Delinearize(IRONode *node, IROLinear *linear);
+extern void IRO_RenumberInts(void);
+extern void IRO_UpdateFlagsOnInts(void);
+extern void IRO_SaveLinearIR(IROLinearIRSave *save);
+extern void IRO_RestoreLinearIR(IROLinearIRSave *save);
+
+#define IS_LINEAR_ENODE(_linear, _nodetype) ( ((_linear)->type == IROLinearOperand) && ((_linear)->u.node->type) == (_nodetype) )
+#define IS_LINEAR_MONADIC(_linear, _nodetype) ( ((_linear)->type == IROLinearOp1Arg) && ((_linear)->nodetype) == (_nodetype) )
+#define IS_LINEAR_MONADIC_2(_linear, _nodetype1, _nodetype2) ( ((_linear)->type == IROLinearOp1Arg) && (((_linear)->nodetype) == (_nodetype1) || ((_linear)->nodetype) == (_nodetype2)) )
+#define IS_LINEAR_DIADIC(_linear, _nodetype) ( ((_linear)->type == IROLinearOp2Arg) && ((_linear)->nodetype) == (_nodetype) )
+#define IS_LINEAR_DIADIC_2(_linear, _nodetype1, _nodetype2) ( ((_linear)->type == IROLinearOp2Arg) && (((_linear)->nodetype) == (_nodetype1) || ((_linear)->nodetype) == (_nodetype2)) )
+#define IS_LINEAR_DIADIC_3(_linear, _nodetype1, _nodetype2, _nodetype3) ( ((_linear)->type == IROLinearOp2Arg) && (((_linear)->nodetype) == (_nodetype1) || ((_linear)->nodetype) == (_nodetype2) || ((_linear)->nodetype) == (_nodetype3)) )
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroLoop.c b/compiler_and_linker/FrontEnd/Optimizer/IroLoop.c
new file mode 100644
index 0000000..850146d
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroLoop.c
@@ -0,0 +1,2324 @@
+#include "IroLoop.h"
+#include "IroCSE.h"
+#include "IroDump.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroPropagate.h"
+#include "IroSubable.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+IRONode *LoopNode;
+Boolean ConditionalHeaderAtBottom;
+IROLoopInd *FirstInd;
+BitVector *InLoop;
+IROList IRO_InitLList;
+BitVector *InLoop_Exits;
+BitVector *InLoop_Tails;
+UInt32 LoopExitNumber;
+UInt32 LoopTailNum;
+IRONode *LoopExitSuccessor;
+IRONode *LoopTail;
+IROLoopMemRef *IRO_LoopMemRefFirst;
+IROLoopMemRef *IRO_LoopMemRefCurrent;
+static IROExpr *RisList;
+static BitVector *AllKills;
+static Boolean KnownBounds;
+static SInt32 Times;
+static IROLinear *PredInt;
+static IROElmList *FirstAddendLinear;
+static IROElmList *LastAddendLinear;
+static int NoSubableSubs;
+
+// forward decls
+static void MyHandleLoop_Vector(IRONode *fnode);
+static void MyHandleLoop_Motion(IRONode *fnode);
+static void CheckAllLoopAddresses(IRONode *fnode, BitVector *bv, Boolean *resultFlag);
+static void MakeLoopEntry(IROLinear *nd, IROAddrRecord *rec, Boolean mustreach1, Boolean flag2);
+static void MoveInvarianceInAddressExpr(void);
+static IROLinear *RearrangeInvarianceInAddressExpr(IROLinear *nd, IROList *list);
+static UInt32 IsAssignmentReductionCandidate(IROLinear *nd);
+
+void FindMustReach(void) {
+ IRONode *fnode;
+ IRONode *fnode2;
+ IRONode *pred;
+ int i;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ fnode->mustreach = 0;
+ if (Bv_IsBitSet(fnode->index, InLoop)) {
+ fnode->mustreach = 1;
+
+ for (i = 0; i < LoopNode->numpred; i++) {
+ pred = IRO_NodeTable[LoopNode->pred[i]];
+ if (Bv_IsBitSet(pred->index, InLoop) && !Bv_IsBitSet(fnode->index, pred->dom)) {
+ fnode->mustreach = 0;
+ break;
+ }
+ }
+
+ for (fnode2 = IRO_FirstNode; fnode2; fnode2 = fnode2->nextnode) {
+ if (Bv_IsBitSet(fnode2->index, InLoop)) {
+ for (i = 0; i < fnode2->numsucc; i++) {
+ if (!Bv_IsBitSet(fnode2->succ[i], InLoop) && !Bv_IsBitSet(fnode->index, fnode2->dom)) {
+ fnode->mustreach = 0;
+ break;
+ }
+ }
+
+ if (!fnode->mustreach)
+ break;
+ }
+ }
+ }
+ }
+}
+
+void FindMustReach1(IRONode *checkfnode) {
+ IRONode *fnode;
+ IRONode *fnode2;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ if (Bv_IsBitSet(fnode->index, InLoop)) {
+ fnode->mustreach1 = 1;
+ for (fnode2 = IRO_FirstNode; fnode2; fnode2 = fnode2->nextnode) {
+ if (Bv_IsBitSet(fnode2->index, InLoop)) {
+ if (Bv_IsBitSet(fnode2->index, InLoop_Tails) && !Bv_IsBitSet(fnode->index, fnode2->dom))
+ fnode->mustreach1 = 0;
+
+ if (Bv_IsBitSet(fnode2->index, InLoop_Exits) && fnode2 != checkfnode && !Bv_IsBitSet(fnode->index, fnode2->dom))
+ fnode->mustreach1 = 0;
+
+ if (!fnode->mustreach1)
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void IRO_FindLoopTailsAndExits(IRONode *fnode) {
+ IRONode *scan;
+ IRONode *succ;
+ int i;
+
+ for (scan = IRO_FirstNode; scan; scan = scan->nextnode) {
+ if (Bv_IsBitSet(scan->index, InLoop)) {
+ for (i = 0; i < scan->numsucc; i++) {
+ succ = IRO_NodeTable[scan->succ[i]];
+ if (succ == fnode) {
+ Bv_SetBit(scan->index, InLoop_Tails);
+ LoopTail = scan;
+ LoopTailNum++;
+ }
+ if (!Bv_IsBitSet(succ->index, InLoop)) {
+ LoopExitNumber++;
+ LoopExitSuccessor = succ;
+ Bv_SetBit(scan->index, InLoop_Exits);
+ }
+ }
+ }
+ }
+
+ IRO_Dump("IRO_FindLoopTailsAndExits:For header %d, Loop exits and loop tails are \n", fnode->index);
+ IRO_DumpBits("Loop Exits: ", InLoop_Exits);
+ IRO_DumpBits("Loop Tails: ", InLoop_Tails);
+ IRO_Dump("LoopExitNum=%d: \n", LoopExitNumber);
+ if (LoopExitSuccessor)
+ IRO_Dump("LoopExitSuccessor node =%d: \n", LoopExitSuccessor->index);
+}
+
+static int IsSafeTypcon(IROLinear *nd) {
+ Type *srcType;
+ Type *destType;
+ SInt32 srcSize;
+ SInt32 destSize;
+ Boolean srcUnsigned;
+ Boolean destUnsigned;
+
+ srcType = nd->u.monadic->rtype;
+ destType = nd->rtype;
+ if (!IS_TYPE_INT(srcType) || !IS_TYPE_INT(destType))
+ return 0;
+
+ srcSize = srcType->size;
+ destSize = destType->size;
+ srcUnsigned = IRO_IsUnsignedType(srcType);
+ destUnsigned = IRO_IsUnsignedType(destType);
+
+ if (srcUnsigned == destUnsigned && destSize >= srcSize)
+ return 1;
+ if (srcUnsigned == 1 && destUnsigned == 0 && destSize > srcSize)
+ return 1;
+ return 0;
+}
+
+static int Reducable(IROLinear *nd, IROLinear **resultNd1, IROLinear **resultNd2, VarRecord **resultVar) {
+ IROLinear *indirect;
+ IROLinear *left;
+ IROLinear *right;
+ Boolean leftInvariant;
+ Boolean rightInvariant;
+ Boolean leftTypcon;
+ Boolean rightTypcon;
+ Object *obj;
+ ENode *enode;
+ IROLoopInd *ind;
+ CInt64 val64;
+ SInt32 val;
+ SInt32 div;
+
+ leftInvariant = 0;
+ rightInvariant = 0;
+ leftTypcon = 0;
+ rightTypcon = 0;
+
+ if (nd->type == IROLinearOp2Arg && nd->nodetype == EADD && (IS_TYPE_INT(nd->rtype) || IS_TYPE_POINTER_ONLY(nd->rtype))) {
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+ if (left->type == IROLinearOp1Arg && left->nodetype == ETYPCON) {
+ leftTypcon = 1;
+ leftInvariant = (left->flags & IROLF_LoopInvariant) != 0;
+ left = left->u.monadic;
+ }
+ if (right->type == IROLinearOp1Arg && right->nodetype == ETYPCON) {
+ rightTypcon = 1;
+ rightInvariant = (right->flags & IROLF_LoopInvariant) != 0;
+ right = right->u.monadic;
+ }
+
+ if (((left->flags & IROLF_LoopInvariant) || leftInvariant) && IRO_IsVariable(right)) {
+ if (leftInvariant || ((!(obj = IRO_IsVariable(left)) || !IRO_IsRegable(obj)) && !IRO_IsConstant(left))) {
+ if (
+ left->type == IROLinearOp2Arg &&
+ left->nodetype == EADD &&
+ (obj = IRO_IsVariable(left->u.diadic.left)) &&
+ IRO_IsRegable(obj) &&
+ IRO_IsConstant(left->u.diadic.right)
+ )
+ return 0;
+
+ if (rightTypcon) {
+ if (!IsSafeTypcon(nd->u.diadic.right))
+ return 0;
+ *resultNd2 = nd->u.diadic.right;
+ } else {
+ *resultNd2 = right;
+ }
+
+ indirect = right;
+ *resultNd1 = IRO_NewLinear(IROLinearOperand);
+
+ enode = IRO_NewENode(EINTCONST);
+ enode->data.intval = cint64_one;
+ enode->rtype = nd->u.diadic.right->rtype;
+ (*resultNd1)->rtype = nd->u.diadic.right->rtype;
+ (*resultNd1)->u.node = enode;
+ } else {
+ return 0;
+ }
+ } else if (
+ ((left->flags & IROLF_LoopInvariant) || leftInvariant) &&
+ right->type == IROLinearOp2Arg &&
+ !rightTypcon &&
+ (right->nodetype == EMUL || right->nodetype == ESHL)
+ ) {
+ if (IRO_IsConstant(right->u.diadic.right)) {
+ if (right->nodetype == ESHL) {
+ right->nodetype = EMUL;
+ right->u.diadic.right->u.node->data.intval = CInt64_Shl(cint64_one, right->u.diadic.right->u.node->data.intval);
+ }
+ if (right->u.diadic.left->type == IROLinearOp1Arg) {
+ if (IRO_IsVariable(right->u.diadic.left)) {
+ *resultNd2 = right->u.diadic.left;
+ indirect = right->u.diadic.left;
+ *resultNd1 = right->u.diadic.right;
+ } else if (right->u.diadic.left->nodetype == ETYPCON && IRO_IsVariable(right->u.diadic.left->u.monadic)) {
+ if (!IsSafeTypcon(right->u.diadic.left))
+ return 0;
+ *resultNd2 = right->u.diadic.left;
+ indirect = right->u.diadic.left->u.monadic;
+ *resultNd1 = right->u.diadic.right;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ } else if (
+ ((right->flags & IROLF_LoopInvariant) || rightInvariant) &&
+ left->type == IROLinearOp2Arg &&
+ !leftTypcon &&
+ (left->nodetype == EMUL || left->nodetype == ESHL)
+ ) {
+ if (IRO_IsConstant(left->u.diadic.right)) {
+ if (left->nodetype == ESHL) {
+ left->nodetype = EMUL;
+ left->u.diadic.right->u.node->data.intval = CInt64_Shl(cint64_one, left->u.diadic.right->u.node->data.intval);
+ }
+ if (left->u.diadic.left->type == IROLinearOp1Arg) {
+ if (IRO_IsVariable(left->u.diadic.left)) {
+ *resultNd2 = left->u.diadic.left;
+ indirect = left->u.diadic.left;
+ *resultNd1 = left->u.diadic.right;
+ } else if (left->u.diadic.left->nodetype == ETYPCON && IRO_IsVariable(left->u.diadic.left->u.monadic)) {
+ if (!IsSafeTypcon(left->u.diadic.left))
+ return 0;
+ *resultNd2 = left->u.diadic.left;
+ indirect = left->u.diadic.left->u.monadic;
+ *resultNd1 = left->u.diadic.right;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ } else if (
+ ((right->flags & IROLF_LoopInvariant) || rightInvariant) &&
+ IRO_IsVariable(left)
+ ) {
+ if (rightInvariant || ((!(obj = IRO_IsVariable(right)) || !IRO_IsRegable(obj)) && !IRO_IsConstant(right))) {
+ if (
+ right->type == IROLinearOp2Arg &&
+ right->nodetype == EADD &&
+ (obj = IRO_IsVariable(right->u.diadic.left)) &&
+ IRO_IsRegable(obj) &&
+ IRO_IsConstant(right->u.diadic.right)
+ )
+ return 0;
+
+ if (leftTypcon) {
+ if (!IsSafeTypcon(nd->u.diadic.left))
+ return 0;
+ *resultNd2 = nd->u.diadic.left;
+ } else {
+ *resultNd2 = left;
+ }
+
+ indirect = left;
+ *resultNd1 = IRO_NewLinear(IROLinearOperand);
+
+ enode = IRO_NewENode(EINTCONST);
+ enode->data.intval = cint64_one;
+ enode->rtype = nd->u.diadic.left->rtype;
+ (*resultNd1)->rtype = nd->u.diadic.left->rtype;
+ (*resultNd1)->u.node = enode;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ } else if (nd->type == IROLinearOp2Arg && (nd->nodetype == EMUL || nd->nodetype == ESHL) && nd->rtype->size <= 4 && (IS_TYPE_INT(nd->rtype) || IS_TYPE_POINTER_ONLY(nd->rtype))) {
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+
+ if (IRO_IsConstant(right) && IRO_IsVariable(left)) {
+ *resultNd2 = left;
+ indirect = left;
+ *resultNd1 = right;
+ } else if (IRO_IsConstant(nd->u.diadic.right) && left->type == IROLinearOp1Arg && left->nodetype == ETYPCON &&
+ IRO_IsVariable(left->u.monadic)) {
+ if (!IsSafeTypcon(left))
+ return 0;
+ *resultNd2 = left;
+ indirect = left->u.monadic;
+ *resultNd1 = right;
+ } else {
+ if (nd->type == IROLinearOp2Arg && nd->nodetype == ESHL)
+ return 0;
+
+ if (nd->u.diadic.right->flags & IROLF_LoopInvariant) {
+ if (IRO_IsVariable(left)) {
+ *resultNd2 = left;
+ indirect = left;
+ *resultNd1 = right;
+ } else if (left->type == IROLinearOp1Arg && left->nodetype == ETYPCON && IRO_IsVariable(left->u.monadic)) {
+ if (!IsSafeTypcon(left))
+ return 0;
+ *resultNd2 = left;
+ indirect = left->u.monadic;
+ *resultNd1 = right;
+ } else {
+ return 0;
+ }
+ } else if (nd->u.diadic.left->flags & IROLF_LoopInvariant) {
+ if (IRO_IsVariable(right)) {
+ *resultNd2 = right;
+ indirect = right;
+ *resultNd1 = left;
+ } else if (right->type == IROLinearOp1Arg && right->nodetype == ETYPCON && IRO_IsVariable(right->u.monadic) && nd->type == IROLinearOp2Arg && nd->nodetype == EMUL) {
+ if (!IsSafeTypcon(right))
+ return 0;
+ *resultNd2 = right;
+ indirect = right->u.monadic;
+ *resultNd1 = left;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+ } else if (nd->type == IROLinearOp2Arg && (nd->nodetype == EDIV || nd->nodetype == ESHR) && nd->rtype->size <= 4 && IS_TYPE_INT(nd->rtype)) {
+ if (IRO_IsVariable(nd->u.diadic.left) && IRO_IsConstant(nd->u.diadic.right)) {
+ val64 = nd->u.diadic.right->u.node->data.intval;
+ if (nd->type == IROLinearOp2Arg && nd->nodetype == ESHR) {
+ CInt64_GetULong(&val64);
+ if (CInt64_GetULong(&val64) > 32 || CTool_EndianReadWord32(&val64.hi))
+ return 0;
+ val64 = CInt64_Shl(cint64_one, val64);
+ }
+ *resultNd2 = nd->u.diadic.left;
+ indirect = nd->u.diadic.left;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+
+ if (
+ nd->type == IROLinearOp2Arg &&
+ nd->nodetype == ESHL &&
+ (
+ !IRO_IsConstant(*resultNd1) ||
+ (SInt32) CInt64_GetULong(&(*resultNd1)->u.node->data.intval) < 0 ||
+ (SInt32) CInt64_GetULong(&(*resultNd1)->u.node->data.intval) > 32 ||
+ CTool_EndianReadWord32(&(*resultNd1)->u.node->data.intval.hi)
+ )
+ )
+ return 0;
+
+ CError_ASSERT(802, indirect->u.monadic->u.node != NULL);
+ *resultVar = IRO_FindVar(indirect->u.monadic->u.node->data.objref, 0, 1);
+ if (!*resultVar || (*resultVar)->xA != 2)
+ return 0;
+
+ if (copts.ANSIstrict || copts.strengthreductionstrict) {
+ Type *type = (*resultVar)->object->type;
+ if (IRO_IsUnsignedType(type) && type->size < stunsignedlong.size)
+ return 0;
+ }
+
+ if (nd->type == IROLinearOp2Arg && (nd->nodetype == ESHR || nd->nodetype == EDIV)) {
+ ind = FirstInd;
+ while (ind && ind->var != *resultVar)
+ ind = ind->next;
+
+ CError_ASSERT(845, ind != NULL);
+
+ if (ind->addNode == NULL) {
+ if (ind->addConst < (val = CInt64_GetULong(&val64)))
+ return 0;
+ if ((div = ind->addConst / val) <= 0)
+ return 0;
+
+ *resultNd1 = IRO_NewLinear(IROLinearOperand);
+ enode = IRO_NewENode(EINTCONST);
+ CInt64_SetULong(&enode->data.intval, div);
+ enode->rtype = nd->u.diadic.left->rtype;
+ (*resultNd1)->rtype = nd->u.diadic.left->rtype;
+ (*resultNd1)->u.node = enode;
+ } else {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void IRO_RemoveExpr_Action(IROLinear *linear, Boolean isFirst) {
+ if (isFirst && linear->expr)
+ IRO_RemoveExpr(linear->expr);
+}
+
+static void IRO_ActUnmarkRISCandidate(IROLinear *linear, Boolean isFirst) {
+ if (isFirst && linear->expr)
+ linear->flags &= ~IROLF_Ris;
+}
+
+static IROExpr *CreateRIS(IROExpr *expr, IROLinear *nd1, IROLinear *nd2, IROLoopInd *induction, int unk) {
+ Object *tempObj;
+ Type *type;
+ Boolean flag23;
+ Object *tempObj2;
+ IROLinear *firstnode;
+ IROLinear *fourthnode;
+ IROLinear *fifthnode;
+ IROLinear *secondnode;
+ IROLinear *thirdnode;
+ IROLinear *tmp;
+ ENode *enode;
+ IROList list1;
+ IROList list2;
+
+ flag23 = 0;
+ type = expr->linear->rtype;
+ tempObj = create_temp_object(type);
+ IRO_FindVar(tempObj, 1, 1);
+ IRO_InitList(&list1);
+
+ if (IS_LINEAR_DIADIC(expr->linear, EADD)) {
+ firstnode = IRO_DuplicateExpr(expr->linear, &list1);
+ } else if (IS_LINEAR_DIADIC_2(expr->linear, EDIV, ESHR)) {
+ firstnode = IRO_DuplicateExpr(expr->linear, &list1);
+ } else {
+ firstnode = IRO_NewLinear(IROLinearOp2Arg);
+ firstnode->index = ++IRO_NumLinear;
+ firstnode->rtype = type;
+ firstnode->nodetype = EMUL;
+ firstnode->u.diadic.left = IRO_DuplicateExpr(nd1, &list1);
+ if (unk)
+ firstnode->u.diadic.right = IRO_DuplicateExpr(nd1, &list1);
+ else
+ firstnode->u.diadic.right = IRO_DuplicateExpr(nd2, &list1);
+ IRO_AddToList(firstnode, &list1);
+ }
+
+ secondnode = IRO_NewLinear(IROLinearOp2Arg);
+ secondnode->index = ++IRO_NumLinear;
+ secondnode->rtype = type;
+ secondnode->nodetype = EASS;
+ secondnode->u.diadic.left = IRO_TempReference(tempObj, &list1);
+ secondnode->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned;
+ secondnode->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned;
+ secondnode->u.diadic.right = firstnode;
+ IRO_AddToList(secondnode, &list1);
+ IRO_Paste(list1.head, list1.tail, PredInt);
+ if (
+ !IS_LINEAR_DIADIC_2(expr->linear, EDIV, ESHR) &&
+ induction->addConst != 1 &&
+ (induction->addNode || !IRO_IsConstant(nd2))
+ ) {
+ flag23 = 1;
+ IRO_InitList(&list1);
+ thirdnode = IRO_NewLinear(IROLinearOp2Arg);
+ thirdnode->index = ++IRO_NumLinear;
+ thirdnode->rtype = nd2->rtype;
+ thirdnode->nodetype = EMUL;
+
+ if (!induction->addNode) {
+ thirdnode->u.diadic.left = IRO_DuplicateExpr(nd2, &list1);
+ thirdnode->u.diadic.right = IRO_NewLinear(IROLinearOperand);
+ thirdnode->u.diadic.right->index = ++IRO_NumLinear;
+ enode = IRO_NewENode(EINTCONST);
+ enode->rtype = nd2->rtype;
+ thirdnode->u.diadic.right->rtype = nd2->rtype;
+ CInt64_SetLong(&enode->data.intval, induction->addConst);
+ thirdnode->u.diadic.right->u.node = enode;
+ IRO_AddToList(thirdnode->u.diadic.right, &list1);
+ } else {
+ thirdnode->u.diadic.left = IRO_DuplicateExpr(nd2, &list1);
+ thirdnode->u.diadic.right = IRO_DuplicateExpr(induction->addNode, &list1);
+ if (nd2->rtype != induction->addNode->rtype) {
+ tmp = IRO_NewLinear(IROLinearOp1Arg);
+ tmp->nodetype = ETYPCON;
+ tmp->index = ++IRO_NumLinear;
+ tmp->rtype = nd2->rtype;
+ tmp->u.monadic = thirdnode->u.diadic.right;
+ IRO_AddToList(tmp, &list1);
+ thirdnode->u.diadic.right = tmp;
+ }
+ }
+ IRO_AddToList(thirdnode, &list1);
+
+ tempObj2 = create_temp_object(nd2->rtype);
+
+ fourthnode = IRO_NewLinear(IROLinearOp2Arg);
+ fourthnode->index = ++IRO_NumLinear;
+ fourthnode->rtype = nd2->rtype;
+ fourthnode->nodetype = EASS;
+ fourthnode->u.diadic.left = IRO_TempReference(tempObj2, &list1);
+ fourthnode->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned;
+ fourthnode->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned;
+ fourthnode->u.diadic.right = thirdnode;
+ IRO_AddToList(fourthnode, &list1);
+ IRO_Paste(list1.head, list1.tail, PredInt);
+ }
+
+ IRO_InitList(&list2);
+ fifthnode = IRO_NewLinear(IROLinearOp2Arg);
+ fifthnode->index = ++IRO_NumLinear;
+ fifthnode->rtype = type;
+ if (induction->nd->type == IROLinearOp2Arg) {
+ if (induction->nd->nodetype == EASS && IS_LINEAR_DIADIC(induction->nd->u.diadic.right, EADD))
+ fifthnode->nodetype = EADDASS;
+ else if (induction->nd->nodetype == EASS && IS_LINEAR_DIADIC(induction->nd->u.diadic.right, ESUB))
+ fifthnode->nodetype = ESUBASS;
+ else
+ fifthnode->nodetype = induction->nd->nodetype;
+ } else {
+ if (induction->nd->nodetype == EPREINC || induction->nd->nodetype == EPOSTINC)
+ fifthnode->nodetype = EADDASS;
+ else
+ fifthnode->nodetype = ESUBASS;
+ }
+
+ fifthnode->u.diadic.left = IRO_TempReference(tempObj, &list2);
+ fifthnode->u.diadic.left->flags |= IROLF_Ind | IROLF_Used | IROLF_Assigned;
+ fifthnode->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Used | IROLF_Assigned;
+ if (!unk) {
+ if (!flag23) {
+ if (induction->addConst == 1 || IS_LINEAR_DIADIC_2(expr->linear, EDIV, ESHR)) {
+ fifthnode->u.diadic.right = IRO_DuplicateExpr(nd2, &list2);
+ } else {
+ fifthnode->u.diadic.right = IRO_NewLinear(IROLinearOperand);
+ fifthnode->u.diadic.right->index = ++IRO_NumLinear;
+ enode = IRO_NewENode(EINTCONST);
+ enode->rtype = nd2->rtype;
+ fifthnode->u.diadic.right->rtype = nd2->rtype;
+ CInt64_SetLong(&enode->data.intval, induction->addConst * CInt64_GetULong(&nd2->u.node->data.intval));
+ fifthnode->u.diadic.right->u.node = enode;
+ IRO_AddToList(fifthnode->u.diadic.right, &list2);
+ }
+ } else {
+ fifthnode->u.diadic.right = IRO_TempReference(tempObj2, &list2);
+ fifthnode->u.diadic.right->flags |= IROLF_Used;
+ }
+ }
+
+ fifthnode->index = ++IRO_NumLinear;
+ IRO_AddToList(fifthnode, &list2);
+ IRO_Paste(list2.head, list2.tail, IRO_FindStart(induction->nd));
+ IRO_WalkTree(expr->linear, IRO_RemoveExpr_Action);
+ expr->x8 = tempObj;
+ expr->next = RisList;
+ RisList = expr;
+ return expr;
+}
+
+static IRONode *CreatePreHeader(IRONode *fnode1, IRONode *fnode2) {
+ IROLinear *labelnode;
+ IRONode *newfnode;
+ IRONode *iter;
+ CLabel *oldlabel;
+ CLabel *newlabel;
+ SwitchInfo *swinfo;
+ SwitchCase *swcase;
+
+ newfnode = oalloc(sizeof(IRONode));
+ memset(newfnode, 0, sizeof(IRONode));
+ newfnode->index = IRO_NumNodes;
+ IRO_NumNodes++;
+
+ labelnode = IRO_NewLinear(IROLinearLabel);
+ labelnode->index = IRO_NumLinear++;
+ labelnode->next = NULL;
+ labelnode->u.label.label = IRO_NewLabel();
+ labelnode->flags |= IROLF_1;
+ labelnode->u.label.label->stmt = (Statement *) newfnode;
+ newfnode->first = labelnode;
+ newfnode->last = labelnode;
+
+ if (fnode2) {
+ fnode2->last->next = labelnode;
+ labelnode->next = IRO_NewLinear(IROLinearNop);
+ labelnode->next->next = fnode1->first;
+ fnode2->nextnode = newfnode;
+ newfnode->nextnode = fnode1;
+ } else {
+ CError_ASSERT(1254, fnode1->first->type == IROLinearLabel);
+ labelnode->next = IRO_NewLinear(IROLinearGoto);
+ labelnode->next->u.label.label = fnode1->first->u.label.label;
+ IRO_LastNode->last->next = labelnode;
+ IRO_LastNode->nextnode = newfnode;
+ IRO_LastNode = newfnode;
+ IRO_LastLinear = labelnode->next;
+ }
+
+ newfnode->last = labelnode->next;
+
+ IRO_NodeTable = oalloc(sizeof(IRONode *) * IRO_NumNodes);
+ memset(IRO_NodeTable, 0, sizeof(IRONode *) * IRO_NumNodes);
+ for (iter = IRO_FirstNode; iter; iter = iter->nextnode)
+ IRO_NodeTable[iter->index] = iter;
+
+ if (fnode1->first->type == IROLinearLabel) {
+ oldlabel = fnode1->first->u.label.label;
+ newlabel = newfnode->first->u.label.label;
+ for (iter = IRO_FirstNode; iter; iter = iter->nextnode) {
+ if (!Bv_IsBitSet(iter->index, InLoop) && iter != newfnode) {
+ switch (iter->last->type) {
+ case IROLinearGoto:
+ if (iter->last->u.label.label == oldlabel)
+ iter->last->u.label.label = newlabel;
+ break;
+ case IROLinearIf:
+ case IROLinearIfNot:
+ if (iter->last->u.label.label == oldlabel)
+ iter->last->u.label.label = newlabel;
+ break;
+ case IROLinearSwitch:
+ swinfo = iter->last->u.swtch.info;
+ for (swcase = swinfo->cases; swcase; swcase = swcase->next) {
+ if (swcase->label == oldlabel)
+ swcase->label = newlabel;
+ }
+ if (swinfo->defaultlabel == oldlabel)
+ swinfo->defaultlabel = newlabel;
+ break;
+ }
+ }
+ }
+ }
+
+ IRO_ComputeSuccPred();
+ IRO_ComputeDom();
+ return newfnode;
+}
+
+static IRONode *CreateNewLoopExitSuccessor(IRONode *fnode1) {
+ IROLinear *labelnode;
+ IRONode *fnode2;
+ IRONode *newfnode;
+ Boolean flag;
+ IRONode *iter;
+ CLabel *oldlabel;
+ CLabel *newlabel;
+ SwitchInfo *swinfo;
+ SwitchCase *swcase;
+ UInt16 i;
+
+ CError_ASSERT(1355, fnode1 != NULL && LoopExitNumber == 1);
+
+ fnode2 = NULL;
+ flag = 0;
+
+ for (i = 0; i < fnode1->numpred; i++) {
+ iter = IRO_NodeTable[fnode1->pred[i]];
+ if (Bv_IsBitSet(iter->index, InLoop_Exits)) {
+ CError_ASSERT(1366, fnode2 == NULL);
+ fnode2 = iter;
+ if (!flag) {
+ if (
+ !iter->last ||
+ !fnode1->first ||
+ fnode1->first->type != IROLinearLabel ||
+ (
+ (iter->last->type == IROLinearIf || iter->last->type == IROLinearIfNot) &&
+ iter->last->u.label.label != fnode1->first->u.label.label
+ ))
+ flag = 1;
+ }
+ }
+ }
+
+ CError_ASSERT(1382, fnode2 != NULL);
+
+ newfnode = oalloc(sizeof(IRONode));
+ memset(newfnode, 0, sizeof(IRONode));
+ newfnode->index = IRO_NumNodes;
+ IRO_NumNodes++;
+
+ labelnode = IRO_NewLinear(IROLinearLabel);
+ labelnode->index = IRO_NumLinear++;
+ labelnode->next = NULL;
+ labelnode->u.label.label = IRO_NewLabel();
+ labelnode->flags |= IROLF_1;
+ labelnode->u.label.label->stmt = (Statement *) newfnode;
+ newfnode->first = labelnode;
+ newfnode->last = labelnode;
+
+ if (flag) {
+ fnode2->last->next = labelnode;
+ labelnode->next = IRO_NewLinear(IROLinearNop);
+ labelnode->next->next = fnode1->first;
+ fnode2->nextnode = newfnode;
+ newfnode->nextnode = fnode1;
+ } else {
+ CError_ASSERT(1422, fnode1->first->type == IROLinearLabel);
+ labelnode->next = IRO_NewLinear(IROLinearGoto);
+ labelnode->next->u.label.label = fnode1->first->u.label.label;
+ IRO_LastNode->last->next = labelnode;
+ IRO_LastNode->nextnode = newfnode;
+ IRO_LastNode = newfnode;
+ IRO_LastLinear = labelnode->next;
+ }
+
+ newfnode->last = labelnode->next;
+
+ IRO_NodeTable = oalloc(sizeof(IRONode *) * IRO_NumNodes);
+ memset(IRO_NodeTable, 0, sizeof(IRONode *) * IRO_NumNodes);
+ for (iter = IRO_FirstNode; iter; iter = iter->nextnode)
+ IRO_NodeTable[iter->index] = iter;
+
+ if (fnode1->first->type == IROLinearLabel) {
+ oldlabel = fnode1->first->u.label.label;
+ newlabel = newfnode->first->u.label.label;
+ switch (fnode2->last->type) {
+ case IROLinearGoto:
+ if (fnode2->last->u.label.label == oldlabel)
+ fnode2->last->u.label.label = newlabel;
+ break;
+ case IROLinearIf:
+ case IROLinearIfNot:
+ if (fnode2->last->u.label.label == oldlabel)
+ fnode2->last->u.label.label = newlabel;
+ break;
+ case IROLinearSwitch:
+ swinfo = fnode2->last->u.swtch.info;
+ for (swcase = swinfo->cases; swcase; swcase = swcase->next) {
+ if (swcase->label == oldlabel)
+ swcase->label = newlabel;
+ }
+ if (swinfo->defaultlabel == oldlabel)
+ swinfo->defaultlabel = newlabel;
+ break;
+ }
+ }
+
+ IRO_ComputeSuccPred();
+ IRO_ComputeDom();
+ return newfnode;
+}
+
+void AddPreds(IRONode *fnode) {
+ IRONode *pred;
+ int i;
+
+ for (i = 0; i < fnode->numpred; i++) {
+ pred = IRO_NodeTable[fnode->pred[i]];
+ if (!Bv_IsBitSet(pred->index, InLoop)) {
+ Bv_SetBit(pred->index, InLoop);
+ AddPreds(pred);
+ }
+ }
+}
+
+static void RemoveNoopsFromExprList(void) {
+ IROExpr *expr;
+ IROExpr *prev;
+
+ expr = IRO_FirstExpr;
+ prev = NULL;
+ while (expr) {
+ if (expr->linear->type == IROLinearNop) {
+ if (prev)
+ prev->next = expr->next;
+ else
+ IRO_FirstExpr = expr->next;
+ expr = expr->next;
+ } else {
+ prev = expr;
+ expr = expr->next;
+ }
+ }
+}
+
+void IncLoopDepth(void) {
+ IRONode *fnode;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ if (Bv_IsBitSet(fnode->index, InLoop))
+ fnode->loopdepth++;
+ }
+}
+
+void IRO_SetLoopDepth(void) {
+ IRONode *fnode;
+ IRONode *pred;
+ UInt16 i;
+ UInt16 flag;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode)
+ fnode->loopdepth = 0;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ flag = 0;
+
+ for (i = 0; i < fnode->numpred; i++) {
+ pred = IRO_NodeTable[fnode->pred[i]];
+ if (Bv_IsBitSet(fnode->index, pred->dom)) {
+ if (!flag) {
+ Bv_AllocVector(&InLoop, IRO_NumNodes + 1);
+ Bv_Clear(InLoop);
+ Bv_SetBit(fnode->index, InLoop);
+ }
+ flag = 1;
+ Bv_SetBit(pred->index, InLoop);
+ if (pred != fnode)
+ AddPreds(pred);
+ }
+ }
+
+ if (flag)
+ IncLoopDepth();
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+static void InsertBranchAroundLoopPreheaders(void) {
+ IRONode *fnode;
+ CLabel *label;
+ IRONode *iter;
+ IROLinear *endnode;
+ IROLinear *labelnode;
+
+ if (IRO_EndNode && IRO_EndNode->last && IRO_EndNode->last->type == IROLinearEnd) {
+ label = IRO_NewLabel();
+ fnode = IRO_NewFlowGraphNode();
+ IRO_LastNode->nextnode = fnode;
+ label->stmt = (Statement *) fnode;
+
+ IRO_NodeTable = oalloc(sizeof(IRONode *) * IRO_NumNodes);
+ memset(IRO_NodeTable, 0, sizeof(IRONode *) * IRO_NumNodes);
+ for (iter = IRO_FirstNode; iter; iter = iter->nextnode)
+ IRO_NodeTable[iter->index] = iter;
+
+ labelnode = IRO_NewLinear(IROLinearLabel);
+ labelnode->index = ++IRO_NumLinear;
+ labelnode->u.label.label = label;
+ labelnode->flags |= IROLF_1;
+ fnode->first = labelnode;
+ IRO_LastLinear->next = labelnode;
+
+ endnode = IRO_NewLinear(IROLinearEnd);
+ memcpy(endnode, IRO_EndNode->last, sizeof(IROLinear));
+ endnode->index = ++IRO_NumLinear;
+ endnode->next = NULL;
+ fnode->last = endnode;
+ labelnode->next = endnode;
+ IRO_LastLinear = endnode;
+
+ IRO_EndNode->last->type = IROLinearGoto;
+ IRO_EndNode->last->u.label.label = label;
+ IRO_LastNode = fnode;
+ IRO_EndNode = fnode;
+
+ IRO_ComputeSuccPred();
+ IRO_ComputeDom();
+ }
+}
+
+void IRO_FindLoops(void) {
+ IRONode *fnode;
+ IRONode *pred;
+ UInt16 i;
+ UInt16 flag;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ flag = 0;
+
+ for (i = 0; i < fnode->numpred; i++) {
+ pred = IRO_NodeTable[fnode->pred[i]];
+ if (Bv_IsBitSet(fnode->index, pred->dom)) {
+ if (!flag) {
+ Bv_AllocVector(&InLoop, IRO_NumNodes + 1);
+ Bv_Clear(InLoop);
+ Bv_SetBit(fnode->index, InLoop);
+ }
+ flag = 1;
+ Bv_SetBit(pred->index, InLoop);
+ if (pred != fnode)
+ AddPreds(pred);
+ }
+ }
+
+ if (flag) {
+ IncLoopDepth();
+ IRO_Dump("IRO_FindLoops:Found loop with header %d\n", fnode->index);
+ IRO_DumpBits("Loop includes: ", InLoop);
+ MyHandleLoop_Motion(fnode);
+ IRO_UpdateFlagsOnInts();
+ MyHandleLoop_Vector(fnode);
+ RemoveNoopsFromExprList();
+ IRO_UpdateFlagsOnInts();
+ IRO_UpdateVars();
+ }
+ }
+
+ if (!IRO_FunctionHasReturn && IRO_EndNode != IRO_LastNode)
+ InsertBranchAroundLoopPreheaders();
+}
+
+static void CheckSubableSub(IROLinear *linear, Boolean isFirst) {
+ if (isFirst && IRO_IsSubableExpression(linear)) {
+ IRO_Dump("Subable Expression is %d\n", linear->index);
+ NoSubableSubs = 0;
+ }
+}
+
+static int NoSubableSubExprs(IROLinear *nd) {
+ NoSubableSubs = 1;
+ IRO_WalkTree(nd, CheckSubableSub);
+ return NoSubableSubs;
+}
+
+void ComputeLoopKills(void) {
+ IRONode *fnode;
+ IROLinear *nd;
+
+ Bv_AllocVector(&AllKills, IRO_NumVars + 1);
+ Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ if (Bv_IsBitSet(fnode->index, InLoop) && (nd = fnode->first)) {
+ Bv_AllocVector(&fnode->x16, IRO_NumVars + 1);
+ Bv_AllocVector(&fnode->x1E, IRO_NumVars + 1);
+ while (1) {
+ Bv_Clear(IRO_VarKills);
+ IRO_GetKills(nd);
+ Bv_Or(IRO_VarKills, AllKills);
+ if (nd == fnode->last)
+ break;
+ nd = nd->next;
+ }
+ }
+ }
+}
+
+void ComputeLoopInvariance(void) {
+ IRONode *fnode;
+ IROLinear *nd;
+
+ IRO_Depends = IRO_VarKills;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ if (Bv_IsBitSet(fnode->index, InLoop) && (nd = fnode->first)) {
+ nd->flags &= ~IROLF_LoopInvariant;
+ while (1) {
+ if ((nd->flags & IROLF_Reffed) && nd->type != IROLinearNop) {
+ IRO_FindDepends_NoAlloc(nd);
+ if (!IRO_IsVolatile && !Bv_BitsInCommon(IRO_Depends, AllKills))
+ nd->flags |= IROLF_LoopInvariant;
+
+ if (IRO_CouldError)
+ nd->flags |= IROLF_CouldError;
+ else
+ nd->flags &= ~IROLF_CouldError;
+ }
+
+ if (nd == fnode->last)
+ break;
+ nd = nd->next;
+ }
+ }
+ }
+}
+
+void ComputeLoopInduction(void) {
+ IRONode *fnode;
+ IROLinear *nd;
+ Boolean flag;
+ Object *obj;
+ Object *obj2;
+ Object *obj3;
+ VarRecord *var;
+ IROLinear *tmpnd;
+ IROLoopInd *ind;
+ Boolean isUnsigned;
+
+ Bv_AllocVector(&AllKills, IRO_NumVars + 1);
+ Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ if (Bv_IsBitSet(fnode->index, InLoop) && (nd = fnode->first)) {
+ while (1) {
+ Bv_Clear(IRO_VarKills);
+ IRO_GetKills(nd);
+ Bv_Or(IRO_VarKills, AllKills);
+ flag = 0;
+ if (
+ (
+ nd->type == IROLinearOp2Arg &&
+ nd->rtype->size <= 4 &&
+ (nd->nodetype == EADDASS || nd->nodetype == ESUBASS) &&
+ (obj = IRO_IsVariable(nd->u.diadic.left)) &&
+ obj->type->size == nd->rtype->size &&
+ IS_TYPE_INT(obj->type) &&
+ (
+ (IRO_IsIntConstant(nd->u.diadic.right) && CInt64_GetULong(&nd->u.diadic.right->u.node->data.intval))
+ ||
+ (nd->u.diadic.right->flags & IROLF_LoopInvariant)
+ )
+ )
+ ||
+ (
+ nd->type == IROLinearOp1Arg &&
+ nd->rtype->size <= 4 &&
+ (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC || nd->nodetype == EPREINC || nd->nodetype == EPREDEC) &&
+ (obj = IRO_IsVariable(nd->u.monadic)) &&
+ obj->type->size == nd->rtype->size &&
+ IS_TYPE_INT(obj->type)
+ )
+ )
+ {
+ flag = 1;
+ }
+ else if (
+ nd->type == IROLinearOp2Arg &&
+ nd->rtype->size <= 4 &&
+ nd->nodetype == EASS &&
+ (obj = IRO_IsVariable(nd->u.diadic.left)) &&
+ obj->type->size == nd->rtype->size &&
+ IS_TYPE_INT(obj->type) &&
+ nd->u.diadic.right->type == IROLinearOp2Arg &&
+ (nd->u.diadic.right->nodetype == EADD || nd->u.diadic.right->nodetype == ESUB)
+ )
+ {
+ if (nd->u.diadic.right->nodetype == EADD) {
+ obj2 = IRO_IsVariable(nd->u.diadic.right->u.diadic.left);
+ obj3 = IRO_IsVariable(nd->u.diadic.right->u.diadic.right);
+ if (obj2 == obj && obj3 != obj && (nd->u.diadic.right->u.diadic.right->flags & IROLF_LoopInvariant))
+ flag = 1;
+
+ if (obj3 == obj && obj2 != obj && (nd->u.diadic.right->u.diadic.left->flags & IROLF_LoopInvariant)) {
+ flag = 1;
+ tmpnd = nd->u.diadic.right->u.diadic.left;
+ nd->u.diadic.right->u.diadic.left = nd->u.diadic.right->u.diadic.right;
+ nd->u.diadic.right->u.diadic.right = tmpnd;
+ }
+ } else {
+ obj2 = IRO_IsVariable(nd->u.diadic.right->u.diadic.left);
+ obj3 = IRO_IsVariable(nd->u.diadic.right->u.diadic.right);
+ if (obj2 == obj && obj3 != obj && (nd->u.diadic.right->u.diadic.right->flags & IROLF_LoopInvariant))
+ flag = 1;
+ }
+ }
+
+ if (flag) {
+ if ((var = IRO_FindAssigned(nd))) {
+ if (var->xA == 2)
+ var->xA = 0;
+ else if (var->xA == 1)
+ var->xA = 2;
+ }
+ } else {
+ for (var = IRO_FirstVar; var; var = var->next) {
+ if (Bv_IsBitSet(var->index, IRO_VarKills))
+ var->xA = 0;
+ }
+ }
+
+ if (nd == fnode->last)
+ break;
+ nd = nd->next;
+ }
+ }
+ }
+
+ IRO_DumpBits("Killed in loop: ", AllKills);
+
+ for (fnode = IRO_FirstNode, FirstInd = NULL; fnode; fnode = fnode->nextnode) {
+ if (Bv_IsBitSet(fnode->index, InLoop) && (nd = fnode->first)) {
+ while (1) {
+ if (
+ (
+ nd->type == IROLinearOp2Arg &&
+ (nd->nodetype == EADDASS || nd->nodetype == ESUBASS || nd->nodetype == EASS)
+ )
+ ||
+ (
+ nd->type == IROLinearOp1Arg &&
+ (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC || nd->nodetype == EPREINC || nd->nodetype == EPREDEC)
+ )
+ ) {
+ if ((var = IRO_FindAssigned(nd)) && var->xA == 2 && var->object->type->size <= 4) {
+ ind = oalloc(sizeof(IROLoopInd));
+ ind->fnode = fnode;
+ ind->var = var;
+ ind->nd = nd;
+ ind->next = FirstInd;
+ ind->addNode = NULL;
+ ind->addConst = 0;
+ ind->flags = 0;
+
+ if (nd->type == IROLinearOp2Arg) {
+ isUnsigned = IRO_IsUnsignedType(nd->rtype);
+ if (IRO_IsIntConstant(nd->u.diadic.right)) {
+ CInt64 val = nd->u.diadic.right->u.node->data.intval;
+ if (IS_LINEAR_DIADIC(nd, EADDASS) && CInt64_Less(val, cint64_zero)) {
+ nd->nodetype = ESUBASS;
+ nd->u.diadic.right->u.node->data.intval = CInt64_Neg(val);
+ }
+ if (isUnsigned) {
+ CInt64_ConvertUInt32(&nd->u.diadic.right->u.node->data.intval);
+ ind->addConst = CInt64_GetULong(&nd->u.diadic.right->u.node->data.intval);
+ } else {
+ CInt64_ConvertInt32(&nd->u.diadic.right->u.node->data.intval);
+ ind->addConst = CInt64_GetULong(&nd->u.diadic.right->u.node->data.intval);
+ }
+ ind->addNode = NULL;
+ } else if (nd->nodetype == EADDASS || nd->nodetype == ESUBASS) {
+ ind->addNode = nd->u.diadic.right;
+ } else if (nd->nodetype == EASS) {
+ ind->addNode = nd->u.diadic.right->u.diadic.right;
+ }
+ } else {
+ if (IS_TYPE_POINTER_ONLY(nd->rtype))
+ ind->addConst = TPTR_TARGET(nd->rtype)->size;
+ else
+ ind->addConst = 1;
+ ind->addNode = NULL;
+ }
+
+ FirstInd = ind;
+
+ if (IS_LINEAR_DIADIC_2(nd, EADDASS, ESUBASS)) {
+ if (nd->u.diadic.right->flags & IROLF_LoopInvariant)
+ IRO_Dump("Found induction variable the new way: %s\n", var->object->name->name);
+ else
+ IRO_Dump("Found induction variable the old way: %s\n", var->object->name->name);
+ } else if (nd->type == IROLinearOp2Arg && (nd->u.diadic.right->nodetype == EADD || nd->u.diadic.right->nodetype == ESUB)) {
+ IRO_Dump("Found induction variable the new way: %s\n", var->object->name->name);
+ } else {
+ IRO_Dump("Found induction variable the old way: %s\n", var->object->name->name);
+ }
+ }
+ }
+
+ if (nd == fnode->last)
+ break;
+ nd = nd->next;
+ }
+ }
+ }
+}
+
+static void IRO_ActUnmarkLoopInvariance(IROLinear *linear, Boolean isFirst) {
+ if (isFirst)
+ linear->flags &= ~IROLF_LoopInvariant;
+}
+
+static void UnmarkSubexpressionsOfInvariantExpressions(void) {
+ IROExpr *expr;
+
+ for (expr = IRO_FirstExpr; expr; expr = expr->next) {
+ if (
+ Bv_IsBitSet(expr->node->index, InLoop) &&
+ !expr->notSubable &&
+ (!expr->couldError || expr->node->mustreach) &&
+ (expr->linear->flags & IROLF_LoopInvariant)
+ ) {
+ IRO_WalkTree(expr->linear, IRO_ActUnmarkLoopInvariance);
+ expr->linear->flags |= IROLF_LoopInvariant;
+ }
+ }
+}
+
+static void MyHandleLoop_Vector(IRONode *fnode) {
+ IRONode *pred;
+ UInt16 i;
+ IROExpr *expr;
+ IROExpr *removedExprs;
+ IROExpr *exprnext;
+ IROLoopInd *induction;
+ IROExpr *exprinner;
+ Boolean flag24;
+ IRONode *v2;
+ IRONode *node22;
+ int flag21;
+ IRONode *iter;
+ IROExpr *searchris;
+ IROLinear *reduceNd1;
+ VarRecord *var;
+ IROLinear *reduceNd2;
+
+ IRO_FirstExpr = NULL;
+ LoopNode = fnode;
+ FindMustReach();
+
+ for (var = IRO_FirstVar; var; var = var->next)
+ var->xA = 1;
+
+ ComputeLoopKills();
+ ComputeLoopInvariance();
+ ComputeLoopInduction();
+ LoopNode = fnode;
+ ConditionalHeaderAtBottom = 0;
+
+ v2 = NULL;
+ flag21 = 0;
+ node22 = NULL;
+ for (i = 0; i < LoopNode->numpred; i++) {
+ pred = IRO_NodeTable[LoopNode->pred[i]];
+ if (!Bv_IsBitSet(pred->index, InLoop)) {
+ if (flag21)
+ node22 = NULL;
+ else
+ node22 = pred;
+ flag21 = 1;
+ if (pred->nextnode == fnode) {
+ CError_ASSERT(2880, v2 == NULL || pred == v2);
+ v2 = pred;
+ }
+ }
+ }
+
+ if (!flag21) {
+ IRO_Dump("No predecessor outside the loop\n");
+ return;
+ }
+
+ if (!node22 || node22->last->type != IROLinearGoto)
+ node22 = CreatePreHeader(fnode, v2);
+ PredInt = node22->last;
+
+ if (PredInt->type == IROLinearGoto && PredInt->u.label.label != LoopNode->first->u.label.label) {
+ if (!KnownBounds || !Times) {
+ for (iter = IRO_FirstNode; iter; iter = iter->nextnode)
+ iter->mustreach = 0;
+ } else {
+ PredInt->u.label.label = LoopNode->first->u.label.label;
+ IRO_ComputeSuccPred();
+ }
+ }
+
+ if (copts.loopinvariants || copts.strengthreduction) {
+ MoveInvarianceInAddressExpr();
+ IRO_DumpAfterPhase("MoveInvarianceInAddressExpr", 0);
+ IRO_FindExpressions(InLoop, 1);
+ IRO_DumpExprs();
+ }
+
+ if (copts.loopinvariants)
+ UnmarkSubexpressionsOfInvariantExpressions();
+
+ if (!copts.optimizesize && copts.strengthreduction) {
+ for (expr = IRO_FirstExpr; expr; expr = expr->next) {
+ if (
+ !(expr->x0 & 4) &&
+ Bv_IsBitSet(expr->node->index, InLoop) &&
+ !expr->notSubable &&
+ (!expr->couldError || expr->node->mustreach) &&
+ Reducable(expr->linear, &reduceNd1, &reduceNd2, &var)
+ ) {
+ IRO_WalkTree(expr->linear, IRO_ActUnmarkRISCandidate);
+ expr->linear->flags |= IROLF_Ris;
+ expr->x1A = reduceNd1;
+ expr->x1E = var;
+ expr->x22 = reduceNd2;
+ }
+ }
+ }
+
+ if (!copts.optimizesize && copts.strengthreduction) {
+ RisList = NULL;
+ for (expr = IRO_FirstExpr; expr; expr = exprnext) {
+ exprnext = expr->next;
+ if (!(expr->x0 & 4) && (expr->linear->flags & IROLF_Ris)) {
+ reduceNd1 = expr->x1A;
+ var = expr->x1E;
+ reduceNd2 = expr->x22;
+
+ induction = FirstInd;
+ while (induction && induction->var != var)
+ induction = induction->next;
+ CError_ASSERT(3529, induction != NULL);
+
+ IRO_FindDepends(reduceNd1);
+ if (!Bv_BitsInCommon(IRO_Depends, AllKills)) {
+ IRO_Dump("Found reduction in strength: %d\n", expr->linear->index);
+ if (IS_LINEAR_DIADIC(expr->linear, ESHL)) {
+ expr->linear->nodetype = EMUL;
+ CInt64_SetULong(&reduceNd1->u.node->data.intval, 1 << CInt64_GetULong(&reduceNd1->u.node->data.intval));
+ reduceNd1->u.node->rtype = expr->linear->rtype;
+ }
+
+ searchris = RisList;
+ while (1) {
+ if (!searchris)
+ break;
+ if (IRO_ExprsSame(expr->linear, searchris->linear))
+ break;
+ searchris = searchris->next;
+ }
+
+ if (searchris) {
+ IRO_Dump("Using existing RIS: %d\n", searchris->linear->index);
+ IRO_WalkTree(expr->linear, IRO_RemoveExpr_Action);
+ } else {
+ searchris = CreateRIS(expr, reduceNd2, reduceNd1, induction, 0);
+ }
+ IRO_ReplaceReference(expr->linear, searchris->x8, expr->linear);
+ IRO_ClipExpr(expr);
+ }
+ }
+ }
+ }
+
+ RisList = NULL;
+
+ expr = IRO_FirstExpr;
+ removedExprs = NULL;
+ if (copts.loopinvariants) {
+ while (expr) {
+ exprnext = expr->next;
+ flag24 = 0;
+
+ if (
+ Bv_IsBitSet(expr->node->index, InLoop) &&
+ !expr->notSubable &&
+ (!expr->couldError || expr->node->mustreach) &&
+ (expr->linear->flags & IROLF_LoopInvariant) &&
+ !(expr->x0 & 4)
+ ) {
+ IRO_Dump("Found loop invariant: %d\n", expr->linear->index);
+
+ for (exprinner = removedExprs; exprinner; exprinner = exprinner->next) {
+ if (IRO_ExprsSame(exprinner->linear, expr->linear)) {
+ IRO_ReplaceReference(expr->linear, exprinner->x8, expr->linear);
+ IRO_NopOut(expr->linear);
+ IRO_Dump("Using already removed expr: %d\n", exprinner->linear->index);
+ IRO_RemoveExpr(expr);
+ flag24 = 1;
+ }
+ }
+
+ if (!flag24 && !expr->x8) {
+ IRO_GetTemp(expr);
+ IRO_ReplaceReference(expr->linear, expr->x8, expr->linear);
+ IRO_MoveExpression(expr, PredInt);
+ IRO_AssignToTemp(expr);
+ IRO_RemoveExpr(expr);
+ expr->next = removedExprs;
+ removedExprs = expr;
+ }
+ }
+
+ expr = exprnext;
+ }
+ }
+}
+
+static void MyHandleLoop_Motion(IRONode *fnode) {
+ IROLoopMemRef *memref;
+ IRONode *pred;
+ UInt16 i;
+ IRONode *v2;
+ IRONode *node21;
+ Object *tempobj;
+ int flag20;
+ IRONode *iter;
+ IROLinear *ass;
+ VarRecord *var;
+ Boolean checkflag;
+ IROLoop *loop;
+ IROList list;
+ IROElmList *refiter;
+
+ IRO_FirstExpr = NULL;
+ LoopNode = fnode;
+ FindMustReach();
+
+ for (var = IRO_FirstVar; var; var = var->next)
+ var->xA = 1;
+
+ ComputeLoopKills();
+ ComputeLoopInvariance();
+ ComputeLoopInduction();
+ LoopNode = fnode;
+ ConditionalHeaderAtBottom = 0;
+
+ v2 = NULL;
+ flag20 = 0;
+ node21 = NULL;
+ for (i = 0; i < LoopNode->numpred; i++) {
+ pred = IRO_NodeTable[LoopNode->pred[i]];
+ if (!Bv_IsBitSet(pred->index, InLoop)) {
+ if (flag20)
+ node21 = NULL;
+ else
+ node21 = pred;
+ flag20 = 1;
+ if (pred->nextnode == fnode) {
+ CError_ASSERT(3880, v2 == NULL || pred == v2);
+ v2 = pred;
+ }
+ }
+ }
+
+ if (!flag20) {
+ IRO_Dump("No predecessor outside the loop\n");
+ return;
+ }
+
+ if (!node21 || node21->last->type != IROLinearGoto)
+ node21 = CreatePreHeader(fnode, v2);
+ PredInt = node21->last;
+
+ if (PredInt->type == IROLinearGoto && PredInt->u.label.label != LoopNode->first->u.label.label) {
+ if (!KnownBounds || !Times) {
+ for (iter = IRO_FirstNode; iter; iter = iter->nextnode)
+ iter->mustreach = 0;
+ } else {
+ PredInt->u.label.label = LoopNode->first->u.label.label;
+ IRO_ComputeSuccPred();
+ }
+ }
+
+ if (copts.loopinvariants || copts.strengthreduction) {
+ MoveInvarianceInAddressExpr();
+ IRO_DumpAfterPhase("MoveInvarianceInAddressExpr", 0);
+ IRO_FindExpressions(InLoop, 0);
+ IRO_DumpExprs();
+ }
+
+ if (copts.loopinvariants)
+ UnmarkSubexpressionsOfInvariantExpressions();
+
+ checkflag = 1;
+ Bv_AllocVector(&InLoop_Exits, IRO_NumNodes + 1);
+ Bv_AllocVector(&InLoop_Tails, IRO_NumNodes + 1);
+ LoopExitNumber = 0;
+ LoopExitSuccessor = NULL;
+ LoopTailNum = 0;
+ LoopTail = NULL;
+ IRO_FindLoopTailsAndExits(fnode);
+ FindMustReach1(fnode);
+
+ loop = NULL;
+ if (LoopTailNum == 1) {
+ if (fnode->last->type == IROLinearIf || fnode->last->type == IROLinearIfNot)
+ loop = ExtractLoopInfo(fnode);
+ else if (LoopTail->last->type == IROLinearIf || LoopTail->last->type == IROLinearIfNot)
+ loop = ExtractLoopInfo(LoopTail);
+ }
+
+ if (loop && !(loop->flags & LP_IFEXPR_NON_CANONICAL) && LoopExitNumber == 1) {
+ IRO_LoopMemRefFirst = NULL;
+ IRO_LoopMemRefCurrent = NULL;
+ CheckAllLoopAddresses(IRO_FirstNode, InLoop, &checkflag);
+ CheckAllLoopAddresses(IRO_FirstNode, InLoop, &checkflag);
+ if (checkflag) {
+ for (memref = IRO_LoopMemRefFirst; memref; memref = memref->next) {
+ if (memref->flags & LoopMemRef_10)
+ memref->flags |= LoopMemRef_8;
+ }
+
+ for (memref = IRO_LoopMemRefFirst; memref; memref = memref->next) {
+ IRO_Dump("Loop Motion Candidate:: Int= %d", memref->nd->index);
+ if (memref->flags & LoopMemRef_8)
+ IRO_Dump("<invalid>");
+ if (memref->flags & LoopMemRef_1)
+ IRO_Dump("<load>");
+ if (memref->flags & LoopMemRef_2)
+ IRO_Dump("<store>");
+ IRO_Dump("\n");
+
+ if (!(memref->flags & LoopMemRef_8)) {
+ tempobj = create_temp_object(memref->nd->rtype);
+ IRO_FindVar(tempobj, 1, 1);
+ if (IRO_FindVar(((IROLinear *) memref->rec->objRefs->element)->u.node->data.objref, 0, 1)) {
+ IRO_InitList(&list);
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->index = ++IRO_NumLinear;
+ ass->rtype = memref->nd->rtype;
+ ass->nodetype = EASS;
+ ass->u.diadic.left = IRO_TempReference(tempobj, &list);
+ ass->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned;
+ ass->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned;
+ ass->u.diadic.right = IRO_DuplicateExpr(memref->nd, &list);
+ IRO_AddToList(ass, &list);
+ IRO_Paste(list.head, list.tail, PredInt);
+ } else {
+ CError_FATAL(4123);
+ }
+
+ if (LoopExitSuccessor->numpred != 1)
+ LoopExitSuccessor = CreateNewLoopExitSuccessor(LoopExitSuccessor);
+
+ IRO_InitList(&list);
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->index = ++IRO_NumLinear;
+ ass->rtype = memref->nd->rtype;
+ ass->nodetype = EASS;
+ ass->u.diadic.left = IRO_DuplicateExpr(memref->nd, &list);
+ ass->u.diadic.left->flags |= IROLF_Ind | IROLF_Assigned;
+ ass->u.diadic.left->u.monadic->flags |= IROLF_Ind | IROLF_Assigned;
+ ass->u.diadic.right = IRO_TempReference(tempobj, &list);
+ IRO_AddToList(ass, &list);
+
+ if (LoopExitSuccessor->first->type == IROLinearLabel)
+ IRO_PasteAfter(list.head, list.tail, LoopExitSuccessor->first);
+ else
+ IRO_Paste(list.head, list.tail, LoopExitSuccessor->first);
+
+ for (refiter = memref->list; refiter; refiter = refiter->next) {
+ IRO_Dump("Loop Motion Candidate Reference at Int= %d\n", ((IROLinear *) refiter->element)->index);
+ IRO_InitList(&list);
+ IRO_TempReference(tempobj, &list);
+ IRO_Paste(list.head, list.tail, refiter->element);
+ IRO_LocateFather_Cut_And_Paste(refiter->element, list.tail);
+ }
+ }
+ }
+ }
+ }
+
+ IRO_DumpAfterPhase("After Motion", 0);
+}
+
+static Boolean CheckLoopAddress(IROLinear *nd, Boolean mustreach1) {
+ IROLoopMemRef *memref;
+ IROAddrRecord *rec;
+ IROAddrRecord *otherrec;
+ IROLinear *inner;
+ IROElmList *list;
+ Boolean flag;
+
+ inner = nd->u.monadic;
+ rec = IRO_InitAddrRecordPointer(inner);
+ if (IS_LINEAR_ENODE(inner, EOBJREF)) {
+ rec->numObjRefs++;
+ IRO_AddElmToList(inner, &rec->objRefs);
+ } else if (IS_LINEAR_DIADIC(inner, EADD)) {
+ IRO_DecomposeAddressExpression(inner, rec);
+ } else {
+ return 0;
+ }
+
+ if (rec->numObjRefs != 1)
+ return 0;
+
+ flag = (nd->flags & IROLF_CouldError) || !(nd->flags & IROLF_Reffed);
+ if (!IRO_LoopMemRefFirst) {
+ MakeLoopEntry(nd, rec, mustreach1, flag);
+ } else {
+ for (memref = IRO_LoopMemRefFirst; memref; memref = memref->next) {
+ otherrec = memref->rec;
+ if (((IROLinear *) rec->objRefs->element)->u.node->data.objref == ((IROLinear *) otherrec->objRefs->element)->u.node->data.objref) {
+ if (IRO_ExprsSame(inner, otherrec->linear)) {
+ list = oalloc(sizeof(IROElmList));
+ list->element = nd;
+ list->next = NULL;
+ if (!memref->list) {
+ memref->list = list;
+ } else {
+ list->next = memref->list;
+ memref->list = list;
+ }
+ } else {
+ memref->flags |= LoopMemRef_8;
+ }
+
+ if (!mustreach1 && flag)
+ memref->flags |= LoopMemRef_8;
+ if (mustreach1 || flag)
+ memref->flags &= ~LoopMemRef_10;
+ break;
+ }
+ }
+
+ if (!memref)
+ MakeLoopEntry(nd, rec, mustreach1, flag);
+ }
+
+ return 1;
+}
+
+static void CheckAllLoopAddresses(IRONode *fnode, BitVector *bv, Boolean *resultFlag) {
+ IROLinear *nd;
+ Boolean flag;
+
+ flag = *resultFlag;
+ while (fnode) {
+ if (Bv_IsBitSet(fnode->index, bv) && (nd = fnode->first)) {
+ while (flag) {
+ if (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT)
+ flag = CheckLoopAddress(nd, fnode->mustreach1);
+ else if (nd->type == IROLinearFunccall)
+ flag = 0;
+
+ if (nd == fnode->last)
+ break;
+ nd = nd->next;
+ }
+
+ if (!flag)
+ break;
+ }
+ fnode = fnode->nextnode;
+ }
+ *resultFlag = flag;
+}
+
+static void MakeLoopEntry(IROLinear *nd, IROAddrRecord *rec, Boolean mustreach1, Boolean flag2) {
+ IROElmList *list;
+
+ if (!IRO_IsRegable(((IROLinear *) rec->objRefs->element)->u.node->data.objref) &&
+ (nd->u.monadic->flags & IROLF_LoopInvariant) &&
+ !IRO_HasSideEffect(nd)) {
+ if (!IRO_LoopMemRefFirst) {
+ IRO_LoopMemRefCurrent = IRO_LoopMemRefFirst = oalloc(sizeof(IROLoopMemRef));
+ } else {
+ IRO_LoopMemRefCurrent->next = oalloc(sizeof(IROLoopMemRef));
+ IRO_LoopMemRefCurrent = IRO_LoopMemRefCurrent->next;
+ }
+ IRO_LoopMemRefCurrent->flags = LoopMemRef_10;
+ IRO_LoopMemRefCurrent->nd = nd;
+ IRO_LoopMemRefCurrent->rec = rec;
+ IRO_LoopMemRefCurrent->next = NULL;
+ IRO_LoopMemRefCurrent->list = NULL;
+
+ list = oalloc(sizeof(IROElmList));
+ list->element = nd;
+ list->next = NULL;
+ if (!IRO_LoopMemRefCurrent->list) {
+ IRO_LoopMemRefCurrent->list = list;
+ } else {
+ list->next = IRO_LoopMemRefCurrent->list;
+ IRO_LoopMemRefCurrent->list = list;
+ }
+
+ if (((IROLinear *) rec->objRefs->element)->flags & IROLF_Assigned) {
+ IRO_LoopMemRefCurrent->flags |= LoopMemRef_2;
+ if (((IROLinear *) rec->objRefs->element)->flags & IROLF_Used)
+ IRO_LoopMemRefCurrent->flags |= LoopMemRef_1;
+ } else {
+ IRO_LoopMemRefCurrent->flags |= LoopMemRef_1;
+ }
+
+ if (!mustreach1 && flag2)
+ IRO_LoopMemRefCurrent->flags |= LoopMemRef_8;
+
+ if (mustreach1 || flag2)
+ IRO_LoopMemRefCurrent->flags &= ~LoopMemRef_10;
+ }
+}
+
+void FindAssignmenttoInductionVar(IROLoop *loop, IRONode *fnode) {
+ IROLinear *nd;
+ UInt32 index;
+
+ if (!loop->induction) {
+ loop->nd14 = NULL;
+ } else {
+ index = loop->induction->var->index;
+ for (nd = fnode->first; nd; nd = nd->next) {
+ Bv_Clear(IRO_VarKills);
+ IRO_GetKills(nd);
+ if (Bv_IsBitSet(index, IRO_VarKills))
+ loop->nd14 = nd;
+
+ if (nd == fnode->last)
+ break;
+ }
+
+ if (loop->nd14 && loop->nd14->type != IROLinearOp2Arg)
+ loop->nd14 = NULL;
+ }
+}
+
+static void ComputeIntWeight(IROLoop *loop, IROLinear *Int) {
+ loop->sizeBySomeMeasurement++;
+}
+
+static IROLinear *IsTypconVar(IROLinear *nd) {
+ if (IS_LINEAR_MONADIC(nd, ETYPCON) && IRO_IsVariable(nd->u.monadic))
+ return nd->u.monadic;
+ else
+ return NULL;
+}
+
+IROLoop *ExtractLoopInfo(IRONode *fnode) {
+ Boolean flag30;
+ Boolean flag29;
+ Boolean flag28;
+ UInt32 counter27;
+ IROLoopInd *ind23;
+ Object *obj;
+ IROLinear *nd21;
+ IRONode *scanfnode;
+ IROLinear *left19;
+ IROLinear *right18;
+ IROLinear *tmp18;
+ IROLinear *scannd;
+ IROLinear *tmp;
+ VarRecord *var;
+ IROLoopInd *scanind;
+ IROLinear *left;
+ IROLinear *right;
+ UInt32 counter2;
+ UInt32 i;
+ IROLoop *loop;
+
+ flag30 = 0;
+ flag29 = 0;
+ flag28 = 0;
+ counter27 = 0;
+ LoopNode = fnode;
+
+ loop = oalloc(sizeof(IROLoop));
+ loop->fnode = fnode;
+ nd21 = LoopNode->last->u.label.x4;
+ loop->nd18 = nd21;
+ loop->flags = 0;
+ loop->x8 = 0;
+ loop->nd14 = NULL;
+ loop->induction = NULL;
+ loop->index20 = -1;
+ loop->index24 = -1;
+ loop->sizeBySomeMeasurement = 0;
+
+ if (nd21->type == IROLinearOp2Arg && IS_TYPE_INT(nd21->rtype)) {
+ ind23 = NULL;
+ left19 = nd21->u.diadic.left;
+ right18 = nd21->u.diadic.right;
+ if (IRO_IsVariable(left19) || (left19 = IsTypconVar(left19))) {
+ if ((var = IRO_FindVar(left19->u.monadic->u.node->data.objref, 0, 1))) {
+ scanind = FirstInd;
+ while (scanind && scanind->var != var)
+ scanind = scanind->next;
+ if (scanind) {
+ ind23 = scanind;
+ loop->flags |= LoopFlags_1;
+ loop->induction = scanind;
+ }
+ }
+ }
+
+ if (IRO_IsVariable(right18) || (right18 = IsTypconVar(right18))) {
+ if ((var = IRO_FindVar(right18->u.monadic->u.node->data.objref, 0, 1))) {
+ scanind = FirstInd;
+ while (scanind && scanind->var != var)
+ scanind = scanind->next;
+ if (scanind) {
+ ind23 = scanind;
+ loop->flags &= ~LoopFlags_1;
+ loop->induction = scanind;
+ }
+ }
+ }
+
+ if (ind23 && ind23->addConst > 0) {
+ if (loop->flags & LoopFlags_1) {
+ if (
+ loop->nd18->type != IROLinearOp2Arg ||
+ !(loop->nd18->nodetype == ELESS || loop->nd18->nodetype == EGREATER || loop->nd18->nodetype == ELESSEQU || loop->nd18->nodetype == EGREATEREQU) ||
+ !loop->nd18->u.diadic.left ||
+ !loop->nd18->u.diadic.left->rtype ||
+ !IS_TYPE_INT(loop->nd18->u.diadic.left->rtype) ||
+ !loop->nd18->u.diadic.right ||
+ !loop->nd18->u.diadic.right->rtype ||
+ !IS_TYPE_INT(loop->nd18->u.diadic.right->rtype)
+ ) {
+ loop->flags |= LP_IFEXPR_NON_CANONICAL;
+ return loop;
+ }
+ } else {
+ if (
+ loop->nd18->type == IROLinearOp2Arg &&
+ (loop->nd18->nodetype == EGREATER || loop->nd18->nodetype == EGREATEREQU) &&
+ (left = loop->nd18->u.diadic.left) &&
+ left->rtype &&
+ IS_TYPE_INT(left->rtype) &&
+ (right = loop->nd18->u.diadic.right) &&
+ right->rtype &&
+ IS_TYPE_INT(right->rtype)
+ ) {
+ loop->nd18->u.diadic.left = right;
+ loop->nd18->u.diadic.right = left;
+ if (loop->nd18->nodetype == EGREATER)
+ loop->nd18->nodetype = ELESS;
+ else if (loop->nd18->nodetype == EGREATEREQU)
+ loop->nd18->nodetype = ELESSEQU;
+ loop->flags |= LoopFlags_1;
+ } else if (
+ loop->nd18->type == IROLinearOp2Arg &&
+ (loop->nd18->nodetype == ELESS || loop->nd18->nodetype == ELESSEQU) &&
+ (left = loop->nd18->u.diadic.left) &&
+ left->rtype &&
+ IS_TYPE_INT(left->rtype) &&
+ (right = loop->nd18->u.diadic.right) &&
+ right->rtype &&
+ IS_TYPE_INT(right->rtype)
+ ) {
+ loop->nd18->u.diadic.left = right;
+ loop->nd18->u.diadic.right = left;
+ if (loop->nd18->nodetype == ELESS)
+ loop->nd18->nodetype = EGREATER;
+ else if (loop->nd18->nodetype == ELESSEQU)
+ loop->nd18->nodetype = EGREATEREQU;
+ loop->flags |= LoopFlags_1;
+ } else {
+ loop->flags |= LP_IFEXPR_NON_CANONICAL;
+ return loop;
+ }
+ }
+ } else {
+ loop->flags |= LP_INDUCTION_NOT_FOUND;
+ return loop;
+ }
+ } else if (nd21->type == IROLinearOp1Arg && IS_TYPE_INT(nd21->rtype)) {
+ if (nd21->nodetype == EPREINC || nd21->nodetype == EPOSTINC || nd21->nodetype == EPREDEC || nd21->nodetype == EPOSTDEC) {
+ if (IRO_IsVariable(nd21->u.monadic)) {
+ if ((var = IRO_FindVar(nd21->u.monadic->u.monadic->u.node->data.objref, 0, 1))) {
+ scanind = FirstInd;
+ while (scanind && scanind->var != var)
+ scanind = scanind->next;
+ if (scanind) {
+ ind23 = scanind;
+ loop->flags |= LoopFlags_10000;
+ loop->induction = scanind;
+ } else {
+ loop->flags |= LP_INDUCTION_NOT_FOUND;
+ return loop;
+ }
+ } else {
+ loop->flags |= LP_INDUCTION_NOT_FOUND;
+ return loop;
+ }
+ } else {
+ loop->flags |= LP_INDUCTION_NOT_FOUND;
+ return loop;
+ }
+ } else {
+ loop->flags |= LP_INDUCTION_NOT_FOUND;
+ return loop;
+ }
+ } else {
+ loop->flags |= LP_IFEXPR_NON_CANONICAL;
+ return loop;
+ }
+
+ counter2 = 0;
+ scanind = FirstInd;
+ while (scanind) {
+ scanind = scanind->next;
+ counter2++;
+ }
+
+ if (counter2 > 1)
+ loop->flags |= LP_HAS_MULTIPLE_INDUCTIONS;
+
+ if ((scanind = loop->induction)) {
+ nd21 = scanind->nd;
+ if (nd21->type == IROLinearOp2Arg) {
+ if (IS_LINEAR_DIADIC_2(loop->nd18, ELESS, ELESSEQU)) {
+ if (nd21->nodetype == EADDASS) {
+ if (scanind->addConst == 1)
+ loop->flags |= LP_LOOP_STEP_ISADD;
+ if (scanind->addConst > 0)
+ loop->flags |= LP_LOOP_STEP_ISPOS;
+ } else if (nd21->nodetype == EASS &&
+ IS_LINEAR_DIADIC(nd21->u.diadic.right, EADD) &&
+ IRO_IsIntConstant(tmp18 = nd21->u.diadic.right->u.diadic.right) &&
+ CTool_EndianReadWord32(&tmp18->u.node->data.intval.hi) == 0) {
+ if (CInt64_GetULong(&tmp18->u.node->data.intval) == 1)
+ loop->flags |= LP_LOOP_STEP_ISADD;
+ if (CInt64_GetULong(&tmp18->u.node->data.intval) > 0)
+ loop->flags |= LP_LOOP_STEP_ISPOS;
+ }
+ }
+ } else if (nd21->type == IROLinearOp1Arg) {
+ if (nd21->nodetype == EPREINC || nd21->nodetype == EPOSTINC) {
+ if (scanind->addConst == 1)
+ loop->flags |= LP_LOOP_STEP_ISADD;
+ if (scanind->addConst > 0)
+ loop->flags |= LP_LOOP_STEP_ISPOS;
+ }
+ if (nd21->nodetype == EPREDEC || nd21->nodetype == EPOSTDEC) {
+ if (scanind->addConst == 1)
+ loop->flags |= LoopFlags_2000;
+ if (scanind->addConst > 0)
+ loop->flags |= LP_LOOP_STEP_ISNEG;
+ }
+ }
+ loop->index24 = nd21->index;
+ loop->index20 = IRO_FindStart(nd21)->index;
+ }
+
+ if (ind23) {
+ tmp = IRO_FindStart(fnode->last->u.diadic.right);
+ loop->flags |= LoopFlags_200;
+ if (loop->flags & LoopFlags_10000) {
+ for (scannd = loop->fnode->first; scannd && scannd != tmp; scannd = scannd->next) {
+ if (scannd->type != IROLinearLabel && scannd->type != IROLinearNop)
+ loop->flags &= ~LoopFlags_200;
+ }
+ } else {
+ for (scannd = ind23->nd->next; scannd && scannd != tmp; scannd = scannd->next){
+ if (scannd->type != IROLinearLabel && scannd->type != IROLinearNop)
+ loop->flags &= ~LoopFlags_200;
+ }
+ for (scannd = loop->fnode->first; scannd && scannd != tmp; scannd = scannd->next){
+ if ((scannd->index < loop->index20 || scannd->index > loop->index24) && scannd->type != IROLinearLabel && scannd->type != IROLinearNop)
+ loop->flags &= ~LoopFlags_200;
+ }
+ }
+ }
+
+ for (scanfnode = IRO_FirstNode; scanfnode; scanfnode = scanfnode->nextnode) {
+ if (Bv_IsBitSet(scanfnode->index, InLoop) && scanfnode != fnode && (scannd = scanfnode->first)) {
+ while (1) {
+ if (scannd->type == IROLinearFunccall)
+ flag30 = 1;
+ if (scannd->type == IROLinearGoto)
+ flag28++;
+ if (flag28 >= 1)
+ flag29 = 1;
+ if (scannd->type == IROLinearIf || scannd->type == IROLinearIfNot || scannd->type == IROLinearSwitch || scannd->type == IROLinearReturn)
+ flag29 = 1;
+
+ if (scannd->type == IROLinearAsm)
+ loop->flags |= LP_LOOP_HAS_ASM;
+
+ if (!(scannd->flags & IROLF_Reffed) && scannd->type != IROLinearNop && scannd->type != IROLinearLabel) {
+ if (!IRO_IsAssignOp[scannd->nodetype]) {
+ loop->flags |= LoopFlags_8;
+ } else if (scannd->index < loop->index20 || scannd->index > loop->index24) {
+ counter27++;
+ if (IsAssignmentReductionCandidate(scannd) && counter27 == 1)
+ loop->flags |= LoopFlags_40000;
+ if (counter27 > 1)
+ loop->flags &= ~LoopFlags_40000;
+ }
+ }
+
+ if (scannd->index < loop->index20 || scannd->index > loop->index24) {
+ if (IS_LINEAR_ENODE(scannd, EOBJREF)) {
+ obj = scannd->u.node->data.objref;
+ if ((scannd->flags & IROLF_Ind) && obj && obj == loop->induction->var->object) {
+ if (!(scannd->flags & IROLF_Assigned) && (scannd->flags & IROLF_Used)) {
+ IRO_Dump("Induction Used in loop\n");
+ loop->flags |= LoopFlags_800;
+ }
+ }
+ }
+
+ if (IS_LINEAR_DIADIC(scannd, ESHR) &&
+ (obj = IRO_IsVariable(scannd->u.diadic.left)) &&
+ IRO_IsIntConstant(scannd->u.diadic.right)) {
+ for (scanind = FirstInd; scanind; scanind = scanind->next) {
+ if (scanind->var->object == obj) {
+ IRO_Dump("Induction has DIV: %s\n", obj->name->name);
+ scanind->flags |= LoopInd_HasDiv;
+ }
+ }
+ }
+
+ if (IS_LINEAR_DIADIC(scannd, EAND) &&
+ (obj = IRO_IsVariable(scannd->u.diadic.left)) &&
+ IRO_IsIntConstant(scannd->u.diadic.right)) {
+ for (scanind = FirstInd; scanind && obj; scanind = scanind->next) {
+ if (scanind->var->object == obj) {
+ IRO_Dump("Induction has MOD: %s\n", obj->name->name);
+ scanind->flags |= LoopInd_HasMod;
+ }
+ }
+ }
+ }
+
+ ComputeIntWeight(loop, scannd);
+ if (scannd == scanfnode->last)
+ break;
+ scannd = scannd->next;
+ }
+ }
+
+ if (flag30)
+ loop->flags |= LP_LOOP_HAS_CALLS;
+ if (flag29)
+ loop->flags |= LP_LOOP_HAS_CNTRLFLOW;
+
+ for (i = 0; i < scanfnode->numsucc && scanfnode != fnode; i++) {
+ if (Bv_IsBitSet(scanfnode->index, InLoop) && !Bv_IsBitSet(scanfnode->succ[i], InLoop)) {
+ IRO_Dump("Node %d has an out of loop successor %d\n", scanfnode->index, scanfnode->succ[i]);
+ IRO_DumpBits("Loop includes: ", InLoop);
+ IRO_Dump("loop has multiple exits\n");
+ loop->flags |= LoopFlags_1000;
+ }
+ }
+ }
+
+ return loop;
+}
+
+CLabel *BuildLabel(IROList *list) {
+ IROLinear *nd;
+
+ nd = IRO_NewLinear(IROLinearLabel);
+ nd->index = IRO_NumLinear++;
+ nd->u.label.label = IRO_NewLabel();
+ nd->flags |= IROLF_1;
+ IRO_AddToList(nd, list);
+ return nd->u.label.label;
+}
+
+static void MoveInvarianceInAddressExpr(void) {
+ IRONode *fnode;
+ IROLinear *nd;
+ IROLinear *start;
+ IROList list;
+
+ IRO_FirstExpr = IRO_LastExpr = NULL;
+ IRO_NumExprs = 0;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ if (Bv_IsBitSet(fnode->index, InLoop)) {
+ for (nd = fnode->first; nd; nd = nd->next) {
+ if (nd->type == IROLinearOp1Arg &&
+ (nd->nodetype == EINDIRECT || nd->nodetype == EINDIRECT) &&
+ IS_LINEAR_DIADIC(nd->u.monadic, EADD)) {
+ RearrangeInvarianceInAddressExpr(nd->u.monadic, &list);
+ start = IRO_FindStart(nd->u.monadic);
+ IRO_LocateFather_Cut_And_Paste(nd->u.monadic, list.tail);
+ IRO_Paste(list.head, list.tail, start);
+ }
+
+ if (nd == fnode->last)
+ break;
+ }
+ }
+ }
+
+ IRO_UpdateFlagsOnInts();
+}
+
+static void AddAddendLinear(IROLinear *nd) {
+ IROElmList *list;
+
+ if (IS_LINEAR_DIADIC(nd, EADD)) {
+ AddAddendLinear(nd->u.diadic.left);
+ AddAddendLinear(nd->u.diadic.right);
+ } else {
+ list = oalloc(sizeof(IROElmList));
+ list->element = nd;
+ list->next = NULL;
+ if (FirstAddendLinear)
+ LastAddendLinear->next = list;
+ else
+ FirstAddendLinear = list;
+ LastAddendLinear = list;
+ }
+}
+
+static IROLinear *RearrangeInvarianceInAddressExpr(IROLinear *nd, IROList *list) {
+ IROLinear *result;
+ IROElmList *scanlist;
+ IROElmList *elist;
+ IROLinear *scannd;
+
+ IRO_InitList(list);
+ FirstAddendLinear = LastAddendLinear = NULL;
+ AddAddendLinear(nd->u.diadic.left);
+ AddAddendLinear(nd->u.diadic.right);
+
+ elist = NULL;
+ result = NULL;
+ for (scanlist = FirstAddendLinear; scanlist; scanlist = scanlist->next) {
+ scannd = scanlist->element;
+ if (!IRO_IsIntConstant(scannd) && (scannd->flags & IROLF_LoopInvariant)) {
+ if (result) {
+ IROLinear *tmp = IRO_NewLinear(IROLinearOp2Arg);
+ tmp->index = ++IRO_NumLinear;
+ tmp->nodetype = EADD;
+ tmp->u.diadic.left = result;
+ tmp->u.diadic.right = IRO_DuplicateExpr(scannd, list);
+ IRO_AddToList(tmp, list);
+ tmp->flags |= IROLF_LoopInvariant;
+ tmp->flags |= IROLF_Reffed;
+ tmp->rtype = result->rtype;
+ result = tmp;
+ } else {
+ result = IRO_DuplicateExpr(scannd, list);
+ }
+
+ if (elist)
+ elist->next = scanlist->next;
+ else
+ FirstAddendLinear = scanlist->next;
+ } else {
+ elist = scanlist;
+ }
+ }
+
+ for (scanlist = FirstAddendLinear, elist = NULL; scanlist; scanlist = scanlist->next) {
+ scannd = scanlist->element;
+ if (!IRO_IsIntConstant(scannd)) {
+ if (result) {
+ IROLinear *tmp = IRO_NewLinear(IROLinearOp2Arg);
+ tmp->index = ++IRO_NumLinear;
+ tmp->nodetype = EADD;
+ tmp->u.diadic.left = result;
+ tmp->u.diadic.right = IRO_DuplicateExpr(scannd, list);
+ IRO_AddToList(tmp, list);
+ tmp->flags |= IROLF_Reffed;
+ tmp->rtype = result->rtype;
+ result = tmp;
+ } else {
+ result = IRO_DuplicateExpr(scannd, list);
+ }
+
+ if (elist)
+ elist->next = scanlist->next;
+ else
+ FirstAddendLinear = scanlist->next;
+ } else {
+ elist = scanlist;
+ }
+ }
+
+ for (scanlist = FirstAddendLinear; scanlist; scanlist = scanlist->next) {
+ scannd = scanlist->element;
+ if (result) {
+ IROLinear *tmp = IRO_NewLinear(IROLinearOp2Arg);
+ tmp->index = ++IRO_NumLinear;
+ tmp->nodetype = EADD;
+ tmp->u.diadic.left = result;
+ tmp->u.diadic.right = scannd;
+ tmp->u.diadic.right = IRO_DuplicateExpr(scannd, list);
+ IRO_AddToList(tmp, list);
+ tmp->flags |= IROLF_Reffed;
+ tmp->rtype = result->rtype;
+ result = tmp;
+ } else {
+ result = IRO_DuplicateExpr(scannd, list);
+ }
+ }
+
+ return result;
+}
+
+static IROLinear *FindAddendForReductionPattern(IROLinear *a, IROLinear *b, Boolean *resultFlag) {
+ IROLinear *left;
+ IROLinear *right;
+ IROLinear *node28;
+ Boolean subflag;
+
+ left = b->u.diadic.left;
+ right = b->u.diadic.right;
+ if (b->nodetype == EADD || b->nodetype == ESUB) {
+ node28 = left;
+ while (IS_LINEAR_MONADIC(node28, ETYPCON))
+ node28 = node28->u.monadic;
+
+ if (IS_LINEAR_MONADIC(node28, EINDIRECT) && (node28->u.monadic->flags & IROLF_LoopInvariant) && IRO_ExprsSame(a, node28)) {
+ *resultFlag = 1;
+ return left;
+ }
+
+ if (IS_LINEAR_DIADIC_2(node28, EADD, ESUB)) {
+ if ((node28 = FindAddendForReductionPattern(a, node28, &subflag))) {
+ *resultFlag = 1;
+ return node28;
+ }
+ }
+ }
+
+ *resultFlag = 0;
+ if (b->nodetype == EADD) {
+ node28 = right;
+ while (IS_LINEAR_MONADIC(node28, ETYPCON))
+ node28 = node28->u.monadic;
+
+ if (IS_LINEAR_MONADIC(node28, EINDIRECT) && (node28->u.monadic->flags & IROLF_LoopInvariant) && IRO_ExprsSame(a, node28)) {
+ return right;
+ }
+
+ if (IS_LINEAR_DIADIC_2(node28, EADD, ESUB)) {
+ if ((node28 = FindAddendForReductionPattern(a, node28, &subflag))) {
+ return node28;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void ReorderOperandsForReductionPattern(IROLinear *a, IROLinear *b) {
+ IROLinear *left;
+ IROLinear *right;
+ IROLinear *addend;
+ IROLinear *tmp;
+ Boolean flag;
+
+ left = b->u.diadic.left;
+ right = b->u.diadic.right;
+
+ if (b->nodetype == EADD && (addend = FindAddendForReductionPattern(a, b, &flag)) && addend != left) {
+ if (flag && IS_LINEAR_DIADIC_2(left, EADD, ESUB) && addend->rtype == right->rtype) {
+ tmp = left;
+ b->u.diadic.left = right;
+ left = right;
+ b->u.diadic.right = tmp;
+ right = tmp;
+ flag = 0;
+ }
+
+ if (!flag && IS_LINEAR_DIADIC_2(right, EADD, ESUB) && addend->rtype == left->rtype) {
+ if (IRO_LocateFather_Cut_And_Paste_Without_Nopping(addend, left))
+ b->u.diadic.left = addend;
+ }
+ }
+}
+
+static UInt32 IsAssignmentReductionCandidate(IROLinear *nd) {
+ IROLinear *left;
+ IROLinear *right;
+ IROLinear *tmp;
+
+ if (nd->type == IROLinearOp2Arg) {
+ if (nd->nodetype == EASS) {
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+ if (IS_LINEAR_MONADIC(left, EINDIRECT) && (left->u.monadic->flags & IROLF_LoopInvariant)) {
+ if (IS_LINEAR_MONADIC(right, ETYPCON) &&
+ right->rtype->type == right->u.monadic->rtype->type &&
+ IS_TYPE_INT(right->rtype) &&
+ right->rtype->size < right->u.monadic->rtype->size)
+ right = right->u.monadic;
+
+ if (IS_LINEAR_DIADIC_2(right, EADD, ESUB)) {
+ ReorderOperandsForReductionPattern(left, right);
+ tmp = right->u.diadic.left;
+ if (IS_LINEAR_MONADIC(tmp, ETYPCON))
+ tmp = tmp->u.monadic;
+ if (IS_LINEAR_MONADIC(tmp, EINDIRECT) &&
+ (tmp->u.monadic->flags & IROLF_LoopInvariant) &&
+ IRO_ExprsSame(left, tmp) &&
+ right->u.diadic.right->type == IROLinearOp2Arg) {
+ if (right->u.diadic.right->nodetype == EADD)
+ return 1;
+ if (right->u.diadic.right->nodetype == ESUB)
+ return 1;
+ if (right->u.diadic.right->nodetype == EMUL)
+ return 1;
+ if (right->u.diadic.right->nodetype == EDIV)
+ return 1;
+ }
+ }
+ }
+ } else if (nd->nodetype == EADDASS || nd->nodetype == ESUBASS) {
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+
+ if (IS_LINEAR_MONADIC(right, ETYPCON) &&
+ right->rtype->type == right->u.monadic->rtype->type &&
+ IS_TYPE_INT(right->rtype) &&
+ right->rtype->size < right->u.monadic->rtype->size)
+ right = right->u.monadic;
+
+ if (IS_LINEAR_MONADIC(left, EINDIRECT) &&
+ (left->u.monadic->flags & IROLF_LoopInvariant) &&
+ right->type == IROLinearOp2Arg) {
+ if (right->nodetype == EADD)
+ return 1;
+ if (right->nodetype == ESUB)
+ return 1;
+ if (right->nodetype == EMUL)
+ return 1;
+ if (right->nodetype == EDIV)
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroLoop.h b/compiler_and_linker/FrontEnd/Optimizer/IroLoop.h
new file mode 100644
index 0000000..2d968ad
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroLoop.h
@@ -0,0 +1,111 @@
+#ifndef COMPILER_IROLOOP_H
+#define COMPILER_IROLOOP_H
+
+#include "IrOptimizer.h"
+#include "BitVector.h"
+
+typedef enum IROLoopIndFlags {
+ LoopInd_HasMod = 1,
+ LoopInd_HasDiv = 2,
+ LoopInd_4 = 4,
+ LoopInd_8 = 8
+} IROLoopIndFlags;
+
+typedef enum IROLoopFlags {
+ LoopFlags_1 = 1, // LP_INDUCTION_AT_LEFT
+ LP_LOOP_HAS_CALLS = 2,
+ LP_LOOP_HAS_CNTRLFLOW = 4,
+ LoopFlags_8 = 8, // LP_HAS_NONASSIGN
+ LP_INDUCTION_NOT_FOUND = 0x10,
+ LP_IFEXPR_NON_CANONICAL = 0x20,
+ LP_HAS_MULTIPLE_INDUCTIONS = 0x40,
+ LP_LOOP_HDR_HAS_SIDEEFFECTS = 0x80,
+ LP_LOOP_STEP_ISADD = 0x100,
+ LoopFlags_200 = 0x200, // LP_HEADER_FOLLOWS_UPDATE?
+ LP_LOOP_STEP_ISPOS = 0x400,
+ LoopFlags_800 = 0x800, // LP_IND_USED_IN_LOOP
+ LoopFlags_1000 = 0x1000, // LP_HAS_MULTIPLE_EXITS
+ LoopFlags_2000 = 0x2000, // inverse of LP_LOOP_STEP_ISADD?
+ LP_LOOP_STEP_ISNEG = 0x4000,
+ LP_LOOP_HAS_ASM = 0x8000,
+ LoopFlags_10000 = 0x10000, // LP_WHILE_LOOP
+ LoopFlags_20000 = 0x20000, // maybe LP_RECURSIVE_LOOP?
+ LoopFlags_40000 = 0x40000 // LP_IS_REDUCTION_CAND
+} IROLoopFlags;
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct IROLoopInd {
+ IROLoopIndFlags flags;
+ VarRecord *var;
+ IRONode *fnode;
+ IROLinear *nd;
+ SInt32 addConst;
+ IROLinear *addNode;
+ struct IROLoopInd *next;
+} IROLoopInd;
+
+struct IROLoop {
+ SInt32 flags;
+ IRONode *fnode;
+ int x8;
+ IRONode *xC;
+ IRONode *x10;
+ IROLinear *nd14; // assignment expression that sets the initial value of induction
+ IROLinear *nd18; // ifexpr?
+ IROLoopInd *induction;
+ int index20;
+ int index24;
+ CInt64 x28;
+ CInt64 x30;
+ int sizeBySomeMeasurement;
+};
+
+typedef enum IROLoopMemRefFlags {
+ LoopMemRef_1 = 1,
+ LoopMemRef_2 = 2,
+ LoopMemRef_4 = 4,
+ LoopMemRef_8 = 8,
+ LoopMemRef_10 = 0x10
+} IROLoopMemRefFlags;
+
+typedef struct IROLoopMemRef {
+ IROLoopMemRefFlags flags;
+ IROLinear *nd;
+ IROElmList *list;
+ IROAddrRecord *rec;
+ struct IROLoopMemRef *next;
+} IROLoopMemRef;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+extern IRONode *LoopNode;
+extern Boolean ConditionalHeaderAtBottom;
+extern IROLoopInd *FirstInd;
+extern BitVector *InLoop;
+extern IROList IRO_InitLList;
+extern BitVector *InLoop_Exits;
+extern BitVector *InLoop_Tails;
+extern UInt32 LoopExitNumber;
+extern UInt32 LoopTailNum;
+extern IRONode *LoopExitSuccessor;
+extern IRONode *LoopTail;
+extern IROLoopMemRef *IRO_LoopMemRefFirst;
+extern IROLoopMemRef *IRO_LoopMemRefCurrent;
+
+extern void FindMustReach(void);
+extern void FindMustReach1(IRONode *checkfnode);
+extern void AddPreds(IRONode *fnode);
+extern void IncLoopDepth(void);
+extern void IRO_SetLoopDepth(void);
+extern void IRO_FindLoops(void);
+extern void ComputeLoopKills(void);
+extern void ComputeLoopInvariance(void);
+extern void ComputeLoopInduction(void);
+extern void FindAssignmenttoInductionVar(IROLoop *loop, IRONode *fnode);
+extern IROLoop *ExtractLoopInfo(IRONode *fnode);
+extern CLabel *BuildLabel(IROList *list);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c b/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c
new file mode 100644
index 0000000..1f15cad
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.c
@@ -0,0 +1,564 @@
+#include "IroMalloc.h"
+#include "compiler/CompilerTools.h"
+
+#define FLAGMASK 0xF
+
+typedef struct Block {
+ struct Block *prev;
+ struct Block *next;
+ void *x8;
+ void *xC;
+ size_t remain;
+ size_t x14;
+} Block;
+
+typedef struct SubBlockBase {
+ size_t x0;
+ Block *block;
+} SubBlockBase;
+
+typedef struct SubBlock {
+ size_t x0;
+ Block *block;
+ struct SubBlock *x8;
+ struct SubBlock *xC;
+} SubBlock;
+
+typedef struct SubBlockTail {
+ size_t x0copy;
+} SubBlockTail;
+
+typedef struct BlockTail {
+ size_t x14copy;
+ SubBlock *unk;
+} BlockTail;
+
+typedef struct FixStart {
+ struct FixBlock *a;
+ struct FixSubBlock *b;
+ long count;
+} FixStart;
+
+typedef struct FixBlock {
+ struct FixBlock *prev;
+ struct FixBlock *next;
+ size_t entrysize;
+} FixBlock;
+
+typedef struct FixSubBlockBase {
+ FixBlock *fixblock;
+} FixSubBlockBase;
+
+typedef struct FixSubBlock {
+ FixBlock *fixblock;
+ struct FixSubBlock *next;
+} FixSubBlock;
+
+static const size_t fix_pool_sizes[] = {0xC, 0x1C, 0x2C, 0x4C};
+static Block *start_;
+static FixStart fix_start[4];
+static int initialized;
+
+// forward decls
+static void Block_link(Block *block, SubBlock *subblock);
+static void Block_unlink(Block *block, SubBlock *subblock);
+static void SubBlock_construct(SubBlock *subblock, size_t size, Block *block, int flag1, int flag2);
+static SubBlock *SubBlock_split(SubBlock *subblock, size_t pos);
+static SubBlock *SubBlock_merge_prev(SubBlock *subblock, SubBlock **sbptr);
+static void SubBlock_merge_next(SubBlock *subblock, SubBlock **sbptr);
+
+#define BLOCK_TAIL(block) ((BlockTail *) ((long) (block) + ((block)->x14 & ~FLAGMASK) - sizeof(BlockTail)))
+
+#define BUF_LOCATOR(buf) (*((size_t *) ((long) (buf) - sizeof(size_t))))
+#define SBB_BLOCK(sbb) ((Block *) ((long) ((sbb)->block) & ~1))
+
+#define BUF_IS_VAR(buf) (BUF_LOCATOR(buf) & 1)
+#define VARBUF_SBB(buf) ((SubBlockBase *) ((long) (buf) - sizeof(SubBlockBase)))
+#define VARBUF_SB(buf) ((SubBlock *) ((long) (buf) - sizeof(SubBlockBase)))
+#define VARBUF_BLOCKSIZE(buf) (VARBUF_SBB(buf)->x0 & ~FLAGMASK)
+#define VARBUF_SIZE(buf) (((VARBUF_SBB(buf)->x0 & ~FLAGMASK) - sizeof(SubBlockBase)))
+#define VARBUF_BLOCK(buf) SBB_BLOCK(VARBUF_SBB(buf))
+#define FIXBUF_SIZE(buf) (((FixBlock *) BUF_LOCATOR(buf))->entrysize)
+
+#define BUF_SIZE(buf) BUF_IS_VAR(buf) ? VARBUF_SIZE(buf) : FIXBUF_SIZE(buf)
+
+static void Block_construct(Block *block, size_t size) {
+ SubBlock *subblock;
+
+ block->x14 = size | 3;
+ ((BlockTail *) ((long) block + size - sizeof(BlockTail)))->x14copy = block->x14;
+
+ subblock = (SubBlock *) (block + 1);
+ SubBlock_construct(subblock, size - sizeof(Block) - sizeof(BlockTail), block, 0, 0);
+
+ block->remain = size - sizeof(Block) - sizeof(BlockTail);
+ BLOCK_TAIL(block)->unk = NULL;
+
+ Block_link(block, subblock);
+}
+
+static SubBlock *Block_subBlock(Block *block, size_t size) {
+ SubBlock *subblock;
+ size_t check;
+ size_t best;
+
+ if (!BLOCK_TAIL(block)->unk)
+ return NULL;
+
+ subblock = BLOCK_TAIL(block)->unk;
+ best = subblock->x0 & ~FLAGMASK;
+ check = subblock->x0 & ~FLAGMASK;
+ while (check < size) {
+ subblock = subblock->xC;
+ check = subblock->x0 & ~FLAGMASK;
+ if (best < check)
+ best = check;
+ if (subblock == BLOCK_TAIL(block)->unk) {
+ block->remain = best;
+ return NULL;
+ }
+ }
+
+ if ((check - size) >= 0x60)
+ SubBlock_split(subblock, size);
+
+ BLOCK_TAIL(block)->unk = subblock->xC;
+ Block_unlink(block, subblock);
+ return subblock;
+}
+
+static void Block_link(Block *block, SubBlock *subblock) {
+ size_t size;
+ SubBlock **sbptr;
+
+ size = subblock->x0 & ~FLAGMASK;
+ subblock->x0 &= ~2;
+ ((SubBlock *) ((long) subblock + size))->x0 &= ~4;
+ ((SubBlockTail *) ((long) subblock + size - sizeof(SubBlockTail)))->x0copy = size;
+
+ sbptr = &BLOCK_TAIL(block)->unk;
+ if (*sbptr) {
+ subblock->x8 = (*sbptr)->x8;
+ subblock->x8->xC = subblock;
+ subblock->xC = *sbptr;
+ (*sbptr)->x8 = subblock;
+ *sbptr = subblock;
+ *sbptr = SubBlock_merge_prev(*sbptr, sbptr);
+ SubBlock_merge_next(*sbptr, sbptr);
+ } else {
+ *sbptr = subblock;
+ subblock->x8 = subblock;
+ subblock->xC = subblock;
+ }
+
+ if (block->remain < ((*sbptr)->x0 & ~FLAGMASK))
+ block->remain = (*sbptr)->x0 & ~FLAGMASK;
+}
+
+static void Block_unlink(Block *block, SubBlock *subblock) {
+ size_t size;
+ SubBlock **sbptr;
+
+ size = subblock->x0 & ~FLAGMASK;
+ subblock->x0 |= 2;
+ ((SubBlock *) ((long) subblock + size))->x0 |= 4;
+
+ sbptr = &BLOCK_TAIL(block)->unk;
+ if (*sbptr == subblock)
+ *sbptr = subblock->xC;
+
+ if (*sbptr == subblock) {
+ *sbptr = NULL;
+ block->remain = 0;
+ } else {
+ subblock->xC->x8 = subblock->x8;
+ subblock->x8->xC = subblock->xC;
+ }
+}
+
+static void SubBlock_construct(SubBlock *subblock, size_t size, Block *block, int flag1, int flag2) {
+ subblock->block = (Block *) ((long) block | 1);
+ subblock->x0 = size;
+ if (flag1)
+ subblock->x0 |= 4;
+ if (flag2) {
+ subblock->x0 |= 2;
+ ((SubBlock *) (((long) subblock) + size))->x0 |= 4;
+ } else {
+ ((SubBlockTail *) (((long) subblock) + size - sizeof(SubBlockTail)))->x0copy = size;
+ }
+}
+
+static SubBlock *SubBlock_split(SubBlock *subblock, size_t pos) {
+ size_t oldsize;
+ int flag;
+ SubBlock *splitright;
+ Block *block;
+
+ oldsize = subblock->x0 & ~FLAGMASK;
+ flag = !(subblock->x0 & 2);
+ splitright = (SubBlock *) ((long) subblock + pos);
+ block = (Block *) ((long) subblock->block & ~1);
+ SubBlock_construct(subblock, pos, block, subblock->x0 & 4, !flag);
+ SubBlock_construct(splitright, oldsize - pos, block, !flag, !flag);
+ if (flag) {
+ splitright->xC = subblock->xC;
+ splitright->xC->x8 = splitright;
+ splitright->x8 = subblock;
+ subblock->xC = splitright;
+ }
+
+ return splitright;
+}
+
+static SubBlock *SubBlock_merge_prev(SubBlock *subblock, SubBlock **sbptr) {
+ size_t prevsize;
+ SubBlock *prevblock;
+
+ if (!(subblock->x0 & 4)) {
+ prevsize = ((SubBlockTail *) ((long) subblock - sizeof(SubBlockTail)))->x0copy;
+ if (prevsize & 2)
+ return subblock;
+
+ prevblock = (SubBlock *) ((long) subblock - prevsize);
+ prevblock->x0 = prevblock->x0 & FLAGMASK;
+ prevblock->x0 |= (prevsize + (subblock->x0 & ~FLAGMASK)) & ~FLAGMASK;
+ if (!(prevblock->x0 & 2))
+ ((SubBlockTail *) ((long) prevblock + prevsize + (subblock->x0 & ~FLAGMASK) - sizeof(SubBlockTail)))->x0copy = prevsize + (subblock->x0 & ~FLAGMASK);
+
+ if (*sbptr == subblock)
+ *sbptr = (*sbptr)->xC;
+
+ subblock->xC->x8 = subblock->x8;
+ subblock->xC->x8->xC = subblock->xC;
+ return prevblock;
+ }
+
+ return subblock;
+}
+
+static void SubBlock_merge_next(SubBlock *subblock, SubBlock **sbptr) {
+ SubBlock *nextblock;
+ size_t nextsize;
+
+ nextblock = (SubBlock *) ((long) subblock + (subblock->x0 & ~FLAGMASK));
+ if (!(nextblock->x0 & 2)) {
+ nextsize = (subblock->x0 & ~FLAGMASK) + (nextblock->x0 & ~FLAGMASK);
+ subblock->x0 = subblock->x0 & FLAGMASK;
+ subblock->x0 |= nextsize & ~FLAGMASK;
+
+ if (!(subblock->x0 & 2))
+ ((SubBlockTail *) ((long) subblock + nextsize - sizeof(SubBlockTail)))->x0copy = nextsize;
+
+ if (!(subblock->x0 & 2))
+ ((SubBlock *) ((long) subblock + nextsize))->x0 &= ~4;
+ else
+ ((SubBlock *) ((long) subblock + nextsize))->x0 |= 4;
+
+ if (*sbptr == nextblock)
+ *sbptr = (*sbptr)->xC;
+ if (*sbptr == nextblock)
+ *sbptr = NULL;
+
+ nextblock->xC->x8 = nextblock->x8;
+ nextblock->x8->xC = nextblock->xC;
+ }
+}
+
+static void link_block(Block *block) {
+ if (start_) {
+ block->prev = start_->prev;
+ block->prev->next = block;
+ block->next = start_;
+
+ start_->prev = block;
+ start_ = block;
+ } else {
+ start_ = block;
+ block->prev = block;
+ block->next = block;
+ }
+}
+
+static Block *unlink_block(Block *block) {
+ Block *newblock;
+
+ newblock = block->next;
+ if (newblock == block)
+ newblock = NULL;
+
+ if (start_ == block)
+ start_ = newblock;
+
+ if (newblock) {
+ newblock->prev = block->prev;
+ newblock->prev->next = newblock;
+ }
+
+ block->prev = block->next = NULL;
+ return newblock;
+}
+
+static Block *link_new_block(size_t size) {
+ Block *block;
+
+ size = (size + 0x1000 + sizeof(Block) + sizeof(BlockTail) - 1) & ~0xFFF;
+ if (size < 0x10000)
+ size = 0x10000;
+
+ if (!(block = galloc(size)))
+ return NULL;
+
+ Block_construct(block, size);
+ link_block(block);
+ return block;
+}
+
+static void *allocate_from_var_pools(size_t size) {
+ Block *block;
+ SubBlock *subblock;
+
+ size = (size + sizeof(Block) - 1) & ~0xF;
+ if (size < 0x60)
+ size = 0x60;
+
+ block = start_ ? start_ : link_new_block(size);
+ if (!block)
+ return NULL;
+
+ do {
+ if (size <= block->remain) {
+ if ((subblock = Block_subBlock(block, size))) {
+ start_ = block;
+ goto allocated;
+ }
+ }
+ } while ((block = block->next) != start_);
+
+ block = link_new_block(size);
+ if (!block)
+ return NULL;
+ subblock = Block_subBlock(block, size);
+allocated:
+ return (SubBlockBase *) subblock + 1;
+}
+
+static void deallocate_from_var_pools(void *buf) {
+ Block *block;
+ SubBlock *subblock;
+ int flag;
+
+ subblock = (SubBlock *) ((long) buf - sizeof(SubBlockBase));
+ block = (Block *) ((long) subblock->block & ~1);
+ Block_link(block, subblock);
+
+ flag = 0;
+ subblock = (SubBlock *) (block + 1);
+ if (!(subblock->x0 & 2)) {
+ if ((subblock->x0 & ~FLAGMASK) == ((block->x14 & ~FLAGMASK) - sizeof(Block) - sizeof(BlockTail)))
+ flag = 1;
+ }
+
+ if (flag)
+ unlink_block(block);
+}
+
+static void FixBlock_construct(FixBlock *fixblock, FixBlock *prev, FixBlock *next, int poolIndex, void *buffer, size_t buffersize) {
+ size_t entrysize;
+ size_t entrycount;
+ size_t i;
+ FixSubBlock *fsb;
+ FixSubBlock *fsbnext;
+
+ fixblock->prev = prev;
+ fixblock->next = next;
+ fixblock->entrysize = fix_pool_sizes[poolIndex];
+
+ entrysize = fix_pool_sizes[poolIndex] + sizeof(void *);
+ entrycount = (buffersize / entrysize);
+ fsb = buffer;
+ for (i = 0; i < (entrycount - 1); i++) {
+ fsbnext = (FixSubBlock *) ((long) fsb + entrysize);
+ fsb->fixblock = fixblock;
+ fsb->next = fsbnext;
+ fsb = fsbnext;
+ }
+
+ fsb->fixblock = fixblock;
+ fsb->next = fix_start[poolIndex].b;
+ fix_start[poolIndex].b = buffer;
+}
+
+static void *allocate_from_fixed_pools(size_t size) {
+ int poolIndex;
+ FixSubBlock *fsb;
+
+ poolIndex = 0;
+ while (size > fix_pool_sizes[poolIndex])
+ poolIndex++;
+
+ if (!fix_start[poolIndex].b) {
+ void *buf;
+ size_t bufsize;
+
+ buf = allocate_from_var_pools(4000);
+ if (!buf)
+ return NULL;
+
+ bufsize = !BUF_IS_VAR(buf) ? FIXBUF_SIZE(buf) : VARBUF_SIZE(buf);
+ FixBlock_construct(
+ buf, NULL, fix_start[poolIndex].a, poolIndex,
+ ((FixBlock *) buf) + 1,
+ bufsize - sizeof(FixBlock)
+ );
+ fix_start[poolIndex].a = buf;
+ }
+
+ fsb = fix_start[poolIndex].b;
+ fix_start[poolIndex].b = fsb->next;
+ fix_start[poolIndex].count++;
+ return ((FixSubBlockBase *) fsb) + 1;
+}
+
+static void deallocate_from_fixed_pools(void *buf, size_t size) {
+ int poolIndex;
+ FixBlock *fixblock;
+ FixBlock *nextfb;
+ FixSubBlock *fsb;
+
+ poolIndex = 0;
+ while (size > fix_pool_sizes[poolIndex])
+ poolIndex++;
+
+ fsb = (FixSubBlock *) ((long) buf - sizeof(FixSubBlockBase));
+ fsb->next = fix_start[poolIndex].b;
+ fix_start[poolIndex].b = fsb;
+ if (--fix_start[poolIndex].count == 0) {
+ fixblock = fix_start[poolIndex].a;
+ while (fixblock) {
+ nextfb = fixblock->next;
+ deallocate_from_var_pools(fixblock);
+ fixblock = nextfb;
+ }
+ fix_start[poolIndex].a = NULL;
+ fix_start[poolIndex].b = NULL;
+ }
+}
+
+size_t IRO_msize(void *buf) {
+ return BUF_SIZE(buf);
+}
+
+void *IRO_malloc(size_t size) {
+ if (!size)
+ return NULL;
+
+ if (size <= 0x4C)
+ return allocate_from_fixed_pools(size);
+ else
+ return allocate_from_var_pools(size);
+}
+
+void IRO_free(void *buf) {
+ if (buf) {
+ size_t size = !BUF_IS_VAR(buf) ? FIXBUF_SIZE(buf) : VARBUF_SIZE(buf);
+
+ if (size <= 0x4C)
+ deallocate_from_fixed_pools(buf, size);
+ else
+ deallocate_from_var_pools(buf);
+ }
+}
+
+void *IRO_realloc(void *buf, size_t newsize) {
+ size_t oldsize;
+ size_t newblocksize;
+ void *newbuf;
+
+ if (!buf)
+ return IRO_malloc(newsize);
+
+ if (!newsize) {
+ IRO_free(buf);
+ return NULL;
+ }
+
+ oldsize = !BUF_IS_VAR(buf) ? FIXBUF_SIZE(buf) : VARBUF_SIZE(buf);
+ if (newsize > oldsize) {
+ if (BUF_IS_VAR(buf)) {
+ newblocksize = (newsize + sizeof(Block) - 1) & ~FLAGMASK;
+ if (newblocksize < 0x60)
+ newblocksize = 0x60;
+ SubBlock_merge_next(VARBUF_SB(buf), &BLOCK_TAIL(VARBUF_BLOCK(buf))->unk);
+ if (VARBUF_BLOCKSIZE(buf) >= newblocksize) {
+ if ((VARBUF_BLOCKSIZE(buf) - newblocksize) >= 0x60) {
+ Block_link(VARBUF_BLOCK(buf), SubBlock_split(VARBUF_SB(buf), newblocksize));
+ }
+ return buf;
+ }
+ }
+
+ newbuf = IRO_malloc(newsize);
+ if (!newbuf)
+ return NULL;
+
+ memcpy(newbuf, buf, oldsize);
+ IRO_free(buf);
+ return newbuf;
+ }
+
+ if (BUF_IS_VAR(buf)) {
+ newsize = (newsize + sizeof(Block) - 1) & ~FLAGMASK;
+ if (newsize < 0x60)
+ newsize = 0x60;
+ if ((VARBUF_BLOCKSIZE(buf) - newsize) >= 0x60) {
+ Block_link(VARBUF_BLOCK(buf), SubBlock_split(VARBUF_SB(buf), newsize));
+ }
+ }
+
+ return buf;
+}
+
+void *IRO_calloc(size_t a, size_t b) {
+ void *buf;
+ size_t len = b * a;
+ buf = IRO_malloc(len);
+ if (buf)
+ memset(buf, 0, len);
+ return buf;
+}
+
+void IRO_pool_free_all(void) {
+ int i;
+ Block *block;
+ if ((block = start_)) {
+ do {
+ block = block->next;
+ } while (block != start_);
+ start_ = NULL;
+
+ for (i = 0; i < 4; i++) {
+ fix_start[i].a = NULL;
+ fix_start[i].b = NULL;
+ fix_start[i].count = 0;
+ }
+ }
+}
+
+void IRO_InitializeAllocator(void) {
+ if (!initialized) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ fix_start[i].a = NULL;
+ fix_start[i].b = NULL;
+ fix_start[i].count = 0;
+ }
+ start_ = NULL;
+ initialized = 1;
+ }
+}
+
+void IRO_TerminateAllocator(void) {
+ initialized = 0;
+}
+
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.h b/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.h
new file mode 100644
index 0000000..7700280
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroMalloc.h
@@ -0,0 +1,15 @@
+#ifndef COMPILER_IROMALLOC_H
+#define COMPILER_IROMALLOC_H
+
+#include "IrOptimizer.h"
+
+extern size_t IRO_msize(void *buf);
+extern void *IRO_malloc(size_t size);
+extern void IRO_free(void *buf);
+extern void *IRO_realloc(void *buf, size_t newsize);
+extern void *IRO_calloc(size_t a, size_t b);
+extern void IRO_pool_free_all(void);
+extern void IRO_InitializeAllocator(void);
+extern void IRO_TerminateAllocator(void);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.c b/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.c
new file mode 100644
index 0000000..3f8989f
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.c
@@ -0,0 +1,5734 @@
+#include "IroPointerAnalysis.h"
+#include "IroEval.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroMalloc.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/CDecl.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CScope.h"
+#include "compiler/InlineAsmPPC.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "IroPointerAnalysisADTs.c"
+
+// forward decls
+static Object *GetLocalObject(PALocalVar *local, Object *proc, Boolean flag);
+static Boolean GetActualLocsOfExtendedParam(LocationSetSet *set, LocationSet *ls, Object *var, Stack **stackPtr, ParamMappingFunction *map, Boolean flag);
+static int ExpandLocationSetSetToActuals(Stack **stackPtr, ParamMappingFunction *map, LocationSetSet *thingsPointedTo);
+static Boolean Lookup(LocationSetSet *set, Stack **stackPtr, Object *proc, ParamMappingFunction *map, PartialTransferFunction *ptf, LocationSet *dst, PointsToFunction *pointsToFunc, Boolean unk, Type *indRtype);
+static ExtendedParam *CreateExtendedParam(Stack **stackPtr, ParamMappingFunction *map, Object *var, Boolean *result);
+static Boolean Assign(PartialTransferFunction *ptf, LocationSet *dst, LocationSetSet *srcs, Object *proc, IROLinear *nd, IRONode *fnode);
+static ObjectList *FunctionArguments(Object *proc);
+static IRONode **FunctionNodeTable(Object *proc);
+static Boolean ApplySummary(PartialTransferFunction *tgtPTF, ParamMappingFunction *tgtMap, Object *proc, IRONode *fnode, IROLinear *nd, PartialTransferFunction *ptf, ParamMappingFunction *map, Boolean flag);
+static PartialTransferFunction *GetPTF(ParamMappingFunction *map, Object *proc, IROLinear *nd, PartialTransferFunction *ptf, Boolean *needVisit);
+static Boolean ObjectIsAFunctionArgument(Object *proc, Object *obj);
+static Boolean ObjectIsARealFunctionArgument(Object *proc, Object *obj);
+static void EvalProc(Object *proc, ParamMappingFunction *map, PartialTransferFunction *ptf);
+static void FindGlobalObjectAction(Object *object, void *refcon);
+
+static Boolean ObjectIsRestrictQualified(Object *obj) {
+ return (CParser_GetTypeQualifiers(obj->type, obj->qual) & Q_RESTRICT) != 0;
+}
+
+static Boolean LocationIsVolatile(LocationSet *loc, Object *proc) {
+ Boolean result;
+ Type *rtype;
+
+ IRO_ASSERT(932, loc != NULL);
+ IRO_ASSERT(933, proc != NULL);
+
+ result = 0;
+
+ if ((rtype = LocationSet_rtype(loc))) {
+ UInt32 qual;
+ switch (rtype->type) {
+ case TYPEARRAY:
+ qual = TYPE_POINTER(rtype)->qual;
+ break;
+ case TYPEPOINTER:
+ qual = TYPE_POINTER(rtype)->qual;
+ break;
+ case TYPEMEMBERPOINTER:
+ qual = TYPE_MEMBER_POINTER(rtype)->qual;
+ break;
+ default:
+ qual = 0;
+ }
+ if (qual & Q_VOLATILE)
+ result = 1;
+ }
+
+ if (!result && !LocationSet_IsUnknown(loc)) {
+ Object *obj = NULL;
+ PAMemoryBlock *block = LocationSet_block(loc);
+
+ switch (PAMemoryBlock_kind(block)) {
+ case PAMEMORYBLOCKKIND_LOCALVAR: {
+ PALocalVar *local = PAMemoryBlock_thing(block);
+ if (local)
+ obj = GetLocalObject(local, proc, 0);
+ break;
+ }
+ case PAMEMORYBLOCKKIND_EXTENDEDPARAM: {
+ ExtendedParam *ep = PAMemoryBlock_thing(block);
+ if (ep) {
+ ObjectSet *objSet = ExtendedParam_objectSet(ep);
+ if (objSet) {
+ if (ObjectSet_Count(objSet) == 1)
+ obj = ObjectSet_FindFirst(objSet);
+ else
+ ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj);
+ }
+ }
+ break;
+ }
+ }
+
+ if (obj && is_volatile_object(obj))
+ result = 1;
+ }
+
+ return result;
+}
+
+static Object *GetLocalObject(PALocalVar *local, Object *proc, Boolean flag) {
+ ObjectList *list;
+ Object *arg;
+ Object *obj;
+ char *name;
+
+ IRO_ASSERT(999, local != NULL);
+ IRO_ASSERT(1000, proc != NULL);
+
+ obj = PALocalVar_Get0_sub_4847E0(local);
+ name = PALocalVar_Get4_sub_4847D0(local);
+
+ if (proc != &stUnknown && !obj && name && name[0] && flag) {
+ for (list = FunctionArguments(proc); list && !obj; list = list->next) {
+ arg = list->object;
+ if (arg && arg != &stUnknown && arg->name && arg->name->name) {
+ if (!strcmp(arg->name->name, name))
+ obj = arg;
+ }
+ }
+ }
+
+ if (obj)
+ PALocalVar_SetSth_sub_4847C0(local, obj);
+
+ return obj;
+}
+
+static Boolean ObjectIsAnExtendedParamCandidate(Object *obj) {
+ IRO_ASSERT(1042, obj != NULL);
+
+ return Inline_IsObjectData(obj) ||
+ obj->datatype == DABSOLUTE ||
+ obj->datatype == DFUNC ||
+ obj->datatype == DVFUNC ||
+ obj->datatype == DINLINEFUNC;
+}
+
+static Boolean ObjectIsAFunction(Object *obj) {
+ IRO_ASSERT(1054, obj != NULL);
+
+ return obj->datatype == DFUNC ||
+ obj->datatype == DVFUNC ||
+ obj->datatype == DINLINEFUNC;
+}
+
+static Boolean LocationSetRepresentsSingleLocation(LocationSet *ls, Object *proc, PointsToFunction *pointsToFunc) {
+ Boolean result;
+ PAMemoryBlock *mb;
+ PAMemoryBlockKind kind;
+ ExtendedParam *ep;
+ ObjectSet *objSet;
+
+ IRO_ASSERT(1073, ls != NULL);
+ IRO_ASSERT(1074, proc == NULL || proc != NULL);
+ IRO_ASSERT(1075, pointsToFunc == NULL || pointsToFunc != NULL);
+
+ result = 1;
+ if (LocationSet_IsUnknown(ls) || LocationSet_stride(ls)) {
+ result = 0;
+ } else {
+ mb = LocationSet_block(ls);
+ IRO_ASSERT(1084, mb != NULL);
+
+ kind = PAMemoryBlock_kind(mb);
+ if (kind == PAMEMORYBLOCKKIND_HEAPBLOCK) {
+ result = 0;
+ } else if (kind == PAMEMORYBLOCKKIND_EXTENDEDPARAM) {
+ ep = PAMemoryBlock_thing(mb);
+ if (!ep) {
+ result = 0;
+ } else {
+ if ((objSet = ExtendedParam_objectSet(ep)) && ObjectSet_Count(objSet) > 1) {
+ Object *obj = NULL;
+ ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj);
+
+ if (!obj) {
+ LocationSetSet *lss;
+ LocationSet *tmp;
+ ExtendedParam *ep;
+ ObjectSet *objSet;
+
+ lss = LocationSetSet_New();
+ LocationSetSet_Init(lss);
+ GetActualLocsOfExtendedParam(lss, ls, NULL, &stCallingContextStack, NULL, 0);
+ if (
+ LocationSetSet_Count(lss) != 1 ||
+ !(tmp = LocationSetSet_FindFirst(lss)) ||
+ LocationSet_IsUnknown(tmp) ||
+ (!((mb = LocationSet_block(tmp)) && (PAMemoryBlock_kind(mb) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) && (ep = PAMemoryBlock_thing(mb)) && (objSet = ExtendedParam_objectSet(ep)) && (ObjectSet_Count(objSet) == 1) &&
+ ObjectIsAnExtendedParamCandidate(ObjectSet_FindFirst(objSet))) &&
+ !LocationSetRepresentsSingleLocation(tmp, proc, pointsToFunc))
+ )
+ result = 0;
+
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static void EvalExprAction(LocationSet *ls, void *refcon) {
+ CInt64 value;
+ UInt32 stride;
+ PAMemoryBlock *mb;
+
+ IRO_ASSERT(1151, ls != NULL);
+ IRO_ASSERT(1152, !LocationSet_IsUnknown(ls));
+ IRO_ASSERT(1153, refcon != NULL);
+
+ value = *((CInt64 *) refcon);
+ stride = LocationSet_stride(ls);
+ mb = LocationSet_block(ls);
+
+ if (mb && PAMemoryBlock_kind(mb) == PAMEMORYBLOCKKIND_INT) {
+ Type *rtype = LocationSet_rtype(ls);
+ LocationSet_Term(ls);
+ value = CInt64_Add(value, *((CInt64 *) PAMemoryBlock_thing(mb)));
+ mb = PAMemoryBlock_New();
+ PAMemoryBlock_Init(mb, PAMEMORYBLOCKKIND_INT, &value);
+ LocationSet_InitKnown(ls, mb, cint64_zero, stride, rtype);
+ } else {
+ value = CInt64_Add(value, LocationSet_field(ls));
+ if (stride) {
+ CInt64 strideval;
+ CInt64_SetLong(&strideval, stride);
+ value = CInt64_Mod(value, strideval);
+ }
+ SetsLocationSetField_sub_4851B0(ls, value);
+ }
+}
+
+static void EvalExprAction2(LocationSet *ls, void *refcon) {
+ UInt32 value;
+
+ IRO_ASSERT(1188, ls != NULL);
+ IRO_ASSERT(1189, !LocationSet_IsUnknown(ls));
+ IRO_ASSERT(1190, refcon != NULL);
+
+ value = CInt64_GetULong((CInt64 *) refcon);
+ if (value) {
+ SetsLocationSetField_sub_4851B0(ls, CInt64_Mod(LocationSet_field(ls), *((CInt64 *) refcon)));
+ }
+ SetsLocationSetStride_sub_4852D0(ls, value);
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct EvalExprAction3Params {
+ LocationSetSet *set;
+ Stack **stackPtr;
+ Object *proc;
+ ParamMappingFunction *map;
+ PartialTransferFunction *ptf;
+ PointsToFunction *pointsToFunc;
+ Type *indRtype;
+ Boolean x1C;
+} EvalExprAction3Params;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void EvalExprAction3(LocationSet *ls, void *refcon) {
+ EvalExprAction3Params *params;
+
+ IRO_ASSERT(1219, ls != NULL);
+ IRO_ASSERT(1220, refcon != NULL);
+
+ params = refcon;
+
+ params->x1C |= Lookup(
+ params->set,
+ params->stackPtr,
+ params->proc,
+ params->map,
+ params->ptf,
+ ls,
+ params->pointsToFunc,
+ 1,
+ params->indRtype
+ );
+}
+
+static void EvalExprAction4(LocationSet *ls, void *refcon) {
+ Type *type;
+ PAMemoryBlock *mb;
+
+ IRO_ASSERT(1235, ls != NULL);
+ IRO_ASSERT(1236, refcon != NULL);
+
+ type = refcon;
+
+ if (LocationSet_IsUnknown(ls)) {
+ LocationSet_SetRtype(ls, type);
+ } else if ((mb = LocationSet_block(ls))) {
+ if (PAMemoryBlock_kind(mb) == PAMEMORYBLOCKKIND_INT) {
+ CInt64 value;
+ CInt64 field;
+ UInt32 stride;
+
+ value = *((CInt64 *) PAMemoryBlock_thing(mb));
+ IRO_TruncateValueToType(&value, type);
+ field = LocationSet_field(ls);
+ IRO_TruncateValueToType(&field, type);
+ stride = LocationSet_stride(ls);
+ LocationSet_Term(ls);
+
+ mb = PAMemoryBlock_New();
+ PAMemoryBlock_Init(mb, PAMEMORYBLOCKKIND_INT, &value);
+
+ LocationSet_InitKnown(ls, mb, field, stride, type);
+ }
+ LocationSet_SetRtype(ls, type);
+ }
+}
+
+static Boolean EvalExpr(LocationSetSet *set, Object *proc, IROLinear *Int, Stack **stackPtr, ParamMappingFunction *map, PartialTransferFunction *ptf) {
+ Boolean result;
+ LocationSetSet *lss;
+ LocationSetSet *lss2;
+ IROLinear *indirect;
+ EvalExprAction3Params params;
+ IROLinear *originalInt;
+
+ IRO_ASSERT(1284, set == NULL || set != NULL);
+ IRO_ASSERT(1285, proc != NULL);
+ IRO_ASSERT(1286, Int != NULL);
+ IRO_ASSERT(1287, map == NULL || map != NULL);
+ IRO_ASSERT(1288, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL);
+
+ result = 0;
+ lss = LocationSetSet_New();
+ LocationSetSet_Init(lss);
+
+ originalInt = Int;
+ while (Int && Int->type == IROLinearOp1Arg && Int->nodetype == ETYPCON)
+ Int = Int->u.monadic;
+
+ IRO_ASSERT(1302, Int != NULL);
+
+ if (IRO_IsAssignment(Int)) {
+ if (Int->type == IROLinearOp1Arg)
+ indirect = Int->u.monadic;
+ else
+ indirect = Int->u.diadic.left;
+ IRO_ASSERT(1310, indirect->type == IROLinearOp1Arg && indirect->nodetype == EINDIRECT);
+
+ lss2 = LocationSetSet_New();
+ LocationSetSet_Init(lss2);
+ result |= EvalExpr(lss2, proc, indirect->u.monadic, stackPtr, map, ptf);
+
+ memset(&params, 0, sizeof(params));
+ params.set = lss;
+ params.stackPtr = stackPtr;
+ params.proc = proc;
+ params.map = map;
+ params.ptf = ptf;
+ if (Int->nodetype == EPOSTINC || Int->nodetype == EPOSTDEC)
+ params.pointsToFunc = indirect->pointsToFunction;
+ else
+ params.pointsToFunc = Int->pointsToFunction;
+ params.indRtype = indirect->rtype;
+ params.x1C = 0;
+ LocationSetSet_ForEach(lss2, EvalExprAction3, &params);
+ result |= params.x1C;
+ LocationSetSet_Term(lss2);
+ LocationSetSet_Delete(lss2);
+ } else if (Int->type == IROLinearFunccall) {
+ IRO_ASSERT(1338, Int->u.funccall.returnedLocs != NULL);
+ LocationSetSet_AddSet(lss, Int->u.funccall.returnedLocs);
+ } else if (Int->type == IROLinearOp1Arg && Int->nodetype == EINDIRECT) {
+ lss2 = LocationSetSet_New();
+ LocationSetSet_Init(lss2);
+ result |= EvalExpr(lss2, proc, Int->u.monadic, stackPtr, map, ptf);
+
+ memset(&params, 0, sizeof(params));
+ params.set = lss;
+ params.stackPtr = stackPtr;
+ params.proc = proc;
+ params.map = map;
+ params.ptf = ptf;
+ params.pointsToFunc = Int->pointsToFunction;
+ params.indRtype = Int->rtype;
+ params.x1C = 0;
+ LocationSetSet_ForEach(lss2, EvalExprAction3, &params);
+ result |= params.x1C;
+ LocationSetSet_Term(lss2);
+ LocationSetSet_Delete(lss2);
+ } else if (Int->type == IROLinearOp2Arg && Int->nodetype == EADD) {
+ IROAddrRecord *addr = IRO_InitAddrRecordPointer(Int);
+ IRO_DecomposeAddressExpression(Int, addr);
+ if (addr->numObjRefs > 1) {
+ LocationSetSet_AddUnknown(lss, NULL, NULL, NULL);
+ } else {
+ CInt64 value;
+ CInt64 max;
+ CInt64 work;
+ Boolean flag1;
+ Boolean flag2;
+
+ CInt64_SetLong(&value, 0);
+ flag1 = 0;
+ flag2 = 0;
+ if (addr->numObjRefs == 1) {
+ Object *obj;
+ IRO_ASSERT(1383, addr->objRefs->element->type == IROLinearOperand);
+ IRO_ASSERT(1384, addr->objRefs->element->u.node->type == EOBJREF);
+ obj = ((IROLinear *) addr->objRefs->element)->u.node->data.objref;
+ IRO_ASSERT(1387, obj != NULL);
+ result |= EvalExpr(lss, proc, addr->objRefs->element, stackPtr, map, ptf);
+ flag2 = 1;
+ }
+
+ if (addr->numMisc != 0) {
+ IROElmList *list;
+ IROLinear *nd;
+ max = cint64_max;
+
+ for (list = addr->misc; list; list = list->next) {
+ nd = list->element;
+ while (nd && nd->type == IROLinearOp1Arg && nd->nodetype == ETYPCON)
+ nd = nd->u.monadic;
+
+ if (nd) {
+ if (nd->type == IROLinearOp2Arg && nd->nodetype == EMUL) {
+ if (IRO_IsIntConstant(nd->u.diadic.left) && IRO_IsIntConstant(nd->u.diadic.right)) {
+ if (IRO_IsUnsignedType(nd->rtype))
+ work = CInt64_MulU(nd->u.diadic.left->u.node->data.intval, nd->u.diadic.right->u.node->data.intval);
+ else
+ work = CInt64_Mul(nd->u.diadic.left->u.node->data.intval, nd->u.diadic.right->u.node->data.intval);
+ IRO_TruncateValueToType(&work, ((IROLinear *) list->element)->rtype);
+ value = CInt64_Add(value, work);
+ } else if (IRO_IsIntConstant(nd->u.diadic.left)) {
+ work = nd->u.diadic.left->u.node->data.intval;
+ if (!CInt64_IsZero(&work) && CInt64_LessU(work, max))
+ max = work;
+ } else if (IRO_IsIntConstant(nd->u.diadic.right)) {
+ work = nd->u.diadic.right->u.node->data.intval;
+ if (!CInt64_IsZero(&work) && CInt64_LessU(work, max))
+ max = work;
+ } else {
+ max = cint64_one;
+ }
+ } else if (nd->type == IROLinearOp2Arg && nd->nodetype == ESHL) {
+ if (IRO_IsIntConstant(nd->u.diadic.left) && IRO_IsIntConstant(nd->u.diadic.right)) {
+ work = CInt64_Shl(nd->u.diadic.left->u.node->data.intval, nd->u.diadic.right->u.node->data.intval);
+ IRO_TruncateValueToType(&work, ((IROLinear *) list->element)->rtype);
+ value = CInt64_Add(value, work);
+ } else if (IRO_IsIntConstant(nd->u.diadic.right)) {
+ work = CInt64_Shl(cint64_one, nd->u.diadic.right->u.node->data.intval);
+ IRO_TruncateValueToType(&work, ((IROLinear *) list->element)->rtype);
+ if (!CInt64_IsZero(&work) && CInt64_LessU(work, max))
+ max = work;
+ } else {
+ max = cint64_one;
+ }
+ } else {
+ LocationSet *tmp;
+ PAMemoryBlock *mb;
+
+ lss2 = LocationSetSet_New();
+ LocationSetSet_Init(lss2);
+ result |= EvalExpr(lss2, proc, nd, stackPtr, map, ptf);
+
+ if (LocationSetSet_FindUnknown(lss2)) {
+ max = cint64_one;
+ } else if (
+ LocationSetSet_Count(lss2) == 1 &&
+ (tmp = LocationSetSet_FindFirst(lss2)) &&
+ (LocationSet_stride(tmp) == 0) &&
+ (mb = LocationSet_block(tmp)) &&
+ (PAMemoryBlock_kind(mb) == PAMEMORYBLOCKKIND_INT)
+ ) {
+ value = CInt64_Add(value, *((CInt64 *) PAMemoryBlock_thing(mb)));
+ } else if (!flag2 && (IS_TYPE_POINTER(nd->rtype) || IS_TYPE_MEMBERPOINTER(nd->rtype))) {
+ if (flag1) {
+ LocationSetSet_RemoveAll(lss);
+ max = cint64_one;
+ }
+ LocationSetSet_AddSet(lss, lss2);
+ flag2 = 1;
+ } else if (IS_TYPE_POINTER(nd->rtype) || IS_TYPE_MEMBERPOINTER(nd->rtype)) {
+ LocationSetSet_AddUnknown(lss, NULL, NULL, NULL);
+ } else if (!flag1) {
+ LocationSetSet_AddSet(lss, lss2);
+ flag1 = 1;
+ } else {
+ LocationSetSet_AddUnknown(lss, NULL, NULL, NULL);
+ }
+ LocationSetSet_Term(lss2);
+ LocationSetSet_Delete(lss2);
+ }
+ }
+ }
+
+ if (IS_TYPE_POINTER(Int->rtype))
+ CInt64_SetLong(&work, TYPE_POINTER(Int->rtype)->target->size);
+ else if (IS_TYPE_MEMBERPOINTER(Int->rtype))
+ CInt64_SetLong(&work, TYPE_MEMBER_POINTER(Int->rtype)->ty1->size);
+ else
+ work = cint64_zero;
+
+ if (CInt64_GreaterU(work, max))
+ max = work;
+ }
+
+ if (addr->numInts != 0) {
+ IROElmList *list;
+ IROLinear *addend;
+
+ for (list = addr->ints; list; list = list->next) {
+ addend = list->element;
+
+ if (addend) {
+ IRO_ASSERT(1536, IRO_IsIntConstant(addend));
+
+ value = CInt64_Add(value, addend->u.node->data.intval);
+ }
+ }
+ }
+
+ IRO_TruncateValueToType(&value, Int->rtype);
+
+ if (LocationSetSet_Count(lss) == 0) {
+ if (CInt64_Equal(max, cint64_max)) {
+ PAMemoryBlock *mb;
+ LocationSet *ls;
+
+ mb = PAMemoryBlock_New();
+ PAMemoryBlock_Init(mb, PAMEMORYBLOCKKIND_INT, &value);
+
+ ls = LocationSet_New();
+ LocationSet_InitKnown(ls, mb, cint64_zero, 0, Int->rtype);
+ LocationSetSet_Add(lss, ls);
+ LocationSet_Term(ls);
+ LocationSet_Delete(ls);
+ } else {
+ LocationSetSet_AddUnknown(lss, NULL, NULL, NULL);
+ }
+ } else {
+ if (!LocationSetSet_FindUnknown(lss) && !CInt64_IsZero(&value))
+ LocationSetSet_ForEach(lss, EvalExprAction, &value);
+ }
+
+ if (!LocationSetSet_FindUnknown(lss) && addr->numMisc && !CInt64_Equal(max, cint64_max))
+ LocationSetSet_ForEach(lss, EvalExprAction2, &max);
+ }
+ } else if (Int->type == IROLinearOperand) {
+ Object *obj;
+ void *thing;
+ PAMemoryBlockKind kind;
+
+ thing = NULL;
+ if (IRO_IsIntConstant(Int)) {
+ kind = PAMEMORYBLOCKKIND_INT;
+ thing = &Int->u.node->data.intval;
+ } else if (Int->u.node->type == ESTRINGCONST) {
+ kind = PAMEMORYBLOCKKIND_6;
+ thing = Int->u.node;
+ } else if (Int->u.node->type == EOBJREF) {
+ obj = Int->u.node->data.objref;
+ IRO_ASSERT(1597, obj != NULL);
+ if (ObjectIsAnExtendedParamCandidate(obj)) {
+ kind = PAMEMORYBLOCKKIND_EXTENDEDPARAM;
+ thing = CreateExtendedParam(stackPtr, map, obj, &result);
+ } else {
+ kind = PAMEMORYBLOCKKIND_LOCALVAR;
+ thing = PALocalVar_New();
+ if (obj->name && obj->name->name && ObjectIsARealFunctionArgument(proc, obj))
+ PALocalVar_InitByName(thing, obj->name->name);
+ else
+ PALocalVar_InitByObject(thing, obj);
+ }
+ }
+
+ if (thing) {
+ PAMemoryBlock *mb;
+ LocationSet *ls;
+
+ mb = PAMemoryBlock_New();
+ PAMemoryBlock_Init(mb, kind, thing);
+
+ ls = LocationSet_New();
+ LocationSet_InitKnown(ls, mb, cint64_zero, 0, Int->rtype);
+ LocationSetSet_Add(lss, ls);
+ LocationSet_Term(ls);
+ LocationSet_Delete(ls);
+ }
+ } else if (Int->type == IROLinearOp1Arg && Int->nodetype == EBITFIELD) {
+ LocationSet *ls;
+
+ lss2 = LocationSetSet_New();
+ LocationSetSet_Init(lss2);
+ result |= EvalExpr(lss2, proc, Int->u.monadic, stackPtr, map, ptf);
+
+ if (LocationSetSet_Count(lss2) == 1 && (ls = LocationSetSet_FindFirst(lss2)))
+ LocationSetSet_AddUnknown(lss, NULL, NULL, ls);
+ else
+ CError_FATAL(1643);
+
+ LocationSetSet_Term(lss2);
+ LocationSetSet_Delete(lss2);
+ } else {
+ LocationSetSet_AddUnknown(lss, NULL, NULL, NULL);
+ }
+
+ LocationSetSet_ForEach(lss, EvalExprAction4, originalInt->rtype);
+
+ if (set && lss)
+ LocationSetSet_AddSet(set, lss);
+
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+
+ return result;
+}
+
+static IROAddrRecord *IRO_InitENodeAddrRecordPointer(ENode *enode) {
+ IROAddrRecord *addr = IRO_malloc(sizeof(IROAddrRecord));
+
+ addr->numObjRefs = 0;
+ addr->objRefs = NULL;
+ addr->numMisc = 0;
+ addr->misc = NULL;
+ addr->numInts = 0;
+ addr->ints = NULL;
+ addr->x16 = 0;
+ addr->linear = (IROLinear *) enode;
+
+ return addr;
+}
+
+static void IRO_AddENodeElmToList(ENode *linear, IROElmList **list) {
+ IROElmList *elmlist = IRO_malloc(sizeof(IROElmList));
+ elmlist->element = linear;
+ elmlist->next = NULL;
+ if (!*list) {
+ *list = elmlist;
+ } else {
+ elmlist->next = *list;
+ *list = elmlist;
+ }
+}
+
+static void IRO_DecomposeENodeAddressExpression(ENode *node, IROAddrRecord *addr) {
+ if (node->data.diadic.left->type == EADD) {
+ IRO_DecomposeENodeAddressExpression(node->data.diadic.left, addr);
+ } else if (node->data.diadic.left->type == EINTCONST) {
+ addr->numInts++;
+ IRO_AddENodeElmToList(node->data.diadic.left, &addr->ints);
+ } else if (node->data.diadic.left->type == EOBJREF) {
+ addr->numObjRefs++;
+ IRO_AddENodeElmToList(node->data.diadic.left, &addr->objRefs);
+ } else {
+ addr->numMisc++;
+ IRO_AddENodeElmToList(node->data.diadic.left, &addr->misc);
+ }
+
+ if (node->data.diadic.right->type == EADD) {
+ IRO_DecomposeENodeAddressExpression(node->data.diadic.right, addr);
+ } else if (node->data.diadic.right->type == EINTCONST) {
+ addr->numInts++;
+ IRO_AddENodeElmToList(node->data.diadic.right, &addr->ints);
+ } else if (node->data.diadic.right->type == EOBJREF) {
+ addr->numObjRefs++;
+ IRO_AddENodeElmToList(node->data.diadic.right, &addr->objRefs);
+ } else {
+ addr->numMisc++;
+ IRO_AddENodeElmToList(node->data.diadic.right, &addr->misc);
+ }
+}
+
+static Boolean EvalENodeExpr(LocationSetSet *set, Object *proc, ENode *Int, Stack **stackPtr, ParamMappingFunction *map, PartialTransferFunction *ptf) {
+ Boolean result;
+ LocationSetSet *lss;
+ LocationSetSet *lss2;
+ ENode *indirect;
+ EvalExprAction3Params params;
+ ENode *originalInt;
+
+ IRO_ASSERT(0, set == NULL || set != NULL);
+ IRO_ASSERT(0, proc != NULL);
+ IRO_ASSERT(0, Int != NULL);
+ IRO_ASSERT(0, map == NULL || map != NULL);
+ IRO_ASSERT(0, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL);
+
+ result = 0;
+ lss = LocationSetSet_New();
+ LocationSetSet_Init(lss);
+
+ originalInt = Int;
+ while (Int && Int->type == ETYPCON)
+ Int = Int->data.monadic;
+
+ IRO_ASSERT(0, Int != NULL);
+
+ if (IRO_IsAssignOp[Int->type]) {
+ if (Int->type == EPOSTINC || Int->type == EPOSTDEC || Int->type == EPREINC || Int->type == EPREDEC)
+ indirect = Int->data.monadic;
+ else
+ indirect = Int->data.diadic.left;
+ IRO_ASSERT(0, indirect->type == EINDIRECT);
+
+ lss2 = LocationSetSet_New();
+ LocationSetSet_Init(lss2);
+ result |= EvalENodeExpr(lss2, proc, indirect->data.monadic, stackPtr, map, ptf);
+
+ memset(&params, 0, sizeof(params));
+ params.set = lss;
+ params.stackPtr = stackPtr;
+ params.proc = proc;
+ params.map = map;
+ params.ptf = ptf;
+ if (Int->type == EPOSTINC || Int->type == EPOSTDEC)
+ params.pointsToFunc = indirect->pointsTo;
+ else
+ params.pointsToFunc = Int->pointsTo;
+ params.indRtype = indirect->rtype;
+ params.x1C = 0;
+ LocationSetSet_ForEach(lss2, EvalExprAction3, &params);
+ result |= params.x1C;
+ LocationSetSet_Term(lss2);
+ LocationSetSet_Delete(lss2);
+ } else if (Int->type == EINDIRECT) {
+ lss2 = LocationSetSet_New();
+ LocationSetSet_Init(lss2);
+ result |= EvalENodeExpr(lss2, proc, Int->data.monadic, stackPtr, map, ptf);
+
+ memset(&params, 0, sizeof(params));
+ params.set = lss;
+ params.stackPtr = stackPtr;
+ params.proc = proc;
+ params.map = map;
+ params.ptf = ptf;
+ params.pointsToFunc = Int->pointsTo;
+ params.indRtype = Int->rtype;
+ params.x1C = 0;
+ LocationSetSet_ForEach(lss2, EvalExprAction3, &params);
+ result |= params.x1C;
+ LocationSetSet_Term(lss2);
+ LocationSetSet_Delete(lss2);
+ } else if (Int->type == EADD) {
+ IROAddrRecord *addr = IRO_InitENodeAddrRecordPointer(Int);
+ IRO_DecomposeENodeAddressExpression(Int, addr);
+ if (addr->numObjRefs > 1) {
+ LocationSetSet_AddUnknown(lss, NULL, NULL, NULL);
+ } else {
+ CInt64 value;
+ CInt64 max;
+ CInt64 work;
+ Boolean flag1;
+ Boolean flag2;
+
+ CInt64_SetLong(&value, 0);
+ flag1 = 0;
+ flag2 = 0;
+ if (addr->numObjRefs == 1) {
+ Object *obj;
+ // IRO_ASSERT(addr->objRefs->element->type == IROLinearOperand);
+ // IRO_ASSERT(addr->objRefs->element->u.node->type == EOBJREF);
+ obj = ((ENode *) addr->objRefs->element)->data.objref;
+ IRO_ASSERT(0, obj != NULL);
+ result |= EvalENodeExpr(lss, proc, addr->objRefs->element, stackPtr, map, ptf);
+ flag2 = 1;
+ }
+
+ if (addr->numMisc != 0) {
+ IROElmList *list;
+ ENode *nd;
+ max = cint64_max;
+
+ for (list = addr->misc; list; list = list->next) {
+ nd = list->element;
+ while (nd && nd->type == ETYPCON)
+ nd = nd->data.monadic;
+
+ if (nd) {
+ if (nd->type == EMUL) {
+ if (nd->data.diadic.left->type == EINTCONST && nd->data.diadic.right->type == EINTCONST) {
+ if (IRO_IsUnsignedType(nd->rtype))
+ work = CInt64_MulU(nd->data.diadic.left->data.intval,
+ nd->data.diadic.right->data.intval);
+ else
+ work = CInt64_Mul(nd->data.diadic.left->data.intval,
+ nd->data.diadic.right->data.intval);
+ IRO_TruncateValueToType(&work, ((ENode *) list->element)->rtype);
+ value = CInt64_Add(value, work);
+ } else if (nd->data.diadic.left->type == EINTCONST) {
+ work = nd->data.diadic.left->data.intval;
+ if (!CInt64_IsZero(&work) && CInt64_LessU(work, max))
+ max = work;
+ } else if (nd->data.diadic.right->type == EINTCONST) {
+ work = nd->data.diadic.right->data.intval;
+ if (!CInt64_IsZero(&work) && CInt64_LessU(work, max))
+ max = work;
+ } else {
+ max = cint64_one;
+ }
+ } else if (nd->type == ESHL) {
+ if (nd->data.diadic.left->type == EINTCONST && nd->data.diadic.right->type == EINTCONST) {
+ work = CInt64_Shl(nd->data.diadic.left->data.intval,
+ nd->data.diadic.right->data.intval);
+ IRO_TruncateValueToType(&work, ((ENode *) list->element)->rtype);
+ value = CInt64_Add(value, work);
+ } else if (nd->data.diadic.right->type == EINTCONST) {
+ work = CInt64_Shl(cint64_one, nd->data.diadic.right->data.intval);
+ IRO_TruncateValueToType(&work, ((ENode *) list->element)->rtype);
+ if (!CInt64_IsZero(&work) && CInt64_LessU(work, max))
+ max = work;
+ } else {
+ max = cint64_one;
+ }
+ } else {
+ LocationSet *tmp;
+ PAMemoryBlock *mb;
+
+ lss2 = LocationSetSet_New();
+ LocationSetSet_Init(lss2);
+ result |= EvalENodeExpr(lss2, proc, nd, stackPtr, map, ptf);
+
+ if (LocationSetSet_FindUnknown(lss2)) {
+ max = cint64_one;
+ } else if (
+ LocationSetSet_Count(lss2) == 1 &&
+ (tmp = LocationSetSet_FindFirst(lss2)) &&
+ (LocationSet_stride(tmp) == 0) &&
+ (mb = LocationSet_block(tmp)) &&
+ (PAMemoryBlock_kind(mb) == PAMEMORYBLOCKKIND_INT)
+ ) {
+ value = CInt64_Add(value, *((CInt64 *) PAMemoryBlock_thing(mb)));
+ } else if (!flag2 && (IS_TYPE_POINTER(nd->rtype) || IS_TYPE_MEMBERPOINTER(nd->rtype))) {
+ if (flag1) {
+ LocationSetSet_RemoveAll(lss);
+ max = cint64_one;
+ }
+ LocationSetSet_AddSet(lss, lss2);
+ flag2 = 1;
+ } else if (IS_TYPE_POINTER(nd->rtype) || IS_TYPE_MEMBERPOINTER(nd->rtype)) {
+ LocationSetSet_AddUnknown(lss, NULL, NULL, NULL);
+ } else if (!flag1) {
+ LocationSetSet_AddSet(lss, lss2);
+ flag1 = 1;
+ } else {
+ LocationSetSet_AddUnknown(lss, NULL, NULL, NULL);
+ }
+ LocationSetSet_Term(lss2);
+ LocationSetSet_Delete(lss2);
+ }
+ }
+ }
+
+ if (IS_TYPE_POINTER(Int->rtype))
+ CInt64_SetLong(&work, TYPE_POINTER(Int->rtype)->target->size);
+ else if (IS_TYPE_MEMBERPOINTER(Int->rtype))
+ CInt64_SetLong(&work, TYPE_MEMBER_POINTER(Int->rtype)->ty1->size);
+ else
+ work = cint64_zero;
+
+ if (CInt64_GreaterU(work, max))
+ max = work;
+ }
+
+ if (addr->numInts != 0) {
+ IROElmList *list;
+ ENode *addend;
+
+ for (list = addr->ints; list; list = list->next) {
+ addend = list->element;
+
+ if (addend) {
+ IRO_ASSERT(0, addend->type == EINTCONST);
+
+ value = CInt64_Add(value, addend->data.intval);
+ }
+ }
+ }
+
+ IRO_TruncateValueToType(&value, Int->rtype);
+
+ if (LocationSetSet_Count(lss) == 0) {
+ if (CInt64_Equal(max, cint64_max)) {
+ PAMemoryBlock *mb;
+ LocationSet *ls;
+
+ mb = PAMemoryBlock_New();
+ PAMemoryBlock_Init(mb, PAMEMORYBLOCKKIND_INT, &value);
+
+ ls = LocationSet_New();
+ LocationSet_InitKnown(ls, mb, cint64_zero, 0, Int->rtype);
+ LocationSetSet_Add(lss, ls);
+ LocationSet_Term(ls);
+ LocationSet_Delete(ls);
+ } else {
+ LocationSetSet_AddUnknown(lss, NULL, NULL, NULL);
+ }
+ } else {
+ if (!LocationSetSet_FindUnknown(lss) && !CInt64_IsZero(&value))
+ LocationSetSet_ForEach(lss, EvalExprAction, &value);
+ }
+
+ if (!LocationSetSet_FindUnknown(lss) && addr->numMisc && !CInt64_Equal(max, cint64_max))
+ LocationSetSet_ForEach(lss, EvalExprAction2, &max);
+ }
+ } else if (Int->type == EOBJREF || Int->type == EINTCONST || Int->type == ESTRINGCONST) {
+ Object *obj;
+ void *thing;
+ PAMemoryBlockKind kind;
+
+ thing = NULL;
+ if (Int->type == EINTCONST) {
+ kind = PAMEMORYBLOCKKIND_INT;
+ thing = &Int->data.intval;
+ } else if (Int->type == ESTRINGCONST) {
+ kind = PAMEMORYBLOCKKIND_6;
+ thing = Int;
+ } else if (Int->type == EOBJREF) {
+ obj = Int->data.objref;
+ IRO_ASSERT(0, obj != NULL);
+ if (ObjectIsAnExtendedParamCandidate(obj)) {
+ kind = PAMEMORYBLOCKKIND_EXTENDEDPARAM;
+ thing = CreateExtendedParam(stackPtr, map, obj, &result);
+ } else {
+ kind = PAMEMORYBLOCKKIND_LOCALVAR;
+ thing = PALocalVar_New();
+ if (obj->name && obj->name->name && ObjectIsARealFunctionArgument(proc, obj))
+ PALocalVar_InitByName(thing, obj->name->name);
+ else
+ PALocalVar_InitByObject(thing, obj);
+ }
+ }
+
+ if (thing) {
+ PAMemoryBlock *mb;
+ LocationSet *ls;
+
+ mb = PAMemoryBlock_New();
+ PAMemoryBlock_Init(mb, kind, thing);
+
+ ls = LocationSet_New();
+ LocationSet_InitKnown(ls, mb, cint64_zero, 0, Int->rtype);
+ LocationSetSet_Add(lss, ls);
+ LocationSet_Term(ls);
+ LocationSet_Delete(ls);
+ }
+ } else if (Int->type == EBITFIELD) {
+ LocationSet *ls;
+
+ lss2 = LocationSetSet_New();
+ LocationSetSet_Init(lss2);
+ result |= EvalENodeExpr(lss2, proc, Int->data.monadic, stackPtr, map, ptf);
+
+ if (LocationSetSet_Count(lss2) == 1 && (ls = LocationSetSet_FindFirst(lss2)))
+ LocationSetSet_AddUnknown(lss, NULL, NULL, ls);
+ else
+ CError_FATAL(2146);
+
+ LocationSetSet_Term(lss2);
+ LocationSetSet_Delete(lss2);
+ } else {
+ LocationSetSet_AddUnknown(lss, NULL, NULL, NULL);
+ }
+
+ LocationSetSet_ForEach(lss, EvalExprAction4, originalInt->rtype);
+
+ if (set && lss)
+ LocationSetSet_AddSet(set, lss);
+
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+
+ return result;
+}
+
+static Boolean EvalVarAddr(LocationSetSet *set, Object *proc, VarRecord *var, Stack **stackPtr, ParamMappingFunction *map) {
+ Boolean result;
+ PAMemoryBlockKind kind;
+ void *thing;
+ Object *obj;
+ PAMemoryBlock *block;
+ LocationSet *loc;
+
+ result = 0;
+ obj = var->object;
+
+ if (ObjectIsAnExtendedParamCandidate(obj)) {
+ kind = PAMEMORYBLOCKKIND_EXTENDEDPARAM;
+ thing = CreateExtendedParam(stackPtr, map, obj, &result);
+ } else {
+ kind = PAMEMORYBLOCKKIND_LOCALVAR;
+ thing = PALocalVar_New();
+ if (obj->name && obj->name->name && ObjectIsAFunctionArgument(proc, obj))
+ PALocalVar_InitByName(thing, obj->name->name);
+ else
+ PALocalVar_InitByObject(thing, obj);
+ }
+
+ block = PAMemoryBlock_New();
+ PAMemoryBlock_Init(block, kind, thing);
+
+ loc = LocationSet_New();
+ LocationSet_InitKnown(loc, block, cint64_zero, 0, CDecl_NewPointerType(obj->type));
+ LocationSetSet_Add(set, loc);
+ LocationSet_Term(loc);
+ LocationSet_Delete(loc);
+
+ return result;
+}
+
+static Boolean EvalVariable(LocationSetSet *set, Object *proc, VarRecord *var, PointsToFunction *pointsToFunc, Stack **stackPtr, ParamMappingFunction *map, PartialTransferFunction *ptf) {
+ LocationSetSet *locs;
+ Boolean result;
+ EvalExprAction3Params params;
+
+ locs = LocationSetSet_New();
+ LocationSetSet_Init(locs);
+ result = EvalVarAddr(locs, proc, var, stackPtr, map);
+
+ memset(&params, 0, sizeof(params));
+ params.set = set;
+ params.stackPtr = stackPtr;
+ params.proc = proc;
+ params.map = map;
+ params.ptf = ptf;
+ params.pointsToFunc = pointsToFunc;
+ params.indRtype = var->object->type;
+ params.x1C = 0;
+ LocationSetSet_ForEach(locs, EvalExprAction3, &params);
+
+ result |= params.x1C;
+ LocationSetSet_Term(locs);
+ LocationSetSet_Delete(locs);
+
+ return result;
+}
+
+static void StoreReturnedLocationsAction(LocationSet *loc, void *refcon) {
+ IRO_ASSERT(2275, loc != NULL);
+ IRO_ASSERT(2276, refcon != NULL);
+
+ if (!LocationSet_IsUnknown(loc)) {
+ if (PAMemoryBlock_kind(LocationSet_block(loc)) == PAMEMORYBLOCKKIND_HEAPBLOCK) {
+ PAHeapBlock *hb;
+ PAMemoryBlock *mb;
+ CInt64 field;
+ UInt32 stride;
+ Type *rtype;
+
+ hb = CreateUniqueHeapAlloc_sub_486420();
+ InitUniqueHeapAlloc_sub_486410(hb, refcon);
+
+ mb = PAMemoryBlock_New();
+ PAMemoryBlock_Init(mb, PAMEMORYBLOCKKIND_HEAPBLOCK, hb);
+
+ field = LocationSet_field(loc);
+ stride = LocationSet_stride(loc);
+ rtype = LocationSet_rtype(loc);
+ LocationSet_Term(loc);
+ LocationSet_InitKnown(loc, mb, field, stride, rtype);
+ }
+ }
+}
+
+static void StoreReturnedLocations(IROLinear *nd, PartialTransferFunction *ptf, ParamMappingFunction *map) {
+ LocationSet *retLoc;
+ LocationSetSet *retLocs;
+
+ IRO_ASSERT(2307, nd != NULL);
+ IRO_ASSERT(2308, nd->type == IROLinearFunccall);
+ IRO_ASSERT(2309, ptf != NULL);
+ IRO_ASSERT(2310, map != NULL);
+
+ retLoc = PartialTransferFunction_returnLocation(ptf);
+ retLocs = nd->u.funccall.returnedLocs;
+ if (!retLocs) {
+ LocationSetSet_Init(retLocs = nd->u.funccall.returnedLocs = LocationSetSet_New());
+ } else {
+ LocationSetSet_RemoveAll(retLocs);
+ }
+
+ Lookup(retLocs, NULL, NULL, NULL, NULL, retLoc, PartialTransferFunction_finalPointsToFn(ptf), 0, NULL);
+ ExpandLocationSetSetToActuals(&stCallingContextStack, map, retLocs);
+ LocationSetSet_ForEach(retLocs, StoreReturnedLocationsAction, nd);
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct EPParams {
+ ParamMappingFunction *map;
+ ExtendedParam *ep;
+ Object *proc;
+ Object *var;
+ unsigned char x10;
+ unsigned char x11;
+} EPParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void FillInAppropriateMappingsWithExtParamAction(Object *obj, void *refcon) {
+ EPParams *params;
+ ParamMapping *mapping;
+
+ IRO_ASSERT(2352, obj != NULL);
+ IRO_ASSERT(2353, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(2357, params->map != NULL);
+ IRO_ASSERT(2358, params->ep != NULL);
+ IRO_ASSERT(2359, params->proc == NULL || params->proc != NULL);
+ IRO_ASSERT(2360, params->proc != &stUnknown);
+ IRO_ASSERT(2361, params->var == NULL || params->var != NULL);
+ IRO_ASSERT(2362, params->var != &stUnknown);
+
+ mapping = ParamMappingFunction_FindMappingByFormal(params->map, obj);
+ if (!mapping) {
+ if (ObjectIsAnExtendedParamCandidate(obj) || !params->proc || ObjectIsAFunctionArgument(params->proc, obj)) {
+ mapping = ParamMapping_New();
+ ParamMapping_Init_PROBABLY(mapping, NULL, obj, params->ep);
+ Pmf_Add_sub_486610(params->map, mapping);
+ ParamMapping_Term(mapping);
+ ParamMapping_Delete(mapping);
+ params->x11 = 1;
+ }
+ } else {
+ if (ParamMapping_extended(mapping) != params->ep) {
+ ParamMapping_SetExtended(mapping, params->ep);
+ params->x11 = 1;
+ }
+ }
+
+ if (obj == params->var)
+ params->x10 = 1;
+}
+
+static Boolean FillInAppropriateMappingsWithExtParam(ParamMappingFunction *map, Object *var, ExtendedParam *ep, Object *proc) {
+ EPParams params;
+ ObjectSet *objSet;
+
+ IRO_ASSERT(2398, map != NULL);
+ IRO_ASSERT(2399, var == NULL || var != NULL);
+ IRO_ASSERT(2400, var != &stUnknown);
+ IRO_ASSERT(2401, ep != NULL);
+ IRO_ASSERT(2402, proc == NULL || proc != NULL);
+ IRO_ASSERT(2403, proc != &stUnknown);
+
+ memset(&params, 0, sizeof(params));
+ params.map = map;
+ params.ep = ep;
+ params.proc = proc;
+ params.var = var;
+ params.x10 = 0;
+ params.x11 = 0;
+
+ if ((objSet = ExtendedParam_objectSet(ep)))
+ ObjectSet_ForEach(objSet, FillInAppropriateMappingsWithExtParamAction, &params);
+
+ if (var && !params.x10) {
+ ExtendedParam_sub_4867B0(ep, var);
+ FillInAppropriateMappingsWithExtParamAction(var, &params);
+ }
+
+ return params.x11;
+}
+
+static void MatchPTFHelper(LocationSet *loc, LocationSetSet *locs, Object *proc, ParamMappingFunction *map, PartialTransferFunction *ptf) {
+ PointsToFunction *initial;
+ PAMemoryBlock *block;
+ PAMemoryBlockKind kind;
+ Object *obj;
+
+ IRO_ASSERT(2448, loc != NULL);
+ IRO_ASSERT(2449, !LocationSet_IsUnknown(loc));
+ IRO_ASSERT(2450, locs != NULL);
+ IRO_ASSERT(2451, proc != NULL);
+ IRO_ASSERT(2452, map != NULL);
+ IRO_ASSERT(2453, ptf != NULL);
+
+ initial = PartialTransferFunction_initialPointsToFn(ptf);
+ IRO_ASSERT(2456, initial != NULL);
+
+ IRO_ASSERT(2458, !LocationSet_IsUnknown(loc));
+
+ block = LocationSet_block(loc);
+ IRO_ASSERT(2460, block != NULL);
+
+ kind = PAMemoryBlock_kind(block);
+
+ if (kind == PAMEMORYBLOCKKIND_LOCALVAR) {
+ PALocalVar *local;
+
+ local = PAMemoryBlock_thing(block);
+ IRO_ASSERT(2466, local != NULL);
+
+ obj = GetLocalObject(local, proc, 1);
+ if (obj && ObjectIsAFunctionArgument(proc, obj)) {
+ if (LocationSetSet_Count(locs) == 1) {
+ LocationSet *ls;
+ ls = LocationSetSet_FindFirst(locs);
+ if (ls && !LocationSet_IsUnknown(ls)) {
+ if ((block = LocationSet_block(ls))) {
+ if (PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) {
+ ExtendedParam *ep;
+ if ((ep = PAMemoryBlock_thing(block))) {
+ ExtendedParam_sub_4867B0(ep, obj);
+ if (stExtParamSet)
+ ExtParamSet_sub_487630(stExtParamSet, ep);
+ FillInAppropriateMappingsWithExtParam(map, obj, ep, proc);
+ }
+ }
+ }
+ }
+ }
+ }
+ } else if (kind == PAMEMORYBLOCKKIND_EXTENDEDPARAM) {
+ void *ep = PAMemoryBlock_thing(block);
+ IRO_ASSERT(2489, ep != NULL);
+
+ obj = NULL;
+ ObjectSet_ForEach(ExtendedParam_objectSet(ep), FindGlobalObjectAction, &obj);
+ if (obj && obj != &stUnknown)
+ FillInAppropriateMappingsWithExtParam(map, obj, ep, proc);
+ } else {
+ CError_FATAL(2500);
+ }
+
+ if (!PointsToFunction_FindByLookupCompatibleLocationSet(initial, loc)) {
+ PointsToEntry *pte = PointsToEntry_New();
+ PointsToEntry_Init(pte, loc, locs);
+ PointsToFunction_AddWithoutChecking(initial, pte);
+ PointsToEntry_Term(pte);
+ PointsToEntry_Delete(pte);
+ }
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct MatchPTFActionParams {
+ Object *proc;
+ PartialTransferFunction *ptfCopy;
+ ParamMappingFunction *mapCopy;
+ Stack **stackPtr;
+} MatchPTFActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void MatchPTFAction1(PointsToEntry *tgtPTE, void *refcon) {
+ MatchPTFActionParams *params;
+ LocationSet *loc;
+ LocationSetSet *locs;
+ PAMemoryBlock *block;
+ PAMemoryBlockKind kind;
+
+ IRO_ASSERT(2525, tgtPTE != NULL);
+ IRO_ASSERT(2526, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(2530, params->proc != NULL);
+ IRO_ASSERT(2531, params->ptfCopy != NULL);
+ IRO_ASSERT(2532, params->mapCopy != NULL);
+
+ if ((loc = PointsToEntry_loc(tgtPTE)) && (locs = PointsToEntry_locs(tgtPTE))) {
+ if ((block = LocationSet_block(loc))) {
+ kind = PAMemoryBlock_kind(block);
+ if (kind == PAMEMORYBLOCKKIND_LOCALVAR) {
+ MatchPTFHelper(loc, locs, params->proc, params->mapCopy, params->ptfCopy);
+ } else if (kind != PAMEMORYBLOCKKIND_EXTENDEDPARAM) {
+ CError_FATAL(2547);
+ }
+ }
+ }
+}
+
+static void MatchPTFAction2(PointsToEntry *tgtPTE, void *refcon) {
+ MatchPTFActionParams *params;
+ LocationSet *loc;
+ LocationSetSet *locs;
+ PAMemoryBlock *block;
+ PAMemoryBlockKind kind;
+
+ IRO_ASSERT(2561, tgtPTE != NULL);
+ IRO_ASSERT(2562, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(2566, params->proc != NULL);
+ IRO_ASSERT(2567, params->ptfCopy != NULL);
+ IRO_ASSERT(2568, params->mapCopy != NULL);
+
+ if ((loc = PointsToEntry_loc(tgtPTE)) && (locs = PointsToEntry_locs(tgtPTE))) {
+ if ((block = LocationSet_block(loc))) {
+ kind = PAMemoryBlock_kind(block);
+ if (kind == PAMEMORYBLOCKKIND_EXTENDEDPARAM) {
+ MatchPTFHelper(loc, locs, params->proc, params->mapCopy, params->ptfCopy);
+ }
+ }
+ }
+}
+
+static Boolean MatchPTF(PartialTransferFunction *tgtPTF, Object *proc, ParamMappingFunction *map, IROLinear *nd, PartialTransferFunction *ptf) {
+ Boolean result;
+ PartialTransferFunction *ptfCopy;
+ ParamMappingFunction *mapCopy;
+ PointsToFunction *initial;
+ MatchPTFActionParams params;
+
+ IRO_ASSERT(2593, tgtPTF != NULL);
+ IRO_ASSERT(2594, proc != NULL);
+ IRO_ASSERT(2595, map != NULL);
+ IRO_ASSERT(2596, nd != NULL);
+ IRO_ASSERT(2597, ptf != NULL);
+
+ ptfCopy = PartialTransferFunction_New();
+ PartialTransferFunction_Copy(ptfCopy, ptf);
+
+ mapCopy = ParamMappingFunction_New();
+ ParamMappingFunction_Copy(mapCopy, map);
+
+ initial = PartialTransferFunction_initialPointsToFn(tgtPTF);
+ PointsToFunction_SortByExtendedParamNum(initial);
+
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.ptfCopy = ptfCopy;
+ params.mapCopy = mapCopy;
+ params.stackPtr = &stCallingContextStack;
+
+ PointsToFunction_ForEach(initial, MatchPTFAction1, &params);
+ PointsToFunction_ForEach(initial, MatchPTFAction2, &params);
+
+ result = PointsToFunctions_Match(initial, PartialTransferFunction_initialPointsToFn(ptfCopy));
+ if (result) {
+ PartialTransferFunction_Term(ptf);
+ PartialTransferFunction_Copy(ptf, ptfCopy);
+
+ ParamMappingFunction_Term(map);
+ ParamMappingFunction_Copy(map, mapCopy);
+ }
+
+ PartialTransferFunction_Term(ptfCopy);
+ PartialTransferFunction_Delete(ptfCopy);
+
+ ParamMappingFunction_Term(mapCopy);
+ ParamMappingFunction_Delete(mapCopy);
+
+ return result;
+}
+
+static void FindCallTargetsAction2(Object *obj, void *refcon) {
+ ObjectSet *procList;
+
+ IRO_ASSERT(2650, obj != NULL);
+ IRO_ASSERT(2651, refcon != NULL);
+
+ procList = refcon;
+
+ if (obj == &stUnknown || ObjectIsAFunction(obj))
+ ObjectSet_sub_4867D0(procList, obj);
+}
+
+static void FindCallTargetsAction(LocationSet *ls, void *refcon) {
+ ObjectSet *procList;
+
+ IRO_ASSERT(2669, ls != NULL);
+ IRO_ASSERT(2670, refcon != NULL);
+
+ procList = refcon;
+
+ if (!LocationSet_IsUnknown(ls)) {
+ PAMemoryBlock *mb = LocationSet_block(ls);
+ if (PAMemoryBlock_kind(mb) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) {
+ ExtendedParam *ep = PAMemoryBlock_thing(mb);
+ ObjectSet *objSet = ExtendedParam_objectSet(ep);
+ ObjectSet_ForEach(objSet, FindCallTargetsAction2, procList);
+ }
+ } else {
+ FindCallTargetsAction2(&stUnknown, procList);
+ }
+}
+
+static int FindCallTargets(ObjectSet *procList, Object *proc, IROLinear *nd, ParamMappingFunction *map, PartialTransferFunction *ptf) {
+ LocationSetSet *set;
+ int evalResult;
+ int result;
+
+ IRO_ASSERT(2696, procList != NULL);
+ IRO_ASSERT(2697, proc != NULL);
+ IRO_ASSERT(2698, nd != NULL);
+ IRO_ASSERT(2699, nd->type == IROLinearFunccall);
+ IRO_ASSERT(2700, map != NULL);
+ IRO_ASSERT(2701, ptf != NULL);
+
+ set = LocationSetSet_New();
+ LocationSetSet_Init(set);
+ evalResult = EvalExpr(set, proc, nd->u.funccall.linear8, &stCallingContextStack, map, ptf);
+ result = evalResult | ExpandLocationSetSetToActuals(&stCallingContextStack, map, set);
+ LocationSetSet_ForEach(set, FindCallTargetsAction, procList);
+ LocationSetSet_Term(set);
+ LocationSetSet_Delete(set);
+
+ return result;
+}
+
+static int LookupParam(LocationSetSet *set, LocationSet *ls, Object *var, Stack **stackPtr, Object *proc, ParamMappingFunction *map, PartialTransferFunction *ptf, Boolean unkflag) {
+ Boolean result;
+ ExtendedParam *ep;
+
+ IRO_ASSERT(2728, set == NULL || set != NULL);
+ IRO_ASSERT(2729, ls != NULL);
+ IRO_ASSERT(2730, var != NULL);
+ IRO_ASSERT(2731, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL);
+ IRO_ASSERT(2732, proc != NULL);
+ IRO_ASSERT(2733, map == NULL || map != NULL);
+ IRO_ASSERT(2734, ptf == NULL || ptf != NULL);
+
+ result = 0;
+
+ ep = ExtendedParam_FindByObject(var);
+ if (!ep)
+ ep = CreateExtendedParam(stackPtr, map, var, &result);
+
+ IRO_ASSERT(2741, ep != NULL);
+
+ if (ep) {
+ PAMemoryBlock *block;
+ LocationSet *newLS;
+
+ block = PAMemoryBlock_New();
+ PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_EXTENDEDPARAM, ep);
+
+ newLS = LocationSet_New();
+ LocationSet_InitKnown(newLS, block, LocationSet_field(ls), LocationSet_stride(ls), LocationSet_rtype(ls));
+ if (set)
+ LocationSetSet_Add(set, newLS);
+
+ if (unkflag) {
+ if (map)
+ result |= FillInAppropriateMappingsWithExtParam(map, var, ep, proc);
+
+ if (ptf) {
+ PointsToFunction *initial;
+
+ initial = PartialTransferFunction_initialPointsToFn(ptf);
+ if (initial && !PointsToFunction_FindByLookupCompatibleLocationSet(initial, ls)) {
+ LocationSet_Term(newLS);
+ LocationSet_InitKnown(newLS, LocationSet_block(ls), cint64_zero, 0, LocationSet_rtype(ls));
+ if (!PointsToFunction_FindByLookupCompatibleLocationSet(initial, newLS)) {
+ LocationSet *newLS2;
+ LocationSetSet *newSet;
+ PointsToEntry *newPTE;
+
+ newLS2 = LocationSet_New();
+ LocationSet_InitKnown(newLS2, block, cint64_zero, 0, LocationSet_rtype(ls));
+
+ newSet = LocationSetSet_New();
+ LocationSetSet_Init(newSet);
+ LocationSetSet_Add(newSet, newLS2);
+
+ newPTE = PointsToEntry_New();
+ PointsToEntry_Init(newPTE, newLS, newSet);
+ result |= PointsToFunction_Add(initial, newPTE);
+ PointsToEntry_Term(newPTE);
+ PointsToEntry_Delete(newPTE);
+
+ LocationSetSet_Term(newSet);
+ LocationSetSet_Delete(newSet);
+
+ LocationSet_Term(newLS2);
+ LocationSet_Delete(newLS2);
+ }
+ }
+ }
+ }
+
+ LocationSet_Term(newLS);
+ LocationSet_Delete(newLS);
+ }
+
+ return result;
+}
+
+static Boolean GetActualLocsOfExtendedParam(LocationSetSet *set, LocationSet *ls, Object *var, Stack **stackPtr, ParamMappingFunction *map, Boolean flag) {
+ Boolean result;
+ PAMemoryBlock *block;
+ IROLinear *nd;
+ ExtendedParam *ep;
+ ParamMapping *mapping;
+ Type *savedRtype;
+ CInt64 savedField;
+ UInt32 savedStride;
+ LocationSetSet *newSet;
+
+ IRO_ASSERT(2821, set == NULL || set != NULL);
+ IRO_ASSERT(2822, (ls != NULL && var == NULL) || (ls == NULL && var != NULL));
+ IRO_ASSERT(2823, ls == NULL || !LocationSet_IsUnknown(ls));
+ IRO_ASSERT(2824, var != &stUnknown);
+ IRO_ASSERT(2825, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL);
+ IRO_ASSERT(2826, map == NULL || map != NULL);
+
+ result = 0;
+ block = NULL;
+ nd = 0;
+ ep = NULL;
+ mapping = NULL;
+
+ if (ls) {
+ block = LocationSet_block(ls);
+ IRO_ASSERT(2838, block != NULL);
+ IRO_ASSERT(2839, PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM);
+
+ ep = PAMemoryBlock_thing(block);
+ IRO_ASSERT(2842, ep != NULL);
+
+ savedField = LocationSet_field(ls);
+ savedStride = LocationSet_stride(ls);
+ savedRtype = LocationSet_rtype(ls);
+ }
+
+ IRO_ASSERT(2848, ep == NULL || ep != NULL);
+
+ if (stackPtr && *stackPtr) {
+ StackElement *element = Stack_Top(stackPtr);
+ if (element && !map)
+ map = StackElement_map(element);
+ }
+
+ IRO_ASSERT(2859, map == NULL || map != NULL);
+
+ if (ep) {
+ IRO_ASSERT(2863, var == NULL);
+ ObjectSet_ForEach(ExtendedParam_objectSet(ep), FindGlobalObjectAction, &var);
+ if (!var)
+ var = ObjectSet_FindFirst(ExtendedParam_objectSet(ep));
+ if (!var)
+ var = &stUnknown;
+ }
+
+ IRO_ASSERT(2870, var != NULL);
+
+ if (map && var != &stUnknown) {
+ if (flag)
+ result |= FillInAppropriateMappingsWithExtParam(map, var, ep, NULL);
+ mapping = ParamMappingFunction_FindMappingByFormal(map, var);
+ }
+
+ newSet = LocationSetSet_New();
+ LocationSetSet_Init(newSet);
+
+ IRO_ASSERT(2884, mapping == NULL || mapping != NULL);
+
+ if (mapping)
+ nd = ParamMapping_actual(mapping);
+
+ if (!nd) {
+ if (!ls) {
+ IRO_ASSERT(2893, var != NULL);
+ IRO_ASSERT(2894, ep == NULL);
+
+ if (var != &stUnknown) {
+ ep = CreateExtendedParam(stackPtr, NULL, var, &result);
+ if (flag && mapping && ParamMapping_extended(mapping) != ep) {
+ ParamMapping_SetExtended(mapping, ep);
+ result = 1;
+ }
+
+ block = PAMemoryBlock_New();
+ PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_EXTENDEDPARAM, ep);
+ savedField = cint64_zero;
+ savedStride = 0;
+ savedRtype = CDecl_NewPointerType(var->type);
+ } else {
+ block = LocationSet_block(stUnknownLs);
+ savedRtype = NULL;
+ }
+ } else if (var == &stUnknown || !ObjectIsAnExtendedParamCandidate(var)) {
+ block = LocationSet_block(stUnknownLs);
+ savedRtype = NULL;
+ }
+
+ IRO_ASSERT(2925, block != NULL);
+
+ if (block == LocationSet_block(stUnknownLs)) {
+ LocationSetSet_AddUnknown(newSet, savedRtype, NULL, NULL);
+ } else {
+ LocationSet *tmp = LocationSet_New();
+ LocationSet_InitKnown(tmp, block, savedField, savedStride, savedRtype);
+ LocationSetSet_Add(newSet, tmp);
+ LocationSet_Term(tmp);
+ LocationSet_Delete(tmp);
+ }
+ } else {
+ Stack *next;
+ StackElement *element;
+ if (stackPtr && *stackPtr && (next = Stack_Next(stackPtr)) && (element = Stack_Top(&next))) {
+ if (ls) {
+ if (!savedStride && !CInt64_IsZero(&savedField)) {
+ IROLinear *ic;
+ IROLinear *d;
+ ic = IRO_NewIntConst(savedField, TYPE(&stunsignedlong));
+ d = IRO_NewLinear(IROLinearOp2Arg);
+ d->index = ++IRO_NumLinear;
+ d->rtype = nd->rtype;
+ d->u.diadic.left = nd;
+ d->u.diadic.right = ic;
+ nd = d;
+ }
+ if (savedStride) {
+ IROLinear *call;
+ IROLinear *d;
+ call = IRO_NewLinear(IROLinearFunccall);
+ call->u.funccall.returnedLocs = LocationSetSet_New();
+ LocationSetSet_Init(call->u.funccall.returnedLocs);
+ LocationSetSet_AddUnknown(call->u.funccall.returnedLocs, NULL, NULL, NULL);
+ d = IRO_NewLinear(IROLinearOp2Arg);
+ d->index = ++IRO_NumLinear;
+ d->rtype = nd->rtype;
+ d->u.diadic.left = nd;
+ d->u.diadic.right = call;
+ nd = d;
+ }
+ }
+ EvalExpr(newSet, StackElement_proc(element), nd, &next, StackElement_map(element), StackElement_ptf(element));
+ } else {
+ LocationSetSet_AddUnknown(newSet, NULL, NULL, NULL);
+ }
+ }
+
+ if (set)
+ LocationSetSet_AddSet(set, newSet);
+
+ LocationSetSet_Term(newSet);
+ LocationSetSet_Delete(newSet);
+
+ return result;
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct ExpandLocationSetSetActionParams {
+ LocationSetSet *toBeRemoved;
+ LocationSetSet *toBeAdded;
+ Stack **stackPtr;
+ ParamMappingFunction *map;
+ Boolean x10;
+} ExpandLocationSetSetActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void ExpandLocationSetSetToActualsAction(LocationSet *ls, void *refcon) {
+ ExpandLocationSetSetActionParams *params;
+
+ IRO_ASSERT(3021, ls != NULL);
+ IRO_ASSERT(3022, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(3026, params->toBeRemoved != NULL);
+ IRO_ASSERT(3027, params->toBeAdded != NULL);
+ IRO_ASSERT(3028, params->stackPtr == NULL || *params->stackPtr == NULL || *params->stackPtr != NULL);
+ IRO_ASSERT(3029, params->map == NULL || params->map != NULL);
+
+ if (!LocationSet_IsUnknown(ls)) {
+ PAMemoryBlock *block = LocationSet_block(ls);
+ if (block && PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) {
+ ExtendedParam *ep = PAMemoryBlock_thing(block);
+ if (ep) {
+ ObjectSet *objSet = ExtendedParam_objectSet(ep);
+ Object *obj = NULL;
+ ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj);
+ if (!obj) {
+ LocationSetSet_Add(params->toBeRemoved, ls);
+ params->x10 |= GetActualLocsOfExtendedParam(params->toBeAdded, ls, NULL, params->stackPtr, params->map, 0);
+ }
+ }
+ }
+ }
+}
+
+static int ExpandLocationSetSetToActuals(Stack **stackPtr, ParamMappingFunction *map, LocationSetSet *thingsPointedTo) {
+ LocationSetSet *toBeRemoved;
+ LocationSetSet *toBeAdded;
+ ExpandLocationSetSetActionParams params;
+ Boolean result;
+
+ IRO_ASSERT(3063, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL);
+ IRO_ASSERT(3064, map == NULL || map != NULL);
+ IRO_ASSERT(3065, thingsPointedTo != NULL);
+
+ toBeRemoved = LocationSetSet_New();
+ LocationSetSet_Init(toBeRemoved);
+
+ toBeAdded = LocationSetSet_New();
+ LocationSetSet_Init(toBeAdded);
+
+ memset(&params, 0, sizeof(params));
+ params.toBeRemoved = toBeRemoved;
+ params.toBeAdded = toBeAdded;
+ params.stackPtr = stackPtr;
+ params.map = map;
+ params.x10 = 0;
+
+ LocationSetSet_ForEach(thingsPointedTo, ExpandLocationSetSetToActualsAction, &params);
+
+ result = params.x10;
+ LocationSetSet_sub_488700(thingsPointedTo, toBeRemoved);
+ LocationSetSet_AddSet(thingsPointedTo, toBeAdded);
+
+ LocationSetSet_Term(toBeRemoved);
+ LocationSetSet_Delete(toBeRemoved);
+
+ LocationSetSet_Term(toBeAdded);
+ LocationSetSet_Delete(toBeAdded);
+
+ return result;
+}
+
+static void EvaluatePartialAbsolute(LocationSetSet *set, LocationSetSet *thingsPointedTo, LocationSet *dst, Type *indRtype) {
+ LocationSet *absLoc;
+ Type *absLocRtype;
+ PAMemoryBlock *block;
+
+ IRO_ASSERT(3108, set != NULL);
+ IRO_ASSERT(3109, thingsPointedTo != NULL);
+ IRO_ASSERT(3110, dst != NULL);
+ IRO_ASSERT(3111, indRtype != NULL);
+
+ absLoc = LocationSetSet_FindFirst(thingsPointedTo);
+ IRO_ASSERT(3114, absLoc != NULL);
+
+ if (!LocationSet_IsUnknown(absLoc))
+ absLocRtype = LocationSet_rtype(absLoc);
+
+ if (!LocationSet_IsUnknown(absLoc) && indRtype->size == absLocRtype->size) {
+ LocationSetSet_AddSet(set, thingsPointedTo);
+ } else if (
+ !LocationSet_IsUnknown(absLoc) &&
+ !LocationSet_stride(absLoc) &&
+ LocationSetSet_Count(thingsPointedTo) == 1 &&
+ (block = LocationSet_block(absLoc)) &&
+ PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_INT &&
+ absLocRtype->size <= stsignedlonglong.size &&
+ indRtype->size < absLocRtype->size
+ ) {
+ CInt64 val2;
+ CInt64 val8;
+ CInt64 val4;
+ CInt64 val5;
+ CInt64 val1;
+ CInt64 val3;
+ CInt64 val7;
+ CInt64 val6;
+ LocationSet *ls;
+
+ val1 = LocationSet_field(absLoc);
+ val2 = *((CInt64 *) PAMemoryBlock_thing(block));
+ CInt64_SetLong(&val3, 8);
+ val4 = cint64_zero;
+ CInt64_SetLong(&val5, stsignedlonglong.size - absLocRtype->size);
+ val6 = CInt64_Sub(LocationSet_field(dst), val1);
+ CInt64_SetLong(&val7, absLocRtype->size - indRtype->size);
+ val5 = CInt64_Add(val5, val6);
+ val4 = CInt64_Add(val4, val7);
+ val4 = CInt64_Sub(val4, val6);
+ val5 = CInt64_MulU(val5, val3);
+ val4 = CInt64_MulU(val4, val3);
+ val8 = cint64_negone;
+ val8 = CInt64_Shl(val8, val5);
+ val8 = CInt64_ShrU(val8, val5);
+ val2 = CInt64_And(val2, val8);
+ val2 = CInt64_ShrU(val2, val4);
+
+ block = PAMemoryBlock_New();
+ PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_INT, &val2);
+
+ ls = LocationSet_New();
+ LocationSet_InitKnown(ls, block, cint64_zero, 0, indRtype);
+ LocationSetSet_Add(set, ls);
+ LocationSet_Term(ls);
+ LocationSet_Delete(ls);
+ } else {
+ LocationSetSet_AddUnknown(set, indRtype, NULL, NULL);
+ }
+}
+
+static Boolean AddToInitialPointsToFunc(Boolean flag, PartialTransferFunction *ptf, LocationSet *dst, LocationSetSet *set) {
+ Boolean result;
+ LocationSet *ls;
+ PointsToFunction *initial;
+ PointsToEntry *pte;
+
+ IRO_ASSERT(3192, ptf == NULL || ptf != NULL);
+ IRO_ASSERT(3193, dst != NULL);
+ IRO_ASSERT(3194, set != NULL);
+
+ result = 0;
+
+ if (flag && ptf) {
+ ls = LocationSetSet_FindUnknown(set);
+ if (!ls || LocationSet_rtype(ls)) {
+ initial = PartialTransferFunction_initialPointsToFn(ptf);
+ if (initial && !PointsToFunction_FindByLookupCompatibleLocationSet(initial, dst)) {
+ IRO_ASSERT(3208, dst != NULL);
+
+ pte = PointsToEntry_New();
+ PointsToEntry_Init(pte, dst, set);
+ result = PointsToFunction_AddWithoutChecking(initial, pte);
+ PointsToEntry_Term(pte);
+ PointsToEntry_Delete(pte);
+ }
+ }
+ }
+
+ return result;
+}
+
+static Boolean Lookup(LocationSetSet *set, Stack **stackPtr, Object *proc, ParamMappingFunction *map, PartialTransferFunction *ptf, LocationSet *dst, PointsToFunction *pointsToFunc, Boolean unk, Type *indRtype) {
+ Boolean result;
+ LocationSetSet *mySet;
+ LocationSetSet *set2;
+ PAMemoryBlock *block;
+ ExtendedParam *ep;
+ PALocalVar *local;
+ ObjectSet *objSet;
+ Object *obj;
+
+ IRO_ASSERT(3245, set == NULL || set != NULL);
+ IRO_ASSERT(3246, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL);
+ IRO_ASSERT(3247, proc == NULL || proc != NULL);
+ IRO_ASSERT(3248, map == NULL || map != NULL);
+ IRO_ASSERT(3249, ptf == NULL || ptf != NULL);
+ IRO_ASSERT(3250, dst != NULL);
+ IRO_ASSERT(3251, pointsToFunc == NULL || pointsToFunc != NULL);
+ IRO_ASSERT(3252, indRtype == NULL || indRtype != NULL);
+
+ result = 0;
+
+ set2 = NULL;
+
+ mySet = LocationSetSet_New();
+ LocationSetSet_Init(mySet);
+
+ if (proc) {
+ if (LocationIsVolatile(dst, proc))
+ LocationSetSet_AddUnknown(mySet, indRtype, NULL, NULL);
+ }
+
+ if (pointsToFunc && !LocationSet_IsUnknown(dst)) {
+ PointsToEntry *pte = PointsToFunction_FindByLookupCompatibleLocationSet(pointsToFunc, dst);
+ if (pte) {
+ set2 = PointsToEntry_locs(pte);
+ } else if (indRtype) {
+ pte = PointsToFunction_FindContainingLocationSet(pointsToFunc, dst, indRtype);
+ if (pte)
+ set2 = PointsToEntry_locs(pte);
+ }
+ }
+
+ if (set2) {
+ if (indRtype)
+ EvaluatePartialAbsolute(mySet, set2, dst, indRtype);
+ else
+ LocationSetSet_AddSet(mySet, set2);
+ } else if (!set2) {
+ block = NULL;
+ if (!LocationSet_IsUnknown(dst))
+ block = LocationSet_block(dst);
+
+ if (!LocationSet_IsUnknown(dst) && LocationSet_stride(dst)) {
+ LocationSetSet_AddUnknown(mySet, indRtype, NULL, NULL);
+ } else if (
+ block &&
+ PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM &&
+ (ep = PAMemoryBlock_thing(block)) &&
+ (objSet = ExtendedParam_objectSet(ep))
+ ) {
+ obj = NULL;
+ ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj);
+ if (!obj) {
+ LocationSetSet *lss3;
+ LocationSet *tmp;
+ // Boolean result1;
+ EvalExprAction3Params params;
+
+ lss3 = LocationSetSet_New();
+ LocationSetSet_Init(lss3);
+ result = GetActualLocsOfExtendedParam(lss3, dst, NULL, stackPtr, map, unk);
+
+ memset(&params, 0, sizeof(params));
+ params.set = mySet;
+ params.stackPtr = stackPtr;
+ params.proc = proc;
+ params.map = map;
+ params.ptf = ptf;
+ params.pointsToFunc = pointsToFunc;
+ params.indRtype = indRtype;
+ params.x1C = 0;
+ LocationSetSet_ForEach(lss3, EvalExprAction3, &params);
+ result |= params.x1C;
+
+ LocationSetSet_Term(lss3);
+ LocationSetSet_Delete(lss3);
+
+ if ((tmp = LocationSetSet_FindUnknown(mySet))) {
+ if (!LocationSet_restriction(tmp) && ObjectSet_Count(objSet) == 1) {
+ if ((obj = ObjectSet_FindFirst(objSet))) {
+ if (ObjectIsRestrictQualified(obj)) {
+ LocationSet_Term(tmp);
+ LocationSet_InitUnknown(tmp, indRtype, block, NULL);
+ }
+ }
+ }
+ }
+
+ result |= AddToInitialPointsToFunc(unk, ptf, dst, mySet);
+ } else {
+ // Boolean result1;
+ Stack *next;
+ StackElement *element;
+
+ result = GetActualLocsOfExtendedParam(NULL, dst, NULL, stackPtr, map, unk);
+ if (stackPtr && *stackPtr && (next = Stack_Next(stackPtr)) && (element = Stack_Top(&next))) {
+ result |= Lookup(mySet, &next, StackElement_proc(element), StackElement_map(element),
+ StackElement_ptf(element), dst, StackElement_funcCall(element)->pointsToFunction, unk, indRtype);
+ } else {
+ LocationSetSet_AddUnknown(mySet, indRtype, NULL, NULL);
+ }
+
+ result |= AddToInitialPointsToFunc(unk, ptf, dst, mySet);
+ }
+ } else if (
+ block &&
+ PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_LOCALVAR &&
+ (local = PAMemoryBlock_thing(block)) &&
+ proc &&
+ (obj = GetLocalObject(local, proc, 1)) &&
+ ObjectIsAFunctionArgument(proc, obj)
+ ) {
+ result = LookupParam(mySet, dst, obj, stackPtr, proc, map, ptf, unk);
+ } else {
+ LocationSetSet_AddUnknown(mySet, indRtype, NULL, NULL);
+ }
+ }
+
+ if (set)
+ LocationSetSet_AddSet(set, mySet);
+
+ LocationSetSet_Term(mySet);
+ LocationSetSet_Delete(mySet);
+
+ return result;
+}
+
+static Boolean InputsHaveNewPointerValues(PartialTransferFunction *tgtPTF, PartialTransferFunction *ptf) {
+ IRO_ASSERT(3393, tgtPTF != NULL);
+ IRO_ASSERT(3394, ptf != NULL);
+
+ return 0;
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct CreateEPActionParams {
+ ParamMapping *last;
+ ParamMapping *lowest;
+} CreateEPActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void CreateExtendedParamAction(ParamMapping *mapping, void *refcon) {
+ CreateEPActionParams *params;
+ ExtendedParam *ep;
+ uint32 value;
+ ExtendedParam *lowestEP;
+ uint32 lowestValue;
+ ExtendedParam *lastEP;
+ uint32 lastValue;
+
+ IRO_ASSERT(3417, mapping != NULL);
+ IRO_ASSERT(3418, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(3422, params->last == NULL || params->last != NULL);
+ IRO_ASSERT(3423, params->lowest == NULL || params->lowest != NULL);
+
+ if ((ep = ParamMapping_extended(mapping))) {
+ value = ExtendedParam_sub_489110(ep);
+
+ if (params->lowest) {
+ lowestEP = ParamMapping_extended(params->lowest);
+ lowestValue = ExtendedParam_sub_489110(lowestEP);
+ if (params->last) {
+ lastEP = ParamMapping_extended(params->last);
+ lastValue = ExtendedParam_sub_489110(lastEP);
+ if (value > lastValue && value < lowestValue)
+ params->lowest = mapping;
+ } else if (value < lowestValue) {
+ params->lowest = mapping;
+ }
+ } else if (params->last) {
+ lastEP = ParamMapping_extended(params->last);
+ lastValue = ExtendedParam_sub_489110(lastEP);
+ if (value > lastValue)
+ params->lowest = mapping;
+ } else {
+ params->lowest = mapping;
+ }
+ }
+}
+
+static ExtendedParam *FindMatchingExtendedParam(Stack **stackPtr, ParamMappingFunction *map, LocationSetSet *lss, ParamMapping *lowest, Boolean *result) {
+ ExtendedParam *ep;
+ ExtendedParam *lowestEP;
+
+ IRO_ASSERT(3473, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL);
+ IRO_ASSERT(3474, map == NULL || map != NULL);
+ IRO_ASSERT(3475, lss != NULL);
+ IRO_ASSERT(3476, lowest != NULL);
+
+ ep = NULL;
+ if ((lowestEP = ParamMapping_extended(lowest))) {
+ PAMemoryBlock *block;
+ LocationSet *lowestLS;
+ LocationSetSet *lowestLSS;
+
+ block = PAMemoryBlock_New();
+ PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_EXTENDEDPARAM, lowestEP);
+
+ lowestLS = LocationSet_New();
+ LocationSet_InitKnown(lowestLS, block, cint64_zero, 0, TYPE(&void_ptr));
+
+ lowestLSS = LocationSetSet_New();
+ LocationSetSet_Init(lowestLSS);
+
+ *result |= GetActualLocsOfExtendedParam(lowestLSS, lowestLS, NULL, stackPtr, map, 0);
+ if (LocationSetSets_Equal(lowestLSS, lss))
+ ep = lowestEP;
+
+ LocationSetSet_Term(lowestLSS);
+ LocationSetSet_Delete(lowestLSS);
+
+ LocationSet_Term(lowestLS);
+ LocationSet_Delete(lowestLS);
+ }
+
+ return ep;
+}
+
+static ExtendedParam *CreateExtendedParam(Stack **stackPtr, ParamMappingFunction *map, Object *var, Boolean *result) {
+ ExtendedParam *ep;
+ ParamMapping *mapping;
+ LocationSetSet *lss;
+ CreateEPActionParams params;
+
+ IRO_ASSERT(3518, map == NULL || map != NULL);
+ IRO_ASSERT(3519, stackPtr == NULL || *stackPtr == NULL || *stackPtr != NULL);
+ IRO_ASSERT(3520, var != NULL);
+
+ mapping = NULL;
+ if (map)
+ mapping = ParamMappingFunction_FindMappingByFormal(map, var);
+
+ ep = ExtendedParam_FindByObject(var);
+ if (ep) {
+ if (mapping)
+ IRO_ASSERT(3535, ep == ParamMapping_extended(mapping) || ParamMapping_extended(mapping) == NULL);
+ } else if (map && !ObjectIsRestrictQualified(var)) {
+ lss = LocationSetSet_New();
+ LocationSetSet_Init(lss);
+ *result |= GetActualLocsOfExtendedParam(lss, NULL, var, stackPtr, map, 0);
+
+ memset(&params, 0, sizeof(params));
+ params.last = NULL;
+ do {
+ params.lowest = NULL;
+ pmf_sub_487C70(map, CreateExtendedParamAction, &params);
+ if (params.lowest && params.lowest != mapping)
+ ep = FindMatchingExtendedParam(stackPtr, map, lss, params.lowest, result);
+ params.last = params.lowest;
+ } while (params.lowest && !ep);
+
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+ }
+
+ if (!ep)
+ ep = ExtendedParam_FindByObject(var);
+
+ if (!ep) {
+ ep = ExtendedParam_New();
+ ExtendedParam_Init(ep, var);
+ } else {
+ ExtendedParam_sub_4867B0(ep, var);
+ }
+
+ if (stExtParamSet)
+ ExtParamSet_sub_487630(stExtParamSet, ep);
+
+ IRO_ASSERT(3583, ep != NULL);
+
+ return ep;
+}
+
+#ifdef IRO_DEBUG
+void __assertion_failed(char *expr, char *filename, int line) {
+ CError_ASSERT(3605, filename);
+ CError_Internal(filename, line);
+}
+#endif
+
+static void RecordActuals(IROLinear *nd, Object *proc, ParamMappingFunction *map) {
+ IRO_ASSERT(3628, nd != NULL);
+ IRO_ASSERT(3629, nd->type == IROLinearFunccall);
+ IRO_ASSERT(3630, proc != NULL);
+ IRO_ASSERT(3631, map != NULL);
+
+ if (proc != &stUnknown) {
+ int i;
+ ObjectList *args;
+ Object *arg;
+
+ args = FunctionArguments(proc);
+ if (args)
+ arg = args->object;
+ else
+ arg = &stUnknown;
+
+ for (i = 0; i < nd->u.funccall.argCount; i++) {
+ IRO_ASSERT(3643, arg != NULL);
+
+ if (arg != &stUnknown) {
+ ParamMapping *mapping = ParamMapping_New();
+ ParamMapping_Init_PROBABLY(mapping, nd->u.funccall.args[i], arg, NULL);
+ Pmf_Add_sub_486610(map, mapping);
+ ParamMapping_Term(mapping);
+ ParamMapping_Delete(mapping);
+ }
+
+ if (args) {
+ args = args->next;
+ if (args)
+ arg = args->object;
+ else
+ arg = &stUnknown;
+ }
+ }
+ }
+}
+
+static Boolean IsAddressableLocation(LocationSet *loc, Object *proc, IRONode *fnode, IROLinear *nd) {
+ IRO_ASSERT(3676, loc != NULL);
+ IRO_ASSERT(3677, fnode != NULL);
+ IRO_ASSERT(3678, nd != NULL);
+
+ if (!LocationSet_IsUnknown(loc)) {
+ PAMemoryBlock *block;
+ PALocalVar *local;
+ Object *obj;
+ ExtendedParam *ep;
+ ObjectSet *objSet;
+
+ block = LocationSet_block(loc);
+ if (
+ PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_LOCALVAR &&
+ (local = PAMemoryBlock_thing(block)) &&
+ (obj = GetLocalObject(local, proc, 0)) &&
+ fnode->addressed &&
+ !ObjectSet_sub_485020(fnode->addressed, obj)
+ ) {
+ return 0;
+ }
+
+ if (
+ PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM &&
+ (ep = PAMemoryBlock_thing(block)) &&
+ (objSet = ExtendedParam_objectSet(ep)) &&
+ ObjectSet_Count(objSet) == 1 &&
+ (obj = ObjectSet_FindFirst(objSet)) &&
+ ObjectIsAFunctionArgument(proc, obj) &&
+ ObjectIsRestrictQualified(obj)
+ ) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static Boolean LocationSetsAlias(LocationSet *ls1, LocationSet *ls2) {
+ IRO_ASSERT(3719, ls1 != NULL);
+ IRO_ASSERT(3720, ls2 != NULL);
+
+ return
+ (ls1 == ls2) ||
+ LocationSet_IsUnknown(ls1) ||
+ LocationSet_IsUnknown(ls2) ||
+ (
+ (LocationSet_stride(ls1) ||
+ LocationSet_stride(ls2) ||
+ CInt64_Equal(LocationSet_field(ls1), LocationSet_field(ls2))) &&
+ MemoryBlocks_Equal(LocationSet_block(ls1), LocationSet_block(ls2))
+ );
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct FindAliasingParams {
+ LocationSetSet *x0;
+ LocationSet *x4;
+ Boolean x8;
+} FindAliasingParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void FindAliasingAction2(LocationSet *ls, void *refcon) {
+ FindAliasingParams *params;
+
+ params = refcon;
+
+ if (!params->x8) {
+ if (LocationSetsAlias(params->x4, ls))
+ params->x8 = 1;
+ }
+}
+
+static void FindAliasingAction(LocationSet *ls, void *refcon) {
+ FindAliasingParams *params;
+
+ IRO_ASSERT(3751, ls != NULL);
+ IRO_ASSERT(3752, refcon != NULL);
+
+ params = refcon;
+
+ if (!params->x8) {
+ params->x4 = ls;
+ LocationSetSet_ForEach(params->x0, FindAliasingAction2, params);
+ }
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct KillLocationParams {
+ Object *proc;
+ IRONode *fnode;
+ IROLinear *nd;
+ PartialTransferFunction *ptf;
+ PointsToFunction *toBeKilled;
+ LocationSet *dst;
+ Boolean x18;
+} KillLocationParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void KillAllAddressableLocationsAction(PointsToEntry *pte, void *refcon) {
+ KillLocationParams *params;
+ LocationSet *loc;
+
+ IRO_ASSERT(3779, pte != NULL);
+ IRO_ASSERT(3780, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(3784, params->proc != NULL);
+ IRO_ASSERT(3785, params->fnode != NULL);
+ IRO_ASSERT(3786, params->nd != NULL);
+ IRO_ASSERT(3787, params->ptf != NULL);
+ IRO_ASSERT(3788, params->toBeKilled != NULL);
+ IRO_ASSERT(3789, params->dst == NULL);
+
+ loc = PointsToEntry_loc(pte);
+ IRO_ASSERT(3793, loc != NULL);
+ IRO_ASSERT(3794, !LocationSet_IsUnknown(loc));
+
+ if (IsAddressableLocation(loc, params->proc, params->fnode, params->nd))
+ PointsToFunction_Add(params->toBeKilled, pte);
+}
+
+static void KillAllAliasingExtParamLocsAction(PointsToEntry *pte, void *refcon) {
+ KillLocationParams *params;
+ LocationSet *loc;
+
+ IRO_ASSERT(3813, pte != NULL);
+ IRO_ASSERT(3814, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(3818, params->proc != NULL);
+ IRO_ASSERT(3819, params->fnode != NULL);
+ IRO_ASSERT(3820, params->nd != NULL);
+ IRO_ASSERT(3821, params->ptf != NULL);
+ IRO_ASSERT(3822, params->toBeKilled != NULL);
+ IRO_ASSERT(3823, params->dst != NULL);
+ IRO_ASSERT(3824, LocationSet_block(params->dst) != NULL);
+ IRO_ASSERT(3825, PAMemoryBlock_kind(LocationSet_block(params->dst)) == PAMEMORYBLOCKKIND_EXTENDEDPARAM);
+
+ loc = PointsToEntry_loc(pte);
+ IRO_ASSERT(3829, loc != NULL);
+ IRO_ASSERT(3830, !LocationSet_IsUnknown(loc));
+
+ if (loc != params->dst) {
+ if (LocationSetsAlias(loc, params->dst)) {
+ PointsToFunction_Add(params->toBeKilled, pte);
+ } else {
+ ExtendedParam *ep;
+ ObjectSet *objSet;
+ Object *obj;
+ PAMemoryBlock *block;
+
+ if (
+ (ep = PAMemoryBlock_thing(LocationSet_block(params->dst))) &&
+ (objSet = ExtendedParam_objectSet(ep)) &&
+ (ObjectSet_Count(objSet) != 1 || !(obj = ObjectSet_FindFirst(objSet)) || !ObjectIsRestrictQualified(obj)) &&
+ (block = LocationSet_block(loc)) &&
+ PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM &&
+ (ep = PAMemoryBlock_thing(block)) &&
+ (objSet = ExtendedParam_objectSet(ep)) &&
+ (ObjectSet_Count(objSet) != 1 || !(obj = ObjectSet_FindFirst(objSet)) || !ObjectIsRestrictQualified(obj))
+ ) {
+ LocationSetSet *lss1;
+ LocationSetSet *lss2;
+ Boolean changed;
+ FindAliasingParams aparams;
+
+ lss1 = LocationSetSet_New();
+ LocationSetSet_Init(lss1);
+ lss2 = LocationSetSet_New();
+ LocationSetSet_Init(lss2);
+
+ changed = GetActualLocsOfExtendedParam(lss1, loc, NULL, &stCallingContextStack, NULL, 0);
+ changed |= GetActualLocsOfExtendedParam(lss2, params->dst, NULL, &stCallingContextStack, NULL, 0);
+
+ memset(&aparams, 0, sizeof(aparams));
+ aparams.x8 = 0;
+ aparams.x0 = lss2;
+ LocationSetSet_ForEach(lss1, FindAliasingAction, &aparams);
+ if (aparams.x8)
+ PointsToFunction_Add(params->toBeKilled, pte);
+
+ LocationSetSet_Term(lss1);
+ LocationSetSet_Delete(lss1);
+ LocationSetSet_Term(lss2);
+ LocationSetSet_Delete(lss2);
+ }
+ }
+ }
+}
+
+static void KillLocationsAction(PointsToEntry *pte, void *refcon) {
+ KillLocationParams *params;
+ LocationSet *loc;
+ LocationSetSet *lss;
+
+ IRO_ASSERT(3886, pte != NULL);
+ IRO_ASSERT(3887, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(3891, params->proc != NULL);
+ IRO_ASSERT(3892, params->fnode != NULL);
+ IRO_ASSERT(3893, params->nd != NULL);
+ IRO_ASSERT(3894, params->ptf != NULL);
+ IRO_ASSERT(3895, params->toBeKilled != NULL);
+ IRO_ASSERT(3896, params->dst == NULL);
+
+ loc = PointsToEntry_loc(pte);
+ IRO_ASSERT(3900, loc != NULL);
+ IRO_ASSERT(3901, !LocationSet_IsUnknown(loc));
+
+ lss = LocationSetSet_New();
+ LocationSetSet_Init(lss);
+ LocationSetSet_AddUnknown(lss, NULL, NULL, NULL);
+
+ params->x18 |= Assign(params->ptf, loc, lss, params->proc, params->nd, params->fnode);
+
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+}
+
+static Boolean KillAllAddressableLocations(Object *proc, IRONode *fnode, IROLinear *nd, PartialTransferFunction *ptf) {
+ Boolean result;
+ PointsToFunction *pointsToFunc;
+ PointsToFunction *pointsToFuncCopy;
+ PointsToFunction *toBeKilled;
+ KillLocationParams params;
+
+ IRO_ASSERT(3921, proc != NULL);
+ IRO_ASSERT(3922, fnode == NULL || fnode != NULL);
+ IRO_ASSERT(3923, nd == NULL || nd != NULL);
+ IRO_ASSERT(3924, ptf != NULL);
+
+ if (nd && nd->pointsToFunction)
+ pointsToFunc = nd->pointsToFunction;
+ else
+ pointsToFunc = PartialTransferFunction_finalPointsToFn(ptf);
+
+ pointsToFuncCopy = PointsToFunction_New();
+ PointsToFunction_Copy(pointsToFuncCopy, pointsToFunc);
+
+ toBeKilled = PointsToFunction_New();
+ PointsToFunction_Init(toBeKilled);
+
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.fnode = fnode;
+ params.nd = nd;
+ params.ptf = ptf;
+ params.toBeKilled = toBeKilled;
+ params.dst = NULL;
+ params.x18 = 0;
+
+ if (pointsToFunc) {
+ PointsToFunction_ForEach(pointsToFunc, KillAllAddressableLocationsAction, &params);
+ PointsToFunction_ForEach(params.toBeKilled, KillLocationsAction, &params);
+ }
+
+ PointsToFunction_Term(toBeKilled);
+ PointsToFunction_Delete(toBeKilled);
+
+ if (params.x18)
+ result = !PointsToFunctions_Equal(pointsToFuncCopy, pointsToFunc);
+ else
+ result = 0;
+
+ PointsToFunction_Term(pointsToFuncCopy);
+ PointsToFunction_Delete(pointsToFuncCopy);
+
+ return result;
+}
+
+static void KillAllAliasingExtParamLocs(Object *proc, IRONode *fnode, IROLinear *nd, PartialTransferFunction *ptf, LocationSet *dst) {
+ PointsToFunction *pointsToFunc;
+ PointsToFunction *toBeKilled;
+ KillLocationParams params;
+
+ IRO_ASSERT(3974, proc != NULL);
+ IRO_ASSERT(3975, fnode == NULL || fnode != NULL);
+ IRO_ASSERT(3976, nd == NULL || nd != NULL);
+ IRO_ASSERT(3977, ptf != NULL);
+ IRO_ASSERT(3978, dst != NULL);
+
+ if (!LocationSet_IsUnknown(dst) && LocationSet_block(dst)) {
+ if (PAMemoryBlock_kind(LocationSet_block(dst)) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) {
+
+ if (nd && nd->pointsToFunction)
+ pointsToFunc = nd->pointsToFunction;
+ else
+ pointsToFunc = PartialTransferFunction_finalPointsToFn(ptf);
+
+ toBeKilled = PointsToFunction_New();
+ PointsToFunction_Init(toBeKilled);
+
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.fnode = fnode;
+ params.nd = nd;
+ params.ptf = ptf;
+ params.toBeKilled = toBeKilled;
+ params.dst = dst;
+ params.x18 = 0;
+
+ if (pointsToFunc) {
+ PointsToFunction_ForEach(pointsToFunc, KillAllAliasingExtParamLocsAction, &params);
+ PointsToFunction_ForEach(params.toBeKilled, KillLocationsAction, &params);
+ }
+
+ PointsToFunction_Term(toBeKilled);
+ PointsToFunction_Delete(toBeKilled);
+ }
+ }
+}
+
+static Boolean Assign(PartialTransferFunction *ptf, LocationSet *dst, LocationSetSet *srcs, Object *proc, IROLinear *nd, IRONode *fnode) {
+ PointsToFunction *pointsToFunc;
+ Boolean result;
+ PointsToEntry *pte;
+ LocationSet *loc;
+ LocationSetSet *locs;
+ LocationSet *bitfieldOf;
+ LocationSetSet *lss;
+
+ IRO_ASSERT(4027, ptf != NULL);
+ IRO_ASSERT(4028, dst != NULL);
+ IRO_ASSERT(4029, srcs != NULL);
+ IRO_ASSERT(4030, proc != NULL);
+ IRO_ASSERT(4031, nd == NULL || nd != NULL);
+ IRO_ASSERT(4032, fnode == NULL || fnode != NULL);
+
+ if (nd) {
+ if (!nd->pointsToFunction) {
+ nd->pointsToFunction = PointsToFunction_New();
+ PointsToFunction_Init(nd->pointsToFunction);
+ }
+ pointsToFunc = nd->pointsToFunction;
+ } else {
+ pointsToFunc = PartialTransferFunction_finalPointsToFn(ptf);
+ }
+
+ pte = PointsToFunction_FindByLookupCompatibleLocationSet(pointsToFunc, dst);
+ if (pte) {
+ loc = PointsToEntry_loc(pte);
+ locs = PointsToEntry_locs(pte);
+ IRO_ASSERT(4056, !LocationSet_IsUnknown(dst));
+ IRO_ASSERT(4057, LocationSet_stride(dst) == 0 || LocationSet_stride(loc) != 0);
+
+ result = !LocationSetSets_Equal(srcs, locs) || LocationSet_stride(dst) != LocationSet_stride(loc);
+
+ if (result) {
+ pte = PointsToEntry_New();
+ PointsToEntry_Init(pte, dst, srcs);
+ PointsToFunction_RemoveByLocationSet(pointsToFunc, loc);
+ PointsToFunction_AddWithoutChecking(pointsToFunc, pte);
+ PointsToEntry_Term(pte);
+ PointsToEntry_Delete(pte);
+ }
+ } else if (!LocationSet_IsUnknown(dst)) {
+ KillAllAliasingExtParamLocs(proc, fnode, nd, ptf, dst);
+
+ pte = PointsToEntry_New();
+ PointsToEntry_Init(pte, dst, srcs);
+ result = PointsToFunction_AddWithoutChecking(pointsToFunc, pte);
+ PointsToEntry_Term(pte);
+ PointsToEntry_Delete(pte);
+ } else if ((bitfieldOf = LocationSet_bitfieldOf(dst))) {
+ lss = LocationSetSet_New();
+ LocationSetSet_Init(lss);
+ LocationSetSet_AddUnknown(lss, NULL, NULL, NULL);
+ result = Assign(ptf, bitfieldOf, lss, proc, nd, fnode);
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+ } else if (!LocationSet_restriction(dst)) {
+ result = KillAllAddressableLocations(proc, fnode, nd, ptf);
+ }
+
+ return result;
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct EvalMeetActionParams {
+ Object *proc;
+ IRONode *fnode;
+ IRONode *pred;
+ IROLinear *nd;
+ PartialTransferFunction *ptf;
+ Boolean x14;
+ Boolean x15;
+} EvalMeetActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void EvalMeetAction(PointsToEntry *pte, void *refcon) {
+ EvalMeetActionParams *params;
+ LocationSet *loc;
+ LocationSetSet *set;
+ UInt16 i;
+
+ IRO_ASSERT(4123, pte != NULL);
+ IRO_ASSERT(4124, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(4128, params->proc != NULL);
+ IRO_ASSERT(4129, params->fnode != NULL);
+ IRO_ASSERT(4130, params->pred != NULL);
+ IRO_ASSERT(4131, params->nd != NULL);
+ IRO_ASSERT(4132, params->ptf != NULL);
+
+ loc = PointsToEntry_loc(pte);
+
+ set = LocationSetSet_New();
+ LocationSetSet_Init(set);
+ LocationSetSet_AddSet(set, PointsToEntry_locs(pte));
+
+ for (i = 0; i < params->fnode->numpred; i++) {
+ IRONode *pred = FunctionNodeTable(params->proc)[params->fnode->pred[i]];
+ if (pred->x3C && pred != params->pred) {
+ params->x14 |= Lookup(set, &stCallingContextStack, params->proc, NULL, params->ptf, loc, pred->last->pointsToFunction, 0, NULL);
+ }
+ }
+
+ params->x15 |= Assign(params->ptf, loc, set, params->proc, params->nd, params->fnode);
+ LocationSetSet_Term(set);
+ LocationSetSet_Delete(set);
+}
+
+static Boolean EvalMeet(Object *proc, IRONode *fnode, IROLinear *nd, PartialTransferFunction *ptf) {
+ PointsToFunction *pointsToFunc;
+ EvalMeetActionParams params;
+ int i;
+
+ IRO_ASSERT(4163, proc != NULL);
+ IRO_ASSERT(4164, fnode != NULL);
+ IRO_ASSERT(4165, nd != NULL);
+ IRO_ASSERT(4166, ptf != NULL);
+
+ pointsToFunc = PointsToFunction_New();
+ if (nd->pointsToFunction)
+ PointsToFunction_Copy(pointsToFunc, nd->pointsToFunction);
+ else
+ PointsToFunction_Init(pointsToFunc);
+
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.fnode = fnode;
+ params.nd = nd;
+ params.ptf = ptf;
+ params.x14 = 0;
+ params.x15 = 0;
+
+ for (i = 0; i < fnode->numpred; i++) {
+ IRONode *pred = FunctionNodeTable(proc)[fnode->pred[i]];
+ params.pred = pred;
+ if (pred->x3C && pred->last->pointsToFunction) {
+ PointsToFunction_ForEach(pred->last->pointsToFunction, EvalMeetAction, &params);
+ }
+ }
+
+ if (!params.x14 && params.x15) {
+ if (nd->pointsToFunction)
+ params.x14 = !PointsToFunctions_Equal(pointsToFunc, nd->pointsToFunction);
+ else
+ params.x14 = PointsToFunction_FindFirst(pointsToFunc) != NULL;
+ }
+
+ PointsToFunction_Term(pointsToFunc);
+ PointsToFunction_Delete(pointsToFunc);
+
+ return params.x14;
+}
+
+static PartialTransferFunction *AllocatePTF(Object *proc, IROLinear *nd, PartialTransferFunction *ptf) {
+ PartialTransferFunction *newPTF;
+
+ IRO_ASSERT(4210, proc != NULL);
+ IRO_ASSERT(4211, proc->u.func.ptfList != NULL);
+ IRO_ASSERT(4212, nd == NULL || nd != NULL);
+ IRO_ASSERT(4213, ptf == NULL || ptf != NULL);
+
+ newPTF = PartialTransferFunction_New();
+ PartialTransferFunction_Init(newPTF, nd, ptf);
+ PTFList_sub_48A050(proc->u.func.ptfList, newPTF);
+ return newPTF;
+}
+
+static Object *FindMainEntryPoint(Object *function) {
+ IRO_ASSERT(4229, function != NULL);
+
+ return function;
+}
+
+static ObjectList *FunctionArguments(Object *proc) {
+ Object *search;
+ ObjectList *scan;
+ ObjectList *list;
+ ObjectList *prev;
+ ExtendedParam *ep;
+ char *name;
+ VarInfo *vi;
+ Object *obj;
+ FuncArg *args;
+ Boolean notFound;
+
+ IRO_ASSERT(4252, proc != NULL);
+
+ if (proc == stCurrentProc) {
+ for (list = arguments; list; list = list->next) {
+ if ((obj = list->object) && obj->name && (name = obj->name->name) && name[0]) {
+ prev = NULL;
+ for (scan = proc->u.func.argList; scan; scan = scan->next) {
+ prev = scan;
+ if ((search = scan->object) && search->name && search->name->name) {
+ if (!strcmp(name, search->name->name))
+ break;
+ }
+ }
+
+ if (!scan)
+ search = NULL;
+
+ notFound = !search;
+
+ if (!search) {
+ search = IRO_malloc(sizeof(Object));
+ ep = NULL;
+ search->u.var.info = IRO_malloc(sizeof(VarInfo));
+ memset(search->u.var.info, 0, sizeof(VarInfo));
+ search->u.var.info->func = proc;
+ } else {
+ ep = search->extParam;
+ }
+
+ vi = search->u.var.info;
+ memcpy(search, obj, sizeof(Object));
+ search->extParam = ep;
+ search->u.var.info = vi;
+ search->u.var.realObj = obj;
+
+ if (notFound) {
+ scan = IRO_malloc(sizeof(ObjectList));
+ scan->next = NULL;
+ scan->object = search;
+ if (!prev)
+ proc->u.func.argList = scan;
+ else
+ prev->next = scan;
+ }
+ }
+ }
+ } else if (proc->type) {
+ for (args = TYPE_FUNC(proc->type)->args; args; args = args->next) {
+ if (args->name && (name = args->name->name) && name[0]) {
+ prev = NULL;
+ for (scan = proc->u.func.argList; scan; scan = scan->next) {
+ prev = scan;
+ if ((search = scan->object) && search->name && search->name->name) {
+ if (!strcmp(name, search->name->name))
+ break;
+ }
+ }
+
+ if (!scan)
+ search = NULL;
+
+ if (!search) {
+ search = IRO_malloc(sizeof(Object));
+ memset(search, 0, sizeof(Object));
+ search->datatype = DLOCAL;
+ search->extParam = NULL;
+ search->name = GetHashNameNodeExport(name);
+ search->type = args->type;
+ search->qual = args->qual;
+ search->u.var.info = IRO_malloc(sizeof(VarInfo));
+ memset(search->u.var.info, 0, sizeof(VarInfo));
+ search->u.var.info->func = proc;
+
+ scan = IRO_malloc(sizeof(ObjectList));
+ scan->next = NULL;
+ scan->object = search;
+ if (!prev)
+ proc->u.func.argList = scan;
+ else
+ prev->next = scan;
+ }
+ }
+ }
+ }
+
+ return proc->u.func.argList;
+}
+
+static IRONode **FunctionNodeTable(Object *proc) {
+ IRO_ASSERT(4383, proc != NULL);
+
+ IRO_ASSERT(4391, proc == stCurrentProc);
+
+ return IRO_NodeTable;
+}
+
+static IRONode *FunctionFirstNode(Object *proc) {
+ IRO_ASSERT(4401, proc != NULL);
+
+ IRO_ASSERT(4409, proc == stCurrentProc);
+
+ return IRO_FirstNode;
+}
+
+static void UpdatePTFDomain() {
+ // no idea what this would've done
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct EvalCallActionParams {
+ Object *proc;
+ IRONode *fnode;
+ IROLinear *nd;
+ PartialTransferFunction *ptf;
+ ParamMappingFunction *map;
+ int x14;
+ Boolean x18;
+ Boolean x19;
+ Boolean x1A;
+} EvalCallActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void EvalCallAction(Object *proc, void *refcon) {
+ EvalCallActionParams *params;
+ ParamMappingFunction *pmf;
+ PartialTransferFunction *tgtPTF;
+ Boolean flag;
+ Boolean flag2;
+
+ IRO_ASSERT(4458, proc != NULL);
+ IRO_ASSERT(4459, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(4463, params->proc != NULL);
+ IRO_ASSERT(4464, params->fnode != NULL);
+ IRO_ASSERT(4465, params->nd != NULL);
+ IRO_ASSERT(4466, params->ptf != NULL);
+ IRO_ASSERT(4467, params->map == NULL || params->map != NULL);
+
+ if (!params->x18) {
+ pmf = ParamMappingFunction_New();
+ ParamMappingFunction_Init(pmf);
+ RecordActuals(params->nd, proc, pmf);
+
+ flag = 0;
+ if (!Stack_sub_48A710(&stCallingContextStack, proc)) {
+ StackElement *element;
+
+ flag2 = 0;
+ tgtPTF = GetPTF(pmf, proc, params->nd, params->ptf, &flag2);
+
+ element = StackElement_New();
+ StackElement_Init(element, proc, tgtPTF, pmf, params->nd);
+ Stack_sub_48A660(&stCallingContextStack, element);
+ StackElement_Term(element);
+ StackElement_Delete(element);
+
+ IRO_ASSERT(4490, tgtPTF != NULL);
+
+ flag = 1;
+
+ if (stPTFList)
+ PTFList_sub_48A050(stPTFList, tgtPTF);
+ PartialTransferFunction_sub_48A610(tgtPTF, 0);
+
+ if (flag2 || params->x1A) {
+ if (params->x1A) {
+ params->x1A = 0;
+ EvalProc(proc, pmf, tgtPTF);
+ } else {
+ tgtPTF = stUnknownPTF;
+ }
+ }
+ } else {
+ tgtPTF = stUnknownPTF;
+ }
+
+ if (params->map)
+ params->x19 |= ApplySummary(tgtPTF, pmf, params->proc, params->fnode, params->nd, params->ptf, params->map, params->x14 == 1);
+
+ if (flag) {
+ StackElement *element = Stack_sub_48A5B0(&stCallingContextStack);
+ StackElement_Term(element);
+ StackElement_Delete(element);
+ }
+
+ ParamMappingFunction_Term(pmf);
+ ParamMappingFunction_Delete(pmf);
+ }
+}
+
+static Boolean EvalCall(Object *proc, IRONode *fnode, IROLinear *nd, ParamMappingFunction *map, PartialTransferFunction *ptf) {
+ EvalCallActionParams params;
+ ObjectSet *objSet;
+
+ IRO_ASSERT(4548, proc != NULL);
+ IRO_ASSERT(4549, fnode != NULL);
+ IRO_ASSERT(4550, nd != NULL);
+ IRO_ASSERT(4551, map != NULL);
+ IRO_ASSERT(4552, ptf != NULL);
+
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.fnode = fnode;
+ params.nd = nd;
+ params.ptf = ptf;
+ params.map = map;
+ params.x18 = 0;
+ params.x19 = 0;
+ params.x1A = 0;
+
+ objSet = ObjectSet_New();
+ ObjectSet_Init(objSet);
+
+ params.x19 |= FindCallTargets(objSet, proc, nd, map, ptf);
+ params.x14 = ObjectSet_Count(objSet);
+ ObjectSet_ForEach(objSet, EvalCallAction, &params);
+
+ ObjectSet_Term(objSet);
+ ObjectSet_Delete(objSet);
+
+ return params.x19;
+}
+
+static void AdjustTypesForVolatilityAction(LocationSet *ls, void *refcon) {
+ Type *type;
+ Type *newtype;
+ UInt32 qual;
+
+ type = LocationSet_rtype(ls);
+ switch (type->type) {
+ case TYPEARRAY:
+ qual = TYPE_POINTER(type)->qual;
+ break;
+ case TYPEPOINTER:
+ qual = TYPE_POINTER(type)->qual;
+ break;
+ case TYPEMEMBERPOINTER:
+ qual = TYPE_MEMBER_POINTER(type)->qual;
+ break;
+ default:
+ CError_FATAL(4604);
+ }
+
+ if (!(qual & Q_VOLATILE)) {
+ switch (type->type) {
+ case TYPEARRAY:
+ newtype = CDecl_NewArrayType(TYPE_POINTER(type)->target, type->size);
+ TYPE_POINTER(newtype)->qual |= Q_VOLATILE;
+ break;
+ case TYPEPOINTER:
+ newtype = CDecl_NewPointerType(TYPE_POINTER(type)->target);
+ TYPE_POINTER(newtype)->qual |= Q_VOLATILE;
+ break;
+ case TYPEMEMBERPOINTER:
+ newtype = galloc(sizeof(TypeMemberPointer));
+ memcpy(newtype, type, sizeof(TypeMemberPointer));
+ TYPE_MEMBER_POINTER(newtype)->qual |= Q_VOLATILE;
+ break;
+ }
+
+ LocationSet_SetRtype(ls, newtype);
+ }
+}
+
+static void AdjustTypesForVolatility(LocationSetSet *set, Object *proc, IROLinear *nd) {
+ if (nd->rtype && CParser_IsVolatile(nd->rtype, nd->nodeflags & ENODE_FLAG_QUALS))
+ LocationSetSet_ForEach(set, AdjustTypesForVolatilityAction, NULL);
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct EvalAssignAction2Params {
+ CInt64 x0;
+ IROLinear *nd;
+ Boolean xC;
+} EvalAssignAction2Params;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void EvalAssignAction2(LocationSet *ls, void *refcon) {
+ EvalAssignAction2Params *params;
+ CInt64 value;
+ IROLinear *nd;
+ ENodeType oper;
+ UInt32 stride;
+ Type *rtype;
+ PAMemoryBlock *block;
+
+ IRO_ASSERT(4657, ls != NULL);
+ IRO_ASSERT(4658, refcon != NULL);
+
+ params = refcon;
+
+ if (!params->xC && !LocationSet_IsUnknown(ls)) {
+ value = params->x0;
+ nd = params->nd;
+ IRO_ASSERT(4665, nd != NULL);
+ oper = nd->nodetype;
+
+ stride = LocationSet_stride(ls);
+ rtype = LocationSet_rtype(ls);
+ block = LocationSet_block(ls);
+
+ if (block && PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_INT) {
+ LocationSet_Term(ls);
+
+ switch (oper) {
+ case EPOSTINC:
+ case EPREINC:
+ case EADDASS:
+ value = CInt64_Add(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ break;
+ case EPOSTDEC:
+ case EPREDEC:
+ case ESUBASS:
+ value = CInt64_Sub(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ break;
+ case EMULASS:
+ if (IRO_IsUnsignedType(nd->rtype))
+ value = CInt64_MulU(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ else
+ value = CInt64_Mul(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ break;
+ case EDIVASS:
+ if (CInt64_IsZero(&value)) {
+ if (nd->stmt->sourceoffset) {
+ TStreamElement *e = CPrep_CurStreamElement();
+ e->tokenoffset = nd->stmt->sourceoffset;
+ CError_SetErrorToken(e);
+ }
+ CError_Warning(CErrorStr139);
+ params->xC = 1;
+ } else {
+ if (IRO_IsUnsignedType(nd->rtype))
+ value = CInt64_DivU(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ else
+ value = CInt64_Div(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ }
+ break;
+ case EMODASS:
+ if (CInt64_IsZero(&value)) {
+ if (nd->stmt->sourceoffset) {
+ TStreamElement *e = CPrep_CurStreamElement();
+ e->tokenoffset = nd->stmt->sourceoffset;
+ CError_SetErrorToken(e);
+ }
+ CError_Warning(CErrorStr139);
+ params->xC = 1;
+ } else {
+ if (IRO_IsUnsignedType(nd->rtype))
+ value = CInt64_ModU(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ else
+ value = CInt64_Mod(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ }
+ break;
+ case ESHLASS:
+ value = CInt64_Shl(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ break;
+ case ESHRASS:
+ if (IRO_IsUnsignedType(nd->rtype))
+ value = CInt64_ShrU(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ else
+ value = CInt64_Shr(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ break;
+ case EANDASS:
+ value = CInt64_And(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ break;
+ case EXORASS:
+ value = CInt64_Xor(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ break;
+ case EORASS:
+ value = CInt64_Or(*((CInt64 *) PAMemoryBlock_thing(block)), value);
+ break;
+ default:
+ CError_FATAL(4746);
+ }
+
+ block = PAMemoryBlock_New();
+ PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_INT, &value);
+ LocationSet_InitKnown(ls, block, cint64_zero, stride, rtype);
+ } else {
+ if (oper == EPOSTDEC || oper == EPREDEC || oper == ESUBASS)
+ value = CInt64_Neg(value);
+
+ switch (oper) {
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EADDASS:
+ case ESUBASS:
+ value = CInt64_Add(LocationSet_field(ls), value);
+ if (stride) {
+ CInt64 tmp;
+ CInt64_SetLong(&tmp, stride);
+ value = CInt64_Mod(value, tmp);
+ }
+ SetsLocationSetField_sub_4851B0(ls, value);
+ break;
+ default:
+ params->xC = 1;
+ break;
+ }
+ }
+ }
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct EvalAssignActionParams {
+ Object *proc;
+ PartialTransferFunction *ptf;
+ IROLinear *nd;
+ IRONode *fnode;
+ LocationSetSet *srcs;
+ Boolean x14;
+ Boolean x15;
+ Boolean x16;
+} EvalAssignActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void EvalAssignAction(LocationSet *dst, void *refcon) {
+ EvalAssignActionParams *params;
+ LocationSetSet *srcs;
+
+ IRO_ASSERT(4797, dst != NULL);
+ IRO_ASSERT(4798, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(4802, params->proc != NULL);
+ IRO_ASSERT(4802, params->ptf != NULL);
+ IRO_ASSERT(4803, params->nd != NULL);
+ IRO_ASSERT(4804, params->fnode != NULL);
+ IRO_ASSERT(4805, params->srcs != NULL);
+
+ srcs = params->srcs;
+ if (
+ !params->x14 ||
+ !LocationSetRepresentsSingleLocation(dst, params->proc, params->nd->pointsToFunction) ||
+ LocationIsVolatile(dst, params->proc) ||
+ LocationSet_sub_48AF30(dst)
+ ) {
+ LocationSetSet *set = LocationSetSet_New();
+ LocationSetSet_Init(set);
+ params->x15 |= Lookup(set, &stCallingContextStack, params->proc, NULL, params->ptf, dst, params->nd->pointsToFunction, 0, params->nd->rtype);
+ LocationSetSet_AddSet(srcs, set);
+ LocationSetSet_Term(set);
+ LocationSetSet_Delete(set);
+ }
+
+ params->x16 |= Assign(params->ptf, dst, srcs, params->proc, params->nd, params->fnode);
+}
+
+static Boolean EvalAssign(Object *proc, IROLinear *nd, IRONode *fnode, ParamMappingFunction *map, PartialTransferFunction *ptf) {
+ EvalAssignActionParams params;
+ EvalAssignAction2Params params2;
+ LocationSetSet *set;
+ LocationSet *tmp;
+ PAMemoryBlock *block;
+ Type *type;
+
+ IRO_ASSERT(4840, proc != NULL);
+ IRO_ASSERT(4841, nd != NULL);
+ IRO_ASSERT(4842, fnode != NULL);
+ IRO_ASSERT(4843, map != NULL);
+ IRO_ASSERT(4844, ptf != NULL);
+
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.ptf = ptf;
+ params.nd = nd;
+ params.fnode = fnode;
+ params.x15 = 0;
+ params.x16 = 0;
+
+ set = LocationSetSet_New();
+ params.srcs = LocationSetSet_New();
+ LocationSetSet_Init(set);
+ LocationSetSet_Init(params.srcs);
+
+ if (nd->type == IROLinearOp2Arg) {
+ IRO_ASSERT(4861, nd->u.diadic.left->type == IROLinearOp1Arg && nd->u.diadic.left->nodetype == EINDIRECT);
+
+ params.x15 |= EvalExpr(set, proc, nd->u.diadic.left->u.monadic, &stCallingContextStack, map, ptf);
+ AdjustTypesForVolatility(set, proc, nd->u.diadic.left);
+ params.x15 |= EvalExpr(params.srcs, proc, nd->u.diadic.right, &stCallingContextStack, map, ptf);
+
+ if (nd->nodetype != EASS) {
+ switch (nd->nodetype) {
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ if (
+ LocationSetSet_Count(params.srcs) == 1 &&
+ (tmp = LocationSetSet_FindFirst(params.srcs)) &&
+ !LocationSet_IsUnknown(tmp) &&
+ !LocationSet_stride(tmp) &&
+ (block = LocationSet_block(tmp)) &&
+ PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_INT
+ ) {
+ LocationSetSet_Term(params.srcs);
+ LocationSetSet_Init(params.srcs);
+ params.x15 |= EvalExpr(params.srcs, proc, nd->u.diadic.left, &stCallingContextStack, map, ptf);
+
+ memset(&params2, 0, sizeof(params2));
+ params2.x0 = *((CInt64 *) PAMemoryBlock_thing(block));
+ IRO_TruncateValueToType(&params2.x0, nd->u.diadic.right->rtype);
+ params2.nd = nd;
+ params2.xC = 0;
+
+ if (!CInt64_IsZero(&params2.x0)) {
+ LocationSetSet_ForEach(params.srcs, EvalAssignAction2, &params2);
+ if (params2.xC) {
+ LocationSetSet_Term(params.srcs);
+ LocationSetSet_Init(params.srcs);
+ params.x15 |= EvalExpr(params.srcs, proc, nd->u.diadic.left, &stCallingContextStack, map, ptf);
+ if (!LocationSetSet_FindUnknown(params.srcs))
+ LocationSetSet_ForEach(params.srcs, EvalExprAction2, (void *) &cint64_one);
+ }
+ }
+ } else {
+ LocationSetSet_Term(params.srcs);
+ LocationSetSet_Init(params.srcs);
+ params.x15 |= EvalExpr(params.srcs, proc, nd->u.diadic.left, &stCallingContextStack, map, ptf);
+ if (!LocationSetSet_FindUnknown(params.srcs))
+ LocationSetSet_ForEach(params.srcs, EvalExprAction2, (void *) &cint64_one);
+ }
+ break;
+ default:
+ LocationSetSet_Term(params.srcs);
+ LocationSetSet_Init(params.srcs);
+ LocationSetSet_AddUnknown(params.srcs, nd->rtype, NULL, NULL);
+ break;
+ }
+ }
+ } else if (nd->type == IROLinearOp1Arg) {
+ IRO_ASSERT(4958, nd->u.monadic.left->type == IROLinearOp1Arg && nd->u.monadic->nodetype == EINDIRECT);
+
+ params.x15 |= EvalExpr(set, proc, nd->u.monadic->u.monadic, &stCallingContextStack, map, ptf);
+ AdjustTypesForVolatility(set, proc, nd->u.monadic);
+ params.x15 |= EvalExpr(params.srcs, proc, nd->u.monadic, &stCallingContextStack, map, ptf);
+
+ switch (nd->nodetype) {
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ memset(&params2, 0, sizeof(params2));
+ params2.x0 = cint64_one;
+ params2.nd = nd;
+ params2.xC = 0;
+
+ type = NULL;
+ if (IS_TYPE_POINTER(nd->rtype))
+ type = TPTR_TARGET(nd->rtype);
+ else if (IS_TYPE_MEMBERPOINTER(nd->rtype))
+ type = TYPE_MEMBER_POINTER(nd->rtype)->ty1;
+
+ if (type)
+ CInt64_SetLong(&params2.x0, type->size);
+
+ if (!CInt64_IsZero(&params2.x0)) {
+ LocationSetSet_ForEach(params.srcs, EvalAssignAction2, &params2);
+ if (params2.xC) {
+ LocationSetSet_Term(params.srcs);
+ LocationSetSet_Init(params.srcs);
+ params.x15 |= EvalExpr(params.srcs, proc, nd->u.monadic, &stCallingContextStack, map, ptf);
+ if (!LocationSetSet_FindUnknown(params.srcs))
+ LocationSetSet_ForEach(params.srcs, EvalExprAction2, (void *) &cint64_one);
+ }
+ }
+ break;
+
+ default:
+ LocationSetSet_Term(params.srcs);
+ LocationSetSet_Init(params.srcs);
+ LocationSetSet_AddUnknown(params.srcs, nd->rtype, NULL, NULL);
+ break;
+ }
+ } else {
+ CError_FATAL(5006);
+ }
+
+ if (LocationSetSet_Count(params.srcs) != 0) {
+ PointsToFunction *pointsToFunc;
+
+ pointsToFunc = PointsToFunction_New();
+ if (nd->pointsToFunction)
+ PointsToFunction_Copy(pointsToFunc, nd->pointsToFunction);
+ else
+ PointsToFunction_Init(pointsToFunc);
+
+ params.x14 = LocationSetSet_Count(set) == 1;
+ LocationSetSet_ForEach(set, EvalAssignAction, &params);
+
+ if (!params.x15 && params.x16) {
+ if (nd->pointsToFunction)
+ params.x15 = !PointsToFunctions_Equal(pointsToFunc, nd->pointsToFunction);
+ else
+ params.x15 = PointsToFunction_FindFirst(pointsToFunc) != NULL;
+ }
+
+ PointsToFunction_Term(pointsToFunc);
+ PointsToFunction_Delete(pointsToFunc);
+ }
+
+ LocationSetSet_Term(set);
+ LocationSetSet_Term(params.srcs);
+ LocationSetSet_Delete(set);
+ LocationSetSet_Delete(params.srcs);
+
+ return params.x15;
+}
+
+static Boolean EvalReturn(Object *proc, IROLinear *nd, IRONode *fnode, ParamMappingFunction *map, PartialTransferFunction *ptf) {
+ EvalAssignActionParams params;
+ LocationSet *loc;
+
+ IRO_ASSERT(5046, proc != NULL);
+ IRO_ASSERT(5047, nd != NULL);
+ IRO_ASSERT(5048, nd->type == IROLinearReturn);
+ IRO_ASSERT(5049, fnode != NULL);
+ IRO_ASSERT(5050, map != NULL);
+ IRO_ASSERT(5051, ptf != NULL);
+
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.ptf = ptf;
+ params.nd = nd;
+ params.fnode = fnode;
+ params.x15 = 0;
+ params.x16 = 0;
+
+ if (nd->u.monadic) {
+ params.srcs = LocationSetSet_New();
+ LocationSetSet_Init(params.srcs);
+
+ loc = PartialTransferFunction_returnLocation(ptf);
+ params.x15 |= EvalExpr(params.srcs, proc, nd->u.monadic, &stCallingContextStack, map, ptf);
+
+ if (LocationSetSet_Count(params.srcs) != 0) {
+ params.x14 = 1;
+ EvalAssignAction(loc, &params);
+ params.x15 |= params.x16;
+ }
+
+ LocationSetSet_Term(params.srcs);
+ LocationSetSet_Delete(params.srcs);
+ }
+
+ return params.x15;
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct ApplySummaryActionParams {
+ ParamMappingFunction *tgtMap;
+ Object *proc;
+ IRONode *fnode;
+ IROLinear *nd;
+ PartialTransferFunction *ptf;
+ ParamMappingFunction *map;
+ LocationSet *loc;
+ LocationSetSet *locs;
+ Boolean x20;
+ Boolean x21;
+ Boolean x22;
+} ApplySummaryActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void ApplySummaryAction2(ParamMapping *mapping, void *refcon) {
+ ApplySummaryActionParams *params;
+ PAMemoryBlock *block;
+ ExtendedParam *ep;
+ IROLinear *nd;
+ LocationSetSet *set;
+ EvalAssignActionParams assignParams;
+
+ IRO_ASSERT(5108, mapping != NULL);
+ IRO_ASSERT(5109, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(5113, params->tgtMap != NULL);
+ IRO_ASSERT(5114, params->proc != NULL);
+ IRO_ASSERT(5115, params->fnode != NULL);
+ IRO_ASSERT(5116, params->nd != NULL);
+ IRO_ASSERT(5117, params->nd->type == IROLinearFunccall);
+ IRO_ASSERT(5118, params->ptf != NULL);
+ IRO_ASSERT(5119, params->map != NULL);
+ IRO_ASSERT(5120, params->loc != NULL);
+ IRO_ASSERT(5121, params->locs != NULL);
+
+ block = LocationSet_block(params->loc);
+
+ IRO_ASSERT(5124, block != NULL);
+ IRO_ASSERT(5125, PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM);
+
+ ep = PAMemoryBlock_thing(block);
+
+ IRO_ASSERT(5127, ep != NULL);
+
+ if (ParamMapping_extended(mapping) == ep && (nd = ParamMapping_actual(mapping))) {
+ set = LocationSetSet_New();
+ LocationSetSet_Init(set);
+ params->x21 |= EvalExpr(set, params->proc, nd, &stCallingContextStack, params->map, params->ptf);
+
+ if (!LocationSetSet_FindUnknown(set)) {
+ CInt64 stride64;
+ CInt64 value;
+
+ value = LocationSet_field(params->loc);
+ LocationSetSet_ForEach(set, EvalExprAction, &value);
+
+ CInt64_SetULong(&stride64, LocationSet_stride(params->loc));
+ LocationSetSet_ForEach(set, EvalExprAction2, &stride64);
+ }
+
+ memset(&assignParams, 0, sizeof(assignParams));
+ assignParams.proc = params->proc;
+ assignParams.ptf = params->ptf;
+ assignParams.nd = params->nd;
+ assignParams.fnode = params->fnode;
+ assignParams.srcs = params->locs;
+ assignParams.x14 = params->x20 && (LocationSetSet_Count(set) == 1);
+ assignParams.x15 = 0;
+ assignParams.x16 = 0;
+ LocationSetSet_ForEach(set, EvalAssignAction, &assignParams);
+
+ LocationSetSet_Term(set);
+ LocationSetSet_Delete(set);
+
+ params->x21 |= assignParams.x15;
+ params->x22 |= assignParams.x16;
+ }
+}
+
+static void ApplySummaryAction(PointsToEntry *pte, void *refcon) {
+ ApplySummaryActionParams *params;
+ LocationSet *loc;
+ PAMemoryBlock *block;
+
+ IRO_ASSERT(5175, pte != NULL);
+ IRO_ASSERT(5176, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(5180, params->tgtMap != NULL);
+ IRO_ASSERT(5181, params->proc != NULL);
+ IRO_ASSERT(5182, params->fnode != NULL);
+ IRO_ASSERT(5183, params->nd != NULL);
+ IRO_ASSERT(5184, params->nd->type == IROLinearFunccall);
+ IRO_ASSERT(5185, params->ptf != NULL);
+ IRO_ASSERT(5186, params->map != NULL);
+
+ loc = PointsToEntry_loc(pte);
+
+ IRO_ASSERT(5189, loc != NULL);
+ IRO_ASSERT(5190, !LocationSet_IsUnknown(loc));
+
+ block = LocationSet_block(loc);
+ if (block && PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) {
+ params->loc = loc;
+ params->locs = PointsToEntry_locs(pte);
+ pmf_sub_487C70(params->tgtMap, ApplySummaryAction2, params);
+ }
+}
+
+static Boolean ApplySummary(PartialTransferFunction *tgtPTF, ParamMappingFunction *tgtMap, Object *proc, IRONode *fnode, IROLinear *nd, PartialTransferFunction *ptf, ParamMappingFunction *map, Boolean flag) {
+ Boolean result;
+ ApplySummaryActionParams params;
+ PointsToFunction *pointsToFunc;
+
+ IRO_ASSERT(5208, tgtPTF != NULL);
+ IRO_ASSERT(5209, tgtMap != NULL);
+ IRO_ASSERT(5210, proc != NULL);
+ IRO_ASSERT(5211, fnode != NULL);
+ IRO_ASSERT(5212, nd != NULL);
+ IRO_ASSERT(5213, nd->type == IROLinearFunccall);
+ IRO_ASSERT(5214, ptf != NULL);
+ IRO_ASSERT(5215, map != NULL);
+
+ StoreReturnedLocations(nd, tgtPTF, tgtMap);
+ if (tgtPTF == stUnknownPTF) {
+ result = KillAllAddressableLocations(proc, fnode, nd, ptf);
+ } else {
+ pointsToFunc = PointsToFunction_New();
+ if (nd->pointsToFunction)
+ PointsToFunction_Copy(pointsToFunc, nd->pointsToFunction);
+ else
+ PointsToFunction_Init(pointsToFunc);
+
+ memset(&params, 0, sizeof(params));
+ params.tgtMap = tgtMap;
+ params.proc = proc;
+ params.fnode = fnode;
+ params.nd = nd;
+ params.ptf = ptf;
+ params.map = map;
+ params.loc = NULL;
+ params.locs = NULL;
+ params.x20 = flag;
+ params.x21 = 0;
+ params.x22 = 0;
+
+ PointsToFunction_ForEach(PartialTransferFunction_finalPointsToFn(tgtPTF), ApplySummaryAction, &params);
+
+ result = params.x21;
+ if (!params.x21 && params.x22) {
+ if (nd->pointsToFunction)
+ result = !PointsToFunctions_Equal(pointsToFunc, nd->pointsToFunction);
+ else
+ result = PointsToFunction_FindFirst(pointsToFunc) != NULL;
+ }
+ }
+
+ return result;
+}
+
+static void GetPTFAction2(ParamMapping *mapping, void *refcon) {
+ IRO_ASSERT(5331, mapping != NULL);
+
+ if (ParamMapping_extended(mapping))
+ ParamMapping_SetExtended(mapping, NULL);
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct GetPTFActionParams {
+ ParamMappingFunction *map;
+ Object *proc;
+ IROLinear *nd;
+ PartialTransferFunction *ptf;
+ Boolean *needVisit;
+ PartialTransferFunction *x14;
+ PartialTransferFunction *x18;
+} GetPTFActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void GetPTFAction(PartialTransferFunction *tgtPTF, void *refcon) {
+ GetPTFActionParams *params;
+
+ IRO_ASSERT(5359, tgtPTF != NULL);
+ IRO_ASSERT(5360, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(5364, params->map != NULL);
+ IRO_ASSERT(5365, params->proc != NULL);
+ IRO_ASSERT(5366, params->proc != &stUnknown);
+ IRO_ASSERT(5367, params->nd != NULL);
+ IRO_ASSERT(5368, params->ptf != NULL);
+ IRO_ASSERT(5369, params->needVisit != NULL);
+
+ if (!params->x18) {
+ if (MatchPTF(tgtPTF, params->proc, params->map, params->nd, params->ptf)) {
+ if (InputsHaveNewPointerValues(tgtPTF, params->ptf))
+ *params->needVisit = 1;
+ params->x18 = tgtPTF;
+ } else {
+ pmf_sub_487C70(params->map, GetPTFAction2, NULL);
+ if (PTF_sub_48B980(tgtPTF) == params->nd && PTF_sub_48B970(tgtPTF) == params->ptf)
+ params->x14 = tgtPTF;
+ }
+ }
+}
+
+static PartialTransferFunction *GetPTF(ParamMappingFunction *map, Object *proc, IROLinear *nd, PartialTransferFunction *ptf, Boolean *needVisit) {
+ PartialTransferFunction *found;
+ PartialTransferFunction *result;
+ GetPTFActionParams params;
+
+ IRO_ASSERT(5396, map != NULL);
+ IRO_ASSERT(5397, proc != NULL);
+ IRO_ASSERT(5398, nd != NULL);
+ IRO_ASSERT(5399, ptf != NULL);
+ IRO_ASSERT(5400, needVisit != NULL);
+
+ if (proc == &stUnknown) {
+ result = stUnknownPTF;
+ } else {
+ memset(&params, 0, sizeof(params));
+ params.map = map;
+ params.proc = proc;
+ params.nd = nd;
+ params.ptf = PartialTransferFunction_New();
+ PartialTransferFunction_Init(params.ptf, nd, ptf);
+ params.needVisit = needVisit;
+ params.x14 = NULL;
+ params.x18 = NULL;
+
+ if (!proc->u.func.ptfList) {
+ proc->u.func.ptfList = PTFList_New();
+ PTFList_Init(proc->u.func.ptfList);
+ }
+
+ PTFList_ForEach(proc->u.func.ptfList, GetPTFAction, &params);
+
+ found = params.x18;
+ if (found && !*needVisit) {
+ PartialTransferFunction_Copy(result = PartialTransferFunction_New(), found);
+ } else {
+ result = stUnknownPTF;
+ }
+
+ PartialTransferFunction_Term(params.ptf);
+ PartialTransferFunction_Delete(params.ptf);
+ }
+
+ return result;
+}
+
+static Boolean IsMeetNode(IRONode *fnode, IROLinear *nd) {
+ return (fnode->numpred > 1) && (fnode->first == nd);
+}
+
+static Boolean IsExitNode(Object *proc, IRONode *fnode) {
+ IRO_ASSERT(5467, proc != NULL);
+ IRO_ASSERT(5468, fnode != NULL);
+
+ return (fnode->numsucc == 0) && Bv_IsBitSet(FunctionFirstNode(proc)->index, fnode->dom);
+}
+
+static Boolean SomePredecessorHasBeenVisited(Object *proc, IRONode *fnode) {
+ UInt16 i;
+
+ IRO_ASSERT(5479, proc != NULL);
+ IRO_ASSERT(5480, fnode != NULL);
+
+ for (i = 0; i < fnode->numpred; i++) {
+ if (FunctionNodeTable(proc)[fnode->pred[i]]->x3C)
+ return 1;
+ }
+
+ return 0;
+}
+
+static Boolean AllPredecessorsHaveBeenVisited(Object *proc, IRONode *fnode) {
+ UInt16 i;
+
+ IRO_ASSERT(0, proc != NULL);
+ IRO_ASSERT(0, fnode != NULL);
+
+ for (i = 0; i < fnode->numpred; i++) {
+ if (!FunctionNodeTable(proc)[fnode->pred[i]]->x3C)
+ return 0;
+ }
+
+ return 1;
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct EvalProcActionParams {
+ Object *proc;
+ IRONode *fnode;
+ PartialTransferFunction *ptf;
+} EvalProcActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void EvalProcAction2(PointsToEntry *pte, void *refcon) {
+ EvalProcActionParams *params;
+ LocationSet *dst;
+ PAMemoryBlock *block;
+ LocationSetSet *set;
+ IRONode *node;
+
+ IRO_ASSERT(5525, pte != NULL);
+ IRO_ASSERT(5526, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(5530, params->proc != NULL);
+ IRO_ASSERT(5531, params->fnode != NULL);
+ IRO_ASSERT(5532, params->ptf != NULL);
+
+ dst = PointsToEntry_loc(pte);
+
+ IRO_ASSERT(5535, dst != NULL);
+ IRO_ASSERT(5536, !LocationSet_IsUnknown(dst));
+
+ block = LocationSet_block(dst);
+
+ if (block && (LocationSet_sub_48AF30(dst) || PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM)) {
+ set = LocationSetSet_New();
+ LocationSetSet_Init(set);
+ LocationSetSet_AddSet(set, PointsToEntry_locs(pte));
+
+ for (node = FunctionFirstNode(params->proc); node; node = node->nextnode) {
+ if (node->x3C && node != params->fnode && IsExitNode(params->proc, node)) {
+ if (node->last->pointsToFunction)
+ Lookup(set, &stCallingContextStack, params->proc, NULL, params->ptf, dst, node->last->pointsToFunction, 0, NULL);
+ }
+ }
+
+ Assign(params->ptf, dst, set, params->proc, NULL, NULL);
+
+ LocationSetSet_Term(set);
+ LocationSetSet_Delete(set);
+ }
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct AssignEachInPointsToFunctionActionParams {
+ Object *proc;
+ IROLinear *nd;
+ IRONode *fnode;
+ PartialTransferFunction *ptf;
+ Boolean x10;
+} AssignEachInPointsToFunctionActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void AssignEachInPointsToFunctionAction(PointsToEntry *pte, void *refcon) {
+ AssignEachInPointsToFunctionActionParams *params;
+ LocationSet *dst;
+ LocationSetSet *srcs;
+
+ IRO_ASSERT(5577, pte != NULL);
+ IRO_ASSERT(5578, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(5582, params->proc != NULL);
+ IRO_ASSERT(5583, params->nd != NULL);
+ IRO_ASSERT(5584, params->fnode != NULL);
+ IRO_ASSERT(5585, params->ptf != NULL);
+
+ dst = PointsToEntry_loc(pte);
+
+ srcs = LocationSetSet_New();
+ LocationSetSet_Init(srcs);
+ LocationSetSet_AddSet(srcs, PointsToEntry_locs(pte));
+ params->x10 |= Assign(params->ptf, dst, srcs, params->proc, params->nd, params->fnode);
+ LocationSetSet_Term(srcs);
+ LocationSetSet_Delete(srcs);
+}
+
+static void AssignEachInPointsToFunction(PointsToFunction *pointsTo, void *refcon) {
+ AssignEachInPointsToFunctionActionParams *params;
+ PointsToFunction *pointsToFunc;
+
+ IRO_ASSERT(5602, pointsTo != NULL);
+ IRO_ASSERT(5603, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(5607, params->nd != NULL);
+
+ pointsToFunc = PointsToFunction_New();
+ if (params->nd->pointsToFunction)
+ PointsToFunction_Copy(pointsToFunc, params->nd->pointsToFunction);
+ else
+ PointsToFunction_Init(pointsToFunc);
+
+ if (PointsToFunction_FindFirst(pointsToFunc)) {
+ PointsToFunction_ForEach(pointsTo, AssignEachInPointsToFunctionAction, params);
+ } else {
+ if (!params->nd->pointsToFunction)
+ params->nd->pointsToFunction = PointsToFunction_New();
+ else
+ PointsToFunction_Term(params->nd->pointsToFunction);
+
+ PointsToFunction_Copy(params->nd->pointsToFunction, pointsTo);
+ params->x10 = 1;
+ }
+
+ if (params->x10) {
+ if (params->nd->pointsToFunction)
+ params->x10 = !PointsToFunctions_Equal(pointsToFunc, params->nd->pointsToFunction);
+ else
+ params->x10 = PointsToFunction_FindFirst(pointsToFunc) != NULL;
+ }
+
+ PointsToFunction_Term(pointsToFunc);
+ PointsToFunction_Delete(pointsToFunc);
+}
+
+static Boolean ObjectIsAFunctionArgument(Object *proc, Object *obj) {
+ ObjectList *list;
+
+ IRO_ASSERT(5643, proc != NULL);
+ IRO_ASSERT(5644, proc != &stUnknown);
+ IRO_ASSERT(5645, obj != NULL);
+
+ if (obj->datatype == DLOCAL) {
+ for (list = FunctionArguments(proc); list; list = list->next) {
+ if (obj == list->object)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static Boolean ObjectIsARealFunctionArgument(Object *proc, Object *obj) {
+ ObjectList *list;
+
+ IRO_ASSERT(5661, proc != NULL);
+ IRO_ASSERT(5662, proc != &stUnknown);
+ IRO_ASSERT(5663, obj != NULL);
+
+ if (obj->datatype == DLOCAL && proc == cscope_currentfunc) {
+ for (list = arguments; list; list = list->next) {
+ if (obj == list->object)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void AddLocalVarsAddressedByExceptionUses(Object *var) {
+ IRO_ASSERT(5699, var != NULL);
+ IRO_ASSERT(5700, stExceptionFNode != NULL);
+ IRO_ASSERT(5701, stExceptionFNode->addressed != NULL);
+
+ if (var->datatype == DLOCAL)
+ ObjectSet_sub_4867D0(stExceptionFNode->addressed, var);
+}
+
+static Boolean LinearNodeIsInFlowgraphNode(IROLinear *nd, IRONode *fnode) {
+ IROLinear *first;
+ IROLinear *last;
+ IROLinear *scan;
+
+ if (fnode && (first = fnode->first) && (last = fnode->last)) {
+ for (scan = first; scan && scan != last->next; scan = scan->next) {
+ if (scan == nd)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+static struct {
+ Object *proc;
+ IRONode *fnode;
+ ParamMappingFunction *map;
+ PartialTransferFunction *ptf;
+ PointsToFunction *pointsToFunc;
+ Boolean *changed;
+ Boolean x18;
+ Boolean x19;
+} stEvalProcActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void EvalProcAction(IROLinear *Int, Boolean flag) {
+ Boolean *changed;
+ Boolean result;
+ Object *proc;
+ PartialTransferFunction *ptf;
+ Boolean x18;
+ Boolean x19;
+ IRONode *fnode;
+ PointsToFunction *pointsToFunc;
+ ParamMappingFunction *map;
+ Object *obj;
+ AssignEachInPointsToFunctionActionParams params;
+
+ static int userBreakCounter;
+
+ if (!flag && !Int->x1E) {
+ IRO_ASSERT(5748, Int != NULL);
+ IRO_ASSERT(5749, stEvalProcActionParams.changed != NULL);
+
+ proc = stEvalProcActionParams.proc;
+ fnode = stEvalProcActionParams.fnode;
+ map = stEvalProcActionParams.map;
+ ptf = stEvalProcActionParams.ptf;
+ pointsToFunc = stEvalProcActionParams.pointsToFunc;
+ changed = stEvalProcActionParams.changed;
+ x18 = stEvalProcActionParams.x18;
+ x19 = stEvalProcActionParams.x19;
+
+ IRO_ASSERT(5760, proc != NULL);
+ IRO_ASSERT(5761, fnode != NULL);
+ IRO_ASSERT(5762, map != NULL);
+ IRO_ASSERT(5763, ptf != NULL);
+
+ if (++userBreakCounter > 40) {
+ IRO_CheckForUserBreak();
+ userBreakCounter = 0;
+ }
+
+ result = 0;
+
+ if (x19 && Int->pointsToFunction) {
+ PointsToFunction_Term(Int->pointsToFunction);
+ PointsToFunction_Delete(Int->pointsToFunction);
+ Int->pointsToFunction = NULL;
+ }
+
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.nd = Int;
+ params.fnode = fnode;
+ params.ptf = ptf;
+ params.x10 = 0;
+
+ if (x18) {
+ PointsToFunction *initial = PartialTransferFunction_initialPointsToFn(ptf);
+ if (fnode == FunctionFirstNode(proc) && initial) {
+ AssignEachInPointsToFunction(initial, &params);
+ result |= params.x10;
+ }
+ result |= EvalMeet(proc, fnode, Int, ptf);
+ pointsToFunc = Int->pointsToFunction;
+ x18 = 0;
+ } else if (!Int->pointsToFunction) {
+ if (pointsToFunc)
+ AssignEachInPointsToFunction(pointsToFunc, &params);
+ result |= params.x10;
+ pointsToFunc = Int->pointsToFunction;
+ }
+
+ if (IRO_IsAssignment(Int)) {
+ if (Int->flags & IROLF_4000)
+ longjmp(stAbortPointerAnalysis, 1);
+ result |= EvalAssign(proc, Int, fnode, map, ptf);
+ pointsToFunc = Int->pointsToFunction;
+ } else if (Int->type == IROLinearReturn) {
+ result |= EvalReturn(proc, Int, fnode, map, ptf);
+ pointsToFunc = Int->pointsToFunction;
+ } else if (Int->type == IROLinearFunccall) {
+ if (Int->flags & IROLF_4000)
+ longjmp(stAbortPointerAnalysis, 1);
+ if (Int->stmt && IRO_FunctionCallMightThrowException(Int)) {
+ stExceptionFNode = fnode;
+ IRO_WalkExcActions(Int->stmt->dobjstack, AddLocalVarsAddressedByExceptionUses);
+ }
+ result |= EvalCall(proc, fnode, Int, map, ptf);
+ pointsToFunc = Int->pointsToFunction;
+ } else if (Int->type == IROLinearOp1Arg && Int->nodetype == EINDIRECT && (!(Int->flags & IROLF_Assigned) || (Int->flags & IROLF_Used))) {
+ result |= EvalExpr(NULL, proc, Int, &stCallingContextStack, map, ptf);
+ } else if (Int->type == IROLinearOperand && !(Int->flags & IROLF_Ind) && Int->u.node->type == EOBJREF && (obj = Int->u.node->data.objref) && obj->datatype == DLOCAL) {
+ ObjectSet_sub_4867D0(fnode->addressed, obj);
+ } else if (Int->type == IROLinearAsm) {
+ IAEffects effects;
+ int i;
+ CodeGen_GetAsmEffects(Int->u.asm_stmt, &effects);
+ for (i = 0; i < effects.numoperands; i++) {
+ obj = effects.operands[i].object;
+ if (obj && obj->datatype == DLOCAL && effects.operands[i].type == IAEffect_3) {
+ ObjectSet_sub_4867D0(fnode->addressed, obj);
+ }
+ }
+ }
+
+ if (result && Int != fnode->last && fnode->last->pointsToFunction) {
+ PointsToFunction_Term(fnode->last->pointsToFunction);
+ PointsToFunction_Delete(fnode->last->pointsToFunction);
+ fnode->last->pointsToFunction = NULL;
+ }
+
+ *changed |= result;
+ x19 |= result;
+
+ stEvalProcActionParams.pointsToFunc = pointsToFunc;
+ stEvalProcActionParams.x18 = x18;
+ stEvalProcActionParams.x19 = x19;
+
+ Int->x1E = 1;
+
+ if (Int->type != IROLinearReturn) {
+ IROLinear *father = IRO_LocateFather(Int);
+ if (father && father->type == IROLinearReturn) {
+ if (LinearNodeIsInFlowgraphNode(father, fnode))
+ EvalProcAction(father, 0);
+ else
+ longjmp(stAbortPointerAnalysis, 1);
+ }
+ }
+ }
+}
+
+static void EvalProc(Object *proc, ParamMappingFunction *map, PartialTransferFunction *ptf) {
+ IRONode *fnode;
+ IRONode *pred;
+ IROLinear *nd;
+ UInt32 passCount;
+ Boolean changed;
+ UInt16 i;
+ AssignEachInPointsToFunctionActionParams assignParams;
+ EvalProcActionParams params;
+
+ IRO_ASSERT(5964, proc != NULL);
+ IRO_ASSERT(5965, map != NULL);
+ IRO_ASSERT(5966, ptf != NULL);
+
+ for (fnode = FunctionFirstNode(proc); fnode; fnode = fnode->nextnode)
+ fnode->x3C = 0;
+
+ passCount = 0;
+ do {
+ clock();
+ changed = 0;
+ for (fnode = FunctionFirstNode(proc); fnode; fnode = fnode->nextnode) {
+ if (fnode->last && ((fnode->numpred == 0) || SomePredecessorHasBeenVisited(proc, fnode))) {
+ clock();
+ if (!fnode->addressed) {
+ fnode->addressed = ObjectSet_New();
+ ObjectSet_Init(fnode->addressed);
+ }
+
+ for (i = 0; i < fnode->numpred; i++) {
+ pred = FunctionNodeTable(proc)[fnode->pred[i]];
+ if (pred->addressed)
+ ObjectSet_sub_48C590(fnode->addressed, pred->addressed);
+ }
+
+ memset(&stEvalProcActionParams, 0, sizeof(stEvalProcActionParams));
+ stEvalProcActionParams.proc = proc;
+ stEvalProcActionParams.fnode = fnode;
+ stEvalProcActionParams.map = map;
+ stEvalProcActionParams.ptf = ptf;
+ stEvalProcActionParams.pointsToFunc = NULL;
+ stEvalProcActionParams.changed = &changed;
+ stEvalProcActionParams.x18 = 1;
+ stEvalProcActionParams.x19 = 0;
+
+ for (nd = fnode->first; nd && nd != fnode->last->next; nd = nd->next)
+ nd->x1E = 0;
+ IRO_WalkInts(fnode->first, fnode->last, EvalProcAction);
+
+ if (stEvalProcActionParams.x18 || !fnode->last->pointsToFunction) {
+ memset(&assignParams, 0, sizeof(assignParams));
+ assignParams.proc = proc;
+ assignParams.nd = fnode->last;
+ assignParams.fnode = fnode;
+ assignParams.ptf = ptf;
+ assignParams.x10 = 0;
+ if (stEvalProcActionParams.x18) {
+ PointsToFunction *initial = PartialTransferFunction_initialPointsToFn(ptf);
+ if (fnode == FunctionFirstNode(proc) && initial) {
+ AssignEachInPointsToFunction(initial, &assignParams);
+ changed |= assignParams.x10;
+ }
+ changed |= EvalMeet(proc, fnode, fnode->last, ptf);
+ stEvalProcActionParams.x18 = 0;
+ } else {
+ if (stEvalProcActionParams.pointsToFunc)
+ AssignEachInPointsToFunction(stEvalProcActionParams.pointsToFunc, &assignParams);
+ changed |= assignParams.x10;
+ }
+ }
+
+ fnode->x3C = 1;
+ clock();
+ }
+ }
+
+ clock();
+ if (++passCount > 32)
+ CError_FATAL(6072);
+ } while (changed);
+
+ if (passCount > stMaxPassCount)
+ stMaxPassCount = passCount;
+
+ PartialTransferFunction_sub_48A610(ptf, 1);
+
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.ptf = ptf;
+ for (fnode = FunctionFirstNode(proc); fnode; fnode = fnode->nextnode) {
+ if (fnode->x3C && IsExitNode(proc, fnode) && fnode->last->pointsToFunction) {
+ params.fnode = fnode;
+ PointsToFunction_ForEach(fnode->last->pointsToFunction, EvalProcAction2, &params);
+ }
+ }
+}
+
+static void PointerAnalysis_Init(void) {
+ stCallingContextStack = Stack_New();
+ Stack_Init(stCallingContextStack);
+
+ stUnknownPTF = PartialTransferFunction_New();
+ PartialTransferFunction_Init(stUnknownPTF, NULL, NULL);
+
+ stExtParamSet = AllocsExtParamSet_sub_4876C0();
+ InitsExtParamSet_sub_4876A0(stExtParamSet);
+
+ stPTFList = PTFList_New();
+ PTFList_Init(stPTFList);
+}
+
+static void CleanseLocationSet(LocationSet *loc, void *refcon) {
+ PAMemoryBlock *block;
+ PALocalVar *local;
+
+ IRO_ASSERT(6161, loc != NULL);
+ IRO_ASSERT(6162, refcon == NULL);
+
+ if (
+ !LocationSet_IsUnknown(loc) &&
+ (block = LocationSet_block(loc)) &&
+ PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_LOCALVAR &&
+ (local = PAMemoryBlock_thing(block))
+ ) {
+ PALocalVar_SetSth_sub_4847C0(local, NULL);
+ }
+}
+
+static void CleansePointsToEntry(PointsToEntry *pte, void *refcon) {
+ IRO_ASSERT(6177, pte != NULL);
+ IRO_ASSERT(6178, refcon == NULL);
+
+ CleanseLocationSet(PointsToEntry_loc(pte), NULL);
+ LocationSetSet_ForEach(PointsToEntry_locs(pte), CleanseLocationSet, NULL);
+}
+
+static void PointerAnalysis_TermAction4(PartialTransferFunction *ptf, void *refcon) {
+ IRO_ASSERT(6187, ptf != NULL);
+ IRO_ASSERT(6188, refcon == NULL);
+
+ if (ptf != stUnknownPTF) {
+ PointsToFunction_ForEach(PartialTransferFunction_initialPointsToFn(ptf), CleansePointsToEntry, NULL);
+ PointsToFunction_ForEach(PartialTransferFunction_finalPointsToFn(ptf), CleansePointsToEntry, NULL);
+ }
+}
+
+static void PointerAnalysis_TermAction3(ExtendedParam *ep) {
+ ExtendedParam_Term(ep);
+ ExtendedParam_Delete(ep);
+}
+
+static void PointerAnalysis_TermAction2(Object *obj, void *refcon) {
+ ObjectSet *objSet;
+ Object *proc;
+ ObjectList *list;
+
+ objSet = refcon;
+
+ if (!ObjectIsAnExtendedParamCandidate(obj)) {
+ if (
+ obj->datatype == DLOCAL &&
+ obj->u.var.info &&
+ (proc = obj->u.var.info->func) &&
+ ObjectIsAFunction(proc) &&
+ proc->u.func.argList
+ ) {
+ for (list = proc->u.func.argList; list; list = list->next) {
+ if (obj == list->object)
+ break;
+ }
+
+ if (!list)
+ ObjectSet_sub_4867D0(objSet, obj);
+ } else {
+ ObjectSet_sub_4867D0(objSet, obj);
+ }
+ }
+}
+
+static void PointerAnalysis_TermAction1(ExtendedParam *ep, void *refcon) {
+ ObjectSet *objSet;
+ ObjectSet *epObjSet;
+ Object *obj;
+
+ objSet = ObjectSet_New();
+ ObjectSet_Init(objSet);
+
+ epObjSet = ExtendedParam_objectSet(ep);
+ obj = NULL;
+ ObjectSet_ForEach(epObjSet, FindGlobalObjectAction, &obj);
+ if (obj) {
+ ObjectSet_ForEach(epObjSet, PointerAnalysis_TermAction2, objSet);
+ if (ObjectSet_FindFirst(objSet))
+ EP_sub_48C850(ep, objSet);
+ }
+
+ ObjectSet_Term(objSet);
+ ObjectSet_Delete(objSet);
+}
+
+static void PointerAnalysis_Term(void) {
+ if (stExtParamSet) {
+ MaybeWalkExtParamSet_sub_48CBE0(stExtParamSet, PointerAnalysis_TermAction1, NULL);
+ TermsExtParamSet_sub_48CB00(stExtParamSet);
+ FreesExtParamSet_sub_48CAE0(stExtParamSet);
+ stExtParamSet = NULL;
+ }
+
+ if (stPTFList) {
+ PTFList_ForEach(stPTFList, PointerAnalysis_TermAction4, NULL);
+ PTFList_Term(stPTFList);
+ PTFList_Delete(stPTFList);
+ stPTFList = NULL;
+ }
+
+ PartialTransferFunction_Term(stUnknownPTF);
+ PartialTransferFunction_Delete(stUnknownPTF);
+ stUnknownPTF = NULL;
+
+ Stack_Term(&stCallingContextStack);
+ Stack_Delete(stCallingContextStack);
+ stCallingContextStack = NULL;
+}
+
+static void InvalidatePointsToFunctions(Object *proc) {
+ IRONode *fnode;
+ IROLinear *nd;
+
+ IRO_ASSERT(6302, proc != NULL);
+
+ for (fnode = FunctionFirstNode(proc); fnode; fnode = fnode->nextnode) {
+ if (fnode->last) {
+ if (fnode->addressed) {
+ ObjectSet_Term(fnode->addressed);
+ ObjectSet_Delete(fnode->addressed);
+ fnode->addressed = NULL;
+ }
+
+ for (nd = fnode->first; nd && nd != fnode->last->next; nd = nd->next) {
+ if (nd->pointsToFunction) {
+ PointsToFunction_Term(nd->pointsToFunction);
+ PointsToFunction_Delete(nd->pointsToFunction);
+ nd->pointsToFunction = NULL;
+ }
+ }
+ }
+ }
+}
+
+static void InitialSetup(void) {
+}
+
+static void PointerAnalysis_HeapErrorProc(void) {
+ longjmp(stAbortPointerAnalysis, 2);
+}
+
+void PointerAnalysis_Setup(void) {
+ IRO_InitializeAllocator();
+ stExtendedParamNum = 0;
+ stParamObjs = NULL;
+ stMaxPassCount = 0;
+}
+
+void PointerAnalysis_Cleanup(void) {
+ ObjectList *list;
+ ObjectList *next;
+
+ for (list = stParamObjs; list; list = next) {
+ IRO_free(list->object);
+ next = list->next;
+ IRO_free(list);
+ }
+ stParamObjs = NULL;
+ IRO_TerminateAllocator();
+}
+
+void IRO_AnalyzePointers(Object *function) {
+ EvalCallActionParams params;
+ IROLinear nd;
+ IRONode fnode;
+ int code;
+ volatile heaperror_t saveheaperror;
+
+ IRO_ASSERT(6393, function != NULL);
+
+ PointerAnalysis_Init();
+
+ memset(&params, 0, sizeof(params));
+ memset(&nd, 0, sizeof(nd));
+ nd.type = IROLinearFunccall;
+ memset(&fnode, 0, sizeof(fnode));
+ params.proc = &stUnknown;
+ params.fnode = &fnode;
+ params.nd = &nd;
+ params.ptf = stUnknownPTF;
+ params.map = NULL;
+ params.x18 = 0;
+ params.x19 = 0;
+ params.x1A = 1;
+
+ stCurrentProc = FindMainEntryPoint(function);
+
+ if ((code = setjmp(stAbortPointerAnalysis)) == 0) {
+ saveheaperror = getheaperror();
+ setheaperror(PointerAnalysis_HeapErrorProc);
+ InitialSetup();
+ EvalCallAction(stCurrentProc, &params);
+ PointerAnalysis_Term();
+ stCurrentProc = NULL;
+ setheaperror(saveheaperror);
+ } else {
+ setheaperror(saveheaperror);
+ InvalidatePointsToFunctions(stCurrentProc);
+ PointerAnalysis_Term();
+ stCurrentProc = NULL;
+ if (code == 2 && saveheaperror)
+ saveheaperror();
+ }
+}
+
+static void RemoveRestrictedExtendedParamsAction(LocationSet *ls, void *refcon) {
+ LocationSetSet *locs;
+ PAMemoryBlock *block;
+ ExtendedParam *ep;
+ ObjectSet *objSet;
+ Object *obj;
+
+ locs = refcon;
+
+ if (
+ !LocationSet_IsUnknown(ls) &&
+ (block = LocationSet_block(ls)) &&
+ PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM &&
+ (ep = PAMemoryBlock_thing(block))
+ ) {
+ objSet = ExtendedParam_objectSet(ep);
+ if (
+ ObjectSet_Count(objSet) == 1 &&
+ (obj = ObjectSet_FindFirst(objSet)) &&
+ ObjectIsRestrictQualified(obj)
+ ) {
+ LocationSetSet_Add(locs, ls);
+ }
+ }
+}
+
+static void RemoveRestrictedExtendedParams(LocationSetSet *locs) {
+ LocationSetSet *set;
+
+ set = LocationSetSet_New();
+ LocationSetSet_Init(set);
+ LocationSetSet_ForEach(locs, RemoveRestrictedExtendedParamsAction, set);
+ LocationSetSet_sub_488700(locs, set);
+ LocationSetSet_Term(set);
+ LocationSetSet_Delete(set);
+}
+
+Boolean PointerAnalysis_TwoLinearNodePointerExprsMightAlias(Object *proc, IROLinear *nd1, IROLinear *nd2) {
+ LocationSetSet *lss1;
+ LocationSetSet *lss2;
+ PointsToFunction *pointsTo1;
+ PointsToFunction *pointsTo2;
+ PointsToFunction *savePointsTo1;
+ PointsToFunction *savePointsTo2;
+ FindAliasingParams params;
+
+ pointsTo1 = nd1->pointsToFunction;
+ pointsTo2 = nd2->pointsToFunction;
+ if (!pointsTo1)
+ pointsTo1 = pointsTo2;
+ if (!pointsTo2)
+ pointsTo2 = pointsTo1;
+
+ if (copts.opt_pointer_analysis_mode == 2 && !is_typeequal(nd1->rtype, nd2->rtype))
+ return 0;
+ if (!pointsTo1 || !pointsTo2)
+ return 1;
+
+ lss1 = LocationSetSet_New();
+ LocationSetSet_Init(lss1);
+ lss2 = LocationSetSet_New();
+ LocationSetSet_Init(lss2);
+
+ savePointsTo1 = nd1->pointsToFunction;
+ nd1->pointsToFunction = pointsTo1;
+ EvalExpr(lss1, proc, nd1, NULL, NULL, NULL);
+ nd1->pointsToFunction = savePointsTo1;
+
+ savePointsTo2 = nd2->pointsToFunction;
+ nd2->pointsToFunction = pointsTo2;
+ EvalExpr(lss2, proc, nd2, NULL, NULL, NULL);
+ nd2->pointsToFunction = savePointsTo2;
+
+ memset(&params, 0, sizeof(params));
+ params.x8 = 0;
+ params.x0 = lss2;
+ LocationSetSet_ForEach(lss1, FindAliasingAction, &params);
+
+ if (!params.x8) {
+ params.x0 = lss1;
+ LocationSetSet_ForEach(lss2, FindAliasingAction, &params);
+
+ if (!params.x8) {
+ RemoveRestrictedExtendedParams(lss1);
+ RemoveRestrictedExtendedParams(lss2);
+ ExpandLocationSetSetToActuals(&stCallingContextStack, NULL, lss1);
+ ExpandLocationSetSetToActuals(&stCallingContextStack, NULL, lss2);
+
+ params.x0 = lss2;
+ LocationSetSet_ForEach(lss1, FindAliasingAction, &params);
+
+ if (!params.x8) {
+ params.x0 = lss1;
+ LocationSetSet_ForEach(lss2, FindAliasingAction, &params);
+ }
+ }
+ }
+
+ LocationSetSet_Term(lss1);
+ LocationSetSet_Delete(lss1);
+ LocationSetSet_Term(lss2);
+ LocationSetSet_Delete(lss2);
+
+ return params.x8;
+}
+
+Boolean PointerAnalysis_TwoENodePointerExprsMightAlias(Object *proc, ENode *nd1, ENode *nd2) {
+ LocationSetSet *lss1;
+ LocationSetSet *lss2;
+ PointsToFunction *pointsTo1;
+ PointsToFunction *pointsTo2;
+ PointsToFunction *savePointsTo1;
+ PointsToFunction *savePointsTo2;
+ FindAliasingParams params;
+
+ pointsTo1 = nd1->pointsTo;
+ pointsTo2 = nd2->pointsTo;
+ if (!pointsTo1)
+ pointsTo1 = pointsTo2;
+ if (!pointsTo2)
+ pointsTo2 = pointsTo1;
+
+ if (copts.opt_pointer_analysis_mode == 2 && !is_typeequal(nd1->rtype, nd2->rtype))
+ return 0;
+ if (!pointsTo1 || !pointsTo2)
+ return 1;
+
+ lss1 = LocationSetSet_New();
+ LocationSetSet_Init(lss1);
+ lss2 = LocationSetSet_New();
+ LocationSetSet_Init(lss2);
+
+ savePointsTo1 = nd1->pointsTo;
+ nd1->pointsTo = pointsTo1;
+ EvalENodeExpr(lss1, proc, nd1, NULL, NULL, NULL);
+ nd1->pointsTo = savePointsTo1;
+
+ savePointsTo2 = nd2->pointsTo;
+ nd2->pointsTo = pointsTo2;
+ EvalENodeExpr(lss2, proc, nd2, NULL, NULL, NULL);
+ nd2->pointsTo = savePointsTo2;
+
+ memset(&params, 0, sizeof(params));
+ params.x8 = 0;
+ params.x0 = lss2;
+ LocationSetSet_ForEach(lss1, FindAliasingAction, &params);
+
+ if (!params.x8) {
+ params.x0 = lss1;
+ LocationSetSet_ForEach(lss2, FindAliasingAction, &params);
+
+ if (!params.x8) {
+ RemoveRestrictedExtendedParams(lss1);
+ RemoveRestrictedExtendedParams(lss2);
+ ExpandLocationSetSetToActuals(&stCallingContextStack, NULL, lss1);
+ ExpandLocationSetSetToActuals(&stCallingContextStack, NULL, lss2);
+
+ params.x0 = lss2;
+ LocationSetSet_ForEach(lss1, FindAliasingAction, &params);
+
+ if (!params.x8) {
+ params.x0 = lss1;
+ LocationSetSet_ForEach(lss2, FindAliasingAction, &params);
+ }
+ }
+ }
+
+ LocationSetSet_Term(lss1);
+ LocationSetSet_Delete(lss1);
+ LocationSetSet_Term(lss2);
+ LocationSetSet_Delete(lss2);
+
+ return params.x8;
+}
+
+Boolean PointerAnalysis_IsLinearNodePointerExprDefinite(Object *proc, IROLinear *nd) {
+ LocationSetSet *lss;
+ LocationSet *loc;
+ Boolean result;
+
+ if (!nd->pointsToFunction)
+ return 0;
+
+ lss = LocationSetSet_New();
+ LocationSetSet_Init(lss);
+ EvalExpr(lss, proc, nd, NULL, NULL, NULL);
+
+ result =
+ (LocationSetSet_Count(lss) == 1) &&
+ (loc = LocationSetSet_FindFirst(lss)) &&
+ LocationSetRepresentsSingleLocation(loc, NULL, NULL);
+
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+
+ return result;
+}
+
+Boolean PointerAnalysis_IsENodePointerExprDefinite(Object *proc, ENode *nd) {
+ LocationSetSet *lss;
+ LocationSet *loc;
+ Boolean result;
+
+ if (!nd->pointsTo)
+ return 0;
+
+ lss = LocationSetSet_New();
+ LocationSetSet_Init(lss);
+ EvalENodeExpr(lss, proc, nd, NULL, NULL, NULL);
+
+ result =
+ (LocationSetSet_Count(lss) == 1) &&
+ (loc = LocationSetSet_FindFirst(lss)) &&
+ LocationSetRepresentsSingleLocation(loc, NULL, NULL);
+
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+
+ return result;
+}
+
+Boolean PointerAnalysis_IsVariableValueDefinite(Object *proc, VarRecord *var, PointsToFunction *pointsTo) {
+ LocationSetSet *lss;
+ LocationSet *loc;
+ Boolean result;
+
+ if (!pointsTo)
+ return 0;
+
+ lss = LocationSetSet_New();
+ LocationSetSet_Init(lss);
+ EvalVariable(lss, proc, var, pointsTo, NULL, NULL, NULL);
+
+ result =
+ (LocationSetSet_Count(lss) == 1) &&
+ (loc = LocationSetSet_FindFirst(lss)) &&
+ LocationSetRepresentsSingleLocation(loc, NULL, NULL);
+
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+
+ return result;
+}
+
+static void FindGlobalObjectAction(Object *object, void *refcon) {
+ if (ObjectIsAnExtendedParamCandidate(object)) {
+ Object **ptr = refcon;
+ *ptr = object;
+ }
+}
+
+static void GetDefiniteObjectOfExtendedParamLoc(LocationSet *loc, Object **resultObj, CInt64 *resultField) {
+ Object *obj;
+ CInt64 field;
+ PAMemoryBlock *block;
+ ExtendedParam *ep;
+ ObjectSet *objSet;
+ LocationSetSet *locs;
+ LocationSet *tmp;
+ PALocalVar *local;
+
+ IRO_ASSERT(6763, loc != NULL);
+ IRO_ASSERT(6764, resultObj != NULL);
+ IRO_ASSERT(6765, resultField != NULL);
+
+ obj = NULL;
+ field = LocationSet_field(loc);
+ block = LocationSet_block(loc);
+
+ if (block && PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) {
+ if ((ep = PAMemoryBlock_thing(block)) && (objSet = ExtendedParam_objectSet(ep))) {
+ IRO_ASSERT(6777, obj == NULL);
+ ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj);
+ }
+ }
+
+ if (!obj) {
+ locs = LocationSetSet_New();
+ LocationSetSet_Init(locs);
+ GetActualLocsOfExtendedParam(locs, loc, NULL, &stCallingContextStack, NULL, 0);
+
+ if (
+ LocationSetSet_Count(locs) == 1 &&
+ (tmp = LocationSetSet_FindFirst(locs)) &&
+ !LocationSet_IsUnknown(tmp))
+ {
+ field = CInt64_Add(field, LocationSet_field(tmp));
+ if (
+ (block = LocationSet_block(tmp)) &&
+ PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM &&
+ (ep = PAMemoryBlock_thing(block)) &&
+ (objSet = ExtendedParam_objectSet(ep))
+ )
+ {
+ IRO_ASSERT(6801, obj == NULL);
+ ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj);
+ } else if (
+ (block = LocationSet_block(tmp)) &&
+ PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_LOCALVAR &&
+ (local = PAMemoryBlock_thing(block))
+ )
+ {
+ obj = GetLocalObject(local, &stUnknown, 0);
+ }
+ }
+
+ LocationSetSet_Term(locs);
+ LocationSetSet_Delete(locs);
+ }
+
+ *resultObj = obj;
+ *resultField = field;
+}
+
+static void CreateExpressionForLocationSet(LocationSet *loc, IROList *list, Type *rtype, Object *proc) {
+ CInt64 field;
+ PAMemoryBlock *block;
+ PAMemoryBlockKind kind;
+ void *thing;
+ IROLinear *nd;
+ Object *obj;
+
+ IRO_ASSERT(6833, loc != NULL);
+ IRO_ASSERT(6834, !LocationSet_IsUnknown(loc));
+ IRO_ASSERT(6835, LocationSet_stride(loc) == 0);
+ IRO_ASSERT(6836, list != NULL);
+ IRO_ASSERT(6837, rtype != NULL);
+ IRO_ASSERT(6838, proc != NULL);
+
+ field = LocationSet_field(loc);
+ block = LocationSet_block(loc);
+ kind = PAMemoryBlock_kind(block);
+ thing = PAMemoryBlock_thing(block);
+ nd = NULL;
+
+ switch (kind) {
+ case PAMEMORYBLOCKKIND_EXTENDEDPARAM:
+ GetDefiniteObjectOfExtendedParamLoc(loc, &obj, &field);
+ if (obj) {
+ nd = IRO_NewLinear(IROLinearOperand);
+ nd->u.node = create_objectrefnode(obj);
+ nd->rtype = rtype;
+ nd->index = ++IRO_NumLinear;
+ IRO_AddToList(nd, list);
+ }
+ break;
+ case PAMEMORYBLOCKKIND_LOCALVAR:
+ obj = GetLocalObject(thing, proc, 0);
+ if (obj) {
+ if (ObjectIsAFunctionArgument(proc, obj) && obj->u.var.realObj)
+ obj = obj->u.var.realObj;
+ nd = IRO_NewLinear(IROLinearOperand);
+ nd->u.node = create_objectrefnode(obj);
+ nd->rtype = rtype;
+ nd->index = ++IRO_NumLinear;
+ IRO_AddToList(nd, list);
+ }
+ break;
+ case PAMEMORYBLOCKKIND_INT:
+ if (IS_TYPE_INT(rtype)) {
+ nd = IRO_NewIntConst(*((CInt64 *) thing), rtype);
+ IRO_AddToList(nd, list);
+ }
+ break;
+ case PAMEMORYBLOCKKIND_6:
+ break;
+ default:
+ CError_FATAL(6894);
+ }
+
+ if (nd && !CInt64_IsZero(&field)) {
+ IROLinear *nd2;
+ IROLinear *nd3;
+
+ nd2 = IRO_NewIntConst(field, TYPE(&stunsignedlong));
+ IRO_AddToList(nd2, list);
+
+ nd3 = IRO_NewLinear(IROLinearOp2Arg);
+ nd3->nodetype = EADD;
+ nd3->index = ++IRO_NumLinear;
+ nd3->rtype = rtype;
+ nd3->u.diadic.left = nd;
+ nd3->u.diadic.right = nd2;
+ IRO_AddToList(nd3, list);
+ }
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct LookupLinearExprActionParams {
+ Object *proc;
+ Type *indirectType;
+ IROListNode **list;
+} LookupLinearExprActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void LookupLinearExprAction(LocationSet *loc, void *refcon) {
+ LookupLinearExprActionParams *params;
+ IROListNode *list;
+
+ IRO_ASSERT(6926, loc != NULL);
+ IRO_ASSERT(6927, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(6931, params->proc != NULL);
+ IRO_ASSERT(6932, params->indirectType != NULL);
+ IRO_ASSERT(6933, params->list != NULL);
+
+ list = *params->list = IRO_malloc(sizeof(IROListNode));
+ IRO_InitList(&list->list);
+ list->nextList = NULL;
+
+ if (!LocationSet_IsUnknown(loc) && LocationSetRepresentsSingleLocation(loc, NULL, NULL))
+ CreateExpressionForLocationSet(loc, &list->list, params->indirectType, params->proc);
+
+ params->list = &list->nextList;
+}
+
+void PointerAnalysis_LookupLinearNodePointerExpr(Object *proc, IROLinear *indirect, IROListNode **list) {
+ LocationSetSet *set;
+ LookupLinearExprActionParams params;
+
+ IRO_ASSERT(6957, indirect != NULL);
+
+ if (indirect->pointsToFunction) {
+ set = LocationSetSet_New();
+ LocationSetSet_Init(set);
+ EvalExpr(set, proc, indirect, NULL, NULL, NULL);
+
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.indirectType = indirect->rtype;
+ params.list = list;
+
+ LocationSetSet_ForEach(set, LookupLinearExprAction, &params);
+ LocationSetSet_Term(set);
+ LocationSetSet_Delete(set);
+ }
+}
+
+static void CreateENodeForLocationSet(LocationSet *loc, ENode **resultNode, Type *rtype, Object *proc) {
+ CInt64 field;
+ PAMemoryBlock *block;
+ PAMemoryBlockKind kind;
+ void *thing;
+ ENode *nd;
+ Object *obj;
+
+ IRO_ASSERT(0, loc != NULL);
+ IRO_ASSERT(0, !LocationSet_IsUnknown(loc));
+ IRO_ASSERT(0, LocationSet_stride(loc) == 0);
+ IRO_ASSERT(0, resultNode != NULL);
+ IRO_ASSERT(0, rtype != NULL);
+ IRO_ASSERT(0, proc != NULL);
+
+ field = LocationSet_field(loc);
+ block = LocationSet_block(loc);
+ kind = PAMemoryBlock_kind(block);
+ thing = PAMemoryBlock_thing(block);
+ nd = NULL;
+
+ switch (kind) {
+ case PAMEMORYBLOCKKIND_EXTENDEDPARAM:
+ GetDefiniteObjectOfExtendedParamLoc(loc, &obj, &field);
+ if (obj) {
+ nd = create_objectrefnode(obj);
+ nd->rtype = rtype;
+ }
+ break;
+ case PAMEMORYBLOCKKIND_LOCALVAR:
+ obj = GetLocalObject(thing, proc, 0);
+ if (obj) {
+ if (ObjectIsAFunctionArgument(proc, obj) && obj->u.var.realObj)
+ obj = obj->u.var.realObj;
+ nd = create_objectrefnode(obj);
+ nd->rtype = rtype;
+ }
+ break;
+ case PAMEMORYBLOCKKIND_INT:
+ if (IS_TYPE_INT(rtype)) {
+ nd = IRO_NewENode(EINTCONST);
+ nd->data.intval = *((CInt64 *) thing);
+ nd->rtype = rtype;
+ }
+ break;
+ case PAMEMORYBLOCKKIND_6:
+ break;
+ default:
+ CError_FATAL(7040);
+ }
+
+ if (nd && !CInt64_IsZero(&field)) {
+ ENode *nd2;
+ ENode *nd3;
+
+ nd2 = IRO_NewENode(EINTCONST);
+ nd2->data.intval = field;
+ nd2->rtype = TYPE(&stunsignedlong);
+
+ nd3 = IRO_NewENode(EADD);
+ nd3->data.diadic.left = nd;
+ nd3->data.diadic.right = nd2;
+ nd3->rtype = rtype;
+
+ *resultNode = nd3;
+ } else {
+ *resultNode = nd;
+ }
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct LookupENodeExprActionParams {
+ Object *proc;
+ Type *indirectType;
+ ENodeList **list;
+} LookupENodeExprActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void LookupENodeExprAction(LocationSet *loc, void *refcon) {
+ LookupENodeExprActionParams *params;
+ ENodeList *list;
+
+ IRO_ASSERT(0, loc != NULL);
+ IRO_ASSERT(0, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(0, params->proc != NULL);
+ IRO_ASSERT(0, params->indirectType != NULL);
+ IRO_ASSERT(0, params->list != NULL);
+
+ list = *params->list = IRO_malloc(sizeof(ENodeList));
+ list->node = NULL;
+ list->next = NULL;
+
+ if (!LocationSet_IsUnknown(loc) && LocationSetRepresentsSingleLocation(loc, NULL, NULL))
+ CreateENodeForLocationSet(loc, &list->node, params->indirectType, params->proc);
+
+ params->list = &list->next;
+}
+
+void PointerAnalysis_LookupENodePointerExpr(Object *proc, ENode *indirect, ENodeList **list) {
+ LocationSetSet *set;
+ LookupENodeExprActionParams params;
+
+ IRO_ASSERT(0, indirect != NULL);
+
+ if (indirect->pointsTo) {
+ set = LocationSetSet_New();
+ LocationSetSet_Init(set);
+ EvalENodeExpr(set, proc, indirect, NULL, NULL, NULL);
+
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.indirectType = indirect->rtype;
+ params.list = list;
+
+ LocationSetSet_ForEach(set, LookupENodeExprAction, &params);
+ LocationSetSet_Term(set);
+ LocationSetSet_Delete(set);
+ }
+}
+
+void PointerAnalysis_LookupVariableIntoLinearNodeExprs(Object *proc, VarRecord *var, PointsToFunction *pointsTo, IROListNode **list) {
+ LocationSetSet *set;
+ LookupLinearExprActionParams params;
+
+ if (pointsTo) {
+ set = LocationSetSet_New();
+ LocationSetSet_Init(set);
+ EvalVariable(set, proc, var, pointsTo, NULL, NULL, NULL);
+
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.indirectType = var->object->type;
+ params.list = list;
+
+ LocationSetSet_ForEach(set, LookupLinearExprAction, &params);
+ LocationSetSet_Term(set);
+ LocationSetSet_Delete(set);
+ }
+}
+
+void PointerAnalysis_LookupVariableIntoENodeExprs(Object *proc, VarRecord *var, PointsToFunction *pointsTo, ENodeList **list) {
+ LocationSetSet *set;
+ LookupENodeExprActionParams params;
+
+ if (pointsTo) {
+ set = LocationSetSet_New();
+ LocationSetSet_Init(set);
+ EvalVariable(set, proc, var, pointsTo, NULL, NULL, NULL);
+
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.indirectType = var->object->type;
+ params.list = list;
+
+ LocationSetSet_ForEach(set, LookupENodeExprAction, &params);
+ LocationSetSet_Term(set);
+ LocationSetSet_Delete(set);
+ }
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct GetFunctionDepsOrKillsActionParams {
+ Object *proc;
+ PartialTransferFunction *ptf;
+ IROLinear *funccall;
+ ParamMappingFunction *map;
+ ObjectList **list;
+} GetFunctionDepsOrKillsActionParams;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void GetFunctionDepsOrKillsAction(LocationSet *ls, void *refcon) {
+ GetFunctionDepsOrKillsActionParams *params;
+ ObjectList *list;
+ PAMemoryBlock *block;
+ ExtendedParam *ep;
+ ObjectSet *objSet;
+ PALocalVar *local;
+ Object *obj;
+
+ IRO_ASSERT(7204, ls != NULL);
+ IRO_ASSERT(7205, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(7209, params->proc != NULL);
+ IRO_ASSERT(7210, params->ptf != NULL);
+ IRO_ASSERT(7211, params->funccall != NULL);
+ IRO_ASSERT(7212, params->map == NULL || params->map != NULL);
+ IRO_ASSERT(7213, params->list != NULL);
+
+ list = *params->list = IRO_malloc(sizeof(ObjectList));
+ list->object = NULL;
+ list->next = NULL;
+
+ if (!LocationSet_IsUnknown(ls) && (block = LocationSet_block(ls))) {
+ obj = NULL;
+ switch (PAMemoryBlock_kind(block)) {
+ case PAMEMORYBLOCKKIND_EXTENDEDPARAM:
+ if ((ep = PAMemoryBlock_thing(block)) && (objSet = ExtendedParam_objectSet(ep))) {
+ IRO_ASSERT(7232, obj == NULL);
+ ObjectSet_ForEach(objSet, FindGlobalObjectAction, &obj);
+ }
+ break;
+ case PAMEMORYBLOCKKIND_LOCALVAR:
+ if ((local = PAMemoryBlock_thing(block))) {
+ obj = GetLocalObject(local, &stUnknown, 0);
+ if (ObjectIsAFunctionArgument(FunctionName, obj) && obj->u.var.realObj)
+ obj = obj->u.var.realObj;
+ }
+ break;
+ }
+
+ list->object = obj;
+ }
+
+ params->list = &list->next;
+}
+
+static void GetFunctionDepsOrKillsAction2(PointsToEntry *pte, void *refcon) {
+ GetFunctionDepsOrKillsActionParams *params;
+ LocationSet *loc;
+ PAMemoryBlock *block;
+ LocationSetSet *set;
+
+ IRO_ASSERT(7264, pte != NULL);
+ IRO_ASSERT(7265, refcon != NULL);
+
+ params = refcon;
+
+ IRO_ASSERT(7269, params->proc != NULL);
+ IRO_ASSERT(7270, params->ptf != NULL);
+ IRO_ASSERT(7271, params->funccall != NULL);
+ IRO_ASSERT(7272, params->map != NULL);
+ IRO_ASSERT(7273, params->list != NULL);
+
+ loc = PointsToEntry_loc(pte);
+
+ IRO_ASSERT(7277, !LocationSet_IsUnknown(loc));
+
+ if ((block = LocationSet_block(loc)) && PAMemoryBlock_kind(block) == PAMEMORYBLOCKKIND_EXTENDEDPARAM) {
+ set = LocationSetSet_New();
+ LocationSetSet_Init(set);
+ GetActualLocsOfExtendedParam(set, loc, NULL, &stCallingContextStack, params->map, 0);
+ LocationSetSet_ForEach(set, GetFunctionDepsOrKillsAction, params);
+ LocationSetSet_Term(set);
+ LocationSetSet_Delete(set);
+ }
+}
+
+static void CreateFalseContext(Object *proc, IROLinear *funccall, PartialTransferFunction **resultPTF, ParamMappingFunction **resultMap) {
+ IROLinear myFunccall;
+ Boolean needVisit;
+ ParamMappingFunction *map;
+ PartialTransferFunction *ptf;
+ StackElement *stackElement;
+ ParamMappingFunction *map2;
+ PartialTransferFunction *ptf2;
+ StackElement *stackElement2;
+
+ PointerAnalysis_Init();
+ memset(&myFunccall, 0, sizeof(myFunccall));
+ myFunccall.type = IROLinearFunccall;
+
+ map = ParamMappingFunction_New();
+ ParamMappingFunction_Init(map);
+ RecordActuals(&myFunccall, FunctionName, map);
+
+ needVisit = 0;
+ ptf = GetPTF(map, FunctionName, &myFunccall, stUnknownPTF, &needVisit);
+
+ stackElement = StackElement_New();
+ StackElement_Init(stackElement, FunctionName, ptf, map, &myFunccall);
+ Stack_sub_48A660(&stCallingContextStack, stackElement);
+ StackElement_Term(stackElement);
+ StackElement_Delete(stackElement);
+
+ map2 = ParamMappingFunction_New();
+ ParamMappingFunction_Init(map2);
+ RecordActuals(funccall, proc, map2);
+
+ if (FunctionName != proc) {
+ needVisit = 0;
+ ptf2 = GetPTF(map2, proc, funccall, ptf, &needVisit);
+
+ stackElement2 = StackElement_New();
+ StackElement_Init(stackElement2, proc, ptf2, map2, funccall);
+ Stack_sub_48A660(&stCallingContextStack, stackElement2);
+ StackElement_Term(stackElement2);
+ StackElement_Delete(stackElement2);
+ } else {
+ ptf2 = stUnknownPTF;
+ }
+
+ *resultPTF = ptf2;
+ *resultMap = map2;
+}
+
+static void DestroyFalseContext(Object *proc, PartialTransferFunction *ptf, ParamMappingFunction *map) {
+ StackElement *element;
+
+ if (FunctionName != proc) {
+ element = Stack_sub_48A5B0(&stCallingContextStack);
+ StackElement_Term(element);
+ StackElement_Delete(element);
+ }
+
+ ParamMappingFunction_Term(map);
+ ParamMappingFunction_Delete(map);
+
+ element = Stack_sub_48A5B0(&stCallingContextStack);
+ map = StackElement_map(element);
+ ParamMappingFunction_Term(map);
+ ParamMappingFunction_Delete(map);
+ StackElement_Term(element);
+ StackElement_Delete(element);
+
+ PointerAnalysis_Term();
+}
+
+void PointerAnalysis_GetFunctionKills(Object *proc, IROLinear *funccall, ObjectList **list) {
+ Boolean fail;
+ PartialTransferFunction *ptf;
+ LocationSetSet *set;
+ GetFunctionDepsOrKillsActionParams params;
+
+ IRO_ASSERT(7398, proc != NULL);
+ IRO_ASSERT(7399, funccall != NULL);
+ IRO_ASSERT(7400, funccall->type == IROLinearFunccall);
+
+ if (!ObjectIsAFunction(proc))
+ return;
+
+ fail = !proc->u.func.ptfList || !(ptf = PTFList_FindFirst(proc->u.func.ptfList));
+ if (!fail) {
+ fail = !(set = PTF_sub_48D750(ptf));
+ if (!fail) {
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.ptf = ptf;
+ params.funccall = funccall;
+ params.map = NULL;
+ params.list = list;
+ LocationSetSet_ForEach(set, GetFunctionDepsOrKillsAction, &params);
+ }
+ }
+
+ if (fail) {
+ *list = IRO_malloc(sizeof(ObjectList));
+ (*list)->object = NULL;
+ (*list)->next = NULL;
+ }
+}
+
+void PointerAnalysis_GetFunctionDependencies(Object *proc, IROLinear *funccall, ObjectList **list) {
+ Boolean fail;
+ PartialTransferFunction *ptf;
+ ParamMappingFunction *map;
+ PointsToFunction *finalPointsTo;
+ GetFunctionDepsOrKillsActionParams params;
+
+ IRO_ASSERT(7446, proc != NULL);
+ IRO_ASSERT(7447, funccall != NULL);
+ IRO_ASSERT(7448, funccall->type == IROLinearFunccall);
+
+ if (!ObjectIsAFunction(proc))
+ return;
+
+ fail = !proc->u.func.ptfList || !PTFList_FindFirst(proc->u.func.ptfList);
+ if (!fail) {
+ CreateFalseContext(proc, funccall, &ptf, &map);
+ fail = !ptf || !map || !(finalPointsTo = PartialTransferFunction_finalPointsToFn(ptf));
+ if (!fail) {
+ memset(&params, 0, sizeof(params));
+ params.proc = proc;
+ params.ptf = ptf;
+ params.funccall = funccall;
+ params.map = map;
+ params.list = list;
+ PointsToFunction_ForEach(finalPointsTo, GetFunctionDepsOrKillsAction2, &params);
+ }
+ DestroyFalseContext(proc, ptf, map);
+ }
+
+ if (fail) {
+ *list = IRO_malloc(sizeof(ObjectList));
+ (*list)->object = NULL;
+ (*list)->next = NULL;
+ }
+}
+
+void PointerAnalysis_PragmaMode(void) {
+ if (cparamblkptr->preprocess) {
+ skipendofline();
+ return;
+ }
+
+ if (notendofline()) {
+ if (plex() == TK_IDENTIFIER) {
+ if (!strcmp(tkidentifier->name, "addr")) {
+ copts.opt_pointer_analysis_mode = 0;
+ return;
+ }
+ if (!strcmp(tkidentifier->name, "ansi")) {
+ copts.opt_pointer_analysis_mode = 1;
+ return;
+ }
+ if (!strcmp(tkidentifier->name, "type")) {
+ copts.opt_pointer_analysis_mode = 2;
+ return;
+ }
+ }
+
+ CPrep_Warning(CErrorStr105);
+ skipendofline();
+ return;
+ }
+
+ if (copts.warn_illpragma)
+ CPrep_Warning(CErrorStr186);
+ skipendofline();
+}
+
+typedef enum CreateNewParamObjects {
+ CREATE_NEW_PARAM_OBJECTS_FALSE,
+ CREATE_NEW_PARAM_OBJECTS_TRUE
+} CreateNewParamObjects;
+
+static void ParseLocationSet(LocationSet *loc, Type *rtype, Object *proc, CreateNewParamObjects createNewParamObjects, Boolean arg5, int arg6, Boolean *arg7, Boolean *resultFailed) {
+ CInt64 field;
+ UInt32 stride;
+ PAMemoryBlock *block;
+ PAMemoryBlock *restriction;
+ Boolean failed;
+ Boolean flag37;
+ Boolean epFlag;
+ Boolean anotherFlag;
+ Boolean isUnknown;
+
+ IRO_ASSERT(7552, loc != NULL);
+ IRO_ASSERT(7553, rtype == NULL || rtype != NULL);
+ IRO_ASSERT(7554, proc != NULL);
+ IRO_ASSERT(7555, createNewParamObjects == CREATE_NEW_PARAM_OBJECTS_FALSE || createNewParamObjects == CREATE_NEW_PARAM_OBJECTS_TRUE);
+ IRO_ASSERT(7556, resultFailed != NULL);
+ IRO_ASSERT(7557, *resultFailed == false);
+ IRO_ASSERT(7558, proc != NULL);
+ IRO_ASSERT(7559, proc == NULL || ObjectIsAFunction(proc));
+
+ failed = 0;
+ isUnknown = 0;
+ anotherFlag = 0;
+ field = cint64_zero;
+ stride = 0;
+
+ tk = lex();
+ if (tk == TK_IDENTIFIER) {
+ if (!strcmp(tkidentifier->name, "__unknown")) {
+ flag37 = 0;
+ isUnknown = 1;
+ tk = lookahead();
+ if (tk == '(') {
+ lex();
+ tk = lex();
+ if (tk != TK_IDENTIFIER) {
+ CError_Error(CErrorStr107);
+ failed = 1;
+ }
+ if (!failed) {
+ PALocalVar *local;
+ local = PALocalVar_New();
+ PALocalVar_InitByName(local, tkidentifier->name);
+
+ block = PAMemoryBlock_New();
+ PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_LOCALVAR, local);
+
+ tk = lex();
+ if (tk != ')') {
+ CError_Error(CErrorStr115);
+ failed = 1;
+ }
+ if (!failed) {
+ rtype = NULL;
+ restriction = block;
+ }
+ }
+ } else {
+ rtype = NULL;
+ restriction = NULL;
+ }
+ } else if (arg5 && !strcmp(tkidentifier->name, "__return_value")) {
+ flag37 = 0;
+ anotherFlag = 1;
+ } else if (!strcmp(tkidentifier->name, "__unique_heap_allocation")) {
+ PAHeapBlock *hb;
+
+ flag37 = 0;
+ hb = CreateUniqueHeapAlloc_sub_486420();
+ InitUniqueHeapAlloc_sub_486410(hb, NULL);
+
+ block = PAMemoryBlock_New();
+ PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_HEAPBLOCK, hb);
+ } else if (!strcmp(tkidentifier->name, "__parameter_representative")) {
+ flag37 = 1;
+ tk = lex();
+
+ if (tk == '(') {
+ tk = lex();
+ if (tk != TK_INTCONST) {
+ CError_Error(CErrorStr121);
+ failed = 1;
+ }
+ if (!failed) {
+ Object *obj;
+ ObjectList *list;
+ ExtendedParam *ep;
+ obj = NULL;
+ for (list = stParamObjs; list; list = list->next) {
+ if ((obj = list->object) && (obj->u.var.uid == CInt64_GetULong(&tkintconst)))
+ break;
+ }
+ if (!list)
+ obj = NULL;
+
+ if (!obj) {
+ if (createNewParamObjects) {
+ obj = IRO_malloc(sizeof(Object));
+ memset(obj, 0, sizeof(Object));
+ obj->datatype = DLOCAL;
+ obj->extParam = NULL;
+ obj->name = CParser_GetUniqueName();
+ obj->type = TYPE(&stunsignedlong);
+ obj->qual = 0;
+ obj->u.var.info = NULL;
+ obj->u.var.uid = CInt64_GetULong(&tkintconst);
+
+ list = IRO_malloc(sizeof(ObjectList));
+ list->next = stParamObjs;
+ list->object = obj;
+ stParamObjs = list;
+
+ ep = CreateExtendedParam(NULL, NULL, obj, &epFlag);
+ } else {
+ char buf[64];
+ sprintf(buf, "__parameter_representative(%" PRId32 ")", obj->u.var.uid);
+ CError_Error(CErrorStr140, buf);
+ failed = 1;
+ }
+ } else {
+ ep = obj->extParam;
+ IRO_ASSERT(7687, ep != NULL);
+ }
+
+ if (!failed) {
+ tk = lex();
+ if (tk != ')') {
+ CError_Error(CErrorStr115);
+ failed = 1;
+ }
+ }
+ if (!failed) {
+ block = PAMemoryBlock_New();
+ PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_EXTENDEDPARAM, ep);
+ }
+ }
+ }
+ } else {
+ Object *obj;
+ NameSpace *nspace;
+
+ obj = NULL;
+ for (nspace = cscope_current; nspace; nspace = nspace->parent) {
+ NameSpaceObjectList *chk;
+ if ((chk = CScope_GetLocalObject(nspace, tkidentifier)) && chk->object->otype == OT_OBJECT) {
+ if (notendofline()) {
+ obj = OBJECT(chk->object);
+ break;
+ }
+ }
+ }
+
+ if (!obj) {
+ ObjectList *chk;
+ for (chk = FunctionArguments(proc); chk; chk = chk->next) {
+ if (chk->object && chk->object->name && chk->object->name->name && !strcmp(tkidentifier->name, chk->object->name->name)) {
+ obj = chk->object;
+ }
+ }
+ }
+
+ if (obj) {
+ PAMemoryBlockKind kind;
+ void *thing;
+
+ if (ObjectIsAnExtendedParamCandidate(obj)) {
+ kind = PAMEMORYBLOCKKIND_EXTENDEDPARAM;
+ thing = CreateExtendedParam(NULL, NULL, obj, &epFlag);
+ } else {
+ kind = PAMEMORYBLOCKKIND_LOCALVAR;
+ thing = PALocalVar_New();
+ if (obj->name && obj->name->name && ObjectIsAFunctionArgument(proc, obj))
+ PALocalVar_InitByName(thing, obj->name->name);
+ else
+ PALocalVar_InitByObject(thing, obj);
+ }
+
+ block = PAMemoryBlock_New();
+ PAMemoryBlock_Init(block, kind, thing);
+ rtype = CDecl_NewPointerType(obj->type);
+ } else {
+ CError_Error(CErrorStr140, tkidentifier->name);
+ failed = 1;
+ }
+ }
+ } else if (tk == TK_INTCONST) {
+ flag37 = 0;
+ block = PAMemoryBlock_New();
+ PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_INT, &tkintconst);
+ } else if (tk == '(') {
+ ParseLocationSet(loc, rtype, proc, createNewParamObjects, arg5, 1, &anotherFlag, &failed);
+ if (!failed) {
+ tk = plex();
+ if (tk != ')')
+ CError_Error(CErrorStr115);
+ failed = 1;
+ }
+ } else {
+ CError_Error(CErrorStr121);
+ failed = 1;
+ }
+
+ if (!failed && flag37) {
+ tk = lookahead();
+ if (tk == '[') {
+ lex();
+ if (rtype && IS_TYPE_POINTER(rtype) && IS_TYPE_POINTER(TPTR_TARGET(rtype))) {
+ tk = lex();
+ if (tk == ']') {
+ if ((stride = rtype->size)) {
+ CInt64 tmp;
+ CInt64_SetLong(&tmp, stride);
+ field = CInt64_Mod(field, tmp);
+ }
+ rtype = TPTR_TARGET(rtype);
+ } else {
+ CError_Error(CErrorStr125);
+ }
+ } else {
+ CError_Error(CErrorStr148);
+ }
+ } else if (tk == '.') {
+ lex();
+ if (rtype && IS_TYPE_POINTER(rtype) && IS_TYPE_STRUCT(TPTR_TARGET(rtype))) {
+ if (TPTR_TARGET(rtype)->size) {
+ tk = lex();
+ if (tk == TK_IDENTIFIER) {
+ StructMember *member;
+ if ((member = ismember(TYPE_STRUCT(TPTR_TARGET(rtype)), tkidentifier))) {
+ CInt64_SetLong(&field, member->offset);
+ rtype = CDecl_NewPointerType(member->type);
+ } else {
+ CError_Error(CErrorStr150, tkidentifier);
+ }
+ } else {
+ CError_Error(CErrorStr107);
+ }
+ } else {
+ CError_Error(CErrorStr136, TPTR_TARGET(rtype), 0);
+ }
+ } else {
+ CError_Error(CErrorStr149);
+ }
+ }
+ }
+
+ if (!failed && !anotherFlag) {
+ LocationSet_Term(loc);
+ if (!isUnknown)
+ LocationSet_InitKnown(loc, block, field, stride, rtype);
+ else
+ LocationSet_InitUnknown(loc, rtype, restriction, NULL);
+ }
+
+ *arg7 = anotherFlag;
+ *resultFailed = failed;
+}
+
+static void ParseLocationSetSet(LocationSetSet *locs, Type *rtype, Object *proc, CreateNewParamObjects createNewParamObjects, Boolean *resultFailed) {
+ Boolean failed;
+
+ IRO_ASSERT(7892, locs != NULL);
+ IRO_ASSERT(7893, rtype == NULL || rtype != NULL);
+ IRO_ASSERT(7894, proc != NULL);
+ IRO_ASSERT(7895, createNewParamObjects == CREATE_NEW_PARAM_OBJECTS_FALSE || createNewParamObjects == CREATE_NEW_PARAM_OBJECTS_TRUE);
+ IRO_ASSERT(7896, resultFailed != NULL);
+ IRO_ASSERT(7897, *resultFailed == false);
+ IRO_ASSERT(7898, proc != NULL);
+ IRO_ASSERT(7899, proc == NULL || ObjectIsAFunction(proc));
+
+ failed = 0;
+
+ tk = lex();
+ if (tk != '(') {
+ CError_Error(CErrorStr114);
+ failed = 1;
+ }
+
+ if (!failed) {
+ Boolean anotherFlag;
+
+ LocationSet *ls;
+ ls = LocationSet_New();
+ LocationSet_InitUnknown(ls, NULL, NULL, NULL);
+
+ tk = lookahead();
+ while (!failed && tk != ')') {
+ ParseLocationSet(ls, rtype, proc, createNewParamObjects, 0, 0, &anotherFlag, &failed);
+ if (!failed)
+ LocationSetSet_Add(locs, ls);
+
+ if (!failed) {
+ tk = lookahead();
+ if (tk == ',') {
+ lex();
+ tk = lookahead();
+ } else if (tk != ')') {
+ lex();
+ CError_Error(CErrorStr121);
+ failed = 1;
+ }
+ }
+ }
+
+ if (!failed)
+ lex();
+
+ LocationSet_Term(ls);
+ LocationSet_Delete(ls);
+ }
+
+ *resultFailed = failed;
+}
+
+static Object *GetFunctionObjectFromDeclInfo(DeclInfo *di) {
+ Object *proc;
+
+ IRO_ASSERT(7953, di != NULL);
+
+ if (di->storageclass != TK_TYPEDEF && IS_TYPE_FUNC(di->thetype)) {
+ Boolean flag;
+ proc = CDecl_GetFunctionObject(di, NULL, &flag, 1);
+ if (flag)
+ di->x64 = 1;
+ } else {
+ proc = NULL;
+ }
+
+ return proc;
+}
+
+void PointerAnalysis_ParseEntryPointsToSpecifier(DeclInfo *di) {
+ Object *proc;
+ Boolean failed;
+ Boolean anotherFlag;
+
+ IRO_ASSERT(7982, di != NULL);
+
+ proc = GetFunctionObjectFromDeclInfo(di);
+ if (proc) {
+ IRO_ASSERT(7987, proc == NULL || ObjectIsAFunction(proc));
+
+ tk = lex();
+ IRO_ASSERT(7996, tk == TK_IDENTIFIER && strcmp(tkidentifier->name,"entry_points_to") == 0);
+
+ failed = 0;
+
+ tk = lex();
+ if (tk != '(') {
+ CError_Error(CErrorStr114);
+ failed = 1;
+ }
+
+ if (!failed) {
+ LocationSet *ls;
+ ls = LocationSet_New();
+ LocationSet_InitUnknown(ls, NULL, NULL, NULL);
+ ParseLocationSet(ls, NULL, proc, CREATE_NEW_PARAM_OBJECTS_FALSE, 0, 0, &anotherFlag, &failed);
+ if (!failed) {
+ if ((tk = lex()) != ',') {
+ CError_Error(CErrorStr116);
+ failed = 1;
+ }
+ }
+ if (!failed) {
+ Type *type;
+ Type *innerType;
+ LocationSetSet *lss;
+
+ type = LocationSet_rtype(ls);
+ if (type && IS_TYPE_POINTER(type))
+ innerType = TPTR_TARGET(type);
+ else
+ innerType = NULL;
+
+ lss = LocationSetSet_New();
+ LocationSetSet_Init(lss);
+ ParseLocationSetSet(lss, innerType, proc, CREATE_NEW_PARAM_OBJECTS_TRUE, &failed);
+ if (!failed) {
+ if ((tk = lex()) != ')') {
+ CError_Error(CErrorStr115);
+ failed = 1;
+ }
+ }
+ if (!failed) {
+ PartialTransferFunction *ptf;
+ PointsToFunction *pointsToFunc;
+ PointsToEntry *pte;
+
+ if (!proc->u.func.ptfList) {
+ proc->u.func.ptfList = PTFList_New();
+ PTFList_Init(proc->u.func.ptfList);
+ }
+ ptf = PTFList_FindFirst(proc->u.func.ptfList);
+ if (!ptf)
+ ptf = AllocatePTF(proc, NULL, NULL);
+
+ pointsToFunc = PartialTransferFunction_initialPointsToFn(ptf);
+ pte = PointsToEntry_New();
+ PointsToEntry_Init(pte, ls, lss);
+ PointsToFunction_Add(pointsToFunc, pte);
+ PointsToEntry_Term(pte);
+ PointsToEntry_Delete(pte);
+ }
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+ }
+ LocationSet_Term(ls);
+ LocationSet_Delete(ls);
+ }
+ }
+}
+
+void PointerAnalysis_ParseExitPointsToSpecifier(DeclInfo *di) {
+ Object *proc;
+ Boolean failed;
+ Boolean anotherFlag;
+
+ IRO_ASSERT(8097, di != NULL);
+
+ proc = GetFunctionObjectFromDeclInfo(di);
+ if (proc) {
+ IRO_ASSERT(8102, proc == NULL || ObjectIsAFunction(proc));
+
+ tk = lex();
+ IRO_ASSERT(8111, tk == TK_IDENTIFIER && strcmp(tkidentifier->name,"exit_points_to") == 0);
+
+ failed = 0;
+
+ tk = lex();
+ if (tk != '(') {
+ CError_Error(CErrorStr114);
+ failed = 1;
+ }
+
+ if (!failed) {
+ LocationSet *ls;
+ ls = LocationSet_New();
+ LocationSet_InitUnknown(ls, NULL, NULL, NULL);
+ ParseLocationSet(ls, NULL, proc, CREATE_NEW_PARAM_OBJECTS_FALSE, 1, 0, &anotherFlag, &failed);
+ if (!failed) {
+ if ((tk = lex()) != ',') {
+ CError_Error(CErrorStr116);
+ failed = 1;
+ }
+ }
+ if (!failed) {
+ Type *type;
+ Type *innerType;
+ LocationSetSet *lss;
+
+ type = LocationSet_rtype(ls);
+ if (type && IS_TYPE_POINTER(type))
+ innerType = TPTR_TARGET(type);
+ else
+ innerType = NULL;
+
+ lss = LocationSetSet_New();
+ LocationSetSet_Init(lss);
+ ParseLocationSetSet(lss, innerType, proc, CREATE_NEW_PARAM_OBJECTS_FALSE, &failed);
+ if (!failed) {
+ if ((tk = lex()) != ')') {
+ CError_Error(CErrorStr115);
+ failed = 1;
+ }
+ }
+ if (!failed) {
+ PartialTransferFunction *ptf;
+ PointsToFunction *pointsToFunc;
+ PointsToEntry *pte;
+
+ if (!proc->u.func.ptfList) {
+ proc->u.func.ptfList = PTFList_New();
+ PTFList_Init(proc->u.func.ptfList);
+ }
+ ptf = PTFList_FindFirst(proc->u.func.ptfList);
+ if (!ptf)
+ ptf = AllocatePTF(proc, NULL, NULL);
+
+ pointsToFunc = PartialTransferFunction_finalPointsToFn(ptf);
+ pte = PointsToEntry_New();
+ if (anotherFlag)
+ PointsToEntry_Init(pte, PartialTransferFunction_returnLocation(ptf), lss);
+ else
+ PointsToEntry_Init(pte, ls, lss);
+ PointsToFunction_Add(pointsToFunc, pte);
+ PointsToEntry_Term(pte);
+ PointsToEntry_Delete(pte);
+ }
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+ }
+ LocationSet_Term(ls);
+ LocationSet_Delete(ls);
+ }
+ }
+}
+
+void PointerAnalysis_ParseFunctionModifiesSpecifier(DeclInfo *di) {
+ Object *proc;
+ Boolean failed;
+ LocationSetSet *lss;
+ PartialTransferFunction *ptf;
+ LocationSetSet *ptfLSS;
+
+ IRO_ASSERT(8211, di != NULL);
+
+ proc = GetFunctionObjectFromDeclInfo(di);
+ if (proc) {
+ IRO_ASSERT(8216, proc == NULL || ObjectIsAFunction(proc));
+
+ tk = lex();
+ IRO_ASSERT(8225, tk == TK_IDENTIFIER && strcmp(tkidentifier->name,"function_modifies") == 0);
+
+ failed = 0;
+ lss = LocationSetSet_New();
+ LocationSetSet_Init(lss);
+ ParseLocationSetSet(lss, NULL, proc, CREATE_NEW_PARAM_OBJECTS_FALSE, &failed);
+ if (!failed) {
+ if (!proc->u.func.ptfList) {
+ proc->u.func.ptfList = PTFList_New();
+ PTFList_Init(proc->u.func.ptfList);
+ }
+ ptf = PTFList_FindFirst(proc->u.func.ptfList);
+ if (!ptf)
+ ptf = AllocatePTF(proc, NULL, NULL);
+ ptfLSS = PTF_sub_48D750(ptf);
+ LocationSetSet_RemoveAll(ptfLSS);
+ LocationSetSet_AddSet(ptfLSS, lss);
+ }
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+ }
+}
+
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.h b/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.h
new file mode 100644
index 0000000..ec50eba
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysis.h
@@ -0,0 +1,25 @@
+#ifndef COMPILER_IROPOINTERANALYSIS_H
+#define COMPILER_IROPOINTERANALYSIS_H
+
+#include "IrOptimizer.h"
+
+extern void PointerAnalysis_Setup(void);
+extern void PointerAnalysis_Cleanup(void);
+extern void IRO_AnalyzePointers(Object *function);
+extern Boolean PointerAnalysis_TwoLinearNodePointerExprsMightAlias(Object *proc, IROLinear *nd1, IROLinear *nd2);
+extern Boolean PointerAnalysis_TwoENodePointerExprsMightAlias(Object *proc, ENode *nd1, ENode *nd2);
+extern Boolean PointerAnalysis_IsLinearNodePointerExprDefinite(Object *proc, IROLinear *nd);
+extern Boolean PointerAnalysis_IsENodePointerExprDefinite(Object *proc, ENode *nd);
+extern Boolean PointerAnalysis_IsVariableValueDefinite(Object *proc, VarRecord *var, PointsToFunction *pointsTo);
+extern void PointerAnalysis_LookupLinearNodePointerExpr(Object *proc, IROLinear *indirect, IROListNode **list);
+extern void PointerAnalysis_LookupENodePointerExpr(Object *proc, ENode *indirect, ENodeList **list);
+extern void PointerAnalysis_LookupVariableIntoLinearNodeExprs(Object *proc, VarRecord *var, PointsToFunction *pointsTo, IROListNode **list);
+extern void PointerAnalysis_LookupVariableIntoENodeExprs(Object *proc, VarRecord *var, PointsToFunction *pointsTo, ENodeList **list);
+extern void PointerAnalysis_GetFunctionKills(Object *proc, IROLinear *funccall, ObjectList **list);
+extern void PointerAnalysis_GetFunctionDependencies(Object *proc, IROLinear *funccall, ObjectList **list);
+extern void PointerAnalysis_PragmaMode(void);
+extern void PointerAnalysis_ParseEntryPointsToSpecifier(DeclInfo *di);
+extern void PointerAnalysis_ParseExitPointsToSpecifier(DeclInfo *di);
+extern void PointerAnalysis_ParseFunctionModifiesSpecifier(DeclInfo *di);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysisADTs.c b/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysisADTs.c
new file mode 100644
index 0000000..dad9501
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroPointerAnalysisADTs.c
@@ -0,0 +1,2736 @@
+#include "IroPointerAnalysis.h"
+#include "IroMalloc.h"
+#include "compiler/CError.h"
+#include "compiler/CInt64.h"
+#include "compiler/CParser.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+// TODO: this should really be elsewhere (but where?)
+CW_INLINE UInt32 gcd(UInt32 a, UInt32 b) {
+ UInt32 chk;
+
+ if (!a)
+ return b;
+ if (!b)
+ return a;
+
+ while (1) {
+ chk = a % b;
+ if (!chk)
+ return b;
+ a = b;
+ b = chk;
+ }
+}
+
+// #define IRO_DEBUG
+
+typedef struct ExtendedParamSet ExtendedParamSet;
+typedef struct LocationSet LocationSet;
+typedef struct LocationSetSet LocationSetSet;
+typedef struct ObjectSet ObjectSet;
+typedef struct PAHeapBlock PAHeapBlock;
+typedef struct PALocalVar PALocalVar;
+typedef struct PAMemoryBlock PAMemoryBlock;
+typedef struct ParamMapping ParamMapping;
+typedef struct ParamMappingFunction ParamMappingFunction;
+typedef struct PartialTransferFunction PartialTransferFunction;
+typedef struct PointsToEntry PointsToEntry;
+// typedef struct PointsToFunction PointsToFunction;
+typedef struct Stack Stack;
+typedef struct StackElement StackElement;
+
+typedef UInt32 uint32;
+
+void __assertion_failed(char *expr, char *filename, int line);
+
+#ifdef IRO_DEBUG
+#define IRO_ASSERT(line, expr) \
+ do { \
+ if (!(expr)) { \
+ __assertion_failed(#expr, __FILE__, line); \
+ } \
+ } while (0);
+
+#define IRO_DEBUG_CLEAR(obj, type) \
+ memset((obj), 0xFF, sizeof(type))
+#else
+#define IRO_ASSERT(line, expr) ((void) 0)
+#define IRO_DEBUG_CLEAR(obj, type) ((void) 0)
+#endif
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+struct StackElement {
+ Object *proc;
+ PartialTransferFunction *ptf;
+ ParamMappingFunction *map;
+ IROLinear *funcCall;
+};
+
+struct Stack {
+ StackElement *top;
+ Stack *next;
+};
+
+struct ObjectSet {
+ Object *proc;
+ ObjectSet *otherProcs;
+};
+
+struct ExtendedParam {
+ ObjectSet *objectSet;
+ uint32 x4;
+};
+
+struct ExtendedParamSet {
+ ExtendedParam *ep;
+ ExtendedParamSet *otherEps;
+};
+
+struct PAHeapBlock {
+ IROLinear *x0;
+};
+
+struct PALocalVar {
+ Object *x0;
+ char *x4;
+};
+
+typedef enum {
+ PAMEMORYBLOCKKIND_INVALID,
+ PAMEMORYBLOCKKIND_1,
+ PAMEMORYBLOCKKIND_EXTENDEDPARAM,
+ PAMEMORYBLOCKKIND_LOCALVAR,
+ PAMEMORYBLOCKKIND_HEAPBLOCK,
+ PAMEMORYBLOCKKIND_INT,
+ PAMEMORYBLOCKKIND_6
+} PAMemoryBlockKind;
+
+struct PAMemoryBlock {
+ PAMemoryBlockKind kind;
+ union {
+ ExtendedParam *ep;
+ PALocalVar *localvar;
+ PAHeapBlock *heapblock;
+ CInt64 intval;
+ void *x6;
+ } u;
+};
+
+struct LocationSet {
+ PAMemoryBlock *block;
+ Type *rtype;
+ union {
+ struct {
+ CInt64 field;
+ UInt32 stride;
+ } known;
+ struct {
+ PAMemoryBlock *restriction;
+ LocationSet *bitfieldOf;
+ } unknown;
+ } u;
+};
+
+struct LocationSetSet {
+ LocationSet *loc;
+ LocationSetSet *otherLocs;
+ UInt8 count;
+};
+
+struct ParamMapping {
+ IROLinear *actual;
+ Object *formal;
+ ExtendedParam *extended;
+};
+
+struct ParamMappingFunction {
+ ParamMapping *mapping;
+ ParamMappingFunction *otherMappings;
+};
+
+struct PointsToEntry {
+ LocationSet *loc;
+ LocationSetSet *locs;
+};
+
+struct PointsToFunction {
+ PointsToEntry *pte;
+ PointsToFunction *otherPtes;
+};
+
+struct PartialTransferFunction {
+ PointsToFunction *initialPointsToFn;
+ PointsToFunction *finalPointsToFn;
+ LocationSetSet *funcModifies;
+ LocationSet *returnLocation;
+ Boolean x10;
+ struct {
+ IROLinear *nd;
+ PartialTransferFunction *ptf;
+ } context;
+};
+
+struct PTFList {
+ PartialTransferFunction *ptf;
+ PTFList *otherPTFs;
+};
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+// TODO: how many of these are actually in IroPointerAnalysis.c?
+static uint32 stExtendedParamNum;
+static PartialTransferFunction *stUnknownPTF;
+static uint32 stIndentationLevel;
+static UInt8 stTabs[0x2C]; // unused mystery object
+static Stack *stCallingContextStack;
+static ObjectList *stParamObjs;
+static jmp_buf stAbortPointerAnalysis;
+static Object stUnknown;
+static Object *stCurrentProc;
+static ExtendedParamSet *stExtParamSet;
+static PTFList *stPTFList;
+static uint32 stMaxPassCount;
+// TODO: stEvalProcActionParams
+static IRONode *stExceptionFNode;
+
+static PAMemoryBlock stDummyMemoryBlock = {
+ PAMEMORYBLOCKKIND_1
+};
+static PAMemoryBlock *stUnknownMb = &stDummyMemoryBlock;
+
+static LocationSet stDummyLocationSet = {
+ &stDummyMemoryBlock
+};
+
+static LocationSet *stUnknownLs = &stDummyLocationSet;
+
+// forward decls
+CW_INLINE StackElement *Stack_sub_48A5B0(Stack **stackPtr);
+CW_INLINE void ObjectSet_RemoveAll(ObjectSet *procList);
+CW_INLINE void ExtendedParamSet_RemoveAll(ExtendedParamSet *epList);
+CW_INLINE void LocationSet_Copy(LocationSet *dest, LocationSet *src);
+CW_INLINE Boolean LocationSet_IsUnknown(LocationSet *ls);
+CW_INLINE void LocationSetSet_RemoveAll(LocationSetSet *lss);
+CW_INLINE void LocationSetSet_AddSet(LocationSetSet *dest, LocationSetSet *src);
+CW_INLINE void ParamMappingFunction_RemoveAll(ParamMappingFunction *pmf);
+CW_INLINE void ParamMappingFunction_AddAllMaybe_sub_487C50(ParamMappingFunction *dest, ParamMappingFunction *src);
+CW_INLINE void PointsToFunction_RemoveAll(PointsToFunction *pointsToFunc);
+CW_INLINE void PointsToFunction_AddAllIGuess_sub_487D80(PointsToFunction *dest, PointsToFunction *src);
+CW_INLINE void PTFList_RemoveAll(PTFList *ptfList);
+
+CW_INLINE StackElement *StackElement_New(void) {
+ StackElement *stackElement = IRO_malloc(sizeof(StackElement));
+ IRO_ASSERT(103, stackElement != NULL);
+#ifdef IRO_DEBUG
+ stackElement->proc = NULL;
+ stackElement->ptf = NULL;
+ stackElement->map = NULL;
+ stackElement->funcCall = NULL;
+#endif
+ return stackElement;
+}
+
+CW_INLINE void StackElement_Delete(StackElement *stackElement) {
+ IRO_ASSERT(117, stackElement != NULL);
+ IRO_ASSERT(118, stackElement->proc == NULL);
+ IRO_ASSERT(119, stackElement->ptf == NULL);
+ IRO_ASSERT(120, stackElement->map == NULL);
+ IRO_ASSERT(121, stackElement->funcCall == NULL);
+ IRO_DEBUG_CLEAR(stackElement, sizeof(StackElement));
+ IRO_free(stackElement);
+}
+
+CW_INLINE void StackElement_Init(StackElement *stackElement, Object *proc, PartialTransferFunction *ptf, ParamMappingFunction *map, IROLinear *funcCall) {
+ IRO_ASSERT(131, stackElement != NULL);
+ IRO_ASSERT(132, proc != NULL);
+ IRO_ASSERT(133, ptf != NULL);
+ IRO_ASSERT(134, map != NULL);
+ IRO_ASSERT(135, funcCall != NULL);
+ stackElement->proc = proc;
+ stackElement->ptf = ptf;
+ stackElement->map = map;
+ stackElement->funcCall = funcCall;
+}
+
+CW_INLINE void StackElement_Copy(StackElement *dest, StackElement *src) {
+ IRO_ASSERT(145, dest != NULL);
+ IRO_ASSERT(146, src != NULL);
+ StackElement_Init(dest, src->proc, src->ptf, src->map, src->funcCall);
+}
+
+CW_INLINE void StackElement_Term(StackElement *stackElement) {
+ IRO_ASSERT(156, stackElement != NULL);
+#ifdef IRO_DEBUG
+ stackElement->proc = NULL;
+ stackElement->ptf = NULL;
+ stackElement->map = NULL;
+ stackElement->funcCall = NULL;
+#endif
+}
+
+CW_INLINE void *StackElement_sub_48A780(StackElement *stackElement) {
+ IRO_ASSERT(213, stackElement != NULL);
+ return stackElement->proc;
+}
+
+CW_INLINE Boolean StackRelated_sub_48A760(void *key1, void *key2) {
+ IRO_ASSERT(220, key1 != NULL);
+ IRO_ASSERT(221, key2 != NULL);
+ return key1 == key2;
+}
+
+CW_INLINE Object *StackElement_proc(StackElement *stackElement) {
+ IRO_ASSERT(228, stackElement != NULL);
+ return stackElement->proc;
+}
+
+CW_INLINE PartialTransferFunction *StackElement_ptf(StackElement *stackElement) {
+ IRO_ASSERT(235, stackElement != NULL);
+ return stackElement->ptf;
+}
+
+CW_INLINE ParamMappingFunction *StackElement_map(StackElement *stackElement) {
+ IRO_ASSERT(242, stackElement != NULL);
+ return stackElement->map;
+}
+
+CW_INLINE IROLinear *StackElement_funcCall(StackElement *stackElement) {
+ IRO_ASSERT(249, stackElement != NULL);
+ return stackElement->funcCall;
+}
+
+CW_INLINE Stack *Stack_New(void) {
+ Stack *stack = IRO_malloc(sizeof(Stack));
+ IRO_ASSERT(265, stack != NULL);
+#ifdef IRO_DEBUG
+ stack->top = NULL;
+ stack->next = NULL;
+#endif
+ return stack;
+}
+
+CW_INLINE void Stack_Delete(Stack *stack) {
+ IRO_ASSERT(277, stack != NULL);
+ IRO_ASSERT(278, stack->top == NULL);
+ IRO_ASSERT(279, stack->next == NULL);
+ IRO_DEBUG_CLEAR(stack, sizeof(Stack));
+ IRO_free(stack);
+}
+
+CW_INLINE void Stack_Init(Stack *stack) {
+ IRO_ASSERT(289, stack != NULL);
+ stack->top = NULL;
+ stack->next = NULL;
+}
+
+CW_INLINE void Stack_Term(Stack **stackPtr) {
+ StackElement *stackElement;
+
+ IRO_ASSERT(299, stackPtr != NULL);
+ IRO_ASSERT(300, *stackPtr != NULL);
+
+ while ((*stackPtr)->top) {
+ stackElement = Stack_sub_48A5B0(stackPtr);
+ StackElement_Term(stackElement);
+ StackElement_Delete(stackElement);
+ }
+}
+
+CW_INLINE void Stack_sub_48A660(Stack **stackPtr, StackElement *stackElement) {
+ StackElement *newElement;
+ Stack *newStack;
+
+ IRO_ASSERT(315, stackPtr != NULL);
+ IRO_ASSERT(316, *stackPtr != NULL);
+
+ newElement = StackElement_New();
+ StackElement_Copy(newElement, stackElement);
+
+ newStack = Stack_New();
+ newStack->top = newElement;
+ newStack->next = *stackPtr;
+ *stackPtr = newStack;
+}
+
+CW_INLINE StackElement *Stack_Top(Stack **stackPtr) {
+ IRO_ASSERT(331, stackPtr != NULL);
+ IRO_ASSERT(332, *stackPtr != NULL);
+
+ return (*stackPtr)->top;
+}
+
+CW_INLINE Stack *Stack_Next(Stack **stackPtr) {
+ IRO_ASSERT(343, stackPtr != NULL);
+ IRO_ASSERT(344, *stackPtr != NULL);
+
+ return (*stackPtr)->next;
+}
+
+CW_INLINE StackElement *Stack_sub_48A5B0(Stack **stackPtr) {
+ StackElement *stackElement;
+
+ IRO_ASSERT(357, stackPtr != NULL);
+ IRO_ASSERT(358, *stackPtr != NULL);
+
+ stackElement = (*stackPtr)->top;
+ if (stackElement) {
+ Stack *next = (*stackPtr)->next;
+ (*stackPtr)->top = NULL;
+ (*stackPtr)->next = NULL;
+ Stack_Delete(*stackPtr);
+ *stackPtr = next;
+ }
+
+ return stackElement;
+}
+
+CW_INLINE StackElement *Stack_sub_48A710(Stack **stackPtr, void *key) {
+ Stack *stack;
+
+ IRO_ASSERT(379, stackPtr != NULL);
+ IRO_ASSERT(380, key != NULL);
+
+ for (stack = *stackPtr; stack; stack = stack->next) {
+ if (stack->top) {
+ if (StackRelated_sub_48A760(StackElement_sub_48A780(stack->top), key))
+ return stack->top;
+ }
+ }
+
+ return NULL;
+}
+
+CW_INLINE ObjectSet *ObjectSet_New(void) {
+ ObjectSet *procList;
+
+ procList = IRO_malloc(sizeof(ObjectSet));
+ IRO_ASSERT(439, procList != NULL);
+#ifdef IRO_DEBUG
+ procList->proc = NULL;
+ procList->otherProcs = NULL;
+#endif
+ return procList;
+}
+
+CW_INLINE void ObjectSet_Delete(ObjectSet *procList) {
+ IRO_ASSERT(451, procList != NULL);
+ IRO_ASSERT(452, procList->proc == NULL);
+ IRO_ASSERT(453, procList->otherProcs == NULL);
+ IRO_DEBUG_CLEAR(procList, sizeof(ObjectSet));
+ IRO_free(procList);
+}
+
+CW_INLINE void ObjectSet_Init(ObjectSet *procList) {
+ IRO_ASSERT(463, procList != NULL);
+ procList->proc = NULL;
+ procList->otherProcs = NULL;
+}
+
+CW_INLINE void ObjectSet_Term(ObjectSet *procList) {
+ IRO_ASSERT(481, procList != NULL);
+ ObjectSet_RemoveAll(procList);
+#ifdef IRO_DEBUG
+ procList->proc = NULL;
+ procList->otherProcs = NULL;
+#endif
+}
+
+CW_INLINE void ObjectSet_ForEach(ObjectSet *procList, void (*action)(Object *, void *), void *refcon) {
+ IRO_ASSERT(528, procList != NULL);
+ IRO_ASSERT(529, action != NULL);
+ IRO_ASSERT(530, refcon == NULL || refcon != NULL);
+
+ while (procList && procList->proc) {
+ action(procList->proc, refcon);
+ procList = procList->otherProcs;
+ }
+}
+
+CW_INLINE Object *ObjectSet_sub_485020(ObjectSet *procList, Object *proc) {
+ IRO_ASSERT(540, procList != NULL);
+ IRO_ASSERT(541, proc != NULL);
+ while (procList && procList->proc) {
+ if (procList->proc == proc)
+ return procList->proc;
+ procList = procList->otherProcs;
+ }
+ return NULL;
+}
+
+CW_INLINE Object *ObjectSet_FindFirst(ObjectSet *procList) {
+ IRO_ASSERT(552, procList != NULL);
+ return procList->proc;
+}
+
+CW_INLINE int ObjectSet_Count(ObjectSet *procList) {
+ int count;
+
+ IRO_ASSERT(561, procList != NULL);
+
+ count = 0;
+ while (procList && procList->proc) {
+ count++;
+ procList = procList->otherProcs;
+ }
+
+ return count;
+}
+
+CW_INLINE void ObjectSet_sub_486800(ObjectSet *procList, Object *proc) {
+ ObjectSet *newProcList;
+
+ IRO_ASSERT(574, procList != NULL);
+ IRO_ASSERT(575, proc != NULL);
+
+ if (procList->proc) {
+ newProcList = ObjectSet_New();
+ ObjectSet_Init(newProcList);
+ newProcList->proc = procList->proc;
+ newProcList->otherProcs = procList->otherProcs;
+ procList->otherProcs = newProcList;
+ }
+
+ procList->proc = proc;
+}
+
+CW_INLINE void ObjectSet_sub_4867D0(ObjectSet *procList, Object *proc) {
+ IRO_ASSERT(592, procList != NULL);
+ IRO_ASSERT(593, proc != NULL);
+
+ if (!ObjectSet_sub_485020(procList, proc))
+ ObjectSet_sub_486800(procList, proc);
+}
+
+CW_INLINE void ObjectSet_Remove(ObjectSet *procList, Object *proc) {
+ ObjectSet *prev;
+ ObjectSet *tmp;
+
+ IRO_ASSERT(605, procList != NULL);
+ IRO_ASSERT(606, proc != NULL);
+
+ prev = NULL;
+ while (procList && procList->proc) {
+ if (procList->proc == proc) {
+ if (!prev) {
+ if (procList->otherProcs == NULL) {
+ procList->proc = NULL;
+ } else {
+ tmp = procList->otherProcs;
+ procList->proc = procList->otherProcs->proc;
+ procList->otherProcs = procList->otherProcs->otherProcs;
+ tmp->proc = NULL;
+ tmp->otherProcs = NULL;
+ ObjectSet_Term(tmp);
+ ObjectSet_Delete(tmp);
+ }
+ } else {
+ prev->otherProcs = procList->otherProcs;
+ procList->proc = NULL;
+ procList->otherProcs = NULL;
+ ObjectSet_Term(procList);
+ ObjectSet_Delete(procList);
+ }
+ return;
+ }
+ prev = procList;
+ procList = procList->otherProcs;
+ }
+}
+
+CW_INLINE void ObjectSet_RemoveAll(ObjectSet *procList) {
+ IRO_ASSERT(645, procList != NULL);
+
+ while (procList && procList->proc)
+ ObjectSet_Remove(procList, procList->proc);
+}
+
+CW_INLINE void ObjectSet_AddSetAction(Object *proc, void *refcon) {
+ IRO_ASSERT(655, proc != NULL);
+ IRO_ASSERT(656, refcon != NULL);
+
+ ObjectSet_sub_4867D0(refcon, proc);
+}
+
+CW_INLINE void ObjectSet_SimpleAddSetAction(Object *proc, void *refcon) {
+ IRO_ASSERT(663, proc != NULL);
+ IRO_ASSERT(664, refcon != NULL);
+
+ ObjectSet_sub_486800(refcon, proc);
+}
+
+CW_INLINE void ObjectSet_sub_48C590(ObjectSet *dest, ObjectSet *src) {
+ IRO_ASSERT(671, dest != NULL);
+ IRO_ASSERT(672, src != NULL);
+
+ if (dest->proc)
+ ObjectSet_ForEach(src, ObjectSet_AddSetAction, dest);
+ else
+ ObjectSet_ForEach(src, ObjectSet_SimpleAddSetAction, dest);
+}
+
+CW_INLINE void ObjectSet_RemoveSetAction(Object *proc, void *refcon) {
+ IRO_ASSERT(682, proc != NULL);
+ IRO_ASSERT(683, refcon != NULL);
+
+ ObjectSet_Remove(refcon, proc);
+}
+
+CW_INLINE void ObjectSet_removeiter_sub_48C890(ObjectSet *dest, ObjectSet *src) {
+ IRO_ASSERT(690, dest != NULL);
+ IRO_ASSERT(691, src != NULL);
+
+ ObjectSet_ForEach(src, ObjectSet_RemoveSetAction, dest);
+}
+
+CW_INLINE Boolean ObjectSet_sub_484FA0(ObjectSet *os1, ObjectSet *os2) {
+ ObjectSet *scan;
+
+ IRO_ASSERT(700, os1 != NULL);
+ IRO_ASSERT(701, os2 != NULL);
+
+ if (os1 == os2)
+ return 1;
+
+ for (scan = os1; scan && scan->proc; scan = scan->otherProcs) {
+ if (!ObjectSet_sub_485020(os2, scan->proc))
+ return 0;
+ }
+
+ for (scan = os2; scan && scan->proc; scan = scan->otherProcs) {
+ if (!ObjectSet_sub_485020(os1, scan->proc))
+ return 0;
+ }
+
+ return 1;
+}
+
+CW_INLINE ExtendedParam *ExtendedParam_New(void) {
+ ExtendedParam *ep = IRO_malloc(sizeof(ExtendedParam));
+
+ IRO_ASSERT(755, ep != NULL);
+#ifdef IRO_DEBUG
+ ep->objectSet = NULL;
+#endif
+ return ep;
+}
+
+CW_INLINE void ExtendedParam_Delete(ExtendedParam *ep) {
+ IRO_ASSERT(762, ep != NULL);
+ IRO_ASSERT(763, ep->objectSet == NULL);
+ IRO_DEBUG_CLEAR(ep, sizeof(ExtendedParam));
+ IRO_free(ep);
+}
+
+CW_INLINE void ExtendedParam_Init(ExtendedParam *ep, Object *obj) {
+ IRO_ASSERT(777, ep != NULL);
+ IRO_ASSERT(778, obj != NULL);
+ IRO_ASSERT(779, obj->extParam == NULL);
+ IRO_ASSERT(780, stExtendedParamNum < ((uint32) -1) / 2 - 1);
+
+ ep->objectSet = ObjectSet_New();
+ ObjectSet_Init(ep->objectSet);
+ ObjectSet_sub_4867D0(ep->objectSet, obj);
+ obj->extParam = ep;
+
+ ep->x4 = stExtendedParamNum++;
+}
+
+CW_INLINE void ExtendedParam_TermAction(Object *obj, void *refcon) {
+ obj->extParam = NULL;
+}
+
+CW_INLINE void ExtendedParam_Term(ExtendedParam *ep) {
+ IRO_ASSERT(800, ep != NULL);
+
+ ObjectSet_ForEach(ep->objectSet, ExtendedParam_TermAction, NULL);
+ ObjectSet_Term(ep->objectSet);
+ ObjectSet_Delete(ep->objectSet);
+#ifdef IRO_DEBUG
+ ep->objectSet = NULL;
+#endif
+}
+
+CW_INLINE Boolean ExtendedParams_Equal(ExtendedParam *ep1, ExtendedParam *ep2) {
+ IRO_ASSERT(841, ep1 != NULL);
+ IRO_ASSERT(842, ep2 != NULL);
+ IRO_ASSERT(843, ep1->objectSet != NULL);
+ IRO_ASSERT(844, ep2->objectSet != NULL);
+
+ if (ep1 == ep2)
+ return 1;
+
+ return ep1->x4 == ep2->x4 && ObjectSet_sub_484FA0(ep1->objectSet, ep2->objectSet);
+}
+
+CW_INLINE ExtendedParam *ExtendedParam_FindByObject(Object *obj) {
+ IRO_ASSERT(856, obj != NULL);
+
+ return obj->extParam;
+}
+
+CW_INLINE void ExtendedParam_sub_4867B0(ExtendedParam *ep, Object *obj) {
+ IRO_ASSERT(863, ep != NULL);
+ IRO_ASSERT(864, ep->objectSet != NULL);
+ IRO_ASSERT(865, obj != NULL);
+
+ ObjectSet_sub_4867D0(ep->objectSet, obj);
+ obj->extParam = ep;
+}
+
+CW_INLINE void ExtendedParam_RemoveObjectSetAction(Object *object, void *refcon) {
+ object->extParam = NULL;
+}
+
+CW_INLINE void EP_sub_48C850(ExtendedParam *ep, ObjectSet *objSet) {
+ IRO_ASSERT(888, ep != NULL);
+ IRO_ASSERT(889, ep->objectSet != NULL);
+ IRO_ASSERT(890, objSet != NULL);
+
+ ObjectSet_removeiter_sub_48C890(ep->objectSet, objSet);
+ ObjectSet_ForEach(objSet, ExtendedParam_RemoveObjectSetAction, NULL);
+}
+
+CW_INLINE ObjectSet *ExtendedParam_objectSet(ExtendedParam *ep) {
+ IRO_ASSERT(898, ep != NULL);
+
+ return ep->objectSet;
+}
+
+CW_INLINE uint32 ExtendedParam_sub_489110(ExtendedParam *ep) {
+ IRO_ASSERT(905, ep != NULL);
+
+ return ep->x4;
+}
+
+CW_INLINE ExtendedParamSet *AllocsExtParamSet_sub_4876C0(void) {
+ ExtendedParamSet *epList = IRO_malloc(sizeof(ExtendedParamSet));
+
+ IRO_ASSERT(924, epList != NULL);
+#ifdef IRO_DEBUG
+ epList->ep = NULL;
+ epList->otherEps = NULL;
+#endif
+ return epList;
+}
+
+CW_INLINE void FreesExtParamSet_sub_48CAE0(ExtendedParamSet *epList) {
+ IRO_ASSERT(936, epList != NULL);
+ IRO_ASSERT(937, epList->ep == NULL);
+ IRO_ASSERT(938, epList->otherEps == NULL);
+ IRO_DEBUG_CLEAR(epList, sizeof(ExtendedParamSet));
+ IRO_free(epList);
+}
+
+CW_INLINE void InitsExtParamSet_sub_4876A0(ExtendedParamSet *epList) {
+ IRO_ASSERT(948, epList != NULL);
+ epList->ep = NULL;
+ epList->otherEps = NULL;
+}
+
+CW_INLINE void TermsExtParamSet_sub_48CB00(ExtendedParamSet *epList) {
+ IRO_ASSERT(966, epList != NULL);
+ ExtendedParamSet_RemoveAll(epList);
+#ifdef IRO_DEBUG
+ epList->ep = NULL;
+ epList->otherEps = NULL;
+#endif
+}
+
+CW_INLINE void MaybeWalkExtParamSet_sub_48CBE0(ExtendedParamSet *epList, void (*action)(ExtendedParam *, void *), void *refcon) {
+ IRO_ASSERT(1010, epList != NULL);
+ IRO_ASSERT(1011, action != NULL);
+
+ while (epList && epList->ep) {
+ action(epList->ep, refcon);
+ epList = epList->otherEps;
+ }
+}
+
+CW_INLINE ExtendedParam *ExtParamSet_sub_4876D0(ExtendedParamSet *epList, ExtendedParam *ep) {
+ IRO_ASSERT(1022, epList != NULL);
+ IRO_ASSERT(1023, ep != NULL);
+
+ while (epList && epList->ep) {
+ if (epList->ep == ep)
+ return epList->ep;
+ epList = epList->otherEps;
+ }
+
+ return NULL;
+}
+
+CW_INLINE void ExtParamSet_sub_487660(ExtendedParamSet *epList, ExtendedParam *ep) {
+ IRO_ASSERT(1056, epList != NULL);
+ IRO_ASSERT(1057, ep != NULL);
+
+ if (epList->ep) {
+ ExtendedParamSet *newSet = AllocsExtParamSet_sub_4876C0();
+ InitsExtParamSet_sub_4876A0(newSet);
+ newSet->ep = epList->ep;
+ newSet->otherEps = epList->otherEps;
+ epList->otherEps = newSet;
+ }
+
+ epList->ep = ep;
+}
+
+CW_INLINE void ExtParamSet_sub_487630(ExtendedParamSet *epList, ExtendedParam *ep) {
+ IRO_ASSERT(1076, epList != NULL);
+ IRO_ASSERT(1077, ep != NULL);
+
+ if (!ExtParamSet_sub_4876D0(epList, ep))
+ ExtParamSet_sub_487660(epList, ep);
+}
+
+CW_INLINE void ExtendedParamSet_Remove(ExtendedParamSet *epList, ExtendedParam *ep) {
+ ExtendedParamSet *prev;
+ ExtendedParamSet *tmp;
+
+ IRO_ASSERT(1089, epList != NULL);
+ IRO_ASSERT(1090, ep != NULL);
+
+ prev = NULL;
+ while (epList && epList->ep) {
+ if (epList->ep == ep) {
+ if (!prev) {
+ if (epList->otherEps == NULL) {
+ epList->ep = NULL;
+ } else {
+ tmp = epList->otherEps;
+ epList->ep = epList->otherEps->ep;
+ epList->otherEps = epList->otherEps->otherEps;
+ tmp->ep = NULL;
+ tmp->otherEps = NULL;
+ TermsExtParamSet_sub_48CB00(tmp);
+ FreesExtParamSet_sub_48CAE0(tmp);
+ }
+ } else {
+ prev->otherEps = epList->otherEps;
+ epList->ep = NULL;
+ epList->otherEps = NULL;
+ TermsExtParamSet_sub_48CB00(epList);
+ FreesExtParamSet_sub_48CAE0(epList);
+ }
+ return;
+ }
+ prev = epList;
+ epList = epList->otherEps;
+ }
+}
+
+CW_INLINE void ExtendedParamSet_RemoveAll(ExtendedParamSet *epList) {
+ IRO_ASSERT(1129, epList != NULL);
+
+ while (epList && epList->ep)
+ ExtendedParamSet_Remove(epList, epList->ep);
+}
+
+CW_INLINE PAHeapBlock *CreateUniqueHeapAlloc_sub_486420(void) {
+ PAHeapBlock *hb = IRO_malloc(sizeof(PAHeapBlock));
+
+ IRO_ASSERT(1225, hb != NULL);
+#ifdef IRO_DEBUG
+ hb->parent = NULL;
+#endif
+ return hb;
+}
+
+CW_INLINE void InitUniqueHeapAlloc_sub_486410(PAHeapBlock *hb, IROLinear *nd) {
+ IRO_ASSERT(1247, hb != NULL);
+
+ hb->x0 = nd;
+}
+
+CW_INLINE Boolean PAHeapBlocks_Equal(PAHeapBlock *hb1, PAHeapBlock *hb2) {
+ IRO_ASSERT(1296, hb1 != NULL);
+ IRO_ASSERT(1297, hb2 != NULL);
+
+ return (hb1 == hb2) || (hb1->x0 == hb2->x0);
+}
+
+CW_INLINE PALocalVar *PALocalVar_New(void) {
+ PALocalVar *local = IRO_malloc(sizeof(PALocalVar));
+
+ IRO_ASSERT(1333, local != NULL);
+#ifdef IRO_DEBUG
+ local->parent = NULL;
+ local->nextSibling = NULL;
+#endif
+ return local;
+}
+
+CW_INLINE void PALocalVar_InitByObject(PALocalVar *local, Object *obj) {
+ IRO_ASSERT(1357, local != NULL);
+ IRO_ASSERT(1358, obj != NULL);
+
+ local->x0 = obj;
+ if (obj->name && obj->name->name) {
+ local->x4 = IRO_malloc(strlen(obj->name->name) + 1);
+ strcpy(local->x4, obj->name->name);
+ } else {
+ local->x4 = NULL;
+ }
+}
+
+CW_INLINE void PALocalVar_InitByName(PALocalVar *local, char *name) {
+ IRO_ASSERT(1372, local != NULL);
+ IRO_ASSERT(1373, name != NULL);
+
+ local->x0 = NULL;
+ local->x4 = IRO_malloc(strlen(name) + 1);
+ strcpy(local->x4, name);
+}
+
+CW_INLINE Boolean PALocalVars_Equal(PALocalVar *local1, PALocalVar *local2) {
+ IRO_ASSERT(1419, local1 == NULL || local1 != NULL);
+ IRO_ASSERT(1420, local2 == NULL || local2 != NULL);
+
+ if (local1 == local2)
+ return 1;
+ if (!local1 || !local2)
+ return 0;
+
+ if (!local1->x0 || !local2->x0) {
+ if (local1->x4)
+ return local2->x4 && !strcmp(local1->x4, local2->x4);
+ }
+
+ return local1->x0 == local2->x0;
+}
+
+CW_INLINE void PALocalVar_SetSth_sub_4847C0(PALocalVar *local, Object *obj) {
+ IRO_ASSERT(1436, local != NULL);
+ IRO_ASSERT(1437, obj == NULL || obj != NULL);
+
+ local->x0 = obj;
+}
+
+CW_INLINE Object *PALocalVar_Get0_sub_4847E0(PALocalVar *local) {
+ IRO_ASSERT(1444, local != NULL);
+ return local->x0;
+}
+
+CW_INLINE char *PALocalVar_Get4_sub_4847D0(PALocalVar *local) {
+ IRO_ASSERT(1451, local != NULL);
+ return local->x4;
+}
+
+CW_INLINE PAMemoryBlock *PAMemoryBlock_New(void) {
+ PAMemoryBlock *mb = IRO_malloc(sizeof(PAMemoryBlock));
+
+ IRO_ASSERT(1491, mb != NULL);
+#ifdef IRO_DEBUG
+ mb->kind = PAMEMORYBLOCKKIND_INVALID;
+#endif
+ return mb;
+}
+
+CW_INLINE void PAMemoryBlock_Delete(PAMemoryBlock *mb) {
+ IRO_ASSERT(1502, mb != NULL);
+ IRO_ASSERT(1503, mb->kind == PAMEMORYBLOCKKIND_INVALID);
+ IRO_free(mb);
+}
+
+CW_INLINE void PAMemoryBlock_Init(PAMemoryBlock *mb, PAMemoryBlockKind kind, void *thing) {
+ IRO_ASSERT(1513, mb != NULL);
+ IRO_ASSERT(1514, thing == NULL || thing != NULL);
+
+ mb->kind = kind;
+ switch (mb->kind) {
+ case PAMEMORYBLOCKKIND_EXTENDEDPARAM:
+ mb->u.ep = (ExtendedParam *) thing;
+ break;
+ case PAMEMORYBLOCKKIND_LOCALVAR:
+ mb->u.localvar = (PALocalVar *) thing;
+ break;
+ case PAMEMORYBLOCKKIND_HEAPBLOCK:
+ mb->u.heapblock = (PAHeapBlock *) thing;
+ break;
+ case PAMEMORYBLOCKKIND_INT:
+ mb->u.intval = *((CInt64 *) thing);
+ break;
+ case PAMEMORYBLOCKKIND_6:
+ mb->u.x6 = (void *) thing;
+ break;
+ default:
+ CError_FATAL(1535);
+ }
+}
+
+CW_INLINE void PAMemoryBlock_Term(PAMemoryBlock *mb) {
+ IRO_ASSERT(1552, mb != NULL);
+
+#ifdef IRO_DEBUG
+ mb->kind = PAMEMORYBLOCKKIND_INVALID;
+#endif
+}
+
+CW_INLINE Boolean MemoryBlocks_Equal(PAMemoryBlock *mb1, PAMemoryBlock *mb2) {
+ IRO_ASSERT(1657, mb1 == NULL || mb1 != NULL);
+ IRO_ASSERT(1658, mb2 == NULL || mb2 != NULL);
+
+ if (mb1 == mb2)
+ return 1;
+
+ if (!mb1 || !mb2 || mb1->kind != mb2->kind)
+ return 0;
+
+ switch (mb1->kind) {
+ case PAMEMORYBLOCKKIND_EXTENDEDPARAM:
+ return ExtendedParams_Equal(mb1->u.ep, mb2->u.ep);
+ case PAMEMORYBLOCKKIND_LOCALVAR:
+ return PALocalVars_Equal(mb1->u.localvar, mb2->u.localvar);
+ case PAMEMORYBLOCKKIND_HEAPBLOCK:
+ return PAHeapBlocks_Equal(mb1->u.heapblock, mb2->u.heapblock);
+ case PAMEMORYBLOCKKIND_INT:
+ return CInt64_Equal(mb1->u.intval, mb2->u.intval);
+ case PAMEMORYBLOCKKIND_6:
+ return mb1->u.x6 == mb2->u.x6;
+ default:
+ CError_FATAL(1684);
+ return 0;
+ }
+}
+
+CW_INLINE PAMemoryBlockKind PAMemoryBlock_kind(PAMemoryBlock *mb) {
+ IRO_ASSERT(1692, mb != NULL);
+
+ return mb->kind;
+}
+
+CW_INLINE void *PAMemoryBlock_thing(PAMemoryBlock *mb) {
+ IRO_ASSERT(1699, mb != NULL);
+
+ switch (mb->kind) {
+ case PAMEMORYBLOCKKIND_EXTENDEDPARAM:
+ return mb->u.ep;
+ case PAMEMORYBLOCKKIND_LOCALVAR:
+ return mb->u.localvar;
+ case PAMEMORYBLOCKKIND_HEAPBLOCK:
+ return mb->u.heapblock;
+ case PAMEMORYBLOCKKIND_INT:
+ return &mb->u.intval;
+ case PAMEMORYBLOCKKIND_6:
+ return mb->u.x6;
+ default:
+ CError_FATAL(1719);
+ return NULL;
+ }
+}
+
+CW_INLINE LocationSet *LocationSet_New(void) {
+ LocationSet *ls = IRO_malloc(sizeof(LocationSet));
+
+ IRO_ASSERT(1767, ls != NULL);
+#ifdef IRO_DEBUG
+ ls->block = NULL;
+ ls->rtype = NULL;
+ ls->u.known.field = cint64_zero;
+ ls->u.known.stride = 0;
+#endif
+ return ls;
+}
+
+CW_INLINE void LocationSet_Delete(LocationSet *ls) {
+ IRO_ASSERT(1781, ls != NULL);
+ IRO_ASSERT(1782, ls != stUnknownLs);
+ IRO_ASSERT(1783, ls->block == NULL);
+ IRO_ASSERT(1784, CInt64_IsZero(&ls->u.known.field));
+ IRO_ASSERT(1785, ls->u.known.stride == 0);
+ IRO_ASSERT(1786, ls->rtype == NULL);
+ IRO_DEBUG_CLEAR(ls, sizeof(LocationSet));
+ IRO_free(ls);
+}
+
+CW_INLINE void LocationSet_InitKnown(LocationSet *ls, PAMemoryBlock *block, CInt64 field, UInt32 stride, Type *rtype) {
+ IRO_ASSERT(1796, ls != NULL);
+ IRO_ASSERT(1797, ls != stUnknownLs);
+ IRO_ASSERT(1798, block != NULL);
+ IRO_ASSERT(1799, rtype == NULL || rtype != NULL);
+ ls->block = block;
+ ls->rtype = rtype;
+ ls->u.known.field = field;
+ ls->u.known.stride = stride;
+}
+
+CW_INLINE void LocationSet_InitUnknown(LocationSet *ls, Type *rtype, PAMemoryBlock *restriction, LocationSet *bitfieldOf) {
+ IRO_ASSERT(1809, ls != NULL);
+ IRO_ASSERT(1810, ls != stUnknownLs);
+ IRO_ASSERT(1811, rtype == NULL || rtype != NULL);
+ IRO_ASSERT(1812, restriction == NULL || restriction != NULL);
+ IRO_ASSERT(1813, bitfieldOf == NULL || bitfieldOf != NULL);
+
+ LocationSet_Copy(ls, stUnknownLs);
+ ls->rtype = rtype;
+ ls->u.unknown.restriction = restriction;
+ if (bitfieldOf) {
+ ls->u.unknown.bitfieldOf = LocationSet_New();
+ LocationSet_Copy(ls->u.unknown.bitfieldOf, bitfieldOf);
+ } else {
+ ls->u.unknown.bitfieldOf = NULL;
+ }
+}
+
+CW_INLINE void LocationSet_Copy(LocationSet *dest, LocationSet *src) {
+ IRO_ASSERT(1829, src != NULL);
+ IRO_ASSERT(1830, dest != NULL);
+
+ dest->block = src->block;
+ dest->rtype = src->rtype;
+
+ if (!LocationSet_IsUnknown(src)) {
+ dest->u.known.field = src->u.known.field;
+ dest->u.known.stride = src->u.known.stride;
+ } else {
+ dest->u.unknown.restriction = src->u.unknown.restriction;
+ if (src->u.unknown.bitfieldOf != NULL) {
+ dest->u.unknown.bitfieldOf = LocationSet_New();
+ LocationSet_Copy(dest->u.unknown.bitfieldOf, src->u.unknown.bitfieldOf);
+ } else {
+ dest->u.unknown.bitfieldOf = NULL;
+ }
+ }
+}
+
+CW_INLINE void LocationSet_Term(LocationSet *ls) {
+ IRO_ASSERT(1857, ls != NULL);
+ IRO_ASSERT(1858, ls != stUnknownLs);
+
+#ifdef IRO_DEBUG
+ if (LocationSet_IsUnknown(ls) && ls->u.unknown.bitfieldOf) {
+ LocationSet_Term(ls->u.unknown.bitfieldOf);
+ LocationSet_Delete(ls->u.unknown.bitfieldOf);
+ }
+ ls->block = NULL;
+ ls->rtype = NULL;
+ ls->u.known.field = cint64_zero;
+ ls->u.known.stride = 0;
+#endif
+}
+
+CW_INLINE Boolean LocationSets_Overlap(LocationSet *ls1, Type *rtype1, LocationSet *ls2, Type *rtype2) {
+ Boolean isUnknown1, isUnknown2;
+ PAMemoryBlock *restriction1, *restriction2;
+
+ IRO_ASSERT(1974, ls1 != NULL);
+ IRO_ASSERT(1975, rtype1 == NULL || rtype1 != NULL);
+ IRO_ASSERT(1976, ls2 != NULL);
+ IRO_ASSERT(1977, rtype2 == NULL || rtype2 != NULL);
+
+ if (ls1 == ls2)
+ return 1;
+
+ isUnknown1 = LocationSet_IsUnknown(ls1);
+ if (isUnknown1)
+ restriction1 = ls1->u.unknown.restriction;
+ else
+ restriction1 = NULL;
+
+ isUnknown2 = LocationSet_IsUnknown(ls2);
+ if (isUnknown2)
+ restriction2 = ls2->u.unknown.restriction;
+ else
+ restriction2 = NULL;
+
+ if (
+ (isUnknown1 && !restriction1) ||
+ (isUnknown2 && !restriction2) ||
+ (isUnknown1 && isUnknown2 && MemoryBlocks_Equal(restriction1, restriction2))
+ )
+ return 1;
+
+ if (isUnknown1 || isUnknown2)
+ return 0;
+
+ if (MemoryBlocks_Equal(ls1->block, ls2->block)) {
+ UInt32 size1;
+ UInt32 size2;
+ UInt32 i;
+ CInt64 work;
+ CInt64 longgcd;
+
+ if (rtype1)
+ size1 = rtype1->size;
+ else
+ size1 = -1;
+
+ if (rtype2)
+ size2 = rtype2->size;
+ else
+ size2 = -1;
+
+ if (ls1->u.known.stride == ls2->u.known.stride) {
+ CInt64 longsize1;
+ CInt64 longsize2;
+ CInt64_SetULong(&longsize1, size1);
+ CInt64_SetULong(&longsize2, size2);
+
+ return CInt64_Equal(ls1->u.known.field, ls2->u.known.field) ||
+ (CInt64_Less(ls1->u.known.field, ls2->u.known.field) && CInt64_Greater(CInt64_Add(ls1->u.known.field, longsize1), ls2->u.known.field)) ||
+ (CInt64_Less(ls2->u.known.field, ls1->u.known.field) && CInt64_Greater(CInt64_Add(ls2->u.known.field, longsize2), ls1->u.known.field));
+ } else {
+ work = CInt64_Sub(ls1->u.known.field, ls2->u.known.field);
+ if (CInt64_IsNegative(&work))
+ work = CInt64_Neg(work);
+
+ CInt64_SetULong(&longgcd, gcd(ls1->u.known.stride, ls2->u.known.stride));
+ if (CInt64_Equal(CInt64_ModU(work, longgcd), cint64_zero))
+ return 1;
+
+ if (size1 == -1)
+ return 1;
+
+ for (i = 1; i < size1; i++) {
+ CInt64_SetLong(&work, i);
+ work = CInt64_Add(work, ls1->u.known.field);
+ work = CInt64_Sub(work, ls2->u.known.field);
+ if (CInt64_IsNegative(&work))
+ work = CInt64_Neg(work);
+ if (CInt64_Equal(CInt64_ModU(work, longgcd), cint64_zero))
+ return 1;
+ }
+
+ if (size2 == -1)
+ return 1;
+
+ for (i = 1; i < size2; i++) {
+ CInt64_SetLong(&work, i);
+ work = CInt64_Add(work, ls2->u.known.field);
+ work = CInt64_Sub(work, ls1->u.known.field);
+ if (CInt64_IsNegative(&work))
+ work = CInt64_Neg(work);
+ if (CInt64_Equal(CInt64_ModU(work, longgcd), cint64_zero))
+ return 1;
+ }
+
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+CW_INLINE Boolean LocationSets_Equal(LocationSet *ls1, LocationSet *ls2) {
+ IRO_ASSERT(2080, ls1 != NULL);
+ IRO_ASSERT(2081, ls2 != NULL);
+
+ return
+ (ls1 == ls2) ||
+ (
+ (LocationSet_IsUnknown(ls1) && LocationSet_IsUnknown(ls2)) &&
+ (MemoryBlocks_Equal(ls1->u.unknown.restriction, ls2->u.unknown.restriction)) &&
+ ((ls1->u.unknown.bitfieldOf == ls2->u.unknown.bitfieldOf) ||
+ (ls1->u.unknown.bitfieldOf && ls2->u.unknown.bitfieldOf && LocationSets_Equal(ls1->u.unknown.bitfieldOf, ls2->u.unknown.bitfieldOf))) &&
+ ((ls1->rtype == ls2->rtype) || (ls1->rtype && ls2->rtype && ls1->rtype->size == ls2->rtype->size))
+ ) ||
+ (
+ (!LocationSet_IsUnknown(ls1) && !LocationSet_IsUnknown(ls2)) &&
+ (ls1->u.known.stride == ls2->u.known.stride) &&
+ ((ls1->rtype == ls2->rtype) || (ls1->rtype && ls2->rtype && ls1->rtype->size == ls2->rtype->size)) &&
+ CInt64_Equal(ls1->u.known.field, ls2->u.known.field) &&
+ MemoryBlocks_Equal(ls1->block, ls2->block)
+ );
+}
+
+CW_INLINE Boolean LocationSets_LookupCompatible(LocationSet *ls1, LocationSet *ls2) {
+ IRO_ASSERT(2119, ls1 != NULL);
+ IRO_ASSERT(2120, ls2 != NULL);
+
+ if (
+ (ls1 == ls2) ||
+ (
+ LocationSet_IsUnknown(ls1) &&
+ LocationSet_IsUnknown(ls2) &&
+ MemoryBlocks_Equal(ls1->u.unknown.restriction, ls2->u.unknown.restriction) &&
+ (ls1->rtype == ls2->rtype || (ls1->rtype && ls2->rtype && ls1->rtype->size == ls2->rtype->size))
+ ))
+ return 1;
+
+ if (
+ (!LocationSet_IsUnknown(ls1) && !LocationSet_IsUnknown(ls2)) &&
+ (ls1->rtype == ls2->rtype || (ls1->rtype && ls2->rtype && ls1->rtype->size == ls2->rtype->size)) &&
+ MemoryBlocks_Equal(ls1->block, ls2->block)
+ ) {
+ CInt64 work;
+ CInt64 longgcd;
+
+ if (ls1->u.known.stride == ls2->u.known.stride)
+ return CInt64_Equal(ls1->u.known.field, ls2->u.known.field);
+
+ work = CInt64_Sub(ls1->u.known.field, ls2->u.known.field);
+ if (CInt64_IsNegative(&work))
+ work = CInt64_Neg(work);
+
+ CInt64_SetULong(&longgcd, gcd(ls1->u.known.stride, ls2->u.known.stride));
+ return CInt64_Equal(CInt64_ModU(work, longgcd), cint64_zero);
+ }
+
+ return 0;
+}
+
+CW_INLINE Boolean LocationSet_Contains(LocationSet *ls1, Type *rtype1, LocationSet *ls2, Type *rtype2) {
+ Boolean unknown1;
+ Boolean unknown2;
+ PAMemoryBlock *restriction2;
+ PAMemoryBlock *restriction1;
+ CInt64 longsize1;
+ CInt64 longsize2;
+
+ IRO_ASSERT(2168, ls1 != NULL);
+ IRO_ASSERT(2169, ls2 != NULL);
+ IRO_ASSERT(2170, rtype1 != NULL);
+ IRO_ASSERT(2171, rtype2 != NULL);
+
+ if (ls1 == ls2)
+ return 1;
+
+ unknown1 = LocationSet_IsUnknown(ls1);
+ if (unknown1)
+ restriction1 = ls1->u.unknown.restriction;
+ else
+ restriction1 = NULL;
+
+ unknown2 = LocationSet_IsUnknown(ls2);
+ if (unknown2)
+ restriction2 = ls2->u.unknown.restriction;
+ else
+ restriction2 = NULL;
+
+ if (unknown1)
+ return !restriction1 || (unknown2 && MemoryBlocks_Equal(restriction2, restriction1));
+
+ CInt64_SetULong(&longsize1, rtype1->size);
+ CInt64_SetULong(&longsize2, rtype2->size);
+
+ return
+ !LocationSet_IsUnknown(ls2) &&
+ (ls1->u.known.stride == 0) &&
+ (ls2->u.known.stride == 0) &&
+ rtype1->size >= rtype2->size &&
+ CInt64_LessEqual(ls1->u.known.field, ls2->u.known.field) &&
+ CInt64_GreaterEqual(CInt64_Add(ls1->u.known.field, longsize1), CInt64_Add(ls2->u.known.field, longsize2)) &&
+ MemoryBlocks_Equal(ls1->block, ls2->block);
+}
+
+CW_INLINE Boolean LocationSet_IsUnknown(LocationSet *ls) {
+ IRO_ASSERT(2233, ls != NULL);
+
+ return (ls == stUnknownLs) || (ls->block == stUnknownMb);
+}
+
+CW_INLINE Boolean LocationSet_sub_48AF30(LocationSet *ls) {
+ return
+ !LocationSet_IsUnknown(ls) &&
+ (ls->u.known.stride == 0) &&
+ CInt64_IsZero(&ls->u.known.field) &&
+ PAMemoryBlock_kind(ls->block) == PAMEMORYBLOCKKIND_LOCALVAR &&
+ !PAMemoryBlock_thing(ls->block);
+}
+
+CW_INLINE void LocationSet_SetRtype(LocationSet *ls, Type *rtype) {
+ IRO_ASSERT(2263, ls != NULL);
+ IRO_ASSERT(2264, ls != stUnknownLs);
+ IRO_ASSERT(2265, rtype != NULL);
+
+ ls->rtype = rtype;
+}
+
+CW_INLINE void SetsLocationSetField_sub_4851B0(LocationSet *ls, CInt64 field) {
+ IRO_ASSERT(2272, ls != NULL);
+ IRO_ASSERT(2273, !LocationSet_IsUnknown(ls));
+
+ ls->u.known.field = field;
+}
+
+CW_INLINE void SetsLocationSetStride_sub_4852D0(LocationSet *ls, SInt32 stride) {
+ IRO_ASSERT(2280, ls != NULL);
+ IRO_ASSERT(2281, !LocationSet_IsUnknown(ls));
+
+ ls->u.known.stride = stride;
+}
+
+CW_INLINE PAMemoryBlock *LocationSet_block(LocationSet *ls) {
+ IRO_ASSERT(2298, ls != NULL);
+
+ return ls->block;
+}
+
+CW_INLINE Type *LocationSet_rtype(LocationSet *ls) {
+ IRO_ASSERT(2306, ls != NULL);
+ IRO_ASSERT(2307, ls != stUnknownLs);
+
+ return ls->rtype;
+}
+
+CW_INLINE CInt64 LocationSet_field(LocationSet *ls) {
+ IRO_ASSERT(2314, ls != NULL);
+ IRO_ASSERT(2315, !LocationSet_IsUnknown(ls));
+
+ return ls->u.known.field;
+}
+
+CW_INLINE UInt32 LocationSet_stride(LocationSet *ls) {
+ IRO_ASSERT(2322, ls != NULL);
+ IRO_ASSERT(2323, !LocationSet_IsUnknown(ls));
+
+ return ls->u.known.stride;
+}
+
+CW_INLINE PAMemoryBlock *LocationSet_restriction(LocationSet *ls) {
+ IRO_ASSERT(2330, ls != NULL);
+ IRO_ASSERT(2331, LocationSet_IsUnknown(ls));
+
+ return ls->u.unknown.restriction;
+}
+
+CW_INLINE LocationSet *LocationSet_bitfieldOf(LocationSet *ls) {
+ IRO_ASSERT(2338, ls != NULL);
+ IRO_ASSERT(2339, LocationSet_IsUnknown(ls));
+
+ return ls->u.unknown.bitfieldOf;
+}
+
+CW_INLINE LocationSetSet *LocationSetSet_New(void) {
+ LocationSetSet *lss = IRO_malloc(sizeof(LocationSetSet));
+
+ IRO_ASSERT(2356, lss != NULL);
+#ifdef IRO_DEBUG
+ lss->loc = NULL;
+ lss->otherLocs = NULL;
+ lss->count = 0;
+#endif
+ return lss;
+}
+
+CW_INLINE void LocationSetSet_Delete(LocationSetSet *lss) {
+ IRO_ASSERT(2369, lss != NULL);
+ IRO_ASSERT(2370, lss->loc == NULL);
+ IRO_ASSERT(2371, lss->otherLocs == NULL);
+ IRO_ASSERT(2372, lss->count == 0);
+ IRO_DEBUG_CLEAR(lss, sizeof(LocationSetSet));
+ IRO_free(lss);
+}
+
+CW_INLINE void LocationSetSet_Init(LocationSetSet *lss) {
+ IRO_ASSERT(2382, lss != NULL);
+
+ lss->loc = NULL;
+ lss->otherLocs = NULL;
+ lss->count = 0;
+}
+
+CW_INLINE void LocationSetSet_Copy(LocationSetSet *dest, LocationSetSet *src) {
+ IRO_ASSERT(2391, dest != NULL);
+ IRO_ASSERT(2392, src != NULL);
+
+ dest->loc = NULL;
+ dest->otherLocs = NULL;
+ dest->count = 0;
+ LocationSetSet_AddSet(dest, src);
+}
+
+CW_INLINE void LocationSetSet_Term(LocationSetSet *lss) {
+ IRO_ASSERT(2402, lss != NULL);
+
+ LocationSetSet_RemoveAll(lss);
+
+#ifdef IRO_DEBUG
+ lss->loc = NULL;
+ lss->otherLocs = NULL;
+ lss->count = 0;
+#endif
+}
+
+CW_INLINE void LocationSetSet_ForEach(LocationSetSet *lss, void (*action)(LocationSet *, void *), void *refcon) {
+ IRO_ASSERT(2446, lss != NULL);
+ IRO_ASSERT(2447, action != NULL);
+ IRO_ASSERT(2448, refcon == NULL || refcon != NULL);
+
+ while (lss && lss->loc) {
+ action(lss->loc, refcon);
+ lss = lss->otherLocs;
+ }
+}
+
+CW_INLINE LocationSet *LocationSetSet_Find(LocationSetSet *lss, LocationSet *ls) {
+ IRO_ASSERT(2458, lss != NULL);
+ IRO_ASSERT(2459, ls != NULL);
+
+ while (lss && lss->loc) {
+ if (LocationSets_Equal(lss->loc, ls))
+ return lss->loc;
+ lss = lss->otherLocs;
+ }
+
+ return NULL;
+}
+
+CW_INLINE LocationSet *LocationSetSet_FindUnknown(LocationSetSet *lss) {
+ IRO_ASSERT(2470, lss != NULL);
+
+ if (!lss->loc)
+ return stUnknownLs;
+
+ while (lss && lss->loc) {
+ if (LocationSet_IsUnknown(lss->loc))
+ return lss->loc;
+ lss = lss->otherLocs;
+ }
+
+ return NULL;
+}
+
+CW_INLINE LocationSet *LocationSetSet_FindFirst(LocationSetSet *lss) {
+ IRO_ASSERT(2498, lss != NULL);
+
+ return lss->loc;
+}
+
+CW_INLINE int LocationSetSet_Count(LocationSetSet *lss) {
+ IRO_ASSERT(2505, lss != NULL);
+
+ return lss->count;
+}
+
+CW_INLINE void LocationSetSet_RemoveAllWithMemoryBlock(LocationSetSet *lss, PAMemoryBlock *block) {
+ LocationSetSet *first;
+ LocationSetSet *prev;
+ LocationSetSet *next;
+ LocationSetSet *tmp;
+
+ IRO_ASSERT(2514, lss != NULL);
+ IRO_ASSERT(2515, block != NULL);
+
+ first = lss;
+ prev = NULL;
+ while (lss && lss->loc) {
+ next = lss->otherLocs;
+ if (MemoryBlocks_Equal(block, lss->loc->block)) {
+ if (lss->loc != stUnknownLs) {
+ LocationSet_Term(lss->loc);
+ LocationSet_Delete(lss->loc);
+ }
+ if (!prev) {
+ if (lss->otherLocs == NULL) {
+ lss->loc = NULL;
+ prev = lss;
+ } else {
+ tmp = lss->otherLocs;
+ lss->loc = lss->otherLocs->loc;
+ lss->otherLocs = lss->otherLocs->otherLocs;
+ tmp->loc = NULL;
+ tmp->otherLocs = NULL;
+ LocationSetSet_Term(tmp);
+ LocationSetSet_Delete(tmp);
+ prev = NULL;
+ next = lss;
+ }
+ } else {
+ prev->otherLocs = lss->otherLocs;
+ lss->loc = NULL;
+ lss->otherLocs = NULL;
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+ prev = lss;
+ }
+ first->count--;
+ }
+ lss = next;
+ }
+}
+
+CW_INLINE void LocationSetSet_SimpleAdd(LocationSetSet *lss, LocationSet *ls) {
+ IRO_ASSERT(2572, lss != NULL);
+ IRO_ASSERT(2573, ls != NULL);
+
+ if (!LocationSet_IsUnknown(ls) && lss->count < 4) {
+ LocationSet *ls2;
+
+ if (ls == stUnknownLs) {
+ ls2 = stUnknownLs;
+ } else {
+ ls2 = LocationSet_New();
+ LocationSet_Copy(ls2, ls);
+ }
+
+ if (lss->loc) {
+ LocationSetSet *lss2 = LocationSetSet_New();
+ LocationSetSet_Init(lss2);
+ lss2->loc = lss->loc;
+ lss2->otherLocs = lss->otherLocs;
+ lss->otherLocs = lss2;
+ }
+
+ lss->loc = ls2;
+ lss->count++;
+ } else {
+ LocationSet *ls2;
+
+ LocationSetSet_RemoveAll(lss);
+ ls2 = LocationSet_New();
+ if (LocationSet_IsUnknown(ls)) {
+ LocationSet_Copy(ls2, ls);
+ } else {
+ LocationSet_Copy(ls2, stUnknownLs);
+ if (ls->rtype)
+ LocationSet_SetRtype(ls2, ls->rtype);
+ }
+
+ lss->loc = ls2;
+ lss->count = 1;
+ }
+}
+
+CW_INLINE void LocationSetSet_Add(LocationSetSet *lss, LocationSet *ls) {
+ IRO_ASSERT(2622, lss != NULL);
+ IRO_ASSERT(2623, ls != NULL);
+
+ if (!lss->loc || (!LocationSet_IsUnknown(lss->loc) && !LocationSetSet_Find(lss, ls))) {
+ if (!LocationSet_IsUnknown(ls) && ls->u.known.stride)
+ LocationSetSet_RemoveAllWithMemoryBlock(lss, ls->block);
+ LocationSetSet_SimpleAdd(lss, ls);
+ }
+}
+
+CW_INLINE void LocationSetSet_AddUnknown(LocationSetSet *lss, Type *rtype, PAMemoryBlock *restriction, LocationSet *bitfieldOf) {
+ LocationSet *ls;
+
+ IRO_ASSERT(2643, lss != NULL);
+ IRO_ASSERT(2644, rtype == NULL || rtype != NULL);
+ IRO_ASSERT(2645, restriction == NULL || restriction != NULL);
+ IRO_ASSERT(2646, bitfieldOf == NULL || bitfieldOf != NULL);
+
+ ls = LocationSet_New();
+ LocationSet_InitUnknown(ls, rtype, restriction, bitfieldOf);
+ LocationSetSet_Add(lss, ls);
+ LocationSet_Term(ls);
+ LocationSet_Delete(ls);
+}
+
+CW_INLINE void LocationSetSet_Remove(LocationSetSet *lss, LocationSet *ls) {
+ LocationSetSet *prev;
+ LocationSetSet *first;
+ LocationSetSet *tmp;
+
+ IRO_ASSERT(2659, lss != NULL);
+ IRO_ASSERT(2660, ls != NULL);
+
+ first = lss;
+ prev = NULL;
+ while (lss && lss->loc) {
+ if (LocationSets_Equal(lss->loc, ls)) {
+ if (lss->loc != stUnknownLs) {
+ LocationSet_Term(lss->loc);
+ LocationSet_Delete(lss->loc);
+ }
+ if (!prev) {
+ if (lss->otherLocs == NULL) {
+ lss->loc = NULL;
+ } else {
+ tmp = lss->otherLocs;
+ lss->loc = lss->otherLocs->loc;
+ lss->otherLocs = lss->otherLocs->otherLocs;
+ tmp->loc = NULL;
+ tmp->otherLocs = NULL;
+ LocationSetSet_Term(tmp);
+ LocationSetSet_Delete(tmp);
+ }
+ } else {
+ prev->otherLocs = lss->otherLocs;
+ lss->loc = NULL;
+ lss->otherLocs = NULL;
+ LocationSetSet_Term(lss);
+ LocationSetSet_Delete(lss);
+ }
+ first->count--;
+ return;
+ }
+
+ prev = lss;
+ lss = lss->otherLocs;
+ }
+}
+
+CW_INLINE void LocationSetSet_RemoveAll(LocationSetSet *lss) {
+ IRO_ASSERT(2707, lss != NULL);
+
+ while (lss && lss->loc)
+ LocationSetSet_Remove(lss, lss->loc);
+}
+
+CW_INLINE void LocationSetSet_AddSetAction(LocationSet *ls, void *refcon) {
+ IRO_ASSERT(2717, ls != NULL);
+ IRO_ASSERT(2718, refcon != NULL);
+
+ LocationSetSet_Add((LocationSetSet *) refcon, ls);
+}
+
+CW_INLINE void LocationSetSet_SimpleAddSetAction(LocationSet *ls, void *refcon) {
+ IRO_ASSERT(2725, ls != NULL);
+ IRO_ASSERT(2726, refcon != NULL);
+
+ LocationSetSet_SimpleAdd((LocationSetSet *) refcon, ls);
+}
+
+CW_INLINE void LocationSetSet_AddSet(LocationSetSet *dest, LocationSetSet *src) {
+ IRO_ASSERT(2733, dest != NULL);
+ IRO_ASSERT(2734, src != NULL);
+
+ if (dest->count)
+ LocationSetSet_ForEach(src, LocationSetSet_AddSetAction, dest);
+ else
+ LocationSetSet_ForEach(src, LocationSetSet_SimpleAddSetAction, dest);
+}
+
+CW_INLINE void LocationSetSet_RemoveSetAction(LocationSet *ls, void *refcon) {
+ IRO_ASSERT(2744, ls != NULL);
+ IRO_ASSERT(2745, refcon != NULL);
+
+ LocationSetSet_Remove((LocationSetSet *) refcon, ls);
+}
+
+CW_INLINE void LocationSetSet_sub_488700(LocationSetSet *dest, LocationSetSet *src) {
+ IRO_ASSERT(2752, dest != NULL);
+ IRO_ASSERT(2753, src != NULL);
+
+ LocationSetSet_ForEach(src, LocationSetSet_RemoveSetAction, dest);
+}
+
+CW_INLINE Boolean LocationSetSets_Equal(LocationSetSet *lss1, LocationSetSet *lss2) {
+ IRO_ASSERT(2826, lss1 != NULL);
+ IRO_ASSERT(2827, lss2 != NULL);
+
+ if (lss1 == lss2)
+ return 1;
+ if (LocationSetSet_Count(lss1) != LocationSetSet_Count(lss2))
+ return 0;
+
+ while (lss1 && lss1->loc) {
+ if (!LocationSetSet_Find(lss2, lss1->loc))
+ return 0;
+ lss1 = lss1->otherLocs;
+ }
+
+ return 1;
+}
+
+CW_INLINE ParamMapping *ParamMapping_New(void) {
+ ParamMapping *pm = IRO_malloc(sizeof(ParamMapping));
+
+ IRO_ASSERT(2885, pm != NULL);
+#ifdef IRO_DEBUG
+ pm->actual = NULL;
+ pm->formal = NULL;
+ pm->extended = NULL;
+#endif
+ return pm;
+}
+
+CW_INLINE void ParamMapping_Delete(ParamMapping *pm) {
+ IRO_ASSERT(2898, pm != NULL);
+ IRO_ASSERT(2899, pm->actual == NULL);
+ IRO_ASSERT(2900, pm->formal == NULL);
+ IRO_ASSERT(2901, pm->extended == NULL);
+ IRO_DEBUG_CLEAR(pm, sizeof(ParamMapping));
+ IRO_free(pm);
+}
+
+CW_INLINE void ParamMapping_Init_PROBABLY(ParamMapping *pm, IROLinear *actual, Object *formal, ExtendedParam *extended) {
+ IRO_ASSERT(2911, pm != NULL);
+
+ pm->actual = actual;
+ pm->formal = formal;
+ pm->extended = extended;
+}
+
+CW_INLINE void ParamMapping_Copy(ParamMapping *dest, ParamMapping *src) {
+ IRO_ASSERT(2920, src != NULL);
+ IRO_ASSERT(2921, dest != NULL);
+
+ dest->actual = src->actual;
+ dest->formal = src->formal;
+ dest->extended = src->extended;
+}
+
+CW_INLINE void ParamMapping_Term(ParamMapping *pm) {
+ IRO_ASSERT(2933, pm != NULL);
+
+#ifdef IRO_DEBUG
+ pm->actual = NULL;
+ pm->formal = NULL;
+ pm->extended = NULL;
+#endif
+}
+
+CW_INLINE void ParamMapping_SetExtended(ParamMapping *pm, ExtendedParam *ep) {
+ IRO_ASSERT(2992, pm != NULL);
+
+ pm->extended = ep;
+}
+
+CW_INLINE IROLinear *ParamMapping_actual(ParamMapping *pm) {
+ IRO_ASSERT(2999, pm != NULL);
+
+ return pm->actual;
+}
+
+CW_INLINE ExtendedParam *ParamMapping_extended(ParamMapping *pm) {
+ IRO_ASSERT(3011, pm != NULL);
+
+ return pm->extended;
+}
+
+CW_INLINE ParamMappingFunction *ParamMappingFunction_New(void) {
+ ParamMappingFunction *pmf = IRO_malloc(sizeof(ParamMappingFunction));
+
+ IRO_ASSERT(3026, pmf != NULL);
+#ifdef IRO_DEBUG
+ pmf->mapping = NULL;
+ pmf->otherMappings = NULL;
+#endif
+ return pmf;
+}
+
+CW_INLINE void ParamMappingFunction_Delete(ParamMappingFunction *pmf) {
+ IRO_ASSERT(3039, pmf != NULL);
+ IRO_ASSERT(3040, pmf->mapping == NULL);
+ IRO_ASSERT(3041, pmf->otherMappings == NULL);
+ IRO_DEBUG_CLEAR(pmf, sizeof(ParamMappingFunction));
+ IRO_free(pmf);
+}
+
+CW_INLINE void ParamMappingFunction_Init(ParamMappingFunction *pmf) {
+ IRO_ASSERT(3050, pmf != NULL);
+
+ pmf->mapping = NULL;
+ pmf->otherMappings = NULL;
+}
+
+CW_INLINE void ParamMappingFunction_Copy(ParamMappingFunction *dest, ParamMappingFunction *src) {
+ IRO_ASSERT(3058, src != NULL);
+ IRO_ASSERT(3059, dest != NULL);
+
+ dest->mapping = NULL;
+ dest->otherMappings = NULL;
+ ParamMappingFunction_AddAllMaybe_sub_487C50(dest, src);
+}
+
+CW_INLINE void ParamMappingFunction_Term(ParamMappingFunction *pmf) {
+ IRO_ASSERT(3068, pmf != NULL);
+
+ ParamMappingFunction_RemoveAll(pmf);
+
+#ifdef IRO_DEBUG
+ pmf->mapping = NULL;
+ pmf->otherMappings = NULL;
+#endif
+}
+
+CW_INLINE void pmf_sub_487C70(ParamMappingFunction *pmf, void (*action)(ParamMapping *, void *), void *refcon) {
+ IRO_ASSERT(3111, pmf != NULL);
+ IRO_ASSERT(3112, action != NULL);
+ IRO_ASSERT(3113, refcon == NULL || refcon != NULL);
+
+ while (pmf && pmf->mapping) {
+ action(pmf->mapping, refcon);
+ pmf = pmf->otherMappings;
+ }
+}
+
+CW_INLINE ParamMapping *ParamMappingFunction_FindMappingByFormal(ParamMappingFunction *pmf, Object *formal) {
+ IRO_ASSERT(3123, pmf != NULL);
+ IRO_ASSERT(3124, formal != NULL);
+
+ while (pmf && pmf->mapping) {
+ if (pmf->mapping->formal == formal)
+ return pmf->mapping;
+ pmf = pmf->otherMappings;
+ }
+
+ return NULL;
+}
+
+CW_INLINE void Pmf_Add_sub_486610(ParamMappingFunction *pmf, ParamMapping *mapping) {
+ ParamMapping *existing;
+
+ IRO_ASSERT(3138, pmf != NULL);
+ IRO_ASSERT(3139, mapping != NULL);
+
+ existing = ParamMappingFunction_FindMappingByFormal(pmf, mapping->formal);
+ if (!existing) {
+ existing = ParamMapping_New();
+ ParamMapping_Copy(existing, mapping);
+ if (pmf->mapping) {
+ ParamMappingFunction *newPMF = ParamMappingFunction_New();
+ ParamMappingFunction_Init(newPMF);
+ newPMF->mapping = pmf->mapping;
+ newPMF->otherMappings = pmf->otherMappings;
+ pmf->otherMappings = newPMF;
+ }
+ pmf->mapping = existing;
+ } else {
+ existing->actual = mapping->actual;
+ existing->extended = mapping->extended;
+ }
+}
+
+CW_INLINE void ParamMappingFunction_Remove(ParamMappingFunction *pmf, ParamMapping *mapping) {
+ ParamMappingFunction *prev;
+ ParamMappingFunction *tmp;
+
+ IRO_ASSERT(3170, pmf != NULL);
+ IRO_ASSERT(3171, mapping != NULL);
+
+ prev = NULL;
+ while (pmf && pmf->mapping) {
+ if (pmf->mapping->formal == mapping->formal) {
+ ParamMapping_Term(pmf->mapping);
+ ParamMapping_Delete(pmf->mapping);
+ if (!prev) {
+ if (pmf->otherMappings == NULL) {
+ pmf->mapping = NULL;
+ } else {
+ tmp = pmf->otherMappings;
+ pmf->mapping = pmf->otherMappings->mapping;
+ pmf->otherMappings = pmf->otherMappings->otherMappings;
+ tmp->mapping = NULL;
+ tmp->otherMappings = NULL;
+ ParamMappingFunction_Term(tmp);
+ ParamMappingFunction_Delete(tmp);
+ }
+ } else {
+ prev->otherMappings = pmf->otherMappings;
+ pmf->mapping = NULL;
+ pmf->otherMappings = NULL;
+ ParamMappingFunction_Term(pmf);
+ ParamMappingFunction_Delete(pmf);
+ }
+ return;
+ }
+
+ prev = pmf;
+ pmf = pmf->otherMappings;
+ }
+}
+
+CW_INLINE void ParamMappingFunction_RemoveAll(ParamMappingFunction *pmf) {
+ IRO_ASSERT(3213, pmf != NULL);
+
+ while (pmf && pmf->mapping)
+ ParamMappingFunction_Remove(pmf, pmf->mapping);
+}
+
+CW_INLINE void ParamMappingFunction_AddFunctionAction(ParamMapping *mapping, void *refcon) {
+ IRO_ASSERT(3223, mapping != NULL);
+ IRO_ASSERT(3224, refcon != NULL);
+
+ Pmf_Add_sub_486610((ParamMappingFunction *) refcon, mapping);
+}
+
+CW_INLINE void ParamMappingFunction_AddAllMaybe_sub_487C50(ParamMappingFunction *dest, ParamMappingFunction *src) {
+ IRO_ASSERT(3231, dest != NULL);
+ IRO_ASSERT(3232, src != NULL);
+
+ pmf_sub_487C70(src, ParamMappingFunction_AddFunctionAction, dest);
+}
+
+CW_INLINE PointsToEntry *PointsToEntry_New(void) {
+ PointsToEntry *pte = IRO_malloc(sizeof(PointsToEntry));
+
+ IRO_ASSERT(3288, pte != NULL);
+#ifdef IRO_DEBUG
+ pte->loc = NULL;
+ pte->locs = NULL;
+#endif
+ return pte;
+}
+
+CW_INLINE void PointsToEntry_Delete(PointsToEntry *pte) {
+ IRO_ASSERT(3300, pte != NULL);
+ IRO_ASSERT(3301, pte->loc == NULL);
+ IRO_ASSERT(3302, pte->locs == NULL);
+ IRO_DEBUG_CLEAR(pte, sizeof(PointsToEntry));
+ IRO_free(pte);
+}
+
+CW_INLINE void PointsToEntry_Init(PointsToEntry *pte, LocationSet *loc, LocationSetSet *locs) {
+ IRO_ASSERT(3312, pte != NULL);
+ IRO_ASSERT(3313, loc != NULL);
+ IRO_ASSERT(3314, !LocationSet_IsUnknown(loc));
+ IRO_ASSERT(3315, locs != NULL);
+
+ pte->loc = LocationSet_New();
+ LocationSet_Copy(pte->loc, loc);
+
+ pte->locs = LocationSetSet_New();
+ LocationSetSet_Copy(pte->locs, locs);
+}
+
+CW_INLINE void PointsToEntry_Copy(PointsToEntry *dest, PointsToEntry *src) {
+ IRO_ASSERT(3325, src != NULL);
+ IRO_ASSERT(3326, dest != NULL);
+
+ PointsToEntry_Init(dest, src->loc, src->locs);
+}
+
+CW_INLINE void PointsToEntry_Term(PointsToEntry *pte) {
+ IRO_ASSERT(3333, pte != NULL);
+
+ LocationSet_Term(pte->loc);
+ LocationSet_Delete(pte->loc);
+ LocationSetSet_Term(pte->locs);
+ LocationSetSet_Delete(pte->locs);
+
+#ifdef IRO_DEBUG
+ pte->loc = NULL;
+ pte->locs = NULL;
+#endif
+}
+
+CW_INLINE Boolean PointsToEntries_Equal(PointsToEntry *pte1, PointsToEntry *pte2) {
+ IRO_ASSERT(3381, pte1 != NULL);
+ IRO_ASSERT(3382, pte2 != NULL);
+
+ if (pte1 == pte2)
+ return 1;
+
+ return LocationSets_Equal(pte1->loc, pte2->loc) && LocationSetSets_Equal(pte1->locs, pte2->locs);
+}
+
+CW_INLINE LocationSet *PointsToEntry_loc(PointsToEntry *pte) {
+ IRO_ASSERT(3407, pte != NULL);
+
+ return pte->loc;
+}
+
+CW_INLINE LocationSetSet *PointsToEntry_locs(PointsToEntry *pte) {
+ IRO_ASSERT(3414, pte != NULL);
+
+ return pte->locs;
+}
+
+CW_INLINE PointsToFunction *PointsToFunction_New(void) {
+ PointsToFunction *pointsToFunc = IRO_malloc(sizeof(PointsToFunction));
+
+ IRO_ASSERT(3430, pointsToFunc != NULL);
+#ifdef IRO_DEBUG
+ pointsToFunc->pte = NULL;
+ pointsToFunc->otherPtes = NULL;
+#endif
+ return pointsToFunc;
+}
+
+CW_INLINE void PointsToFunction_Delete(PointsToFunction *pointsToFunc) {
+ IRO_ASSERT(3442, pointsToFunc != NULL);
+ IRO_ASSERT(3443, pointsToFunc->pte == NULL);
+ IRO_ASSERT(3444, pointsToFunc->otherPtes == NULL);
+ IRO_DEBUG_CLEAR(pointsToFunc, sizeof(PointsToFunction));
+ IRO_free(pointsToFunc);
+}
+
+CW_INLINE void PointsToFunction_Init(PointsToFunction *pointsToFunc) {
+ IRO_ASSERT(3454, pointsToFunc != NULL);
+
+ pointsToFunc->pte = NULL;
+ pointsToFunc->otherPtes = NULL;
+}
+
+CW_INLINE void PointsToFunction_Copy(PointsToFunction *dest, PointsToFunction *src) {
+ IRO_ASSERT(3462, src != NULL);
+ IRO_ASSERT(3463, dest != NULL);
+
+ dest->pte = NULL;
+ dest->otherPtes = NULL;
+ PointsToFunction_AddAllIGuess_sub_487D80(dest, src);
+}
+
+CW_INLINE void PointsToFunction_Term(PointsToFunction *pointsToFunc) {
+ IRO_ASSERT(3472, pointsToFunc != NULL);
+
+ PointsToFunction_RemoveAll(pointsToFunc);
+
+#ifdef IRO_DEBUG
+ pointsToFunc->pte = NULL;
+ pointsToFunc->otherPtes = NULL;
+#endif
+}
+
+CW_INLINE void PointsToFunction_ForEach(PointsToFunction *pointsToFunc, void (*action)(PointsToEntry *, void *), void *refcon) {
+ IRO_ASSERT(3515, pointsToFunc != NULL);
+ IRO_ASSERT(3516, action != NULL);
+ IRO_ASSERT(3517, refcon == NULL || refcon != NULL);
+
+ while (pointsToFunc && pointsToFunc->pte) {
+ action(pointsToFunc->pte, refcon);
+ pointsToFunc = pointsToFunc->otherPtes;
+ }
+}
+
+CW_INLINE PointsToEntry *PointsToFunction_FindByLocationSet(PointsToFunction *pointsToFunc, LocationSet *ls) {
+ IRO_ASSERT(3527, pointsToFunc != NULL);
+ IRO_ASSERT(3528, ls != NULL);
+
+ while (pointsToFunc && pointsToFunc->pte) {
+ if (LocationSets_Equal(pointsToFunc->pte->loc, ls))
+ return pointsToFunc->pte;
+ pointsToFunc = pointsToFunc->otherPtes;
+ }
+
+ return NULL;
+}
+
+CW_INLINE PointsToEntry *PointsToFunction_FindFirst(PointsToFunction *pointsToFunc) {
+ IRO_ASSERT(3539, pointsToFunc != NULL);
+
+ return pointsToFunc->pte;
+}
+
+CW_INLINE PointsToEntry *PointsToFunction_FindByLookupCompatibleLocationSet(PointsToFunction *pointsToFunc, LocationSet *ls) {
+ IRO_ASSERT(3546, pointsToFunc != NULL);
+ IRO_ASSERT(3547, ls != NULL);
+
+ while (pointsToFunc && pointsToFunc->pte) {
+ if (ls->u.known.stride) {
+ if (LocationSets_Equal(pointsToFunc->pte->loc, ls))
+ return pointsToFunc->pte;
+ } else if (LocationSets_LookupCompatible(pointsToFunc->pte->loc, ls)) {
+ return pointsToFunc->pte;
+ }
+ pointsToFunc = pointsToFunc->otherPtes;
+ }
+
+ return NULL;
+}
+
+CW_INLINE PointsToEntry *PointsToFunction_FindContainingLocationSet(PointsToFunction *pointsToFunc, LocationSet *ls, Type *rtype) {
+ IRO_ASSERT(3565, pointsToFunc != NULL);
+ IRO_ASSERT(3566, ls != NULL);
+ IRO_ASSERT(3567, rtype != NULL);
+
+ while (pointsToFunc && pointsToFunc->pte) {
+ if (pointsToFunc->pte->locs->loc && !LocationSet_IsUnknown(pointsToFunc->pte->locs->loc)) {
+ if (!pointsToFunc->pte->locs->otherLocs && LocationSet_Contains(pointsToFunc->pte->loc, pointsToFunc->pte->locs->loc->rtype, ls, rtype))
+ return pointsToFunc->pte;
+ }
+ pointsToFunc = pointsToFunc->otherPtes;
+ }
+
+ return NULL;
+}
+
+CW_INLINE void PointsToFunction_RemoveOverlappingLocations(PointsToFunction *pointsToFunc, PointsToEntry *pte) {
+ Type *rtype1;
+ Type *rtype2;
+ LocationSet *ls;
+ PointsToFunction *prev;
+ PointsToFunction *next;
+ PointsToFunction *tmp;
+
+ IRO_ASSERT(3601, pointsToFunc != NULL);
+ IRO_ASSERT(3602, pte != NULL);
+ IRO_ASSERT(3603, pte->locs != NULL);
+
+ if (pte->locs->loc && pte->locs->loc != stUnknownLs)
+ rtype1 = pte->locs->loc->rtype;
+ else
+ rtype1 = NULL;
+ ls = pte->loc;
+ IRO_ASSERT(3614, ls != NULL);
+
+ prev = NULL;
+ while (pointsToFunc && pointsToFunc->pte) {
+ next = pointsToFunc->otherPtes;
+ if (pointsToFunc->pte->locs->loc && pointsToFunc->pte->locs->loc != stUnknownLs)
+ rtype2 = pointsToFunc->pte->locs->loc->rtype;
+ else
+ rtype2 = NULL;
+
+ if (LocationSets_Overlap(ls, rtype1, pointsToFunc->pte->loc, rtype2)) {
+ PointsToEntry_Term(pointsToFunc->pte);
+ PointsToEntry_Delete(pointsToFunc->pte);
+ if (!prev) {
+ if (pointsToFunc->otherPtes == NULL) {
+ pointsToFunc->pte = NULL;
+ prev = pointsToFunc;
+ } else {
+ tmp = pointsToFunc->otherPtes;
+ pointsToFunc->pte = pointsToFunc->otherPtes->pte;
+ pointsToFunc->otherPtes = pointsToFunc->otherPtes->otherPtes;
+ tmp->pte = NULL;
+ tmp->otherPtes = NULL;
+ PointsToFunction_Term(tmp);
+ PointsToFunction_Delete(tmp);
+ prev = NULL;
+ next = pointsToFunc;
+ }
+ } else {
+ prev->otherPtes = pointsToFunc->otherPtes;
+ pointsToFunc->pte = NULL;
+ pointsToFunc->otherPtes = NULL;
+ PointsToFunction_Term(pointsToFunc);
+ PointsToFunction_Delete(pointsToFunc);
+ prev = pointsToFunc;
+ }
+ }
+
+ pointsToFunc = next;
+ }
+}
+
+CW_INLINE Boolean ShouldAddNewPointsToEntryToFunction(PointsToFunction *pointsToFunc, PointsToEntry *pte) {
+ Boolean flag;
+ Boolean isKnown;
+ SInt32 stride;
+ PointsToFunction *next;
+ LocationSet *loc;
+ LocationSet *loc2;
+ Type *rtype1;
+ Type *rtype2;
+ LocationSetSet *locs2;
+ LocationSet *tmp;
+ LocationSet *unknown;
+ Boolean flag2;
+ Boolean flag3;
+
+ IRO_ASSERT(3675, pointsToFunc != NULL);
+ IRO_ASSERT(3676, pte != NULL);
+ IRO_ASSERT(3677, pte->locs != NULL);
+ IRO_ASSERT(3678, PointsToFunction_FindByLookupCompatibleLocationSet(pointsToFunc, pte->loc) == NULL);
+ IRO_ASSERT(3679, (unknown = LocationSetSet_FindFirst(pte->locs)) != NULL);
+ IRO_ASSERT(3680, LocationSet_IsUnknown(unknown));
+ IRO_ASSERT(3681, LocationSet_bitfieldOf(unknown) == NULL);
+ IRO_ASSERT(3682, LocationSet_restriction(unknown) == NULL);
+
+ if (pte->locs->loc && pte->locs->loc != stUnknownLs)
+ rtype1 = pte->locs->loc->rtype;
+ else
+ rtype1 = NULL;
+
+ loc = pte->loc;
+ IRO_ASSERT(3693, loc != NULL);
+
+ isKnown = !LocationSet_IsUnknown(loc);
+ if (isKnown)
+ stride = LocationSet_stride(loc);
+
+ flag = 0;
+ while (pointsToFunc && pointsToFunc->pte) {
+ next = pointsToFunc->otherPtes;
+
+ locs2 = pointsToFunc->pte->locs;
+
+ if (locs2->loc && locs2->loc != stUnknownLs)
+ rtype2 = locs2->loc->rtype;
+ else
+ rtype2 = NULL;
+
+ loc2 = pointsToFunc->pte->loc;
+
+ flag2 = !(tmp = LocationSetSet_FindFirst(locs2)) ||
+ !LocationSet_IsUnknown(tmp) ||
+ LocationSet_bitfieldOf(tmp) ||
+ LocationSet_restriction(tmp);
+
+ flag3 = LocationSets_Overlap(loc, rtype1, loc2, rtype2);
+
+ if (!flag && flag3)
+ flag = 1;
+
+ if (flag3 && (flag2 || (isKnown && stride && LocationSet_stride(loc2) == 0)))
+ return 1;
+
+ pointsToFunc = next;
+ }
+
+ return !flag;
+}
+
+CW_INLINE Boolean PointsToFunction_SimpleAdd(PointsToFunction *pointsToFunc, PointsToEntry *pte) {
+ PointsToEntry *newPTE;
+
+ IRO_ASSERT(3741, pointsToFunc != NULL);
+ IRO_ASSERT(3742, pte != NULL);
+
+ newPTE = PointsToEntry_New();
+ PointsToEntry_Copy(newPTE, pte);
+ if (pointsToFunc->pte) {
+ PointsToFunction *newPointsToFunc = PointsToFunction_New();
+ PointsToFunction_Init(newPointsToFunc);
+ newPointsToFunc->pte = pointsToFunc->pte;
+ newPointsToFunc->otherPtes = pointsToFunc->otherPtes;
+ pointsToFunc->otherPtes = newPointsToFunc;
+ }
+ pointsToFunc->pte = newPTE;
+ return 1;
+}
+
+CW_INLINE Boolean PointsToFunction_Add(PointsToFunction *pointsToFunc, PointsToEntry *pte) {
+ IRO_ASSERT(3766, pointsToFunc != NULL);
+ IRO_ASSERT(3767, pte != NULL);
+
+ if (!PointsToFunction_FindByLookupCompatibleLocationSet(pointsToFunc, pte->loc)) {
+ LocationSet *ls;
+ if (!(ls = LocationSetSet_FindFirst(pte->locs)) || !LocationSet_IsUnknown(ls) || LocationSet_bitfieldOf(ls) ||
+ LocationSet_restriction(ls) || ShouldAddNewPointsToEntryToFunction(pointsToFunc, pte)) {
+ PointsToFunction_RemoveOverlappingLocations(pointsToFunc, pte);
+ if (!LocationSet_IsUnknown(pte->loc) || pte->loc->rtype)
+ PointsToFunction_SimpleAdd(pointsToFunc, pte);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+CW_INLINE Boolean PointsToFunction_AddWithoutChecking(PointsToFunction *pointsToFunc, PointsToEntry *pte) {
+ LocationSet *ls;
+
+ IRO_ASSERT(3793, pointsToFunc != NULL);
+ IRO_ASSERT(3794, pte != NULL);
+
+ if (!(ls = LocationSetSet_FindFirst(pte->locs)) || !LocationSet_IsUnknown(ls) || LocationSet_bitfieldOf(ls) ||
+ LocationSet_restriction(ls) || ShouldAddNewPointsToEntryToFunction(pointsToFunc, pte)) {
+ PointsToFunction_RemoveOverlappingLocations(pointsToFunc, pte);
+ if (!LocationSet_IsUnknown(pte->loc) || pte->loc->rtype)
+ PointsToFunction_SimpleAdd(pointsToFunc, pte);
+ return 1;
+ }
+
+ return 0;
+}
+
+CW_INLINE void PointsToFunction_RemoveByLocationSet(PointsToFunction *pointsToFunc, LocationSet *ls) {
+ PointsToFunction *prev;
+ PointsToFunction *tmp;
+
+ IRO_ASSERT(3818, pointsToFunc != NULL);
+ IRO_ASSERT(3819, ls != NULL);
+ IRO_ASSERT(3820, !LocationSet_IsUnknown(ls));
+
+ prev = NULL;
+ while (pointsToFunc && pointsToFunc->pte) {
+ if (LocationSets_Equal(pointsToFunc->pte->loc, ls)) {
+ PointsToEntry_Term(pointsToFunc->pte);
+ PointsToEntry_Delete(pointsToFunc->pte);
+ if (!prev) {
+ if (pointsToFunc->otherPtes == NULL) {
+ pointsToFunc->pte = NULL;
+ } else {
+ tmp = pointsToFunc->otherPtes;
+ pointsToFunc->pte = pointsToFunc->otherPtes->pte;
+ pointsToFunc->otherPtes = pointsToFunc->otherPtes->otherPtes;
+ tmp->pte = NULL;
+ tmp->otherPtes = NULL;
+ PointsToFunction_Term(tmp);
+ PointsToFunction_Delete(tmp);
+ }
+ } else {
+ prev->otherPtes = pointsToFunc->otherPtes;
+ pointsToFunc->pte = NULL;
+ pointsToFunc->otherPtes = NULL;
+ PointsToFunction_Term(pointsToFunc);
+ PointsToFunction_Delete(pointsToFunc);
+ }
+ return;
+ }
+
+ prev = pointsToFunc;
+ pointsToFunc = pointsToFunc->otherPtes;
+ }
+}
+
+CW_INLINE void PointsToFunction_RemoveAll(PointsToFunction *pointsToFunc) {
+ IRO_ASSERT(3862, pointsToFunc != NULL);
+
+ while (pointsToFunc && pointsToFunc->pte)
+ PointsToFunction_RemoveByLocationSet(pointsToFunc, pointsToFunc->pte->loc);
+}
+
+CW_INLINE void PointsToFunction_AddFunctionAction(PointsToEntry *pte, void *refcon) {
+ IRO_ASSERT(3872, pte != NULL);
+ IRO_ASSERT(3873, refcon != NULL);
+
+ PointsToFunction_Add((PointsToFunction *) refcon, pte);
+}
+
+CW_INLINE void PointsToFunction_SimpleAddFunctionAction(PointsToEntry *pte, void *refcon) {
+ IRO_ASSERT(3880, pte != NULL);
+ IRO_ASSERT(3881, refcon != NULL);
+
+ PointsToFunction_SimpleAdd((PointsToFunction *) refcon, pte);
+}
+
+CW_INLINE void PointsToFunction_AddAllIGuess_sub_487D80(PointsToFunction *dest, PointsToFunction *src) {
+ IRO_ASSERT(3888, dest != NULL);
+ IRO_ASSERT(3889, src != NULL);
+
+ if (dest->pte)
+ PointsToFunction_ForEach(src, PointsToFunction_AddFunctionAction, dest);
+ else
+ PointsToFunction_ForEach(src, PointsToFunction_SimpleAddFunctionAction, dest);
+}
+
+CW_INLINE void PointsToFunction_SortByExtendedParamNum(PointsToFunction *pointsToFunc) {
+ UInt32 value1;
+ UInt32 value2;
+ PointsToFunction *scan;
+
+ while (pointsToFunc && pointsToFunc->pte) {
+ value1 = 0;
+ if (pointsToFunc->pte->loc && pointsToFunc->pte->loc->block) {
+ PAMemoryBlock *block = pointsToFunc->pte->loc->block;
+ if (block->kind == PAMEMORYBLOCKKIND_EXTENDEDPARAM && block->u.ep) {
+ value1 = 2 * (block->u.ep->x4) + 1;
+ } else if (block->kind == PAMEMORYBLOCKKIND_LOCALVAR && block->u.localvar) {
+ if (block->u.localvar->x0 && block->u.localvar->x0->extParam)
+ value1 = 2 * block->u.localvar->x0->extParam->x4;
+ }
+ }
+
+ for (scan = pointsToFunc->otherPtes; scan && scan->pte; scan = scan->otherPtes) {
+ value2 = 0;
+ if (scan->pte->loc && scan->pte->loc->block) {
+ PAMemoryBlock *block = scan->pte->loc->block;
+ if (block->kind == PAMEMORYBLOCKKIND_EXTENDEDPARAM && block->u.ep) {
+ value2 = 2 * (block->u.ep->x4) + 1;
+ } else if (block->kind == PAMEMORYBLOCKKIND_LOCALVAR && block->u.localvar) {
+ if (block->u.localvar->x0 && block->u.localvar->x0->extParam)
+ value2 = 2 * block->u.localvar->x0->extParam->x4;
+ }
+ }
+
+ if (value2 < value1) {
+ LocationSet *saveloc;
+ LocationSetSet *savelocs;
+ saveloc = pointsToFunc->pte->loc;
+ savelocs = pointsToFunc->pte->locs;
+ pointsToFunc->pte->loc = scan->pte->loc;
+ pointsToFunc->pte->locs = scan->pte->locs;
+ scan->pte->loc = saveloc;
+ scan->pte->locs = savelocs;
+ }
+ }
+
+ pointsToFunc = pointsToFunc->otherPtes;
+ }
+}
+
+CW_INLINE Boolean PointsToFunctions_Equal(PointsToFunction *pointsToFunc1, PointsToFunction *pointsToFunc2) {
+ PointsToFunction *scan;
+ PointsToEntry *pte;
+
+ IRO_ASSERT(3968, pointsToFunc1 != NULL);
+ IRO_ASSERT(3969, pointsToFunc2 != NULL);
+
+ if (pointsToFunc1 == pointsToFunc2)
+ return 1;
+
+ for (scan = pointsToFunc1; scan && scan->pte; scan = scan->otherPtes) {
+ pte = PointsToFunction_FindByLocationSet(pointsToFunc2, scan->pte->loc);
+ if (!pte || !PointsToEntries_Equal(pte, scan->pte))
+ return 0;
+ }
+
+ for (scan = pointsToFunc2; scan && scan->pte; scan = scan->otherPtes) {
+ pte = PointsToFunction_FindByLocationSet(pointsToFunc1, scan->pte->loc);
+ if (!pte || !PointsToEntries_Equal(pte, scan->pte))
+ return 0;
+ }
+
+ return 1;
+}
+
+CW_INLINE Boolean PointsToFunctions_Match(PointsToFunction *pointsToFunc1, PointsToFunction *pointsToFunc2) {
+ return 1;
+}
+
+CW_INLINE PartialTransferFunction *PartialTransferFunction_New(void) {
+ PartialTransferFunction *ptf = IRO_malloc(sizeof(PartialTransferFunction));
+
+ IRO_ASSERT(4110, ptf != NULL);
+#ifdef IRO_DEBUG
+ ptf->initialPointsToFn = NULL;
+ ptf->finalPointsToFn = NULL;
+ ptf->funcModifies = NULL;
+ ptf->context.nd = NULL;
+ ptf->context.ptf = NULL;
+ ptf->returnLocation = NULL;
+#endif
+ return ptf;
+}
+
+CW_INLINE void PartialTransferFunction_Delete(PartialTransferFunction *ptf) {
+ IRO_ASSERT(4126, ptf != NULL);
+ IRO_ASSERT(4127, ptf->initialPointsToFn == NULL);
+ IRO_ASSERT(4128, ptf->finalPointsToFn == NULL);
+ IRO_ASSERT(4129, ptf->funcModifies == NULL);
+ IRO_ASSERT(4130, ptf->context.nd == NULL);
+ IRO_ASSERT(4131, ptf->context.ptf == NULL);
+ IRO_ASSERT(4132, ptf->returnLocation == NULL);
+ IRO_DEBUG_CLEAR(ptf, sizeof(PartialTransferFunction));
+ IRO_free(ptf);
+}
+
+CW_INLINE void PartialTransferFunction_Init(PartialTransferFunction *ptf, IROLinear *contextNd, PartialTransferFunction *contextPTF) {
+ IRO_ASSERT(4142, ptf != NULL);
+ IRO_ASSERT(4143, contextNd != NULL);
+ IRO_ASSERT(4144, contextPTF != NULL);
+
+ ptf->initialPointsToFn = PointsToFunction_New();
+ PointsToFunction_Init(ptf->initialPointsToFn);
+ ptf->finalPointsToFn = PointsToFunction_New();
+ PointsToFunction_Init(ptf->finalPointsToFn);
+
+ ptf->funcModifies = LocationSetSet_New();
+ LocationSetSet_Init(ptf->funcModifies);
+ LocationSetSet_AddUnknown(ptf->funcModifies, NULL, NULL, NULL);
+
+ ptf->returnLocation = NULL;
+ ptf->x10 = 0;
+
+ ptf->context.nd = contextNd;
+ ptf->context.ptf = contextPTF;
+}
+
+CW_INLINE void PartialTransferFunction_Copy(PartialTransferFunction *dest, PartialTransferFunction *src) {
+ IRO_ASSERT(4164, src != NULL);
+ IRO_ASSERT(4165, dest != NULL);
+
+ dest->initialPointsToFn = PointsToFunction_New();
+ PointsToFunction_Copy(dest->initialPointsToFn, src->initialPointsToFn);
+ dest->finalPointsToFn = PointsToFunction_New();
+ PointsToFunction_Copy(dest->finalPointsToFn, src->finalPointsToFn);
+
+ dest->funcModifies = LocationSetSet_New();
+ LocationSetSet_Copy(dest->funcModifies, src->funcModifies);
+
+ if (src->returnLocation) {
+ dest->returnLocation = LocationSet_New();
+ LocationSet_Copy(dest->returnLocation, src->returnLocation);
+ } else {
+ dest->returnLocation = NULL;
+ }
+
+ dest->x10 = src->x10;
+ dest->context = src->context;
+}
+
+CW_INLINE void PartialTransferFunction_Term(PartialTransferFunction *ptf) {
+ IRO_ASSERT(4190, ptf != NULL);
+
+ PointsToFunction_Term(ptf->initialPointsToFn);
+ PointsToFunction_Delete(ptf->initialPointsToFn);
+ PointsToFunction_Term(ptf->finalPointsToFn);
+ PointsToFunction_Delete(ptf->finalPointsToFn);
+ LocationSetSet_Term(ptf->funcModifies);
+ LocationSetSet_Delete(ptf->funcModifies);
+
+ if (ptf->returnLocation) {
+ PAMemoryBlock_Term(ptf->returnLocation->block);
+ PAMemoryBlock_Delete(ptf->returnLocation->block);
+ LocationSet_Term(ptf->returnLocation);
+ LocationSet_Delete(ptf->returnLocation);
+ ptf->returnLocation = NULL;
+ }
+
+#ifdef IRO_DEBUG
+ ptf->initialPointsToFn = NULL;
+ ptf->finalPointsToFn = NULL;
+ ptf->funcModifies = NULL;
+ ptf->context.nd = NULL;
+ ptf->context.ptf = NULL;
+#endif
+}
+
+CW_INLINE PointsToFunction *PartialTransferFunction_initialPointsToFn(PartialTransferFunction *ptf) {
+ IRO_ASSERT(4221, ptf != NULL);
+
+ return ptf->initialPointsToFn;
+}
+
+CW_INLINE PointsToFunction *PartialTransferFunction_finalPointsToFn(PartialTransferFunction *ptf) {
+ IRO_ASSERT(4227, ptf != NULL);
+
+ return ptf->finalPointsToFn;
+}
+
+CW_INLINE LocationSetSet *PTF_sub_48D750(PartialTransferFunction *ptf) {
+ IRO_ASSERT(4233, ptf != NULL);
+
+ return ptf->funcModifies;
+}
+
+CW_INLINE LocationSet *PartialTransferFunction_returnLocation(PartialTransferFunction *ptf) {
+ IRO_ASSERT(4249, ptf != NULL);
+
+ if (!ptf->returnLocation) {
+ PAMemoryBlock *block;
+ LocationSet *ls;
+
+ block = PAMemoryBlock_New();
+ PAMemoryBlock_Init(block, PAMEMORYBLOCKKIND_LOCALVAR, NULL);
+ ls = LocationSet_New();
+ LocationSet_InitKnown(ls, block, cint64_zero, 0, TYPE(&void_ptr));
+ ptf->returnLocation = ls;
+ }
+
+ return ptf->returnLocation;
+}
+
+CW_INLINE IROLinear *PTF_sub_48B980(PartialTransferFunction *ptf) {
+ IRO_ASSERT(4265, ptf != NULL);
+
+ return ptf->context.nd;
+}
+
+CW_INLINE PartialTransferFunction *PTF_sub_48B970(PartialTransferFunction *ptf) {
+ IRO_ASSERT(4271, ptf != NULL);
+
+ return ptf->context.ptf;
+}
+
+CW_INLINE void PartialTransferFunction_sub_48A610(PartialTransferFunction *ptf, Boolean value) {
+ IRO_ASSERT(4298, ptf != NULL);
+
+ ptf->x10 = (value != 0) ? 1 : 0;
+}
+
+CW_INLINE PTFList *PTFList_New(void) {
+ PTFList *ptfList = IRO_malloc(sizeof(PTFList));
+
+ IRO_ASSERT(4393, ptfList != NULL);
+#ifdef IRO_DEBUG
+ ptfList->ptf = NULL;
+ ptfList->otherPTFs = NULL;
+#endif
+ return ptfList;
+}
+
+CW_INLINE void PTFList_Delete(PTFList *ptfList) {
+ IRO_ASSERT(4405, ptfList != NULL);
+ IRO_ASSERT(4406, ptfList->ptf == NULL);
+ IRO_ASSERT(4407, ptfList->otherPTFs == NULL);
+ IRO_DEBUG_CLEAR(ptfList, sizeof(PTFList));
+ IRO_free(ptfList);
+}
+
+CW_INLINE void PTFList_Init(PTFList *ptfList) {
+ IRO_ASSERT(4417, ptfList != NULL);
+
+ ptfList->ptf = NULL;
+ ptfList->otherPTFs = NULL;
+}
+
+CW_INLINE void PTFList_Term(PTFList *ptfList) {
+ IRO_ASSERT(4435, ptfList != NULL);
+
+ PTFList_RemoveAll(ptfList);
+
+#ifdef IRO_DEBUG
+ ptfList->ptf = NULL;
+ ptfList->otherPTFs = NULL;
+#endif
+}
+
+CW_INLINE void PTFList_ForEach(PTFList *ptfList, void (*action)(PartialTransferFunction *, void *), void *refcon) {
+ IRO_ASSERT(4478, ptfList != NULL);
+ IRO_ASSERT(4479, action != NULL);
+ IRO_ASSERT(4480, refcon == NULL || refcon != NULL);
+
+ while (ptfList && ptfList->ptf) {
+ action(ptfList->ptf, refcon);
+ ptfList = ptfList->otherPTFs;
+ }
+}
+
+CW_INLINE PartialTransferFunction *PTFList_sub_48A0F0(PTFList *ptfList, PartialTransferFunction *ptf) {
+ IRO_ASSERT(4490, ptfList != NULL);
+ IRO_ASSERT(4491, ptf != NULL);
+
+ while (ptfList && ptfList->ptf) {
+ if (ptfList->ptf == ptf)
+ return ptfList->ptf;
+
+ ptfList = ptfList->otherPTFs;
+ }
+
+ return NULL;
+}
+
+CW_INLINE PartialTransferFunction *PTFList_FindFirst(PTFList *ptfList) {
+ IRO_ASSERT(4502, ptfList != NULL);
+
+ return ptfList->ptf;
+}
+
+CW_INLINE void PTFList_sub_48A080(PTFList *ptfList, PartialTransferFunction *ptf) {
+ IRO_ASSERT(4511, ptfList != NULL);
+ IRO_ASSERT(4512, ptf != NULL);
+
+ if (ptfList->ptf) {
+ PTFList *newList = PTFList_New();
+ PTFList_Init(newList);
+ newList->ptf = ptfList->ptf;
+ newList->otherPTFs = ptfList->otherPTFs;
+ ptfList->otherPTFs = newList;
+ }
+
+ ptfList->ptf = ptf;
+}
+
+CW_INLINE void PTFList_sub_48A050(PTFList *ptfList, PartialTransferFunction *ptf) {
+ IRO_ASSERT(4529, ptfList != NULL);
+ IRO_ASSERT(4530, ptf != NULL);
+
+ if (!PTFList_sub_48A0F0(ptfList, ptf))
+ PTFList_sub_48A080(ptfList, ptf);
+}
+
+CW_INLINE void PTFList_Remove(PTFList *ptfList, PartialTransferFunction *ptf) {
+ PTFList *prev;
+ PTFList *tmp;
+
+ IRO_ASSERT(4542, ptfList != NULL);
+ IRO_ASSERT(4543, ptf != NULL);
+
+ prev = NULL;
+ while (ptfList && ptfList->ptf) {
+ if (ptfList->ptf == ptf) {
+ if (!prev) {
+ if (ptfList->otherPTFs == NULL) {
+ ptfList->ptf = NULL;
+ } else {
+ tmp = ptfList->otherPTFs;
+ ptfList->ptf = ptfList->otherPTFs->ptf;
+ ptfList->otherPTFs = ptfList->otherPTFs->otherPTFs;
+ tmp->ptf = NULL;
+ tmp->otherPTFs = NULL;
+ PTFList_Term(tmp);
+ PTFList_Delete(tmp);
+ }
+ } else {
+ prev->otherPTFs = ptfList->otherPTFs;
+ ptfList->ptf = NULL;
+ ptfList->otherPTFs = NULL;
+ PTFList_Term(ptfList);
+ PTFList_Delete(ptfList);
+ }
+ return;
+ }
+
+ prev = ptfList;
+ ptfList = ptfList->otherPTFs;
+ }
+}
+
+CW_INLINE void PTFList_RemoveAll(PTFList *ptfList) {
+ IRO_ASSERT(4582, ptfList != NULL);
+
+ while (ptfList && ptfList->ptf)
+ PTFList_Remove(ptfList, ptfList->ptf);
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c b/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c
new file mode 100644
index 0000000..c5ad708
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.c
@@ -0,0 +1,593 @@
+#include "IroPropagate.h"
+#include "IroCSE.h"
+#include "IroDump.h"
+#include "IroEval.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IROUseDef.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/objects.h"
+#include "compiler/CExpr.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/CParser.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/InlineAsmPPC.h"
+
+IROAssign *IRO_FirstAssign;
+IROAssign *IRO_LastAssign;
+SInt32 IRO_NumAssign;
+
+static Boolean VarIsUsedInOtherFNodes(VarRecord *var, IRONode *node) {
+ if (var->defs && var->uses) {
+ IROUse *use;
+ IRODef *def = NULL;
+ for (use = var->uses; use; use = use->varnext) {
+ if (!def && use->node == node && use->linear && !(use->linear->flags & IROLF_Assigned)) {
+ for (def = var->defs; def; def = def->varnext) {
+ if (Bv_IsBitSet(def->index, use->x18))
+ break;
+ }
+ }
+ }
+
+ if (def) {
+ for (use = var->uses; use; use = use->varnext) {
+ if (use->node != node && use->linear && !(use->linear->flags & IROLF_Assigned)) {
+ if (Bv_IsBitSet(def->index, use->x18))
+ return 1;
+ }
+ }
+ }
+ } else {
+ IROLinear *linear;
+ IRONode *scan;
+ for (scan = IRO_FirstNode; scan; scan = scan->nextnode) {
+ if (scan != node) {
+ linear = scan->first;
+ while (1) {
+ if (!linear)
+ break;
+
+ if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) {
+ if (IRO_FindVar(linear->u.diadic.left->u.node->data.objref, 0, 1) == var)
+ return 1;
+ }
+
+ if (linear == scan->last)
+ break;
+ linear = linear->next;
+ }
+ }
+ }
+ IRO_CheckForUserBreak();
+ }
+
+ return 0;
+}
+
+static void GetExprUses(IROLinear *linear, Boolean isFirst) {
+ if (isFirst && IS_LINEAR_ENODE(linear, EOBJREF)) {
+ Object *obj = linear->u.node->data.objref;
+ if ((linear->flags & IROLF_Ind) && (!(linear->flags & IROLF_Assigned) || (linear->flags & IROLF_Used))) {
+ VarRecord *var = IRO_FindVar(obj, 0, 1);
+ if (var)
+ Bv_SetBit(var->index, IRO_VarKills);
+ }
+ }
+}
+
+static void GetExprKills(IROLinear *linear, Boolean isFirst) {
+ if (isFirst)
+ IRO_GetKills(linear);
+}
+
+static void CheckUnorderedRegionForDefs(IROLinear *linear, BitVector *a, BitVector *b, Boolean *flag) {
+ Bv_Clear(a);
+ Bv_Clear(IRO_VarKills);
+ IRO_WalkTree(linear, GetExprKills);
+ Bv_Or(IRO_VarKills, a);
+ if (Bv_BitsInCommon(a, b))
+ *flag = 1;
+}
+
+static void CheckUnorderedRegionsForDefs(IROLinear *linear1, IROLinear *linear2, BitVector *a, BitVector *b, Boolean *flag) {
+ int i;
+
+ switch (linear1->type) {
+ case IROLinearOp2Arg:
+ if (linear1->nodetype == ELAND) break;
+ if (linear1->nodetype == ELOR) break;
+ if (linear1->nodetype == ECOMMA) break;
+ if (linear1->u.diadic.left != linear2)
+ CheckUnorderedRegionForDefs(linear1->u.diadic.left, a, b, flag);
+ if (linear1->u.diadic.right != linear2)
+ CheckUnorderedRegionForDefs(linear1->u.diadic.right, a, b, flag);
+ break;
+ case IROLinearFunccall:
+ if (linear1->u.funccall.linear8 != linear2)
+ CheckUnorderedRegionForDefs(linear1->u.funccall.linear8, a, b, flag);
+ for (i = 0; !*flag && i < linear1->u.funccall.argCount; i++) {
+ if (linear1->u.funccall.args[i] != linear2)
+ CheckUnorderedRegionForDefs(linear1->u.funccall.args[i], a, b, flag);
+ }
+ break;
+ }
+}
+
+static Boolean PropagationHasDefsInUnorderedRegions(IROLinear *a, IROLinear *b) {
+ Boolean flag;
+ IROLinear *father;
+ BitVector *bv1;
+ BitVector *bv2;
+ VarRecord *var;
+
+ flag = 0;
+ if ((father = IRO_LocateFather(a))) {
+ Bv_AllocVector(&bv1, IRO_NumVars + 1);
+ Bv_AllocVector(&bv2, IRO_NumVars + 1);
+ Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
+ IRO_WalkTree(b, GetExprUses);
+ Bv_Or(IRO_VarKills, bv2);
+ var = IRO_FindVar(a->u.diadic.left->u.node->data.objref, 0, 1);
+ Bv_SetBit(var->index, bv2);
+ while (father && !flag) {
+ CheckUnorderedRegionsForDefs(father, a, bv1, bv2, &flag);
+ a = father;
+ father = IRO_LocateFather(father);
+ }
+ }
+
+ return flag;
+}
+
+int IRO_IsRegable(Object *obj) {
+ if (obj->datatype == DLOCAL && obj->u.var.info)
+ return obj->u.var.info->noregister == 0;
+ return 0;
+}
+
+static Boolean IsPropagatable(IROLinear *linear) {
+ Object *obj;
+ Object *obj2;
+
+ if (IS_LINEAR_DIADIC(linear, EASS) && (obj = IRO_IsVariable(linear->u.diadic.left)) && obj->type == linear->rtype && !is_volatile_object(obj)) {
+ if (linear->u.diadic.left->flags & IROLF_BitfieldIndirect) {
+ if (!IRO_IsConstant(linear->u.diadic.right))
+ return 0;
+ else
+ return 1;
+ }
+
+ if (IRO_IsConstant(linear->u.diadic.right))
+ return 1;
+
+ if ((obj2 = IRO_IsVariable(linear->u.diadic.right)) && !is_volatile_object(obj2) && IRO_TypesEqual(obj->type, linear->rtype)) {
+ if (!Inline_IsObjectData(linear->u.diadic.right->u.monadic->u.node->data.objref)) {
+ if (IRO_IsRegable(obj) && !IRO_IsRegable(obj2))
+ return 0;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static Boolean IsIntGenKillCandidate(IROLinear *linear) {
+ if (linear->type == IROLinearFunccall)
+ return 1;
+
+ if (IRO_IsAssignOp[linear->nodetype] && (linear->type == IROLinearOp1Arg || linear->type == IROLinearOp2Arg))
+ return 1;
+
+ if (linear->type == IROLinearAsm)
+ return 1;
+
+ return 0;
+}
+
+static Boolean IsPropagatableExpr(IROLinear *linear, IROList *list) {
+ Object *obj;
+ if (IS_LINEAR_DIADIC(linear, EASS) && !(linear->flags & IROLF_Reffed)) {
+ if ((obj = IRO_IsVariable(linear->u.diadic.left)) && !is_volatile_object(obj) && !(linear->u.diadic.left->flags & IROLF_BitfieldIndirect)) {
+ if (!IRO_IsRegable(obj))
+ return 0;
+ if (IS_LINEAR_ENODE(linear->u.diadic.right, ESTRINGCONST))
+ return 0;
+
+ IRO_FindDepends(linear->u.diadic.right);
+ if (!IRO_NotSubable)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void ClearAvailibilityOnNode(IRONode *node, UInt32 bit) {
+ IRONode *scan;
+
+ for (scan = node->nextnode; scan; scan = scan->nextnode)
+ Bv_ClearBit(bit, scan->x16);
+}
+
+Boolean IRO_CopyAndConstantPropagation(void) {
+ IROAssign *ass2;
+ IROAssign *ass;
+ IROLinear *linear;
+ IRONode *node;
+ VarRecord *var;
+ BitVector *bv;
+ Boolean flag;
+ Boolean result;
+
+ IRO_FirstAssign = NULL;
+ IRO_NumAssign = 0;
+ result = 0;
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ linear = node->first;
+ while (1) {
+ if (!linear)
+ break;
+
+ if (IsPropagatable(linear) && (var = IRO_FindAssigned(linear))) {
+ IROAssign *newass;
+ IRO_Dump("Found propagatable assignment at: %d\n", linear->index);
+ newass = oalloc(sizeof(IROAssign));
+ newass->linear = linear;
+ newass->next = NULL;
+ newass->index = ++IRO_NumAssign;
+ newass->varIndex = var->index;
+ newass->linear2 = linear->u.diadic.right;
+ newass->var = NULL;
+ newass->varObj = IRO_IsVariable(linear->u.diadic.right);
+ newass->node = node;
+ if (newass->varObj)
+ newass->var = IRO_FindVar(newass->varObj, 0, 1);
+ if (!IRO_FirstAssign)
+ IRO_FirstAssign = newass;
+ else
+ IRO_LastAssign->next = newass;
+ IRO_LastAssign = newass;
+ }
+
+ if (linear == node->last)
+ break;
+ linear = linear->next;
+ }
+ }
+
+ IRO_CheckForUserBreak();
+
+ node = IRO_FirstNode;
+ ass = IRO_FirstAssign;
+ Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
+ while (node) {
+ Bv_AllocVector(&node->x16, IRO_NumAssign);
+ if (node != IRO_FirstNode)
+ Bv_Set(node->x16);
+ Bv_AllocVector(&node->x22, IRO_NumAssign);
+ Bv_AllocVector(&node->x1E, IRO_NumAssign);
+ Bv_AllocVector(&node->x2A, IRO_NumAssign);
+ node->x1A = NULL;
+
+ linear = node->first;
+ while (1) {
+ if (!linear)
+ break;
+
+ if (IsIntGenKillCandidate(linear)) {
+ //IROAssign *ass2;
+ Bv_Clear(IRO_VarKills);
+ IRO_GetKills(linear);
+
+ for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) {
+ if (Bv_IsBitSet(ass2->varIndex, IRO_VarKills)) {
+ Bv_SetBit(ass2->index, node->x22);
+ Bv_ClearBit(ass2->index, node->x1E);
+ }
+ if (ass2->var && Bv_IsBitSet(ass2->var->index, IRO_VarKills)) {
+ Bv_SetBit(ass2->index, node->x22);
+ Bv_ClearBit(ass2->index, node->x1E);
+ }
+ }
+ }
+
+ while (ass && ass->linear == linear) {
+ Bv_SetBit(ass->index, node->x1E);
+ ass = ass->next;
+ }
+
+ if (linear == node->last)
+ break;
+ linear = linear->next;
+ }
+
+ Bv_Copy(node->x16, node->x2A);
+ Bv_Minus(node->x22, node->x2A);
+ Bv_Or(node->x1E, node->x2A);
+ node = node->nextnode;
+ }
+
+ IRO_CheckForUserBreak();
+
+ Bv_AllocVector(&bv, IRO_NumAssign);
+ do {
+ flag = 0;
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (node == IRO_FirstNode) {
+ Bv_Clear(bv);
+ } else {
+ UInt16 i;
+ Bv_Set(bv);
+ for (i = 0; i < node->numpred; i++)
+ Bv_And(IRO_NodeTable[node->pred[i]]->x2A, bv);
+ }
+
+ if (!Bv_Compare(bv, node->x16)) {
+ flag = 1;
+ Bv_Copy(bv, node->x16);
+ }
+
+ Bv_Copy(node->x16, node->x2A);
+ Bv_Minus(node->x22, node->x2A);
+ Bv_Or(node->x1E, node->x2A);
+ }
+ } while (flag);
+
+ IRO_CheckForUserBreak();
+
+ node = IRO_FirstNode;
+ ass = IRO_FirstAssign;
+ while (node) {
+ IRO_Avail = node->x16;
+ linear = node->first;
+ while (1) {
+ if (!linear)
+ break;
+
+ if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) {
+ if ((var = IRO_FindVar(linear->u.diadic.left->u.node->data.objref, 0, 1))) {
+ //IROAssign *ass2;
+ for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) {
+ if (
+ ass2->varIndex == var->index &&
+ Bv_IsBitSet(ass2->index, IRO_Avail) &&
+ (IRO_IsConstant(ass2->linear2) || node->loopdepth <= ass2->node->loopdepth) &&
+ !PropagationHasDefsInUnorderedRegions(linear, ass2->linear2)
+ ) {
+ if (ass2->linear2->type == IROLinearOperand && IRO_is_CPtypeequal(linear->rtype, ass2->linear->u.diadic.left->rtype)) {
+ ENode *enode = IRO_NewENode(ass2->linear2->u.node->type);
+ *enode = *ass2->linear2->u.node;
+ if (enode->type == EINTCONST) {
+ if (linear->flags & IROLF_BitfieldIndirect) {
+ IRO_TruncateBitfieldValueToType(&enode->data.intval, linear->rtype, var->x1A);
+ enode->rtype = linear->rtype;
+ result = 1;
+ } else {
+ IRO_TruncateValueToType(&enode->data.intval, linear->rtype);
+ enode->rtype = linear->rtype;
+ }
+ }
+ linear->u.monadic->type = IROLinearNop;
+ linear->type = IROLinearOperand;
+ linear->u.node = enode;
+ } else if (ass2->varObj && IRO_is_CPtypeequal(linear->rtype, ass2->linear->rtype)) {
+ linear->u.diadic.left->u.node = create_objectrefnode(ass2->varObj);
+ if (ass2->linear2->flags & IROLF_BitfieldIndirect)
+ linear->flags |= IROLF_BitfieldIndirect;
+ }
+ IRO_Dump("Found propagation at %d from %d\n", linear->index, ass2->linear->index);
+ break;
+ }
+ }
+ }
+ } else if (linear->type == IROLinearAsm) {
+ IAEffects effects;
+ int i;
+ CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects);
+
+ for (i = 0; i < effects.numoperands; i++) {
+ if (effects.operands[i].type == IAEffect_0 && effects.operands[i].offset == 0 && effects.operands[i].object->type->size == effects.operands[i].size) {
+ if ((var = IRO_FindVar(effects.operands[i].object, 0, 1))) {
+ //IROAssign *ass2;
+ for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) {
+ if (ass2->varIndex == var->index && Bv_IsBitSet(ass2->index, IRO_Avail) && ass2->linear->rtype->size == effects.operands[i].size) {
+ ENode *enode;
+ if (ass2->varObj)
+ enode = create_objectrefnode(ass2->varObj);
+ else if (ass2->linear2->type == IROLinearOperand)
+ enode = ass2->linear2->u.node;
+ else
+ CError_FATAL(768);
+ CodeGen_PropagateIntoAsm(linear->u.asm_stmt, effects.operands[i].object, enode);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (IsIntGenKillCandidate(linear)) {
+ //IROAssign *ass2;
+ Bv_Clear(IRO_VarKills);
+ IRO_GetKills(linear);
+
+ for (ass2 = IRO_FirstAssign; ass2; ass2 = ass2->next) {
+ if (Bv_IsBitSet(ass2->varIndex, IRO_VarKills)) {
+ Bv_ClearBit(ass2->index, IRO_Avail);
+ }
+ if (ass2->var && Bv_IsBitSet(ass2->var->index, IRO_VarKills)) {
+ Bv_ClearBit(ass2->index, IRO_Avail);
+ }
+ }
+
+ while (ass && ass->linear == linear) {
+ Bv_SetBit(ass->index, IRO_Avail);
+ ass = ass->next;
+ }
+ }
+
+ if (linear == node->last)
+ break;
+ linear = linear->next;
+ }
+ node = node->nextnode;
+ }
+
+ IRO_CheckForUserBreak();
+
+ return result;
+}
+
+void IRO_ExpressionPropagation(void) {
+ IRONode *node;
+ IROLinear *linear;
+ Object *obj;
+ VarRecord *var;
+ IROAssign *ass;
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ IRO_FirstAssign = NULL;
+ IRO_LastAssign = NULL;
+ IRO_NumAssign = 0;
+
+ linear = node->first;
+ while (1) {
+ IROList list;
+ if (!linear)
+ break;
+
+ IRO_InitList(&list);
+ if (IsPropagatableExpr(linear, &list)) {
+ if ((var = IRO_FindAssigned(linear))) {
+ IRO_Dump("Found propagatable expression assignment at: %d\n", linear->index);
+ ass = oalloc(sizeof(IROAssign));
+ ass->linear = linear;
+ ass->next = NULL;
+ ass->index = ++IRO_NumAssign;
+ ass->varIndex = var->index;
+ ass->linear2 = linear->u.diadic.right;
+ ass->x20 = 0;
+ ass->node = node;
+ IRO_FindDepends(linear->u.diadic.right);
+ ass->depends = IRO_Depends;
+ if (!IRO_FirstAssign) {
+ IRO_FirstAssign = ass;
+ ass->prev = NULL;
+ } else {
+ IRO_LastAssign->next = ass;
+ ass->prev = IRO_LastAssign;
+ }
+ IRO_LastAssign = ass;
+ }
+ }
+
+ if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) {
+ if ((var = IRO_FindVar(linear->u.monadic->u.node->data.objref, 0, 1))) {
+ for (ass = IRO_LastAssign; ass; ass = ass->prev) {
+ if (ass->varIndex == var->index)
+ ass->x20++;
+ }
+ }
+ }
+
+ if (linear == node->last)
+ break;
+ linear = linear->next;
+ }
+
+ Bv_AllocVector(&IRO_Avail, IRO_NumAssign);
+
+ linear = node->first;
+ while (1) {
+ if (!linear)
+ break;
+
+ if (IRO_IsVariable(linear) && !(linear->flags & IROLF_Assigned)) {
+ if ((var = IRO_FindVar(linear->u.monadic->u.node->data.objref, 0, 1))) {
+ for (ass = IRO_FirstAssign; ass; ass = ass->next) {
+ if (ass->varIndex == var->index && Bv_IsBitSet(ass->index, IRO_Avail) && !PropagationHasDefsInUnorderedRegions(linear, ass->linear2)) {
+ if (ass->linear2->type == IROLinearOperand && IRO_is_CPtypeequal(linear->rtype, ass->linear->u.diadic.left->rtype)) {
+ ENode *enode = IRO_NewENode(ass->linear2->u.node->type);
+ *enode = *ass->linear2->u.node;
+ if (enode->type == EINTCONST) {
+ IRO_TruncateValueToType(&enode->data.intval, linear->rtype);
+ enode->rtype = linear->rtype;
+ } else if (enode->type == EOBJREF) {
+ IROLinear *tmp = IRO_LocateFather(linear);
+ if (tmp && (tmp->flags & IROLF_Assigned))
+ linear->flags |= IROLF_Assigned;
+ }
+ linear->u.monadic->type = IROLinearNop;
+ linear->type = IROLinearOperand;
+ linear->u.node = enode;
+ } else if (IRO_IsVariable(ass->linear2) && IRO_is_CPtypeequal(linear->rtype, ass->linear->rtype)) {
+ linear->u.monadic->u.node = create_objectrefnode(ass->linear2->u.monadic->u.node->data.objref);
+ if (ass->linear2->flags & IROLF_BitfieldIndirect)
+ linear->flags |= IROLF_BitfieldIndirect;
+ } else if (IRO_is_CPtypeequal(linear->rtype, ass->linear->rtype) && ass->x20 == 1 && !VarIsUsedInOtherFNodes(var, node)) {
+ IROList list;
+ IRO_InitList(&list);
+ IRO_DuplicateExpr(ass->linear->u.diadic.right, &list);
+ if (IS_TYPE_FLOAT(ass->linear->rtype)) {
+ IROLinear *tmp = IRO_NewLinear(IROLinearOp1Arg);
+ tmp->index = ++IRO_NumLinear;
+ tmp->rtype = ass->linear->rtype;
+ tmp->nodetype = ETYPCON;
+ tmp->nodeflags = ENODE_FLAG_80;
+ tmp->u.monadic = list.tail;
+ IRO_AddToList(tmp, &list);
+ }
+ IRO_PasteAfter(list.head, list.tail, linear);
+ IRO_LocateFather_Cut_And_Paste(linear, list.tail);
+ linear = list.tail;
+ }
+ IRO_Dump("Found expression propagation at %d from %d\n", linear->index, ass->linear->index);
+ break;
+ }
+ }
+ }
+ }
+
+ if (linear->type != IROLinearNop && IsIntGenKillCandidate(linear)) {
+ Bv_Clear(IRO_VarKills);
+ IRO_GetKills(linear);
+ for (ass = IRO_FirstAssign; ass; ass = ass->next) {
+ if (Bv_IsBitSet(ass->varIndex, IRO_VarKills))
+ Bv_ClearBit(ass->index, IRO_Avail);
+ if ((obj = IRO_IsVariable(ass->linear->u.diadic.right))) {
+ if ((var = IRO_FindVar(obj, 0, 1))) {
+ if (Bv_IsBitSet(var->index, IRO_VarKills))
+ Bv_ClearBit(ass->index, IRO_Avail);
+ }
+ } else {
+ IROList list;
+ IRO_InitList(&list);
+ IRO_Depends = ass->depends;
+ IRO_FindDepends_NoAlloc(ass->linear->u.diadic.right);
+ if (Bv_BitsInCommon(IRO_VarKills, ass->depends))
+ Bv_ClearBit(ass->index, IRO_Avail);
+ }
+ }
+
+ for (ass = IRO_FirstAssign; ass; ass = ass->next) {
+ IRO_Depends = ass->depends;
+ IRO_FindDepends_NoAlloc(ass->linear->u.diadic.right);
+ if (ass->linear == linear && !Bv_IsBitSet(ass->varIndex, ass->depends))
+ Bv_SetBit(ass->index, IRO_Avail);
+ }
+ }
+
+ if (linear == node->last)
+ break;
+ linear = linear->next;
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
+
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.h b/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.h
new file mode 100644
index 0000000..ff9fadb
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroPropagate.h
@@ -0,0 +1,35 @@
+#ifndef COMPILER_IROPROPAGATE_H
+#define COMPILER_IROPROPAGATE_H
+
+#include "IrOptimizer.h"
+#include "BitVector.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+struct IROAssign {
+ IROLinear *linear;
+ UInt16 index;
+ UInt16 varIndex;
+ IROLinear *linear2;
+ BitVector *depends;
+ Object *varObj;
+ VarRecord *var;
+ IROAssign *next;
+ IROAssign *prev;
+ UInt16 x20;
+ IRONode *node;
+};
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+extern IROAssign *IRO_FirstAssign;
+extern IROAssign *IRO_LastAssign;
+extern SInt32 IRO_NumAssign;
+
+extern int IRO_IsRegable(Object *obj);
+extern Boolean IRO_CopyAndConstantPropagation(void);
+extern void IRO_ExpressionPropagation(void);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c b/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c
new file mode 100644
index 0000000..737035f
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.c
@@ -0,0 +1,774 @@
+#include "IroRangePropagation.h"
+#include "IroDump.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroMalloc.h"
+#include "IroPointerAnalysis.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/CInt64.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef enum ERangeType {
+ ERangeType0,
+ ERangeType1,
+ ERangeType2,
+ ERangeType3
+} ERangeType;
+
+typedef struct ERange {
+ ERangeType type;
+ CInt64 upper;
+ CInt64 lower;
+} ERange;
+
+typedef struct ERecord {
+ Object *object;
+ ERange *range;
+ struct ERecord *next;
+} ERecord;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static ERecord *ERangeFirst;
+static ERecord *ERangeLast;
+
+static ERange *ERnewERange(ERangeType type) {
+ ERange *range;
+
+ range = oalloc(sizeof(ERange));
+ range->type = type;
+ return range;
+}
+
+static ERecord *ERnewRecord(Object *object, ERange *range) {
+ ERecord *record;
+
+ record = oalloc(sizeof(ERecord));
+ record->object = object;
+ record->range = range;
+ record->next = ERangeFirst;
+ ERangeFirst = record;
+ if (!ERangeLast)
+ ERangeLast = record;
+ return record;
+}
+
+static ERecord *ERecordFound(Object *obj) {
+ ERecord *scan;
+
+ scan = ERangeFirst;
+ while (scan && obj != scan->object)
+ scan = scan->next;
+
+ return scan;
+}
+
+static Boolean EREandHasNoUse(ERange *range, CInt64 val) {
+ UInt16 i;
+ CInt64 v11;
+ CInt64 work;
+
+ i = 0;
+ work = range->upper;
+ while (CInt64_NotEqual(work = CInt64_ShrU(work, cint64_one), cint64_zero))
+ i++;
+
+ if (CInt64_NotEqual(range->upper, cint64_zero))
+ i++;
+
+ CInt64_SetULong(&work, i);
+ v11 = CInt64_Sub(CInt64_Shl(cint64_one, work), cint64_one);
+ if (CInt64_NotEqual(cint64_zero, CInt64_And(CInt64_Inv(val), v11)))
+ return 0;
+ else
+ return 1;
+}
+
+static void ERcheckOverflow(ERange *range, Type *type) {
+ CInt64 typeSize;
+ CInt64 work;
+ CInt64 work2;
+ CInt64 value3;
+
+ if (!range)
+ return;
+
+ if (!IS_TYPE_INT(type)) {
+ range->type = ERangeType3;
+ return;
+ }
+
+ CInt64_SetLong(&typeSize, type->size);
+ CInt64_SetLong(&value3, 3);
+
+ if (IRO_IsUnsignedType(type)) {
+ if (type->size < 8) {
+ work = CInt64_Sub(CInt64_Shl(cint64_one, CInt64_Shl(typeSize, value3)), cint64_one);
+ if (CInt64_GreaterU(range->upper, work))
+ range->type = ERangeType3;
+ } else {
+ range->type = ERangeType3;
+ }
+ } else {
+ if (type->size < 8) {
+ work = CInt64_Sub(CInt64_Shl(cint64_one, CInt64_Sub(CInt64_Shl(typeSize, value3), cint64_one)), cint64_one);
+ work2 = CInt64_Shl(cint64_negone, CInt64_Sub(CInt64_Shl(typeSize, value3), cint64_one));
+ if (CInt64_Greater(range->upper, work) || CInt64_Less(range->lower, work2))
+ range->type = ERangeType3;
+ } else {
+ range->type = ERangeType3;
+ }
+ }
+}
+
+static void ERinvalidAll(void) {
+ ERecord *record;
+
+ for (record = ERangeFirst; record; record = record->next)
+ record->range->type = ERangeType3;
+}
+
+static void SetRangesForKillsByIndirectAssignment(IROLinear *nd) {
+ IROListNode *list;
+ IROListNode *scan;
+ IROLinear *inner;
+ Boolean failed;
+ IROListNode *resultList;
+ IROLinear *scannd;
+ Boolean foundObjRef;
+ ERecord *record;
+ ERange *range;
+ IROListNode *next;
+ Object *obj;
+ IROLinear *analysend;
+ Object *proc;
+
+ failed = 0;
+ if (nd->type == IROLinearOp2Arg)
+ inner = nd->u.diadic.left;
+ else
+ inner = nd->u.monadic;
+
+ if (
+ inner &&
+ inner->type == IROLinearOp1Arg &&
+ inner->nodetype == EINDIRECT &&
+ (analysend = inner->u.monadic) &&
+ copts.opt_pointer_analysis &&
+ analysend->pointsToFunction &&
+ (proc = FunctionName)
+ ) {
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(proc, analysend, &resultList);
+
+ if ((list = resultList)) {
+ for (scan = list; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ failed = 1;
+ break;
+ }
+
+ foundObjRef = 0;
+ for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ foundObjRef = 1;
+ break;
+ }
+ }
+
+ if (!foundObjRef) {
+ failed = 1;
+ break;
+ }
+ }
+
+ if (!failed) {
+ for (; list; list = list->nextList) {
+ for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ obj = scannd->u.node->data.objref;
+ CError_ASSERT(302, obj != NULL);
+
+ range = nd->x16;
+ if (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC)
+ range = inner->x16;
+
+ record = ERecordFound(obj);
+ if (!record)
+ ERnewRecord(obj, range);
+ else
+ record->range = range;
+ }
+ }
+ }
+ }
+
+ while (resultList) {
+ next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ failed = 1;
+ }
+ } else {
+ failed = 1;
+ }
+
+ if (failed) {
+ ERinvalidAll();
+ nd->x16 = ERnewERange(ERangeType3);
+ }
+}
+
+static void InvalidateRangesForKillsByFunctionCall(IROLinear *nd) {
+ IROListNode *scan;
+ IROLinear *scannd;
+ Boolean failed;
+ Boolean foundObjRef;
+ IROListNode *list;
+ IROListNode *resultList;
+ ERecord *record;
+ IROListNode *next;
+ Object *obj;
+ IROLinear *analysend;
+ Object *proc;
+ ObjectList *olist;
+ ObjectList *killList;
+
+ failed = 0;
+
+ if (
+ (analysend = nd->u.funccall.linear8) &&
+ copts.opt_pointer_analysis &&
+ analysend->pointsToFunction &&
+ (proc = FunctionName)
+ ) {
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(proc, analysend, &resultList);
+
+ if (resultList) {
+ for (scan = resultList; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ failed = 1;
+ break;
+ }
+
+ foundObjRef = 0;
+ for (scannd = scan->list.head; scannd != scan->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ foundObjRef = 1;
+ obj = scannd->u.node->data.objref;
+ CError_ASSERT(385, obj != NULL);
+
+ killList = NULL;
+ PointerAnalysis_GetFunctionKills(obj, nd, &killList);
+
+ for (olist = killList; olist; olist = olist->next) {
+ if (!olist->object) {
+ failed = 1;
+ break;
+ }
+ }
+
+ while (killList) {
+ olist = killList->next;
+ IRO_free(killList);
+ killList = olist;
+ }
+
+ if (failed)
+ break;
+ }
+ }
+
+ if (!foundObjRef)
+ failed = 1;
+ if (failed)
+ break;
+ }
+
+ if (!failed) {
+ for (list = resultList; list; list = list->nextList) {
+ for (scannd = list->list.head; scannd != list->list.tail->next; scannd = scannd->next) {
+ if (scannd->type == IROLinearOperand && scannd->u.node->type == EOBJREF) {
+ obj = scannd->u.node->data.objref;
+ killList = NULL;
+ PointerAnalysis_GetFunctionKills(obj, nd, &killList);
+
+ for (olist = killList; olist; olist = olist->next) {
+ if ((record = ERecordFound(olist->object)))
+ record->range->type = ERangeType3;
+ }
+
+ while (killList) {
+ olist = killList->next;
+ IRO_free(killList);
+ killList = olist;
+ }
+ }
+ }
+ }
+ }
+
+ while (resultList) {
+ next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ failed = 1;
+ }
+ } else {
+ failed = 1;
+ }
+
+ if (failed)
+ ERinvalidAll();
+}
+
+static void ERfoldOperand(IROLinear *nd) {
+ switch (nd->u.node->type) {
+ case EOBJREF:
+ nd->x16 = NULL;
+ break;
+ case EINTCONST:
+ nd->x16 = ERnewERange(ERangeType0);
+ nd->x16->upper = nd->x16->lower = nd->u.node->data.intval;
+ break;
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ nd->x16 = ERnewERange(ERangeType0);
+ break;
+ }
+}
+
+static Boolean ERfoldExpr(IROLinear *nd) {
+ ERecord *record;
+ ERange *range;
+ IROLinear *tmp;
+ IROLinear *inner;
+ Object *obj;
+
+ switch (nd->nodetype) {
+ case EINDIRECT:
+ inner = nd->u.monadic;
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (inner->type == IROLinearOperand && inner->u.node->type == EOBJREF) {
+ if (!inner->x16 && (obj = inner->u.node->data.objref)) {
+ if ((record = ERecordFound(obj))) {
+ inner->x16 = ERnewERange(ERangeType3);
+ *inner->x16 = *record->range;
+ } else {
+ inner->x16 = ERnewERange(ERangeType3);
+ inner->x16->upper = cint64_max;
+ inner->x16->lower = cint64_min;
+ ERnewRecord(obj, inner->x16);
+ }
+ }
+ nd->x16 = inner->x16;
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ } else {
+ if (inner->type == IROLinearOperand && inner->u.node->type == EOBJREF && !inner->x16)
+ inner->x16 = ERnewERange(ERangeType3);
+ nd->x16 = ERnewERange(ERangeType3);
+ }
+ break;
+ case EAND:
+ case EANDASS:
+ if (IRO_IsIntConstant(nd->u.diadic.right)) {
+ CInt64 val = nd->u.diadic.right->u.node->data.intval;
+ nd->x16 = ERnewERange(ERangeType1);
+ nd->x16->upper = val;
+ nd->x16->lower = cint64_zero;
+ if (
+ (range = nd->u.diadic.left->x16) &&
+ range->type != ERangeType3 &&
+ CInt64_LessEqualU(range->upper, val) &&
+ CInt64_LessEqualU(range->lower, val) &&
+ EREandHasNoUse(range, val) &&
+ !IRO_HasSideEffect(nd->u.diadic.left)
+ ) {
+ IRO_Dump("eliminating redundant EAND %" PRId32 "; upperBound==0x%x, lowerBound==0x%x, Constant==0x%x\n",
+ nd->index,
+ CInt64_GetULong(&range->upper),
+ CInt64_GetULong(&range->upper),
+ CInt64_GetULong(&val)
+ );
+ IRO_NopOut(nd->u.diadic.right);
+ nd->type = IROLinearNop;
+ nd->expr = NULL;
+ tmp = nd->u.diadic.left;
+ nd->u.diadic.left = nd->u.diadic.right;
+ if (!IRO_LocateFather_Cut_And_Paste(nd, tmp)) {
+ tmp->flags &= ~IROLF_Reffed;
+ if (IRO_IsVariable(tmp))
+ IRO_NopOut(tmp);
+ }
+ }
+ } else {
+ if (nd->u.diadic.right->x16) {
+ nd->x16 = ERnewERange(ERangeType3);
+ *nd->x16 = *nd->u.diadic.right->x16;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case ELOGNOT:
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ case ENOTEQU:
+ case ELAND:
+ case ELOR:
+ nd->x16 = ERnewERange(ERangeType1);
+ nd->x16->upper = cint64_one;
+ nd->x16->lower = cint64_zero;
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EBINNOT:
+ case EFORCELOAD:
+ case EXOR:
+ case EOR:
+ case EXORASS:
+ case EORASS:
+ case ECOMMA:
+ case ETYPCON:
+ case EBITFIELD:
+ case ECOND:
+ case ENULLCHECK:
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ break;
+ case EASS:
+ if (IS_TYPE_INT(nd->rtype))
+ nd->x16 = nd->u.diadic.right->x16;
+ break;
+ case EMUL:
+ case EMULV:
+ case EMULASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ if (IRO_IsUnsignedType(nd->rtype)) {
+ nd->x16->upper = CInt64_MulU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper);
+ nd->x16->lower = CInt64_MulU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower);
+ } else {
+ nd->x16->upper = CInt64_Mul(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper);
+ nd->x16->lower = CInt64_Mul(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower);
+ }
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EDIV:
+ case EDIVASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ if (!CInt64_IsZero(&nd->u.diadic.right->x16->lower) && !CInt64_IsZero(&nd->u.diadic.right->x16->upper)) {
+ if (IRO_IsUnsignedType(nd->rtype)) {
+ nd->x16->upper = CInt64_DivU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_DivU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ } else {
+ nd->x16->upper = CInt64_Div(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_Div(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ }
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EMODULO:
+ case EMODASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ if (!CInt64_IsZero(&nd->u.diadic.right->x16->lower) && !CInt64_IsZero(&nd->u.diadic.right->x16->upper)) {
+ if (IRO_IsUnsignedType(nd->rtype)) {
+ nd->x16->upper = CInt64_ModU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_ModU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ } else {
+ nd->x16->upper = CInt64_Mod(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_Mod(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ }
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EADDV:
+ case EADD:
+ case EADDASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ nd->x16->upper = CInt64_Add(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper);
+ nd->x16->lower = CInt64_Add(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case ESUBV:
+ case ESUB:
+ case ESUBASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ nd->x16->upper = CInt64_Sub(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_Sub(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case ESHL:
+ case ESHLASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ nd->x16->upper = CInt64_Shl(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->upper);
+ nd->x16->lower = CInt64_Shl(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->lower);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case ESHR:
+ case ESHRASS:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.diadic.left->x16 && nd->u.diadic.left->x16->type != ERangeType3 &&
+ nd->u.diadic.right->x16 && nd->u.diadic.right->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ if (IRO_IsUnsignedType(nd->rtype)) {
+ nd->x16->upper = CInt64_ShrU(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_ShrU(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ } else {
+ nd->x16->upper = CInt64_Shr(nd->u.diadic.left->x16->upper, nd->u.diadic.right->x16->lower);
+ nd->x16->lower = CInt64_Shr(nd->u.diadic.left->x16->lower, nd->u.diadic.right->x16->upper);
+ }
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EPOSTINC:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ range = nd->u.monadic->x16;
+ *nd->x16 = *range;
+ range->upper = CInt64_Add(range->upper, cint64_one);
+ range->lower = CInt64_Add(range->lower, cint64_one);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EPOSTDEC:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ range = nd->u.monadic->x16;
+ *nd->x16 = *range;
+ range->upper = CInt64_Sub(range->upper, cint64_one);
+ range->lower = CInt64_Sub(range->lower, cint64_one);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EPREINC:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ range = nd->u.monadic->x16;
+ nd->x16->upper = CInt64_Add(range->upper, cint64_one);
+ nd->x16->lower = CInt64_Add(range->lower, cint64_one);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EPREDEC:
+ if (IS_TYPE_INT(nd->rtype)) {
+ if (nd->u.monadic->x16 && nd->u.monadic->x16->type != ERangeType3) {
+ nd->x16 = ERnewERange(ERangeType2);
+ range = nd->u.monadic->x16;
+ nd->x16->upper = CInt64_Sub(range->upper, cint64_one);
+ nd->x16->lower = CInt64_Sub(range->lower, cint64_one);
+ } else {
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ }
+ }
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ case EMONMIN:
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ break;
+ case EPMODULO:
+ case EROTL:
+ case EROTR:
+ case EBCLR:
+ case EBTST:
+ case EBSET:
+ nd->x16 = ERnewERange(ERangeType3);
+ nd->x16->upper = cint64_max;
+ nd->x16->lower = cint64_min;
+ break;
+ default:
+ ERcheckOverflow(nd->x16, nd->rtype);
+ break;
+ }
+
+ if (
+ (nd->type == IROLinearOp1Arg || nd->type == IROLinearOp2Arg) &&
+ IRO_IsAssignOp[nd->nodetype] &&
+ nd->x16 &&
+ IS_TYPE_INT(nd->rtype)
+ ) {
+ IROLinear *x = NULL;
+ if (nd->type == IROLinearOp2Arg)
+ x = nd->u.diadic.left;
+ else if (nd->type == IROLinearOp1Arg)
+ x = nd->u.monadic;
+
+ if (x->type == IROLinearOp1Arg &&
+ x->nodetype == EINDIRECT &&
+ (x->u.monadic->nodetype == EINDIRECT || x->u.monadic->nodetype == EADD)) {
+ SetRangesForKillsByIndirectAssignment(nd);
+ } else {
+ obj = NULL;
+ if (x)
+ obj = IRO_IsVariable(x);
+ if (!obj)
+ return 0;
+
+ range = nd->x16;
+ if (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC)
+ range = x->x16;
+
+ record = ERecordFound(obj);
+ if (!record)
+ ERnewRecord(obj, range);
+ else
+ record->range = range;
+ }
+ }
+
+ return nd->x16 != NULL;
+}
+
+static Boolean ERfoldLinear(IROLinear *nd) {
+ nd->x16 = 0;
+
+ switch (nd->type) {
+ case IROLinearNop:
+ case IROLinearEnd:
+ break;
+ case IROLinearOperand:
+ ERfoldOperand(nd);
+ break;
+ case IROLinearOp1Arg:
+ case IROLinearOp2Arg:
+ ERfoldExpr(nd);
+ break;
+ case IROLinearFunccall:
+ InvalidateRangesForKillsByFunctionCall(nd);
+ break;
+ case IROLinearAsm:
+ ERinvalidAll();
+ break;
+ }
+
+ return 0;
+}
+
+Boolean IRO_RangePropagateInFNode(void) {
+ IRONode *fnode;
+ IROLinear *nd;
+ Boolean result;
+
+ result = 0;
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ ERangeFirst = ERangeLast = NULL;
+ for (nd = fnode->first; nd != fnode->last; nd = nd->next)
+ ERfoldLinear(nd);
+ if (ERfoldLinear(nd))
+ result = 1;
+ }
+
+ if (result) {
+ IRO_ComputeSuccPred();
+ IRO_ComputeDom();
+ }
+
+ IRO_CheckForUserBreak();
+ return result;
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.h b/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.h
new file mode 100644
index 0000000..96888ac
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroRangePropagation.h
@@ -0,0 +1,8 @@
+#ifndef COMPILER_IRORANGEPROPAGATION_H
+#define COMPILER_IRORANGEPROPAGATION_H
+
+#include "IrOptimizer.h"
+
+extern Boolean IRO_RangePropagateInFNode(void);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroSubable.c b/compiler_and_linker/FrontEnd/Optimizer/IroSubable.c
new file mode 100644
index 0000000..513ac6c
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroSubable.c
@@ -0,0 +1,160 @@
+#include "IroSubable.h"
+#include "IroLinearForm.h"
+#include "IroPropagate.h"
+#include "IroUtil.h"
+#include "compiler/enode.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+static Boolean IsSubableOp[MAXEXPR];
+
+void IRO_InitializeIsSubableOpArray(void) {
+ int i;
+
+ for (i = 0; i < MAXEXPR; i++)
+ IsSubableOp[i] = 0;
+
+ IsSubableOp[EPOSTINC] = 0;
+ IsSubableOp[EPOSTDEC] = 0;
+ IsSubableOp[EPREINC] = 0;
+ IsSubableOp[EPREDEC] = 0;
+ IsSubableOp[EINDIRECT] = 0;
+ IsSubableOp[EMONMIN] = 1;
+ IsSubableOp[EBINNOT] = 1;
+ IsSubableOp[ELOGNOT] = 1;
+ IsSubableOp[EFORCELOAD] = 0;
+ IsSubableOp[EMUL] = 1;
+ IsSubableOp[EMULV] = 1;
+ IsSubableOp[EDIV] = 1;
+ IsSubableOp[EMODULO] = 1;
+ IsSubableOp[EADDV] = 1;
+ IsSubableOp[ESUBV] = 1;
+ IsSubableOp[EADD] = 1;
+ IsSubableOp[ESUB] = 1;
+ IsSubableOp[ESHL] = 1;
+ IsSubableOp[ESHR] = 1;
+ IsSubableOp[ELESS] = 0;
+ IsSubableOp[EGREATER] = 0;
+ IsSubableOp[ELESSEQU] = 0;
+ IsSubableOp[EGREATEREQU] = 0;
+ IsSubableOp[EEQU] = 0;
+ IsSubableOp[ENOTEQU] = 0;
+ IsSubableOp[EAND] = 1;
+ IsSubableOp[EXOR] = 1;
+ IsSubableOp[EOR] = 1;
+ IsSubableOp[ELAND] = 0;
+ IsSubableOp[ELOR] = 0;
+ IsSubableOp[EASS] = 0;
+ IsSubableOp[EMULASS] = 0;
+ IsSubableOp[EDIVASS] = 0;
+ IsSubableOp[EMODASS] = 0;
+ IsSubableOp[EADDASS] = 0;
+ IsSubableOp[ESUBASS] = 0;
+ IsSubableOp[ESHLASS] = 0;
+ IsSubableOp[ESHRASS] = 0;
+ IsSubableOp[EANDASS] = 0;
+ IsSubableOp[EXORASS] = 0;
+ IsSubableOp[EORASS] = 0;
+ IsSubableOp[ECOMMA] = 0;
+ IsSubableOp[EPMODULO] = 0;
+ IsSubableOp[EROTL] = 0;
+ IsSubableOp[EROTR] = 0;
+ IsSubableOp[EBCLR] = 0;
+ IsSubableOp[EBTST] = 0;
+ IsSubableOp[EBSET] = 0;
+ IsSubableOp[ETYPCON] = 0;
+ IsSubableOp[EBITFIELD] = 0;
+ IsSubableOp[EINTCONST] = 0;
+ IsSubableOp[EFLOATCONST] = 0;
+ IsSubableOp[ESTRINGCONST] = 0;
+ IsSubableOp[ECOND] = 0;
+ IsSubableOp[EFUNCCALL] = 0;
+ IsSubableOp[EFUNCCALLP] = 0;
+ IsSubableOp[EOBJREF] = 0;
+ IsSubableOp[EMFPOINTER] = 0;
+ IsSubableOp[ENULLCHECK] = 0;
+ IsSubableOp[EPRECOMP] = 0;
+ IsSubableOp[ETEMP] = 0;
+ IsSubableOp[EARGOBJ] = 0;
+ IsSubableOp[ELOCOBJ] = 0;
+ IsSubableOp[ELABEL] = 0;
+ IsSubableOp[ESETCONST] = 0;
+ IsSubableOp[ENEWEXCEPTION] = 0;
+ IsSubableOp[ENEWEXCEPTIONARRAY] = 0;
+ IsSubableOp[EOBJLIST] = 0;
+ IsSubableOp[EMEMBER] = 0;
+ IsSubableOp[ETEMPLDEP] = 0;
+ IsSubableOp[EINSTRUCTION] = 0;
+ IsSubableOp[EDEFINE] = 0;
+ IsSubableOp[EREUSE] = 0;
+ IsSubableOp[EASSBLK] = 0;
+ IsSubableOp[EVECTOR128CONST] = 0;
+ IsSubableOp[ECONDASS] = 0;
+}
+
+static int IsSubscript(IROLinear *nd) {
+ return 0;
+}
+
+Boolean IRO_IsSubableExpression(IROLinear *nd) {
+ Object *varobj;
+ Boolean result;
+
+ switch (nd->type) {
+ case IROLinearOp2Arg:
+ if (nd->nodetype == EADD || nd->nodetype == ESUB) {
+ if (
+ IRO_IsConstant(nd->u.diadic.right) &&
+ (varobj = IRO_IsVariable(nd->u.diadic.left)) &&
+ varobj->datatype == DLOCAL &&
+ varobj->u.var.info &&
+ !varobj->u.var.info->noregister)
+ return 0;
+
+ }
+ result = IsSubableOp[nd->nodetype] && !IsSubscript(nd);
+ return result;
+ case IROLinearOp1Arg:
+ if (IsSubableOp[nd->nodetype] && !IsSubscript(nd))
+ return 1;
+
+ if (nd->nodetype == EINDIRECT && !(nd->flags & IROLF_Assigned)) {
+ if (nd->flags & IROLF_Ind) {
+ nd = nd->u.monadic;
+ if (nd->type == IROLinearOperand &&
+ nd->u.node->type == EOBJREF &&
+ nd->u.node->data.objref->datatype == DLOCAL &&
+ nd->u.node->data.objref->u.var.info &&
+ !nd->u.node->data.objref->u.var.info->noregister
+ )
+ return 0;
+ return 1;
+ }
+
+ if (IRO_IsVariable(nd) && IRO_IsRegable(nd->u.monadic->u.node->data.objref))
+ return 0;
+ return 1;
+ } else if (nd->nodetype == ETYPCON && IS_TYPE_INT(nd->rtype) && nd->rtype->size >= nd->u.monadic->rtype->size) {
+ return 1;
+ } else {
+ return 0;
+ }
+ case IROLinearOperand:
+ default:
+ return 0;
+ }
+}
+
+Boolean IRO_IsVectorTempCandidate(IROLinear *nd) {
+ return
+ (
+ nd->type == IROLinearOp1Arg ||
+ nd->type == IROLinearOp2Arg ||
+ nd->type == IROLinearOp3Arg ||
+ nd->type == IROLinearOperand ||
+ nd->type == IROLinearFunccall
+ ) && (
+ (nd->flags & IROLF_LoopInvariant) &&
+ !(nd->flags & IROLF_Ind)
+ );
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroSubable.h b/compiler_and_linker/FrontEnd/Optimizer/IroSubable.h
new file mode 100644
index 0000000..db5f860
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroSubable.h
@@ -0,0 +1,10 @@
+#ifndef COMPILER_IROSUBABLE_H
+#define COMPILER_IROSUBABLE_H
+
+#include "IrOptimizer.h"
+
+extern void IRO_InitializeIsSubableOpArray(void);
+extern Boolean IRO_IsSubableExpression(IROLinear *nd);
+extern Boolean IRO_IsVectorTempCandidate(IROLinear *nd);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroTransform.c b/compiler_and_linker/FrontEnd/Optimizer/IroTransform.c
new file mode 100644
index 0000000..8a4af16
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroTransform.c
@@ -0,0 +1,2794 @@
+#include "IroTransform.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInt64.h"
+#include "compiler/CIRTransform.h"
+#include "compiler/CMachine.h"
+#include "compiler/CPrep.h"
+#include "compiler/CompilerTools.h"
+#include "IroDump.h"
+#include "IroLinearForm.h"
+#include "IroMalloc.h"
+#include "IroPointerAnalysis.h"
+#include "IROUseDef.h"
+#include "IroUtil.h"
+#include "IroVars.h"
+#include "compiler/enode.h"
+#include "compiler/types.h"
+
+ENodeType ExprType;
+ENode *IndirectRef;
+Boolean FirstTime;
+CInt64 OperandConst;
+Object *OperandObject;
+ENodeList *FirstAddend;
+ENodeList *LastAddend;
+static ENodeType AssignmentOp[MAXEXPR];
+static ENodeType ComplementaryOpLogical[MAXEXPR];
+static ENodeType ComplementaryOp[MAXEXPR];
+
+// forward decls
+static void DoDiadic(IROLinear *nd);
+
+static int GetTypeSize(Type *type) {
+ if (type->size == 1)
+ return 0;
+ if (type->size == 2)
+ return 1;
+ if (type->size == 4)
+ return 2;
+ if (type->size == 8)
+ return 3;
+ return -1;
+}
+
+void IRO_InitializeAssignmentOpArray(void) {
+ int i;
+
+ for (i = 0; i < MAXEXPR; i++)
+ AssignmentOp[i] = MAXEXPR;
+
+ AssignmentOp[EPOSTINC] = MAXEXPR;
+ AssignmentOp[EPOSTDEC] = MAXEXPR;
+ AssignmentOp[EPREINC] = MAXEXPR;
+ AssignmentOp[EPREDEC] = MAXEXPR;
+ AssignmentOp[EINDIRECT] = MAXEXPR;
+ AssignmentOp[EMONMIN] = MAXEXPR;
+ AssignmentOp[EBINNOT] = MAXEXPR;
+ AssignmentOp[ELOGNOT] = MAXEXPR;
+ AssignmentOp[EFORCELOAD] = MAXEXPR;
+ AssignmentOp[EMUL] = EMULASS;
+ AssignmentOp[EMULV] = MAXEXPR;
+ AssignmentOp[EDIV] = EDIVASS;
+ AssignmentOp[EMODULO] = EMODASS;
+ AssignmentOp[EADDV] = MAXEXPR;
+ AssignmentOp[ESUBV] = MAXEXPR;
+ AssignmentOp[EADD] = EADDASS;
+ AssignmentOp[ESUB] = ESUBASS;
+ AssignmentOp[ESHL] = ESHLASS;
+ AssignmentOp[ESHR] = ESHRASS;
+ AssignmentOp[ELESS] = MAXEXPR;
+ AssignmentOp[EGREATER] = MAXEXPR;
+ AssignmentOp[ELESSEQU] = MAXEXPR;
+ AssignmentOp[EGREATEREQU] = MAXEXPR;
+ AssignmentOp[EEQU] = MAXEXPR;
+ AssignmentOp[ENOTEQU] = MAXEXPR;
+ AssignmentOp[EAND] = EANDASS;
+ AssignmentOp[EXOR] = EXORASS;
+ AssignmentOp[EOR] = EORASS;
+ AssignmentOp[ELAND] = MAXEXPR;
+ AssignmentOp[ELOR] = MAXEXPR;
+ AssignmentOp[EASS] = MAXEXPR;
+ AssignmentOp[EMULASS] = MAXEXPR;
+ AssignmentOp[EDIVASS] = MAXEXPR;
+ AssignmentOp[EMODASS] = MAXEXPR;
+ AssignmentOp[EADDASS] = MAXEXPR;
+ AssignmentOp[ESUBASS] = MAXEXPR;
+ AssignmentOp[ESHLASS] = MAXEXPR;
+ AssignmentOp[ESHRASS] = MAXEXPR;
+ AssignmentOp[EANDASS] = MAXEXPR;
+ AssignmentOp[EXORASS] = MAXEXPR;
+ AssignmentOp[EORASS] = MAXEXPR;
+ AssignmentOp[ECOMMA] = MAXEXPR;
+ AssignmentOp[EPMODULO] = MAXEXPR;
+ AssignmentOp[EROTL] = MAXEXPR;
+ AssignmentOp[EROTR] = MAXEXPR;
+ AssignmentOp[EBCLR] = MAXEXPR;
+ AssignmentOp[EBTST] = MAXEXPR;
+ AssignmentOp[EBSET] = MAXEXPR;
+ AssignmentOp[ETYPCON] = MAXEXPR;
+ AssignmentOp[EBITFIELD] = MAXEXPR;
+ AssignmentOp[EINTCONST] = MAXEXPR;
+ AssignmentOp[EFLOATCONST] = MAXEXPR;
+ AssignmentOp[ESTRINGCONST] = MAXEXPR;
+ AssignmentOp[ECOND] = MAXEXPR;
+ AssignmentOp[EFUNCCALL] = MAXEXPR;
+ AssignmentOp[EFUNCCALLP] = MAXEXPR;
+ AssignmentOp[EOBJREF] = MAXEXPR;
+ AssignmentOp[EMFPOINTER] = MAXEXPR;
+ AssignmentOp[ENULLCHECK] = MAXEXPR;
+ AssignmentOp[EPRECOMP] = MAXEXPR;
+ AssignmentOp[ETEMP] = MAXEXPR;
+ AssignmentOp[EARGOBJ] = MAXEXPR;
+ AssignmentOp[ELOCOBJ] = MAXEXPR;
+ AssignmentOp[ELABEL] = MAXEXPR;
+ AssignmentOp[ESETCONST] = MAXEXPR;
+ AssignmentOp[ENEWEXCEPTION] = MAXEXPR;
+ AssignmentOp[ENEWEXCEPTIONARRAY] = MAXEXPR;
+ AssignmentOp[EOBJLIST] = MAXEXPR;
+ AssignmentOp[EMEMBER] = MAXEXPR;
+ AssignmentOp[ETEMPLDEP] = MAXEXPR;
+ AssignmentOp[EINSTRUCTION] = MAXEXPR;
+ AssignmentOp[EDEFINE] = MAXEXPR;
+ AssignmentOp[EREUSE] = MAXEXPR;
+ AssignmentOp[EASSBLK] = MAXEXPR;
+ AssignmentOp[EVECTOR128CONST] = MAXEXPR;
+ AssignmentOp[ECONDASS] = MAXEXPR;
+}
+
+void IRO_InitializeComplementaryOpArray(void) {
+ int i;
+
+ for (i = 0; i < MAXEXPR; i++)
+ ComplementaryOp[i] = MAXEXPR;
+
+ ComplementaryOp[EPOSTINC] = EPOSTDEC;
+ ComplementaryOp[EPOSTDEC] = EPOSTINC;
+ ComplementaryOp[EPREINC] = EPREDEC;
+ ComplementaryOp[EPREDEC] = EPREINC;
+ ComplementaryOp[EINDIRECT] = MAXEXPR;
+ ComplementaryOp[EMONMIN] = EMONMIN;
+ ComplementaryOp[EBINNOT] = EBINNOT;
+ ComplementaryOp[ELOGNOT] = ELOGNOT;
+ ComplementaryOp[EFORCELOAD] = MAXEXPR;
+ ComplementaryOp[EMUL] = EDIV;
+ ComplementaryOp[EMULV] = MAXEXPR;
+ ComplementaryOp[EDIV] = EMUL;
+ ComplementaryOp[EMODULO] = MAXEXPR;
+ ComplementaryOp[EADDV] = ESUBV;
+ ComplementaryOp[ESUBV] = EADDV;
+ ComplementaryOp[EADD] = ESUB;
+ ComplementaryOp[ESUB] = EADD;
+ ComplementaryOp[ESHL] = ESHR;
+ ComplementaryOp[ESHR] = ESHL;
+ ComplementaryOp[ELESS] = EGREATER;
+ ComplementaryOp[EGREATER] = ELESS;
+ ComplementaryOp[ELESSEQU] = EGREATEREQU;
+ ComplementaryOp[EGREATEREQU] = ELESSEQU;
+ ComplementaryOp[EEQU] = ENOTEQU;
+ ComplementaryOp[ENOTEQU] = EEQU;
+ ComplementaryOp[EAND] = EOR;
+ ComplementaryOp[EXOR] = MAXEXPR;
+ ComplementaryOp[EOR] = EAND;
+ ComplementaryOp[ELAND] = ELOR;
+ ComplementaryOp[ELOR] = ELAND;
+ ComplementaryOp[EASS] = MAXEXPR;
+ ComplementaryOp[EMULASS] = EDIVASS;
+ ComplementaryOp[EDIVASS] = EMULASS;
+ ComplementaryOp[EMODASS] = MAXEXPR;
+ ComplementaryOp[EADDASS] = ESUBASS;
+ ComplementaryOp[ESUBASS] = EADDASS;
+ ComplementaryOp[ESHLASS] = ESHRASS;
+ ComplementaryOp[ESHRASS] = ESHLASS;
+ ComplementaryOp[EANDASS] = EORASS;
+ ComplementaryOp[EXORASS] = MAXEXPR;
+ ComplementaryOp[EORASS] = EANDASS;
+ ComplementaryOp[ECOMMA] = MAXEXPR;
+ ComplementaryOp[EPMODULO] = MAXEXPR;
+ ComplementaryOp[EROTL] = EROTR;
+ ComplementaryOp[EROTR] = EROTL;
+ ComplementaryOp[EBCLR] = MAXEXPR;
+ ComplementaryOp[EBTST] = MAXEXPR;
+ ComplementaryOp[EBSET] = MAXEXPR;
+ ComplementaryOp[ETYPCON] = MAXEXPR;
+ ComplementaryOp[EBITFIELD] = MAXEXPR;
+ ComplementaryOp[EINTCONST] = MAXEXPR;
+ ComplementaryOp[EFLOATCONST] = MAXEXPR;
+ ComplementaryOp[ESTRINGCONST] = MAXEXPR;
+ ComplementaryOp[ECOND] = MAXEXPR;
+ ComplementaryOp[EFUNCCALL] = MAXEXPR;
+ ComplementaryOp[EFUNCCALLP] = MAXEXPR;
+ ComplementaryOp[EOBJREF] = MAXEXPR;
+ ComplementaryOp[EMFPOINTER] = MAXEXPR;
+ ComplementaryOp[ENULLCHECK] = MAXEXPR;
+ ComplementaryOp[EPRECOMP] = MAXEXPR;
+ ComplementaryOp[ETEMP] = MAXEXPR;
+ ComplementaryOp[EARGOBJ] = MAXEXPR;
+ ComplementaryOp[ELOCOBJ] = MAXEXPR;
+ ComplementaryOp[ELABEL] = MAXEXPR;
+ ComplementaryOp[ESETCONST] = MAXEXPR;
+ ComplementaryOp[ENEWEXCEPTION] = MAXEXPR;
+ ComplementaryOp[ENEWEXCEPTIONARRAY] = MAXEXPR;
+ ComplementaryOp[EOBJLIST] = MAXEXPR;
+ ComplementaryOp[EMEMBER] = MAXEXPR;
+ ComplementaryOp[ETEMPLDEP] = MAXEXPR;
+ ComplementaryOp[EINSTRUCTION] = MAXEXPR;
+ ComplementaryOp[EDEFINE] = MAXEXPR;
+ ComplementaryOp[EREUSE] = MAXEXPR;
+ ComplementaryOp[EASSBLK] = MAXEXPR;
+ ComplementaryOp[EVECTOR128CONST] = MAXEXPR;
+ ComplementaryOp[ECONDASS] = MAXEXPR;
+}
+
+void IRO_InitializeComplementaryOpLogicalArray(void) {
+ int i;
+
+ for (i = 0; i < MAXEXPR; i++)
+ ComplementaryOpLogical[i] = MAXEXPR;
+
+ ComplementaryOpLogical[EPOSTINC] = MAXEXPR;
+ ComplementaryOpLogical[EPOSTDEC] = MAXEXPR;
+ ComplementaryOpLogical[EPREINC] = MAXEXPR;
+ ComplementaryOpLogical[EPREDEC] = MAXEXPR;
+ ComplementaryOpLogical[EINDIRECT] = MAXEXPR;
+ ComplementaryOpLogical[EMONMIN] = MAXEXPR;
+ ComplementaryOpLogical[EBINNOT] = MAXEXPR;
+ ComplementaryOpLogical[ELOGNOT] = ELOGNOT;
+ ComplementaryOpLogical[EFORCELOAD] = MAXEXPR;
+ ComplementaryOpLogical[EMUL] = MAXEXPR;
+ ComplementaryOpLogical[EMULV] = MAXEXPR;
+ ComplementaryOpLogical[EDIV] = MAXEXPR;
+ ComplementaryOpLogical[EMODULO] = MAXEXPR;
+ ComplementaryOpLogical[EADDV] = MAXEXPR;
+ ComplementaryOpLogical[ESUBV] = MAXEXPR;
+ ComplementaryOpLogical[EADD] = MAXEXPR;
+ ComplementaryOpLogical[ESUB] = MAXEXPR;
+ ComplementaryOpLogical[ESHL] = MAXEXPR;
+ ComplementaryOpLogical[ESHR] = MAXEXPR;
+ ComplementaryOpLogical[ELESS] = EGREATEREQU;
+ ComplementaryOpLogical[EGREATER] = ELESSEQU;
+ ComplementaryOpLogical[ELESSEQU] = EGREATER;
+ ComplementaryOpLogical[EGREATEREQU] = ELESS;
+ ComplementaryOpLogical[EEQU] = ENOTEQU;
+ ComplementaryOpLogical[ENOTEQU] = EEQU;
+ ComplementaryOpLogical[EAND] = MAXEXPR;
+ ComplementaryOpLogical[EXOR] = MAXEXPR;
+ ComplementaryOpLogical[EOR] = MAXEXPR;
+ ComplementaryOpLogical[ELAND] = ELOR;
+ ComplementaryOpLogical[ELOR] = ELAND;
+ ComplementaryOpLogical[EASS] = MAXEXPR;
+ ComplementaryOpLogical[EMULASS] = MAXEXPR;
+ ComplementaryOpLogical[EDIVASS] = MAXEXPR;
+ ComplementaryOpLogical[EMODASS] = MAXEXPR;
+ ComplementaryOpLogical[EADDASS] = MAXEXPR;
+ ComplementaryOpLogical[ESUBASS] = MAXEXPR;
+ ComplementaryOpLogical[ESHLASS] = MAXEXPR;
+ ComplementaryOpLogical[ESHRASS] = MAXEXPR;
+ ComplementaryOpLogical[EANDASS] = MAXEXPR;
+ ComplementaryOpLogical[EXORASS] = MAXEXPR;
+ ComplementaryOpLogical[EORASS] = MAXEXPR;
+ ComplementaryOpLogical[ECOMMA] = MAXEXPR;
+ ComplementaryOpLogical[EPMODULO] = MAXEXPR;
+ ComplementaryOpLogical[EROTL] = MAXEXPR;
+ ComplementaryOpLogical[EROTR] = MAXEXPR;
+ ComplementaryOpLogical[EBCLR] = MAXEXPR;
+ ComplementaryOpLogical[EBTST] = MAXEXPR;
+ ComplementaryOpLogical[EBSET] = MAXEXPR;
+ ComplementaryOpLogical[ETYPCON] = MAXEXPR;
+ ComplementaryOpLogical[EBITFIELD] = MAXEXPR;
+ ComplementaryOpLogical[EINTCONST] = MAXEXPR;
+ ComplementaryOpLogical[EFLOATCONST] = MAXEXPR;
+ ComplementaryOpLogical[ESTRINGCONST] = MAXEXPR;
+ ComplementaryOpLogical[ECOND] = MAXEXPR;
+ ComplementaryOpLogical[EFUNCCALL] = MAXEXPR;
+ ComplementaryOpLogical[EFUNCCALLP] = MAXEXPR;
+ ComplementaryOpLogical[EOBJREF] = MAXEXPR;
+ ComplementaryOpLogical[EMFPOINTER] = MAXEXPR;
+ ComplementaryOpLogical[ENULLCHECK] = MAXEXPR;
+ ComplementaryOpLogical[EPRECOMP] = MAXEXPR;
+ ComplementaryOpLogical[ETEMP] = MAXEXPR;
+ ComplementaryOpLogical[EARGOBJ] = MAXEXPR;
+ ComplementaryOpLogical[ELOCOBJ] = MAXEXPR;
+ ComplementaryOpLogical[ELABEL] = MAXEXPR;
+ ComplementaryOpLogical[ESETCONST] = MAXEXPR;
+ ComplementaryOpLogical[ENEWEXCEPTION] = MAXEXPR;
+ ComplementaryOpLogical[ENEWEXCEPTIONARRAY] = MAXEXPR;
+ ComplementaryOpLogical[EOBJLIST] = MAXEXPR;
+ ComplementaryOpLogical[EMEMBER] = MAXEXPR;
+ ComplementaryOpLogical[ETEMPLDEP] = MAXEXPR;
+ ComplementaryOpLogical[EINSTRUCTION] = MAXEXPR;
+ ComplementaryOpLogical[EDEFINE] = MAXEXPR;
+ ComplementaryOpLogical[EREUSE] = MAXEXPR;
+ ComplementaryOpLogical[EASSBLK] = MAXEXPR;
+ ComplementaryOpLogical[EVECTOR128CONST] = MAXEXPR;
+ ComplementaryOpLogical[ECONDASS] = MAXEXPR;
+}
+
+static void DoTransformations(IROLinear *nd) {
+ IROLinear *nd2;
+ IROLinear *nd3;
+ IROLinear *nd4;
+ IROLinear *nd5;
+ Type *newtype;
+ SInt32 value;
+
+ if (nd->type == IROLinearOp2Arg) {
+ switch (nd->nodetype) {
+ case EASS:
+ nd2 = nd->u.diadic.right;
+ if (
+ nd2->type == IROLinearOp2Arg &&
+ AssignmentOp[nd2->nodetype] < MAXEXPR &&
+ IRO_TypesEqual(nd->rtype, nd2->rtype) &&
+ IRO_IsVariable(nd3 = nd->u.diadic.left) &&
+ !(nd3->flags & IROLF_BitfieldIndirect) &&
+ IRO_ExprsSame(nd3, nd2->u.diadic.left)
+ )
+ {
+ nd->nodetype = AssignmentOp[nd2->nodetype];
+ nd->u.diadic.right = nd2->u.diadic.right;
+ IRO_NopOut(nd2->u.diadic.left);
+ nd2->type = IROLinearNop;
+
+ nd3->flags |= IROLF_Used;
+ nd3->u.diadic.left->flags |= IROLF_Used;
+ }
+ break;
+
+ case EMUL:
+ if (
+ IS_TYPE_INT(nd->rtype) &&
+ IRO_IsPow2(nd->u.diadic.right, &value)
+ )
+ {
+ nd->nodetype = ESHL;
+ CInt64_SetLong(&nd->u.diadic.right->u.node->data.intval, value);
+ }
+ break;
+
+ case EDIV:
+ if (
+ IS_TYPE_INT(nd->rtype) &&
+ IRO_IsPow2(nd->u.diadic.right, &value)
+ )
+ {
+ if (IRO_IsUnsignedType(nd->rtype)) {
+ nd->nodetype = ESHR;
+ CInt64_SetLong(&nd->u.diadic.right->u.node->data.intval, value);
+ } else if (
+ !IRO_IsUnsignedType(nd->rtype) &&
+ TYPE_INTEGRAL(nd->rtype)->integral != IT_BOOL &&
+ nd->u.diadic.left->nodetype == ETYPCON &&
+ IS_TYPE_INT(nd->u.diadic.left->u.monadic->rtype) &&
+ IRO_IsUnsignedType(nd->u.diadic.left->u.monadic->rtype) &&
+ nd->u.diadic.left->u.monadic->rtype->size < nd->u.diadic.left->rtype->size
+ )
+ {
+ nd->nodetype = ESHR;
+ CInt64_SetLong(&nd->u.diadic.right->u.node->data.intval, value);
+ if (nd->flags & IROLF_Reffed) {
+ IROLinear *copy = IRO_NewLinear(IROLinearOp1Arg);
+ memcpy(copy, nd, sizeof(IROLinear));
+ copy->type = IROLinearOp1Arg;
+ copy->nodetype = ETYPCON;
+ copy->index = IRO_NumLinear++;
+ copy->rtype = nd->rtype;
+ IRO_PasteAfter(copy, copy, nd);
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, copy);
+ copy->u.monadic = nd;
+ nd->flags |= IROLF_Reffed;
+ }
+ nd->rtype = IRO_UnsignedType(nd->rtype);
+ newtype = IRO_UnsignedType(nd->u.diadic.right->rtype);
+ nd->u.diadic.right->u.node->rtype = newtype;
+ nd->u.diadic.right->rtype = newtype;
+ nd->u.diadic.left->rtype = IRO_UnsignedType(nd->u.diadic.left->rtype);
+ }
+ }
+ break;
+
+ case EMODULO:
+ if (
+ IS_TYPE_INT(nd->rtype) &&
+ IRO_IsUnsignedType(nd->rtype) &&
+ IRO_IsPow2(nd->u.diadic.right, &value)
+ )
+ {
+ nd->nodetype = EAND;
+ nd->u.diadic.right->u.node->data.intval = CInt64_Sub(nd->u.diadic.right->u.node->data.intval, cint64_one);
+ }
+ break;
+
+ case EEQU:
+ if (
+ (nd2 = IRO_LocateFather(nd)) &&
+ nd2->nodetype == ETYPCON &&
+ IS_TYPE_INT(nd2->rtype) &&
+ (nd3 = IRO_LocateFather(nd2)) &&
+ nd3->nodetype == ELOGNOT &&
+ (nd4 = IRO_LocateFather(nd3)) &&
+ nd4->nodetype == ETYPCON &&
+ IS_TYPE_INT(nd4->rtype) &&
+ (
+ ((nd5 = IRO_LocateFather(nd4)) && nd5->type == IROLinearIf) ||
+ nd5->type == IROLinearIfNot
+ )
+ )
+ {
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd4, nd);
+ nd->nodetype = ENOTEQU;
+ nd2->type = IROLinearNop;
+ nd3->type = IROLinearNop;
+ nd4->type = IROLinearNop;
+ }
+ break;
+ }
+ }
+}
+
+static void IRO_SwitchChildren(IROLinear *nd) {
+ IROLinear *tmp = nd->u.diadic.left;
+ nd->u.diadic.left = nd->u.diadic.right;
+ nd->u.diadic.right = tmp;
+}
+
+static void ReplaceExprWithConst(IROLinear *nd, CInt64 val) {
+ IRO_NopOut(nd);
+ nd->type = IROLinearOperand;
+ nd->nodetype = EINTCONST;
+ nd->u.node = IRO_NewENode(EINTCONST);
+ nd->u.node->data.intval = val;
+ nd->u.node->flags = nd->nodeflags;
+ nd->u.node->rtype = nd->rtype;
+
+ if (IS_TYPE_FLOAT(nd->rtype)) {
+ nd->u.node->type = EFLOATCONST;
+ nd->nodetype = EFLOATCONST;
+ nd->u.node->data.floatval = CMach_CalcFloatConvertFromInt(TYPE(&stsignedlong), val);
+ }
+}
+
+static void ReplaceExprWithLeftChild(IROLinear *nd) {
+ IROLinear *left = nd->u.diadic.left;
+ IROLinear *right = nd->u.diadic.right;
+
+ if (left->rtype == nd->rtype) {
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, left);
+ left->flags = nd->flags;
+ left->nodeflags = nd->nodeflags;
+ nd->type = IROLinearNop;
+ IRO_NopOut(right);
+ } else {
+ nd->type = IROLinearOp1Arg;
+ nd->nodetype = ETYPCON;
+ nd->u.monadic = left;
+ IRO_NopOut(right);
+ }
+}
+
+static void ReplaceExprWithRightChild(IROLinear *nd) {
+ IROLinear *left = nd->u.diadic.left;
+ IROLinear *right = nd->u.diadic.right;
+
+ if (right->rtype == nd->rtype) {
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, right);
+ right->flags = nd->flags;
+ right->nodeflags = nd->nodeflags;
+ nd->type = IROLinearNop;
+ IRO_NopOut(left);
+ } else {
+ nd->type = IROLinearOp1Arg;
+ nd->nodetype = ETYPCON;
+ nd->u.monadic = right;
+ IRO_NopOut(left);
+ }
+}
+
+static void ReplaceExprWithMonaminRight(IROLinear *nd) {
+ IROLinear *left = nd->u.diadic.left;
+ IROLinear *right = nd->u.diadic.right;
+
+ if (right->rtype == nd->rtype) {
+ nd->type = IROLinearOp1Arg;
+ nd->nodetype = EMONMIN;
+ nd->u.monadic = right;
+ IRO_NopOut(left);
+ } else {
+ IRO_NopOut(left);
+ left->type = IROLinearOp1Arg;
+ left->nodetype = ETYPCON;
+ left->expr = right->expr;
+ left->rtype = nd->rtype;
+ left->u.monadic = right;
+ nd->type = IROLinearOp1Arg;
+ nd->nodetype = EMONMIN;
+ nd->u.monadic = left;
+ }
+}
+
+static void ReplaceExprWithMonaminLeft(IROLinear *nd) {
+ IROLinear *left = nd->u.diadic.left;
+ IROLinear *right = nd->u.diadic.right;
+
+ if (left->rtype == nd->rtype) {
+ nd->type = IROLinearOp1Arg;
+ nd->nodetype = EMONMIN;
+ nd->u.monadic = left;
+ IRO_NopOut(right);
+ } else {
+ IRO_NopOut(right);
+ right->type = IROLinearOp1Arg;
+ right->nodetype = ETYPCON;
+ right->expr = left->expr;
+ right->rtype = nd->rtype;
+ right->u.monadic = left;
+ nd->type = IROLinearOp1Arg;
+ nd->nodetype = EMONMIN;
+ nd->u.monadic = right;
+ }
+}
+
+static void switchFatherLeftMonadic(IROLinear *nd) {
+ IROLinear *inner = nd->u.monadic;
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, inner);
+ nd->u.monadic = inner->u.monadic;
+ inner->u.monadic = nd;
+ inner->rtype = nd->rtype;
+ inner->flags = nd->flags;
+ inner->nodeflags = nd->nodeflags;
+ IRO_CutAndPasteAfter(inner, inner, nd);
+}
+
+static void switchFatherLeft(IROLinear *nd, int isRight) {
+ IROLinear *a;
+ IROLinear *b;
+
+ a = nd->u.diadic.left;
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, a);
+
+ if (isRight) {
+ nd->u.diadic.left = a->u.diadic.left;
+ a->u.diadic.left = nd;
+ b = a->u.diadic.right;
+ } else {
+ nd->u.diadic.left = a->u.diadic.right;
+ a->u.diadic.right = nd;
+ b = a->u.diadic.left;
+ }
+
+ a->rtype = nd->rtype;
+ a->flags = nd->flags;
+ a->nodeflags = nd->nodeflags;
+ IRO_CutAndPasteAfter(a, a, nd);
+ IRO_CutAndPasteAfter(IRO_FindFirst(b), b, nd);
+}
+
+static void PickCommonsubAtLeftLeft(IROLinear *nd) {
+ switchFatherLeft(nd, 0);
+ ReplaceExprWithRightChild(nd->u.diadic.right);
+}
+
+static void PickCommonsubAtRightLeft(IROLinear *nd) {
+ switchFatherLeft(nd, 1);
+ ReplaceExprWithRightChild(nd->u.diadic.right);
+}
+
+static void PickCommonsubAtLeftRight(IROLinear *nd) {
+ switchFatherLeft(nd, 0);
+ ReplaceExprWithLeftChild(nd->u.diadic.right);
+}
+
+static void PickCommonsubAtRightRight(IROLinear *nd) {
+ switchFatherLeft(nd, 1);
+ ReplaceExprWithLeftChild(nd->u.diadic.right);
+}
+
+static void DoTransformations11(IROLinear *nd) {
+ IROLinear *left;
+ IROLinear *right;
+ int changed;
+ int compare;
+ Type *type;
+ SInt32 tmp1;
+ SInt32 tmp2;
+ CInt64 val;
+
+ if (nd->type == IROLinearOp2Arg) {
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+ if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype))
+ return;
+
+ changed = 0;
+ if (!IRO_HasSideEffect(left) && !IRO_HasSideEffect(right)) {
+ if (IRO_IsIntConstant(right) || IRO_IsFloatConstant(right)) {
+ if (IRO_IsConstantZero(right)) {
+ switch (nd->nodetype) {
+ case EADDV:
+ case ESUBV:
+ case EADD:
+ case ESUB:
+ case ESHL:
+ case ESHR:
+ case EXOR:
+ case EOR:
+ case ELOR:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EXORASS:
+ case EORASS:
+ ReplaceExprWithLeftChild(nd);
+ changed = 1;
+ break;
+ case EMUL:
+ case EAND:
+ case ELAND:
+ ReplaceExprWithConst(nd, cint64_zero);
+ changed = 1;
+ break;
+ case EMULASS:
+ case EANDASS:
+ nd->nodetype = EASS;
+ nd->u.diadic.right->rtype = nd->rtype;
+ nd->u.diadic.right->u.node->rtype = nd->rtype;
+ changed = 1;
+ break;
+ case EDIV:
+ case EMODULO:
+ case EDIVASS:
+ case EMODASS:
+ if (nd->stmt->sourceoffset) {
+ TStreamElement *token = CPrep_CurStreamElement();
+ token->tokenoffset = nd->stmt->sourceoffset;
+ CError_SetErrorToken(token);
+ }
+ CError_Warning(CErrorStr139);
+ break;
+ }
+ } else if (nd->nodetype == ELAND) {
+ ReplaceExprWithLeftChild(nd);
+ changed = 1;
+ } else if (nd->nodetype == ELOR) {
+ ReplaceExprWithConst(nd, cint64_one);
+ changed = 1;
+ } else if (nd->nodetype == ESHL || nd->nodetype == ESHR || nd->nodetype == ESHLASS || nd->nodetype == ESHRASS) {
+ type = nd->rtype;
+ tmp1 = type->size * 8;
+ if (left->type == IROLinearOp1Arg && left->nodetype == ETYPCON) {
+ type = left->u.monadic->rtype;
+ if (
+ left->u.monadic->type == IROLinearOp1Arg &&
+ left->u.monadic->nodetype == EINDIRECT &&
+ left->u.monadic->u.monadic->type == IROLinearOp1Arg &&
+ left->u.monadic->u.monadic->nodetype == EBITFIELD &&
+ IS_TYPE_BITFIELD(left->u.monadic->u.monadic->rtype)
+ )
+ tmp2 = TYPE_BITFIELD(left->u.monadic->u.monadic->rtype)->bitlength;
+ else
+ tmp2 = type->size * 8;
+ } else {
+ tmp2 = tmp1;
+ }
+
+ switch (nd->nodetype) {
+ case ESHL:
+ case ESHLASS:
+ CInt64_SetLong(&val, tmp1);
+ if (IRO_IsUnsignedType(type))
+ compare = CInt64_GreaterEqualU(right->u.node->data.intval, val);
+ else
+ compare = CInt64_GreaterEqual(right->u.node->data.intval, val);
+ break;
+ case ESHR:
+ case ESHRASS:
+ CInt64_SetLong(&val, tmp2);
+ compare = IRO_IsUnsignedType(type) && CInt64_GreaterEqualU(right->u.node->data.intval, val);
+ break;
+ }
+
+ if (compare) {
+ switch (nd->nodetype) {
+ case ESHL:
+ case ESHR:
+ ReplaceExprWithConst(nd, cint64_zero);
+ break;
+ case ESHLASS:
+ case ESHRASS:
+ nd->nodetype = EASS;
+ ReplaceExprWithConst(right, cint64_zero);
+ break;
+ }
+ changed = 1;
+ }
+ } else if (IRO_IsConstantOne(right)) {
+ switch (nd->nodetype) {
+ case EMUL:
+ case EMULV:
+ case EDIV:
+ case EMULASS:
+ case EDIVASS:
+ ReplaceExprWithLeftChild(nd);
+ changed = 1;
+ break;
+ case EMODULO:
+ ReplaceExprWithConst(nd, cint64_zero);
+ changed = 1;
+ break;
+ case EMODASS:
+ nd->nodetype = EASS;
+ ReplaceExprWithConst(right, cint64_zero);
+ nd->u.diadic.right->rtype = nd->rtype;
+ nd->u.diadic.right->u.node->rtype = nd->rtype;
+ changed = 1;
+ break;
+ }
+ } else if (IRO_IsConstantNegativeOne(right)) {
+ switch (nd->nodetype) {
+ case EMUL:
+ case EMULV:
+ case EDIV:
+ ReplaceExprWithMonaminLeft(nd);
+ changed = 1;
+ break;
+ case EMODULO:
+ ReplaceExprWithConst(nd, cint64_zero);
+ changed = 1;
+ break;
+ case EMODASS:
+ nd->nodetype = EASS;
+ ReplaceExprWithConst(right, cint64_zero);
+ nd->u.diadic.right->rtype = nd->rtype;
+ nd->u.diadic.right->u.node->rtype = nd->rtype;
+ changed = 1;
+ break;
+ }
+ }
+ }
+
+ if (!changed && (IRO_IsIntConstant(left) || IRO_IsFloatConstant(left))) {
+ if (IRO_IsConstantZero(left)) {
+ switch (nd->nodetype) {
+ case EADDV:
+ case EADD:
+ case EXOR:
+ case EOR:
+ case ELOR:
+ ReplaceExprWithRightChild(nd);
+ break;
+ case EMUL:
+ case ESHL:
+ case ESHR:
+ case EAND:
+ case ELAND:
+ ReplaceExprWithConst(nd, cint64_zero);
+ break;
+ case ESUBV:
+ case ESUB:
+ ReplaceExprWithMonaminRight(nd);
+ break;
+ }
+ } else if (nd->nodetype == ELAND) {
+ ReplaceExprWithRightChild(nd);
+ } else if (nd->nodetype == ELOR) {
+ ReplaceExprWithConst(nd, cint64_one);
+ } else if (IRO_IsConstantOne(left)) {
+ switch (nd->nodetype) {
+ case EMUL:
+ case EMULV:
+ ReplaceExprWithRightChild(nd);
+ break;
+ }
+ } else if (IRO_IsConstantNegativeOne(left)) {
+ switch (nd->nodetype) {
+ case EMUL:
+ case EMULV:
+ ReplaceExprWithMonaminRight(nd);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void DoTransformations12(IROLinear *nd) {
+ IROLinear *left;
+ IROLinear *right;
+
+ if (nd->type == IROLinearOp2Arg) {
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+ if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype))
+ return;
+
+ if (IRO_ExprsSameSemantically(left, right) && !IRO_HasSideEffect(left)) {
+ switch (nd->nodetype) {
+ case ESUBV:
+ case ESUB:
+ case ELESS:
+ case EGREATER:
+ case ENOTEQU:
+ case EXOR:
+ ReplaceExprWithConst(nd, cint64_zero);
+ break;
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ ReplaceExprWithConst(nd, cint64_one);
+ break;
+ case EAND:
+ case EOR:
+ case ELAND:
+ case ELOR:
+ case EASS:
+ case EANDASS:
+ case EORASS:
+ ReplaceExprWithLeftChild(nd);
+ break;
+ case ESUBASS:
+ case EXORASS:
+ nd->nodetype = EASS;
+ ReplaceExprWithConst(right, cint64_zero);
+ break;
+ }
+ }
+ }
+}
+
+static void DoTransformations13(IROLinear *nd) {
+ IROLinear *left;
+ IROLinear *right;
+ IROLinear *left2;
+ IROLinear *right2;
+ IROListNode *tmp;
+ IROListNode *leftlist;
+ IROListNode *rightlist;
+
+ if (nd->type == IROLinearOp2Arg) {
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+
+ if (
+ !IRO_HasSideEffect(left) &&
+ !IRO_HasSideEffect(right) &&
+ (nd->nodetype == EEQU || nd->nodetype == ENOTEQU) &&
+ PointerAnalysis_IsLinearNodePointerExprDefinite(FunctionName, left) &&
+ PointerAnalysis_IsLinearNodePointerExprDefinite(FunctionName, right)
+ )
+ {
+ leftlist = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, left, &leftlist);
+ if (leftlist) {
+ if (leftlist->list.head && leftlist->list.tail && !leftlist->nextList) {
+ rightlist = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, right, &rightlist);
+ if (rightlist) {
+ if (rightlist->list.head && rightlist->list.tail && !rightlist->nextList) {
+ left2 = leftlist->list.tail;
+ right2 = rightlist->list.tail;
+ if (IRO_ExprsSameSemantically(left2, right2)) {
+ ReplaceExprWithConst(nd, (nd->nodetype == EEQU) ? cint64_one : cint64_zero);
+ } else if (left2->type == right2->type && IRO_TypesEqual(left2->rtype, right2->rtype)) {
+ ReplaceExprWithConst(nd, (nd->nodetype == EEQU) ? cint64_zero : cint64_one);
+ }
+ }
+
+ while (rightlist) {
+ tmp = rightlist->nextList;
+ IRO_free(rightlist);
+ rightlist = tmp;
+ }
+ }
+ }
+
+ while (leftlist) {
+ tmp = leftlist->nextList;
+ IRO_free(leftlist);
+ leftlist = tmp;
+ }
+ }
+ }
+ }
+}
+
+static void DoTransformations21(IROLinear *nd) {
+ IROLinear *left;
+ IROLinear *right;
+ Boolean changed;
+
+ if (nd->type == IROLinearOp2Arg) {
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+
+ if (left->type == IROLinearOp1Arg && right->type == IROLinearOp1Arg && left->nodetype == right->nodetype) {
+ switch (left->nodetype) {
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ changed = 0;
+ switch (nd->nodetype) {
+ case EXOR:
+ if (left->nodetype == EBINNOT)
+ goto collapse;
+ break;
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ if (left->nodetype == EMONMIN) {
+ nd->nodetype = ComplementaryOp[nd->nodetype];
+ goto collapse;
+ }
+ break;
+ case EMUL:
+ case EDIV:
+ if (left->nodetype == EMONMIN)
+ goto collapse;
+ break;
+ case EEQU:
+ case ENOTEQU:
+ if (left->nodetype != ELOGNOT) {
+ collapse:
+ nd->u.diadic.left = left->u.monadic;
+ nd->u.diadic.right = right->u.monadic;
+ left->type = right->type = IROLinearNop;
+ changed = 1;
+ }
+ break;
+ case ELAND:
+ case ELOR:
+ if (left->nodetype == ELOGNOT) {
+ nd->nodetype = ComplementaryOp[nd->nodetype];
+ goto switchfather;
+ }
+ break;
+ case EAND:
+ case EOR:
+ if (
+ !IS_TYPE_FLOAT(nd->rtype) &&
+ !IS_TYPE_FLOAT(left->rtype) &&
+ !IS_TYPE_FLOAT(right->rtype) &&
+ left->nodetype != EMONMIN
+ )
+ {
+ nd->nodetype = ComplementaryOp[nd->nodetype];
+ goto switchfather;
+ }
+ break;
+ case EADD:
+ case ESUB:
+ if (
+ !IS_TYPE_FLOAT(nd->rtype) &&
+ !IS_TYPE_FLOAT(left->rtype) &&
+ !IS_TYPE_FLOAT(right->rtype) &&
+ left->nodetype == EMONMIN
+ )
+ {
+ switchfather:
+ switchFatherLeftMonadic(nd);
+ nd->u.diadic.right = right->u.monadic;
+ right->type = IROLinearNop;
+ changed = 1;
+ }
+ break;
+ }
+
+ if (changed) {
+ DoTransformations(nd);
+ DoTransformations11(nd);
+ DoTransformations12(nd);
+ DoTransformations13(nd);
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void DoTransformations22(IROLinear *nd) {
+ IROLinear *left;
+ IROLinear *right;
+ IROLinear *ndtmp;
+
+ if (nd->type == IROLinearOp2Arg) {
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+ if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype))
+ return;
+
+ if (!IRO_HasSideEffect(left) && !IRO_HasSideEffect(right)) {
+ if (left->type == IROLinearOp1Arg && left->nodetype == EMONMIN) {
+ switch (nd->nodetype) {
+ case ESUB:
+ case ESUBV:
+ nd->nodetype = ComplementaryOp[nd->nodetype];
+ switchFatherLeftMonadic(nd);
+ break;
+
+ case EADD:
+ case EADDV:
+ nd->nodetype = ComplementaryOp[nd->nodetype];
+ nd->u.diadic.left = right;
+ nd->u.diadic.right = left->u.monadic;
+ left->type = IROLinearNop;
+ DoTransformations(nd);
+ DoTransformations12(nd);
+ DoTransformations21(nd);
+ break;
+
+ case EDIV:
+ if (IRO_ExprsSameSemantically(left->u.monadic, right))
+ ReplaceExprWithConst(nd, cint64_negone);
+ break;
+ }
+ } else {
+ ndtmp = NULL;
+ if (left->type == IROLinearOp1Arg && IRO_ExprsSameSemantically(left->u.monadic, right))
+ ndtmp = left;
+ else if (right->type == IROLinearOp1Arg && IRO_ExprsSameSemantically(left, right->u.monadic))
+ ndtmp = right;
+
+ if (ndtmp) {
+ switch (nd->nodetype) {
+ case EAND:
+ if (ndtmp->nodetype == EBINNOT || ndtmp->nodetype == ELOGNOT)
+ ReplaceExprWithConst(nd, cint64_zero);
+ break;
+
+ case EANDASS:
+ if (ndtmp->nodetype == EBINNOT || ndtmp->nodetype == ELOGNOT) {
+ nd->nodetype = EASS;
+ ReplaceExprWithConst(right, cint64_zero);
+ nd->u.diadic.right->rtype = nd->rtype;
+ nd->u.diadic.right->u.node->rtype = nd->rtype;
+ }
+ break;
+
+ case EXOR:
+ case EOR:
+ if (ndtmp->nodetype == EBINNOT) {
+ ReplaceExprWithConst(nd, cint64_zero);
+ nd->u.node->data.intval = CInt64_Inv(nd->u.node->data.intval);
+ }
+ break;
+
+ case EXORASS:
+ case EORASS:
+ if (ndtmp->nodetype == EBINNOT) {
+ nd->nodetype = EASS;
+ ReplaceExprWithConst(right, cint64_zero);
+ right->u.node->data.intval = CInt64_Inv(right->u.node->data.intval);
+ nd->u.diadic.right->rtype = nd->rtype;
+ nd->u.diadic.right->u.node->rtype = nd->rtype;
+ }
+ break;
+
+ case ELOR:
+ if (ndtmp->nodetype == EBINNOT || ndtmp->nodetype == ELOGNOT)
+ ReplaceExprWithConst(nd, cint64_one);
+ break;
+
+ case ELAND:
+ if (ndtmp->nodetype == ELOGNOT)
+ ReplaceExprWithConst(nd, cint64_zero);
+ break;
+
+ case EDIV:
+ if (ndtmp->nodetype == EMONMIN)
+ ReplaceExprWithConst(nd, cint64_negone);
+ break;
+
+ case EDIVASS:
+ if (ndtmp->nodetype == EMONMIN) {
+ nd->nodetype = EASS;
+ ReplaceExprWithConst(right, cint64_negone);
+ nd->u.diadic.right->rtype = nd->rtype;
+ nd->u.diadic.right->u.node->rtype = nd->rtype;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void DoTransformations23(IROLinear *nd) {
+ Boolean changed;
+ Boolean isCompare;
+ UInt8 which;
+ IROLinear *left;
+ IROLinear *right;
+ CInt64 size;
+ CInt64 val;
+
+ if (nd->type == IROLinearOp2Arg && !IRO_HasSideEffect(nd)) {
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+ if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype))
+ return;
+
+ isCompare = 0;
+ changed = 0;
+ which = 0;
+
+ switch (nd->nodetype) {
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ isCompare = 1;
+ case EADDV:
+ case EADD:
+ case EEQU:
+ case ENOTEQU:
+ case EAND:
+ case EOR:
+ if (left->type == IROLinearOp2Arg) {
+ if (IRO_ExprsSameSemantically(right, left->u.diadic.left))
+ which = 1;
+ else if (IRO_ExprsSameSemantically(right, left->u.diadic.right))
+ which = 2;
+
+ if (which) {
+ if (isCompare)
+ nd->nodetype = ComplementaryOp[nd->nodetype];
+ IRO_SwitchChildren(nd);
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+ break;
+ }
+ }
+ case ESUBV:
+ case ESUB:
+ case EADDASS:
+ case ESUBASS:
+ case EANDASS:
+ case EORASS:
+ if (right->type == IROLinearOp2Arg) {
+ if (IRO_ExprsSameSemantically(left, right->u.diadic.left))
+ which = 1;
+ else if (IRO_ExprsSameSemantically(left, right->u.diadic.right))
+ which = 2;
+ }
+ break;
+
+ default:
+ goto done;
+ }
+
+ if (which) {
+ switch (right->nodetype) {
+ case EAND:
+ case EOR:
+ if (which == 2)
+ IRO_SwitchChildren(right);
+
+ if (
+ nd->nodetype == right->nodetype ||
+ (nd->nodetype == EANDASS && right->nodetype == EAND) ||
+ (nd->nodetype == EORASS && right->nodetype == EOR)
+ )
+ {
+ ReplaceExprWithRightChild(right);
+ changed = 1;
+ }
+ else if (
+ nd->nodetype == ComplementaryOp[right->nodetype] ||
+ (nd->nodetype == EANDASS && right->nodetype == EOR) ||
+ (nd->nodetype == EORASS && right->nodetype == EAND)
+ )
+ {
+ ReplaceExprWithLeftChild(nd);
+ }
+ break;
+
+ case EADD:
+ if (which == 2)
+ IRO_SwitchChildren(right);
+
+ switch (nd->nodetype) {
+ case EEQU:
+ case ENOTEQU:
+ ReplaceExprWithConst(left, cint64_zero);
+ ReplaceExprWithRightChild(right);
+ IRO_SwitchChildren(nd);
+ if (isCompare)
+ nd->nodetype = ComplementaryOp[nd->nodetype];
+ changed = 1;
+ break;
+
+ case ESUB:
+ case ESUBV:
+ ReplaceExprWithRightChild(right);
+ ReplaceExprWithMonaminRight(nd);
+ changed = 1;
+ break;
+
+ case ESUBASS:
+ ReplaceExprWithRightChild(right);
+ changed = 1;
+ break;
+ }
+ break;
+
+ case ESUB:
+ switch (nd->nodetype) {
+ case EEQU:
+ case ENOTEQU:
+ if (which == 1) {
+ ReplaceExprWithConst(left, cint64_zero);
+ ReplaceExprWithRightChild(right);
+ IRO_SwitchChildren(nd);
+ }
+ break;
+ case EADD:
+ case EADDV:
+ if (which == 2) {
+ ReplaceExprWithLeftChild(right);
+ ReplaceExprWithRightChild(nd);
+ }
+ break;
+ case ESUB:
+ case ESUBV:
+ if (which == 1) {
+ ReplaceExprWithRightChild(right);
+ ReplaceExprWithRightChild(nd);
+ }
+ break;
+ case EADDASS:
+ if (which == 2) {
+ nd->nodetype = EASS;
+ ReplaceExprWithLeftChild(right);
+ changed = 1;
+ }
+ break;
+ case ESUBASS:
+ if (which == 1) {
+ nd->nodetype = EASS;
+ ReplaceExprWithRightChild(right);
+ changed = 1;
+ }
+ break;
+ }
+ break;
+ }
+ }
+
+ done:
+ if (!changed) {
+ switch (nd->nodetype) {
+ case ESUB:
+ case ESUBV:
+ which = 0;
+ if (left->type == IROLinearOp2Arg) {
+ if (IRO_ExprsSameSemantically(right, left->u.diadic.left))
+ which = 1;
+ else if (IRO_ExprsSameSemantically(right, left->u.diadic.right))
+ which = 2;
+ }
+
+ if (which == 1) {
+ if (left->nodetype == ESUB) {
+ ReplaceExprWithMonaminRight(left);
+ ReplaceExprWithLeftChild(nd);
+ } else if (left->nodetype == EADD) {
+ ReplaceExprWithRightChild(left);
+ ReplaceExprWithLeftChild(nd);
+ }
+ } else if (which == 2) {
+ if (left->nodetype == EADD) {
+ ReplaceExprWithLeftChild(left);
+ ReplaceExprWithLeftChild(nd);
+ }
+ }
+ break;
+ }
+
+ switch (nd->nodetype) {
+ case ESHL:
+ case ESHR:
+ case ESHLASS:
+ case ESHRASS:
+ which = 0;
+ if (left->type == IROLinearOp2Arg) {
+ if (left->nodetype == ComplementaryOp[nd->nodetype] || left->nodetype == AssignmentOp[ComplementaryOp[nd->nodetype]]) {
+ if (IRO_IsIntConstant(right) && IRO_ExprsSameSemantically(right, left->u.diadic.right))
+ which = 2;
+ }
+ }
+
+ if (which == 2) {
+ val = right->u.node->data.intval;
+ if (left->nodetype == ESHR || left->nodetype == ESHRASS) {
+ ReplaceExprWithLeftChild(left);
+ nd->nodetype = (nd->nodetype == ESHL) ? EAND : EANDASS;
+ right->u.node->data.intval = CInt64_Shl(cint64_negone, val);
+ changed = 1;
+ } else if (IRO_IsUnsignedType(nd->rtype)) {
+ ReplaceExprWithLeftChild(left);
+ nd->nodetype = (nd->nodetype == ESHR) ? EAND : EANDASS;
+ if (nd->rtype->size < 8) {
+ CInt64_SetLong(&size, 64 - 8 * nd->rtype->size);
+ val = CInt64_Add(val, size);
+ }
+ right->u.node->data.intval = CInt64_ShrU(cint64_negone, val);
+ changed = 1;
+ }
+ }
+ break;
+ }
+ }
+
+ if (changed) {
+ DoTransformations(nd);
+ DoTransformations11(nd);
+ DoTransformations12(nd);
+ DoTransformations13(nd);
+ DoTransformations21(nd);
+ DoTransformations22(nd);
+ DoTransformations23(nd);
+ }
+ }
+}
+
+static void DoTransformations24(IROLinear *nd) {
+ IROLinear *left;
+ IROLinear *right;
+ UInt8 changed;
+
+ if (nd->type == IROLinearOp2Arg) {
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+ if (IS_TYPE_FLOAT(nd->rtype) || IS_TYPE_FLOAT(left->rtype) || IS_TYPE_FLOAT(right->rtype))
+ return;
+
+ if (left->type == IROLinearOp2Arg && right->type == IROLinearOp2Arg && !IRO_HasSideEffect(nd)) {
+ changed = 0;
+
+ if (IRO_ExprsSameSemantically(left->u.diadic.left, right->u.diadic.left)) {
+ if (left->nodetype == right->nodetype) {
+ switch (left->nodetype) {
+ case EADD:
+ if (nd->nodetype == ComplementaryOp[left->nodetype]) {
+ ReplaceExprWithRightChild(left);
+ ReplaceExprWithRightChild(right);
+ changed = 1;
+ }
+ break;
+ case ESUB:
+ if (nd->nodetype == ESUB || nd->nodetype == ESUBV) {
+ ReplaceExprWithRightChild(left);
+ ReplaceExprWithRightChild(right);
+ IRO_SwitchChildren(nd);
+ changed = 1;
+ }
+ break;
+ case EMUL:
+ switch (nd->nodetype) {
+ case EADD:
+ case ESUB:
+ PickCommonsubAtLeftLeft(nd);
+ changed = 3;
+ break;
+ }
+ break;
+ case EAND:
+ if (nd->nodetype == EXOR) {
+ PickCommonsubAtLeftLeft(nd);
+ changed = 3;
+ break;
+ }
+ case EOR:
+ if (nd->nodetype == left->nodetype) {
+ ReplaceExprWithRightChild(left);
+ changed = 1;
+ } else if (nd->nodetype == ComplementaryOp[left->nodetype]) {
+ PickCommonsubAtLeftLeft(nd);
+ changed = 3;
+ }
+ break;
+ }
+ } else if (left->nodetype == ComplementaryOp[right->nodetype]) {
+ switch (nd->nodetype) {
+ case ESUB:
+ case ESUBV:
+ switch (left->nodetype) {
+ case EADD:
+ nd->nodetype = ComplementaryOp[nd->nodetype];
+ ReplaceExprWithRightChild(left);
+ ReplaceExprWithRightChild(right);
+ changed = 1;
+ break;
+ case ESUB:
+ ReplaceExprWithMonaminRight(left);
+ ReplaceExprWithRightChild(right);
+ changed = 1;
+ break;
+ }
+ break;
+
+ case EAND:
+ case EOR:
+ if (left->nodetype == nd->nodetype)
+ ReplaceExprWithLeftChild(nd);
+ else if (right->nodetype == nd->nodetype)
+ ReplaceExprWithRightChild(nd);
+ break;
+ }
+ }
+ } else if (IRO_ExprsSameSemantically(left->u.diadic.right, right->u.diadic.left)) {
+ if (left->nodetype == right->nodetype) {
+ switch (left->nodetype) {
+ case EADD:
+ if (nd->nodetype == ComplementaryOp[left->nodetype]) {
+ ReplaceExprWithLeftChild(left);
+ ReplaceExprWithRightChild(right);
+ changed = 1;
+ }
+ break;
+ case EMUL:
+ switch (nd->nodetype) {
+ case EADD:
+ case ESUB:
+ PickCommonsubAtRightLeft(nd);
+ changed = 3;
+ break;
+ }
+ break;
+ case EAND:
+ if (nd->nodetype == EXOR) {
+ PickCommonsubAtRightLeft(nd);
+ changed = 3;
+ break;
+ }
+ case EOR:
+ if (nd->nodetype == left->nodetype) {
+ ReplaceExprWithLeftChild(left);
+ changed = 1;
+ } else if (nd->nodetype == ComplementaryOp[left->nodetype]) {
+ PickCommonsubAtRightLeft(nd);
+ changed = 3;
+ }
+ break;
+ }
+ } else if (left->nodetype == ComplementaryOp[right->nodetype]) {
+ switch (nd->nodetype) {
+ case ESUB:
+ case ESUBV:
+ if (left->nodetype == EADD) {
+ nd->nodetype = ComplementaryOp[nd->nodetype];
+ ReplaceExprWithLeftChild(left);
+ ReplaceExprWithRightChild(right);
+ changed = 1;
+ }
+ break;
+
+ case EADD:
+ case EADDV:
+ if (left->nodetype == ESUB) {
+ ReplaceExprWithLeftChild(left);
+ ReplaceExprWithRightChild(right);
+ changed = 1;
+ }
+ break;
+
+ case EAND:
+ case EOR:
+ if (left->nodetype == nd->nodetype)
+ ReplaceExprWithLeftChild(nd);
+ else if (right->nodetype == nd->nodetype)
+ ReplaceExprWithRightChild(nd);
+ break;
+ }
+ }
+ } else if (IRO_ExprsSameSemantically(left->u.diadic.left, right->u.diadic.right)) {
+ if (left->nodetype == right->nodetype) {
+ switch (left->nodetype) {
+ case EADD:
+ if (nd->nodetype == ComplementaryOp[left->nodetype]) {
+ ReplaceExprWithRightChild(left);
+ ReplaceExprWithLeftChild(right);
+ changed = 1;
+ }
+ break;
+ case ESUB:
+ switch (nd->nodetype) {
+ case EADDV:
+ case EADD:
+ nd->nodetype = ComplementaryOp[nd->nodetype];
+ ReplaceExprWithRightChild(left);
+ ReplaceExprWithLeftChild(right);
+ IRO_SwitchChildren(nd);
+ changed = 1;
+ break;
+ }
+ break;
+ case EMUL:
+ switch (nd->nodetype) {
+ case EADD:
+ case ESUB:
+ PickCommonsubAtLeftRight(nd);
+ changed = 2;
+ break;
+ }
+ break;
+ case EAND:
+ if (nd->nodetype == EXOR) {
+ PickCommonsubAtLeftRight(nd);
+ changed = 2;
+ break;
+ }
+ case EOR:
+ if (nd->nodetype == left->nodetype) {
+ ReplaceExprWithRightChild(left);
+ changed = 1;
+ } else if (nd->nodetype == ComplementaryOp[left->nodetype]) {
+ PickCommonsubAtLeftRight(nd);
+ changed = 2;
+ }
+ break;
+ }
+ } else if (left->nodetype == ComplementaryOp[right->nodetype]) {
+ switch (nd->nodetype) {
+ case EADD:
+ case EADDV:
+ if (left->nodetype == EADD) {
+ ReplaceExprWithRightChild(left);
+ ReplaceExprWithLeftChild(right);
+ changed = 1;
+ }
+ break;
+
+ case ESUB:
+ case ESUBV:
+ if (left->nodetype == ESUB) {
+ ReplaceExprWithMonaminRight(left);
+ ReplaceExprWithRightChild(right);
+ changed = 1;
+ }
+ break;
+
+ case EAND:
+ case EOR:
+ if (left->nodetype == nd->nodetype)
+ ReplaceExprWithLeftChild(nd);
+ else if (right->nodetype == nd->nodetype)
+ ReplaceExprWithRightChild(nd);
+ break;
+ }
+ }
+ } else if (IRO_ExprsSameSemantically(left->u.diadic.right, right->u.diadic.right)) {
+ if (left->nodetype == right->nodetype) {
+ switch (nd->nodetype) {
+ case ESUB:
+ switch (left->nodetype) {
+ case EADD:
+ case ESUB:
+ ReplaceExprWithLeftChild(left);
+ ReplaceExprWithLeftChild(right);
+ changed = 1;
+ }
+ case EADD:
+ switch (left->nodetype) {
+ case EMUL:
+ case ESHL:
+ PickCommonsubAtRightRight(nd);
+ changed = 2;
+ break;
+ }
+ break;
+ case EXOR:
+ switch (left->nodetype) {
+ case ESHL:
+ case ESHR:
+ case EAND:
+ PickCommonsubAtRightRight(nd);
+ changed = 2;
+ break;
+ }
+ break;
+ case EAND:
+ case EOR:
+ if (left->nodetype == nd->nodetype) {
+ ReplaceExprWithLeftChild(right);
+ changed = 1;
+ } else if (
+ left->nodetype == ComplementaryOp[nd->nodetype] ||
+ left->nodetype == ESHR ||
+ left->nodetype == ESHL
+ )
+ {
+ PickCommonsubAtRightRight(nd);
+ changed = 2;
+ }
+ break;
+ }
+ } else if (left->nodetype == ComplementaryOp[right->nodetype]) {
+ switch (nd->nodetype) {
+ case EADD:
+ case EADDV:
+ switch (left->nodetype) {
+ case EADD:
+ case ESUB:
+ ReplaceExprWithLeftChild(left);
+ ReplaceExprWithLeftChild(right);
+ changed = 1;
+ break;
+ }
+ break;
+
+ case EAND:
+ case EOR:
+ if (left->nodetype == nd->nodetype)
+ ReplaceExprWithLeftChild(nd);
+ else if (right->nodetype == nd->nodetype)
+ ReplaceExprWithRightChild(nd);
+ break;
+ }
+ }
+ }
+
+ if (changed) {
+ DoDiadic(nd);
+ if (changed == 2)
+ DoDiadic(nd->u.diadic.left);
+ else if (changed == 3)
+ DoDiadic(nd->u.diadic.right);
+ IRO_Dump("remove common op at: %d\n", nd->index);
+ }
+ }
+ }
+}
+
+static void DoTransformations25(IROLinear *nd) {
+ int changed = 0;
+ IROLinear *left;
+ IROLinear *right;
+
+ if (nd->type == IROLinearOp2Arg) {
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+
+ if (
+ (left->type == IROLinearOp2Arg && (IS_TYPE_FLOAT(left->u.diadic.left->rtype) || IS_TYPE_FLOAT(left->u.diadic.right->rtype))) ||
+ (right->type == IROLinearOp2Arg && (IS_TYPE_FLOAT(right->u.diadic.left->rtype) || IS_TYPE_FLOAT(right->u.diadic.right->rtype)))
+ )
+ return;
+
+ switch (left->nodetype) {
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ case ENOTEQU:
+ switch (nd->nodetype) {
+ case EEQU:
+ if (IRO_IsConstantOne(right)) {
+ ReplaceExprWithLeftChild(nd);
+ changed = 1;
+ } else if (IRO_IsConstantZero(right)) {
+ left->nodetype = ComplementaryOpLogical[left->nodetype];
+ ReplaceExprWithLeftChild(nd);
+ changed = 1;
+ }
+ break;
+ case ENOTEQU:
+ if (IRO_IsConstantOne(right)) {
+ left->nodetype = ComplementaryOpLogical[left->nodetype];
+ ReplaceExprWithLeftChild(nd);
+ changed = 1;
+ } else if (IRO_IsConstantZero(right)) {
+ ReplaceExprWithLeftChild(nd);
+ changed = 1;
+ }
+ break;
+ }
+ break;
+ case ELAND:
+ case ELOR:
+ switch (nd->nodetype) {
+ case EEQU:
+ if (IRO_IsConstantOne(right)) {
+ ReplaceExprWithLeftChild(nd);
+ changed = 1;
+ }
+ break;
+ case ENOTEQU:
+ if (IRO_IsConstantZero(right)) {
+ ReplaceExprWithLeftChild(nd);
+ changed = 1;
+ }
+ break;
+ }
+ break;
+ }
+
+ if (!changed) {
+ switch (right->nodetype) {
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ case ENOTEQU:
+ switch (nd->nodetype) {
+ case EEQU:
+ if (IRO_IsConstantOne(left)) {
+ ReplaceExprWithRightChild(nd);
+ } else if (IRO_IsConstantZero(left)) {
+ right->nodetype = ComplementaryOpLogical[right->nodetype];
+ ReplaceExprWithRightChild(nd);
+ }
+ break;
+ case ENOTEQU:
+ if (IRO_IsConstantOne(left)) {
+ right->nodetype = ComplementaryOpLogical[right->nodetype];
+ ReplaceExprWithRightChild(nd);
+ } else if (IRO_IsConstantZero(left)) {
+ ReplaceExprWithRightChild(nd);
+ }
+ break;
+ }
+ break;
+ case ELAND:
+ case ELOR:
+ switch (nd->nodetype) {
+ case EEQU:
+ if (IRO_IsConstantOne(left)) {
+ ReplaceExprWithRightChild(nd);
+ }
+ break;
+ case ENOTEQU:
+ if (IRO_IsConstantZero(left)) {
+ ReplaceExprWithRightChild(nd);
+ }
+ break;
+ }
+ break;
+ }
+ }
+ }
+}
+
+static Boolean isOrderingOperator(ENodeType op) {
+ switch (op) {
+ case ELAND:
+ case ELOR:
+ case ECOMMA:
+ case ECOND:
+ case ECONDASS:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static void RemoveUnreffed(IROLinear *nd) {
+ if (!(nd->flags & IROLF_Reffed)) {
+ switch (nd->type) {
+ case IROLinearOperand:
+ IRO_NopNonSideEffects(nd, 0);
+ break;
+ case IROLinearOp1Arg:
+ case IROLinearOp2Arg:
+ case IROLinearOp3Arg:
+ case IROLinearFunccall:
+ if (!isOrderingOperator(nd->nodetype))
+ IRO_NopNonSideEffects(nd, 0);
+ break;
+ }
+ }
+}
+
+static void RemoveRedundantMonadicOp(IROLinear *nd) {
+ IROLinear *nd2;
+ IROLinear *nd3;
+
+ if (nd->type == IROLinearOp1Arg && (nd2 = IRO_LocateFather(nd)) && nd2->nodetype == nd->nodetype) {
+ switch (nd->nodetype) {
+ case ELOGNOT:
+ if ((nd3 = IRO_LocateFather(nd2))) {
+ if (
+ nd3->rtype &&
+ TYPE_INTEGRAL(nd3->rtype)->integral == IT_BOOL &&
+ nd->u.monadic->rtype &&
+ TYPE_INTEGRAL(nd->u.monadic->rtype)->integral == IT_BOOL
+ )
+ goto remove;
+
+ if (nd3->type == IROLinearIf)
+ goto remove;
+ if (nd3->type == IROLinearIfNot)
+ goto remove;
+ if (nd3->type == IROLinearOp3Arg && nd == nd3->u.args3.a)
+ goto remove;
+
+ switch (nd3->nodetype) {
+ case ELOGNOT:
+ case ELAND:
+ case ELOR:
+ goto remove;
+ }
+ }
+
+ if (nd->u.monadic->type == IROLinearOp1Arg || nd->u.monadic->type == IROLinearOp2Arg) {
+ switch (nd->u.monadic->nodetype) {
+ case ELOGNOT:
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ case ENOTEQU:
+ case ELAND:
+ case ELOR:
+ goto remove;
+ }
+ }
+ break;
+
+ case EMONMIN:
+ case EBINNOT:
+ remove:
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd2, nd->u.monadic);
+ nd2->type = IROLinearNop;
+ nd->type = IROLinearNop;
+ break;
+
+ case ETYPCON:
+ if (TYPE_INTEGRAL(nd->rtype)->integral == IT_FLOAT) {
+ switch (TYPE_INTEGRAL(nd2->rtype)->integral) {
+ case IT_DOUBLE:
+ case IT_LONGDOUBLE:
+ switch (TYPE_INTEGRAL(nd->u.monadic->rtype)->integral) {
+ case IT_BOOL:
+ case IT_CHAR:
+ case IT_SCHAR:
+ case IT_UCHAR:
+ case IT_SHORT:
+ case IT_USHORT:
+ nd->type = IROLinearNop;
+ nd2->u.monadic = nd->u.monadic;
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+}
+
+static void ReverseOpForMonmin(IROLinear *nd) {
+ IROLinear *father;
+
+ if (
+ nd->type == IROLinearOp1Arg &&
+ nd->nodetype == EMONMIN &&
+ (father = IRO_LocateFather(nd)) &&
+ father->type == IROLinearOp2Arg &&
+ father->u.diadic.right == nd
+ )
+ {
+ switch (father->nodetype) {
+ case EADDV:
+ case ESUBV:
+ case EADD:
+ case ESUB:
+ case EADDASS:
+ case ESUBASS:
+ father->nodetype = ComplementaryOp[father->nodetype];
+ nd->type = IROLinearNop;
+ father->u.diadic.right = nd->u.monadic;
+ break;
+ }
+ }
+}
+
+static void DoDiadic(IROLinear *nd) {
+ RemoveUnreffed(nd);
+ DoTransformations(nd);
+ DoTransformations11(nd);
+ DoTransformations12(nd);
+ DoTransformations13(nd);
+ DoTransformations21(nd);
+ DoTransformations22(nd);
+ DoTransformations23(nd);
+ DoTransformations24(nd);
+ DoTransformations25(nd);
+}
+
+void IRO_DoTransformations(void) {
+ IROLinear *nd;
+
+ for (nd = IRO_FirstLinear; nd; nd = nd->next) {
+ switch (nd->type) {
+ case IROLinearOp2Arg:
+ DoDiadic(nd);
+ break;
+ case IROLinearOp1Arg:
+ RemoveUnreffed(nd);
+ RemoveRedundantMonadicOp(nd);
+ ReverseOpForMonmin(nd);
+ break;
+ case IROLinearOperand:
+ RemoveUnreffed(nd);
+ break;
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+static Boolean ReconcileAssignments(IROLinear *nd1, IROLinear *nd2, IROList *list) {
+ IROLinear *copy;
+ Boolean result = 0;
+ int argCount;
+ int i;
+ IROLinear *tmp;
+
+ if (
+ (nd2->type == IROLinearOp1Arg && nd2->nodetype == ETYPCON) &&
+ !(nd1->type == IROLinearOp1Arg && nd1->nodetype == ETYPCON) &&
+ ReconcileAssignments(nd1, nd2->u.monadic, list)
+ )
+ {
+ result = 1;
+ }
+
+ if (
+ (nd1->type == IROLinearOp1Arg && nd1->nodetype == ETYPCON) &&
+ !(nd2->type == IROLinearOp1Arg && nd2->nodetype == ETYPCON) &&
+ ReconcileAssignments(nd1->u.monadic, nd2, list)
+ )
+ {
+ copy = IRO_NewLinear(IROLinearOp1Arg);
+ *copy = *nd2;
+ copy->index = IRO_NumLinear++;
+ copy->type = IROLinearOp1Arg;
+ copy->nodetype = ETYPCON;
+ copy->rtype = nd1->rtype;
+ copy->next = NULL;
+ copy->u.monadic = list->tail;
+ IRO_AddToList(copy, list);
+ result = 1;
+ }
+
+ if (nd1->type == nd2->type && nd1->nodetype == nd2->nodetype) {
+ copy = IRO_NewLinear(IROLinearNop);
+ *copy = *nd2;
+ copy->index = IRO_NumLinear++;
+ copy->rtype = nd1->rtype;
+ copy->next = NULL;
+ switch (nd1->type) {
+ case IROLinearOperand:
+ if (nd1->u.node->type == nd2->u.node->type) {
+ if (!(nd1->u.node->type == EOBJREF && nd1->u.node->data.objref != nd2->u.node->data.objref))
+ result = 1;
+ }
+ break;
+
+ case IROLinearOp1Arg:
+ if (ReconcileAssignments(nd1->u.monadic, nd2->u.monadic, list)) {
+ copy->u.monadic = list->tail;
+ result = 1;
+ }
+ break;
+
+ case IROLinearOp2Arg:
+ tmp = list->tail;
+ if (ReconcileAssignments(nd1->u.diadic.left, nd2->u.diadic.left, list)) {
+ copy->u.diadic.left = list->tail;
+ if (ReconcileAssignments(nd1->u.diadic.right, nd2->u.diadic.right, list)) {
+ copy->u.diadic.right = list->tail;
+ result = 1;
+ }
+ }
+
+ if (!result && !IRO_HasSideEffect(nd1) && !IRO_HasSideEffect(nd2)) {
+ if (nd1->nodetype == EMUL || nd1->nodetype == EADD || nd1->nodetype == EAND || nd1->nodetype == EXOR || nd1->nodetype == EOR) {
+ list->tail = tmp;
+ if (ReconcileAssignments(nd1->u.diadic.left, nd2->u.diadic.right, list)) {
+ copy->u.diadic.right = list->tail;
+ if (ReconcileAssignments(nd1->u.diadic.right, nd2->u.diadic.left, list)) {
+ copy->u.diadic.left = list->tail;
+ result = 1;
+ }
+ }
+ }
+ }
+ break;
+
+ case IROLinearOp3Arg:
+ if (ReconcileAssignments(nd1->u.args3.c, nd2->u.args3.c, list)) {
+ copy->u.args3.c = list->tail;
+ if (ReconcileAssignments(nd1->u.args3.b, nd2->u.args3.b, list)) {
+ copy->u.args3.b = list->tail;
+ if (ReconcileAssignments(nd1->u.args3.a, nd2->u.args3.a, list)) {
+ copy->u.args3.a = list->tail;
+ result = 1;
+ }
+ }
+ }
+ break;
+
+ case IROLinearFunccall:
+ argCount = nd1->u.funccall.argCount;
+ if (argCount == nd2->u.funccall.argCount) {
+ result = 1;
+ copy->u.funccall.args = oalloc(sizeof(IROLinear *) * argCount);
+ for (i = argCount - 1; i >= 0; i--) {
+ if (!ReconcileAssignments(nd1->u.funccall.args[i], nd2->u.funccall.args[i], list)) {
+ result = 0;
+ break;
+ }
+ copy->u.funccall.args[i] = list->tail;
+ }
+
+ if (result) {
+ if (!ReconcileAssignments(nd1->u.funccall.linear8, nd2->u.funccall.linear8, list)) {
+ result = 0;
+ break;
+ }
+ copy->u.funccall.linear8 = list->tail;
+ }
+ }
+ break;
+ }
+
+ if (result)
+ IRO_AddToList(copy, list);
+ }
+
+ return result;
+}
+
+static IROLinear *FrontendTransformSelfAssignmentToAssignment(IROLinear *nd) {
+ Statement *stmt;
+ IROList list;
+ IROLinearIRSave save;
+
+ IRO_SaveLinearIR(&save);
+
+ IRO_InitList(&list);
+ IRO_DuplicateExpr(nd, &list);
+
+ stmt = IRO_Delinearize(NULL, list.head);
+ CError_ASSERT(3550, stmt);
+ CError_ASSERT(3552, stmt->expr);
+ stmt->expr = CIRTrans_TransformOpAss(stmt->expr);
+ CError_ASSERT(3557, stmt->expr);
+
+ if (DoLinearize)
+ IRO_PreLinearize(stmt);
+ IRO_Linearize(stmt);
+
+ IRO_InitList(&list);
+ list.head = IRO_FirstLinear;
+ list.tail = IRO_LastLinear;
+
+ IRO_RestoreLinearIR(&save);
+
+ for (nd = list.head; nd; nd = nd->next) {
+ if (!(nd->flags & IROLF_Reffed) && IRO_IsAssignment(nd))
+ break;
+ }
+
+ return nd;
+}
+
+static Type *PromotedIntegralType(Type *type) {
+ CError_ASSERT(3586, IS_TYPE_ENUM(type) || IS_TYPE_INT(type));
+
+ if (IS_TYPE_ENUM(type))
+ type = TYPE_ENUM(type)->enumtype;
+
+ if (TYPE_INTEGRAL(type)->integral < IT_INT) {
+ if (IRO_IsUnsignedType(type))
+ return TYPE(&stunsignedint);
+ else
+ return TYPE(&stsignedint);
+ } else {
+ return type;
+ }
+}
+
+static Boolean TransformMonadicSelfAssignmentToDiadicSelfAssignment(IROLinear *nd) {
+ ENodeType t;
+ ENodeType newtype;
+ IROLinear *incExpr;
+ IROLinear *varExpr;
+
+ t = nd->nodetype;
+
+ if (IRO_IsAssignment(nd) && IRO_IsModifyOp[t]) {
+ incExpr = NULL;
+ varExpr = NULL;
+ newtype = MAXEXPR;
+
+ if (
+ nd->type == IROLinearOp1Arg &&
+ (t == EPOSTINC || t == EPOSTDEC || t == EPREINC || t == EPREDEC) &&
+ (!(nd->flags & IROLF_Reffed) || t == EPREINC || t == EPREDEC)
+ )
+ {
+ Type *type = nd->rtype;
+ TypeType typetype = type->type;
+ varExpr = nd->u.monadic;
+ if (typetype == TYPEINT || typetype == TYPEENUM) {
+ incExpr = IRO_NewIntConst(cint64_one, PromotedIntegralType(type));
+ } else if (typetype == TYPEPOINTER || typetype == TYPEARRAY || typetype == TYPEMEMBERPOINTER) {
+ Type *inner = NULL;
+ CInt64 val = cint64_zero;
+
+ if (typetype == TYPEPOINTER || typetype == TYPEARRAY)
+ inner = TPTR_TARGET(type);
+ else if (typetype == TYPEMEMBERPOINTER)
+ inner = TYPE_MEMBER_POINTER(type)->ty1;
+
+ if (inner)
+ CInt64_SetLong(&val, inner->size);
+
+ if (!CInt64_IsZero(&val)) {
+ incExpr = IRO_NewIntConst(val, TYPE(&stsignedlong));
+ } else {
+ return 0;
+ }
+ } else if (typetype == TYPEFLOAT) {
+ Float fval;
+ fval = CMach_CalcFloatConvertFromInt(type, cint64_one);
+ incExpr = IRO_NewFloatConst(fval, nd->rtype);
+ } else {
+ return 0;
+ }
+
+ if (t == EPOSTINC || t == EPREINC)
+ newtype = EADDASS;
+ else
+ newtype = ESUBASS;
+ }
+
+ if (
+ varExpr &&
+ incExpr &&
+ newtype != MAXEXPR &&
+ varExpr->u.diadic.left &&
+ varExpr->u.diadic.left->type == IROLinearOperand &&
+ varExpr->u.diadic.left->u.node &&
+ varExpr->u.diadic.left->u.node->type == EOBJREF &&
+ !IRO_HasSideEffect(varExpr)
+ )
+ {
+ incExpr->flags |= IROLF_Reffed;
+ nd->nodetype = newtype;
+ nd->u.diadic.right = incExpr;
+ nd->type = IROLinearOp2Arg;
+ IRO_Paste(incExpr, incExpr, nd);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+Boolean IRO_TransformSelfAssignmentToAssignment(IROLinear *nd) {
+ ENodeType nonAssOp;
+ IROLinear *left;
+ IROLinear *right;
+ ENodeType nodetype;
+ IROLinear *nonAss;
+ IROLinear *dupLeft;
+ IROLinear *last;
+ IROList list1;
+ IROList list2;
+
+ nodetype = nd->nodetype;
+ if (
+ IRO_IsAssignment(nd) &&
+ IRO_IsModifyOp[nodetype] &&
+ nd->type == IROLinearOp1Arg &&
+ TransformMonadicSelfAssignmentToDiadicSelfAssignment(nd)
+ )
+ nodetype = nd->nodetype;
+
+ if (
+ IRO_IsAssignment(nd) &&
+ IRO_IsModifyOp[nodetype] &&
+ nd->type == IROLinearOp2Arg &&
+ IRO_NonAssignmentOp[nodetype] != MAXEXPR
+ )
+ {
+ left = nd->u.diadic.left;
+ right = nd->u.diadic.right;
+ nonAssOp = IRO_NonAssignmentOp[nodetype];
+ if (
+ left &&
+ right &&
+ nonAssOp != MAXEXPR &&
+ left->u.monadic &&
+ left->u.monadic->type == IROLinearOperand &&
+ left->u.monadic->u.node &&
+ left->u.monadic->u.node->type == EOBJREF &&
+ !IRO_HasSideEffect(left)
+ )
+ {
+ IRO_InitList(&list1);
+ dupLeft = IRO_DuplicateExpr(left, &list1);
+
+ if (left->rtype != right->rtype) {
+ IROLinear *tmp = IRO_NewLinear(IROLinearOp1Arg);
+ tmp->nodetype = ETYPCON;
+ tmp->flags |= IROLF_Reffed;
+ tmp->rtype = right->rtype;
+ tmp->index = ++IRO_NumLinear;
+ tmp->u.monadic = dupLeft;
+ IRO_AddToList(tmp, &list1);
+ dupLeft = tmp;
+ }
+
+ nonAss = IRO_NewLinear(IROLinearOp2Arg);
+ nonAss->nodetype = nonAssOp;
+ nonAss->flags |= IROLF_Reffed;
+ nonAss->rtype = dupLeft->rtype;
+ nonAss->index = ++IRO_NumLinear;
+ nonAss->u.diadic.left = dupLeft;
+ nonAss->u.diadic.right = right;
+ IRO_AddToList(nonAss, &list1);
+
+ if (left->rtype != right->rtype) {
+ IROLinear *tmp = IRO_NewLinear(IROLinearOp1Arg);
+ tmp->nodetype = ETYPCON;
+ tmp->flags |= IROLF_Reffed;
+ tmp->rtype = left->rtype;
+ tmp->index = ++IRO_NumLinear;
+ tmp->u.monadic = nonAss;
+ IRO_AddToList(tmp, &list1);
+ nonAss = tmp;
+ }
+
+ IRO_InitList(&list2);
+ last = FrontendTransformSelfAssignmentToAssignment(nd);
+ if (
+ last &&
+ last->type == IROLinearOp2Arg &&
+ ReconcileAssignments(last->u.diadic.right, nonAss, &list2)
+ )
+ {
+ IRO_NopOut(nd->u.diadic.right);
+ nd->nodetype = EASS;
+ nd->u.diadic.right = list2.tail;
+ nd->type = IROLinearOp2Arg;
+ IRO_Paste(list2.head, list2.tail, nd);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void AddAddend(ENode *expr) {
+ if (expr->type == EADD) {
+ AddAddend(expr->data.diadic.left);
+ AddAddend(expr->data.diadic.right);
+ } else {
+ ENodeList *list = oalloc(sizeof(ENodeList));
+ list->node = expr;
+ list->next = NULL;
+
+ if (FirstAddend)
+ LastAddend->next = list;
+ else
+ FirstAddend = list;
+ LastAddend = list;
+ }
+}
+
+static ENode *CombineConstants(ENode *expr) {
+ ENode *addend;
+ ENodeList *el;
+ ENode *result;
+ ENode *var;
+ Type *type;
+ ENode *tmp;
+ ENodeList *prev;
+ CInt64 val;
+
+ FirstAddend = LastAddend = NULL;
+ AddAddend(expr->data.diadic.left);
+ AddAddend(expr->data.diadic.right);
+
+ // these variable names are courtesy of the resource fork in abort_exit.c
+ el = FirstAddend;
+ prev = NULL;
+ var = NULL;
+ while (el) {
+ addend = el->node;
+ if (addend->type == EOBJREF) {
+ var = addend;
+ if (prev)
+ prev->next = el->next;
+ else
+ FirstAddend = el->next;
+ break;
+ }
+ prev = el;
+ el = el->next;
+ }
+
+ if (!var) {
+ el = FirstAddend;
+ prev = NULL;
+ while (el) {
+ addend = el->node;
+ if (addend->type == EINDIRECT) {
+ var = addend;
+ if (prev)
+ prev->next = el->next;
+ else
+ FirstAddend = el->next;
+ break;
+ }
+ prev = el;
+ el = el->next;
+ }
+ }
+
+ prev = NULL;
+ CInt64_SetLong(&val, 0);
+ type = NULL;
+
+ for (el = FirstAddend; el; el = el->next) {
+ addend = el->node;
+ if (addend->type == EINTCONST && addend->rtype) {
+ if (!type || type->size < addend->rtype->size)
+ type = addend->rtype;
+ val = CInt64_Add(val, addend->data.intval);
+ if (prev)
+ prev->next = el->next;
+ else
+ FirstAddend = el->next;
+ } else if (addend->type == EMUL && addend->data.diadic.right->type == EINTCONST && addend->rtype) {
+ if (!type || type->size < addend->rtype->size)
+ type = addend->rtype;
+
+ tmp = addend->data.diadic.left;
+ if (tmp->type == EADD && tmp->data.diadic.right->type == EINTCONST) {
+ val = CInt64_Add(val, CInt64_MulU(tmp->data.diadic.right->data.intval, addend->data.diadic.right->data.intval));
+ addend->data.diadic.left = tmp->data.diadic.left;
+ }
+ prev = el;
+ } else {
+ prev = el;
+ }
+ }
+
+ result = NULL;
+ if (var) {
+ result = var;
+ if (!CInt64_IsZero(&val)) {
+ result = IRO_NewENode(EADD);
+ result->data.diadic.left = var;
+ result->data.diadic.right = IRO_NewENode(EINTCONST);
+ result->data.diadic.right->data.intval = val;
+ result->data.diadic.right->rtype = type;
+ result->rtype = var->rtype;
+ result->cost = 1;
+ CInt64_SetLong(&val, 0);
+ }
+ }
+
+ for (el = FirstAddend; el; el = el->next) {
+ addend = el->node;
+ if (result) {
+ tmp = IRO_NewENode(EADD);
+ tmp->data.diadic.left = result;
+ tmp->data.diadic.right = addend;
+ tmp->cost = result->cost + 1;
+ tmp->rtype = result->rtype;
+ result = tmp;
+ } else {
+ result = addend;
+ }
+ }
+
+ if (!CInt64_IsZero(&val)) {
+ tmp = IRO_NewENode(EADD);
+ tmp->data.diadic.left = result;
+ tmp->data.diadic.right = IRO_NewENode(EINTCONST);
+ tmp->data.diadic.right->data.intval = val;
+ tmp->data.diadic.right->rtype = type;
+ tmp->cost = result->cost + 1;
+ tmp->rtype = result->rtype;
+ result = tmp;
+ }
+
+ return result;
+}
+
+static ENode *TransformExprNode(ENode *expr) {
+ ENode *left;
+ ENode *right;
+
+ switch (expr->type) {
+ case EINDIRECT:
+ if (ENODE_IS(expr->data.monadic, EADD))
+ expr->data.monadic = CombineConstants(expr->data.monadic);
+ break;
+
+ case EMUL:
+ case EADD:
+ case EAND:
+ case EXOR:
+ case EOR:
+ if (
+ IS_TYPE_INT(expr->rtype) &&
+ !ENODE_IS(right = expr->data.diadic.right, EINTCONST) &&
+ ENODE_IS(left = expr->data.diadic.left, EINTCONST)
+ )
+ {
+ expr->data.diadic.left = right;
+ expr->data.diadic.right = left;
+ }
+ break;
+
+ case EEQU:
+ case ENOTEQU:
+ if (
+ IS_TYPE_INT(expr->rtype) &&
+ !ENODE_IS(left = expr->data.diadic.right, EINTCONST) &&
+ ENODE_IS(right = expr->data.diadic.left, EINTCONST)
+ )
+ {
+ expr->data.diadic.left = left;
+ expr->data.diadic.right = right;
+ }
+
+ if (
+ ENODE_IS(expr->data.diadic.right, EINTCONST) &&
+ ENODE_IS(left = expr->data.diadic.left, EBINNOT)
+ )
+ {
+ expr->data.diadic.left = left->data.monadic;
+ left->data.monadic = expr->data.diadic.right;
+ expr->data.diadic.right = left;
+ }
+
+ break;
+ }
+
+ return expr;
+}
+
+static ENode *TransformExprTree(ENode *expr) {
+ ENodeList *list;
+
+ switch (expr->type) {
+ ENODE_CASE_MONADIC:
+ expr->data.monadic = TransformExprTree(expr->data.monadic);
+ break;
+
+ ENODE_CASE_DIADIC_ALL:
+ expr->data.diadic.left = TransformExprTree(expr->data.diadic.left);
+ expr->data.diadic.right = TransformExprTree(expr->data.diadic.right);
+ break;
+
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ TransformExprTree(expr->data.funccall.funcref);
+ for (list = expr->data.funccall.args; list; list = list->next)
+ TransformExprTree(list->node);
+ break;
+
+ case ECOND:
+ TransformExprTree(expr->data.cond.cond);
+ TransformExprTree(expr->data.cond.expr1);
+ TransformExprTree(expr->data.cond.expr2);
+ break;
+
+ case ENULLCHECK:
+ TransformExprTree(expr->data.nullcheck.nullcheckexpr);
+ TransformExprTree(expr->data.nullcheck.condexpr);
+ break;
+ }
+
+ return TransformExprNode(expr);
+}
+
+static void FoldConstantsinAssociativeExprs(ENode *expr) {
+ short nodetype1;
+ short nodetype2;
+ short nodetype3;
+ Boolean changed;
+ short op;
+ CInt64 val1;
+ CInt64 val2;
+ CInt64 tmpval;
+
+ if (
+ (
+ expr->type == EADD ||
+ expr->type == EMUL ||
+ expr->type == EAND ||
+ expr->type == EXOR ||
+ expr->type == EOR ||
+ expr->type == ESHL ||
+ expr->type == ESHR
+ ) &&
+ IS_TYPE_INT(expr->rtype) &&
+ expr->data.diadic.right->type == EINTCONST
+ )
+ {
+ do {
+ changed = 0;
+
+ if (
+ expr->data.diadic.left->type == expr->type &&
+ expr->data.diadic.left->data.diadic.right->type == EINTCONST
+ )
+ {
+ val1 = expr->data.diadic.right->data.intval;
+ val2 = expr->data.diadic.left->data.diadic.right->data.intval;
+ switch (expr->type) {
+ case EADD:
+ case ESHL:
+ op = '+';
+ break;
+ case ESHR:
+ op = '+';
+ if (!IRO_IsUnsignedType(expr->rtype)) {
+ CInt64_SetLong(&tmpval, expr->rtype->size * 8);
+ if (CInt64_GreaterEqualU(val1, tmpval) || CInt64_GreaterEqualU(val2, tmpval))
+ return;
+
+ if (CInt64_GreaterEqualU(CMach_CalcIntDiadic(expr->rtype, val1, '+', val2), tmpval)) {
+ val1 = CInt64_Sub(tmpval, cint64_one);
+ val2 = cint64_zero;
+ }
+ }
+ break;
+ case EMUL:
+ op = '*';
+ break;
+ case EAND:
+ op = '&';
+ break;
+ case EOR:
+ op = '|';
+ break;
+ case EXOR:
+ op = '^';
+ break;
+ default:
+ return;
+ }
+
+ expr->data.diadic.right->data.intval = CMach_CalcIntDiadic(expr->rtype, val1, op, val2);
+ expr->data.diadic.left = expr->data.diadic.left->data.diadic.left;
+ changed = 1;
+ } else if (
+ ((nodetype1 = expr->type) == EAND || nodetype1 == EOR) &&
+ ((nodetype2 = expr->data.diadic.left->type) == EAND || nodetype2 == EOR) &&
+ ((nodetype3 = expr->data.diadic.left->data.diadic.left->type) == EAND || nodetype3 == EOR) &&
+ expr->data.diadic.left->data.diadic.left->data.diadic.right->type == EINTCONST
+ )
+ {
+ val1 = expr->data.diadic.right->data.intval;
+ if (CInt64_Equal(val1, expr->data.diadic.left->data.diadic.left->data.diadic.right->data.intval)) {
+ if (nodetype1 == nodetype3) {
+ expr->data.diadic.left->data.diadic.left = expr->data.diadic.left->data.diadic.left->data.diadic.left;
+ changed = 1;
+ } else if (nodetype2 == nodetype3) {
+ *expr = *expr->data.diadic.right;
+ changed = 1;
+ } else {
+ expr->data.diadic.left = expr->data.diadic.left->data.diadic.right;
+ changed = 1;
+ }
+ }
+ }
+ } while (changed);
+ }
+}
+
+static void TransformExprTree1(ENode *expr) {
+ ENodeList *list;
+
+ switch (expr->type) {
+ ENODE_CASE_MONADIC:
+ TransformExprTree1(expr->data.monadic);
+ break;
+
+ ENODE_CASE_DIADIC_ALL:
+ TransformExprTree1(expr->data.diadic.left);
+ TransformExprTree1(expr->data.diadic.right);
+ break;
+
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ TransformExprTree1(expr->data.funccall.funcref);
+ for (list = expr->data.funccall.args; list; list = list->next)
+ TransformExprTree1(list->node);
+ break;
+
+ case ECOND:
+ TransformExprTree1(expr->data.cond.cond);
+ TransformExprTree1(expr->data.cond.expr1);
+ TransformExprTree1(expr->data.cond.expr2);
+ break;
+
+ case ENULLCHECK:
+ TransformExprTree1(expr->data.nullcheck.nullcheckexpr);
+ TransformExprTree1(expr->data.nullcheck.condexpr);
+ break;
+ }
+
+ FoldConstantsinAssociativeExprs(expr);
+}
+
+static int RemoveRedundantBitOperations(ENode *expr) {
+ Boolean a;
+ Boolean b;
+
+ if (expr->type == ExprType) {
+ a = RemoveRedundantBitOperations(expr->data.diadic.left);
+ b = RemoveRedundantBitOperations(expr->data.diadic.right);
+ return a & b;
+ }
+
+ if (expr->type == EINDIRECT) {
+ if (expr->data.monadic->type == EOBJREF) {
+ if (!OperandObject) {
+ OperandObject = expr->data.monadic->data.objref;
+ IndirectRef = expr;
+ return 1;
+ } else {
+ return expr->data.monadic->data.objref == OperandObject;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ if (expr->type == EINTCONST) {
+ if (FirstTime) {
+ OperandConst = expr->data.intval;
+ FirstTime = 0;
+ } else if (ExprType == EAND) {
+ OperandConst = CInt64_And(expr->data.intval, OperandConst);
+ } else if (ExprType == EOR) {
+ OperandConst = CInt64_Or(expr->data.intval, OperandConst);
+ } else if (ExprType == EXOR) {
+ OperandConst = CInt64_Xor(expr->data.intval, OperandConst);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+static void TransformExprTree2(ENode *expr) {
+ ENodeList *list;
+
+ switch (expr->type) {
+ ENODE_CASE_MONADIC:
+ TransformExprTree2(expr->data.monadic);
+ break;
+
+ ENODE_CASE_DIADIC_ALL:
+ TransformExprTree2(expr->data.diadic.left);
+ TransformExprTree2(expr->data.diadic.right);
+ break;
+
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ TransformExprTree2(expr->data.funccall.funcref);
+ for (list = expr->data.funccall.args; list; list = list->next)
+ TransformExprTree2(list->node);
+ break;
+
+ case ECOND:
+ TransformExprTree2(expr->data.cond.cond);
+ TransformExprTree2(expr->data.cond.expr1);
+ TransformExprTree2(expr->data.cond.expr2);
+ break;
+
+ case ENULLCHECK:
+ TransformExprTree2(expr->data.nullcheck.nullcheckexpr);
+ TransformExprTree2(expr->data.nullcheck.condexpr);
+ break;
+ }
+
+ if (
+ ENODE_IS3(expr, EAND, EOR, EXOR) &&
+ (expr->type == expr->data.diadic.left->type || expr->type == expr->data.diadic.right->type)
+ )
+ {
+ OperandObject = NULL;
+ ExprType = expr->type;
+ FirstTime = 1;
+ IndirectRef = NULL;
+
+ if (RemoveRedundantBitOperations(expr)) {
+ expr->data.diadic.left = IndirectRef;
+ expr->data.diadic.right->type = EINTCONST;
+ expr->data.diadic.right->data.intval = OperandConst;
+ }
+ }
+}
+
+static void PullOutPostOps(Statement *stmt, ENode **pExpr) {
+ ENode *ind;
+ ENode *inner;
+ Statement *newStmt;
+
+ switch ((*pExpr)->type) {
+ ENODE_CASE_MONADIC:
+ if ((*pExpr)->type != EFORCELOAD)
+ PullOutPostOps(stmt, &(*pExpr)->data.monadic);
+
+ if (ENODE_IS2(*pExpr, EPOSTINC, EPOSTDEC)) {
+ inner = (*pExpr)->data.monadic;
+ if (
+ ENODE_IS(inner, EINDIRECT) &&
+ inner->rtype &&
+ !CParser_IsVolatile(inner->rtype, ENODE_QUALS(inner)) &&
+ ENODE_IS(inner->data.monadic, EOBJREF) &&
+ !is_volatile_object(inner->data.monadic->data.objref)
+ )
+ {
+ newStmt = lalloc(sizeof(Statement));
+ memset(newStmt, 0, sizeof(Statement));
+ newStmt->type = ST_EXPRESSION;
+ newStmt->expr = *pExpr;
+ newStmt->dobjstack = stmt->dobjstack;
+ newStmt->sourceoffset = stmt->sourceoffset;
+ newStmt->sourcefilepath = stmt->sourcefilepath;
+ newStmt->value = stmt->value;
+ newStmt->flags = stmt->flags;
+ newStmt->next = stmt->next;
+ stmt->next = newStmt;
+
+ ind = IRO_NewENode(EINDIRECT);
+ *ind = *inner;
+ ind->data.monadic = IRO_NewENode(EOBJREF);
+ *ind->data.monadic = *inner->data.monadic;
+ *pExpr = ind;
+ }
+ }
+ break;
+
+ ENODE_CASE_DIADIC_ALL:
+ if (ENODE_IS(*pExpr, ECOND))
+ break;
+ if (ENODE_IS(*pExpr, ECOMMA))
+ break;
+ if (ENODE_IS(*pExpr, ELOR))
+ break;
+ if (ENODE_IS(*pExpr, ELAND))
+ break;
+ if (ENODE_IS(*pExpr, ENULLCHECK))
+ break;
+ PullOutPostOps(stmt, &(*pExpr)->data.diadic.left);
+ PullOutPostOps(stmt, &(*pExpr)->data.diadic.right);
+ break;
+ }
+}
+
+void IRO_TransformTree(Statement *statements) {
+ Statement *stmt;
+ Statement *next;
+
+ for (stmt = statements; stmt; stmt = next) {
+ next = stmt->next;
+ switch (stmt->type) {
+ case ST_EXPRESSION:
+ case ST_SWITCH:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ case ST_RETURN:
+ if (stmt->expr) {
+ stmt->expr = TransformExprTree(stmt->expr);
+ TransformExprTree2(stmt->expr);
+ TransformExprTree1(stmt->expr);
+ }
+ break;
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroTransform.h b/compiler_and_linker/FrontEnd/Optimizer/IroTransform.h
new file mode 100644
index 0000000..104657f
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroTransform.h
@@ -0,0 +1,13 @@
+#ifndef COMPILER_IROTRANSFORM_H
+#define COMPILER_IROTRANSFORM_H
+
+#include "IrOptimizer.h"
+
+extern void IRO_InitializeAssignmentOpArray(void);
+extern void IRO_InitializeComplementaryOpArray(void);
+extern void IRO_InitializeComplementaryOpLogicalArray(void);
+extern void IRO_DoTransformations(void);
+extern Boolean IRO_TransformSelfAssignmentToAssignment(IROLinear *nd);
+extern void IRO_TransformTree(Statement *statements);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.c b/compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.c
new file mode 100644
index 0000000..cf3f1bf
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.c
@@ -0,0 +1,2305 @@
+#include "IroUnrollLoop.h"
+#include "compiler/CError.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroUtil.h"
+#include "compiler/LoopDetection.h"
+#include "IroLoop.h"
+#include "IroDump.h"
+#include "IroVars.h"
+#include "compiler/CFunc.h"
+#include "compiler/CMachine.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct LoopList {
+ UInt8 flags;
+ BitVector *bv;
+ struct LoopList *next;
+ IRONode *fnode;
+ int xE;
+} LoopList;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+// forward decls
+static void IRO_FindLoops_Unroll(void);
+static void LoopUnroll(int count, IRONode *fnode);
+static int IsLoopUnrollable(IROLoop *loop);
+static int IsDifferenceOfTermsConstant(IROAddrRecord *lowerRec, IROAddrRecord *upperRec, int isUnsigned, CInt64 *pval);
+static IROLinear *BuildOrigIterationCount_DoWhile(IROList *list, IROLoop *loop);
+static IROLinear *BuildPreAlignTemp(IROLoopInd *ind, UInt32 unrollFactor, IROList *list);
+static IROLinear *BuildNewFinalvalue_DoWhile(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop);
+static IROLinear *BuildUnrolledFinalvalue_DoWhile(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop);
+
+void IRO_LoopUnroller(void) {
+ VectorPhaseCalledFromUnroll = 1;
+ IRO_FindLoops_Unroll();
+ IRO_CheckForUserBreak();
+}
+
+static void IRO_FindLoops_Unroll(void) {
+ IRONode *fnode;
+ IRONode *pred;
+ UInt16 i;
+ UInt16 flag;
+ LoopList *list;
+ LoopList *list2;
+
+ fnode = IRO_FirstNode;
+ LoopList_First = NULL;
+
+ while (fnode) {
+ flag = 0;
+ for (i = 0; i < fnode->numpred; i++) {
+ pred = IRO_NodeTable[fnode->pred[i]];
+ if (Bv_IsBitSet(fnode->index, pred->dom)) {
+ if (!flag) {
+ Bv_AllocVector(&InLoop, IRO_NumNodes + 1);
+ Bv_Clear(InLoop);
+ Bv_SetBit(fnode->index, InLoop);
+ }
+ flag = 1;
+ Bv_SetBit(pred->index, InLoop);
+ if (pred != fnode)
+ AddPreds(pred);
+ }
+ }
+
+ if (flag) {
+ if (!LoopList_First) {
+ list = oalloc(sizeof(LoopList));
+ list->next = NULL;
+ } else {
+ list = oalloc(sizeof(LoopList));
+ list->next = LoopList_First;
+ }
+ LoopList_First = list;
+
+ Bv_AllocVector(&list->bv, IRO_NumNodes + 1);
+ list->flags |= 1;
+ Bv_Copy(InLoop, list->bv);
+ list->fnode = fnode;
+ list->xE = 0;
+ }
+
+ fnode = fnode->nextnode;
+ }
+
+ list = LoopList_First;
+ Bv_AllocVector(&LoopTemp, IRO_NumNodes + 1);
+ while (list) {
+ for (list2 = LoopList_First; list2; list2 = list2->next) {
+ if (list2 != list) {
+ IRO_Dump(" header = %d \n", list2->fnode->index);
+ IRO_Dump(" l1 bit vector=\n");
+ IRO_DumpBits("", list2->bv);
+ IRO_Dump(" l bit vector=\n");
+ IRO_DumpBits("", list->bv);
+ if (Bv_IsSubset(list->bv, list2->bv))
+ list2->flags &= ~1;
+ }
+ }
+ list = list->next;
+ }
+
+ for (list = LoopList_First; list; list = list->next) {
+ if (list->flags & 1) {
+ IRONode *listfnode;
+ Bv_Copy(list->bv, InLoop);
+ listfnode = list->fnode;
+ IRO_Dump("IRO_FindLoops_Unroll:Found loop with header %d\n", listfnode->index);
+ IRO_DumpBits("Loop includes: ", InLoop);
+ LoopUnroll(copts.unrollfactor, listfnode);
+ IRO_UpdateFlagsOnInts();
+ }
+ }
+}
+
+static int CheckConstant(CInt64 a, CInt64 b, CInt64 *result) {
+ CInt64 shl = cint64_zero;
+ CInt64 work = cint64_zero;
+ CInt64 and = cint64_zero;
+ CInt64 i;
+
+ for (i = cint64_zero; CInt64_Less(i, a); i = CInt64_Add(i, cint64_one)) {
+ shl = CInt64_Shl(b, i);
+ and = CInt64_And(shl, work);
+ if (CInt64_NotEqual(and, cint64_zero))
+ return 0;
+ work = CInt64_Or(shl, work);
+ }
+
+ *result = work;
+ return 1;
+}
+
+typedef struct LoopPattern {
+ IROLinear *nd0;
+ IROLinear *nd4;
+ Type *type;
+ IROLinear *ndC;
+ IROLinear *nd10;
+ CInt64 val14;
+ CInt64 val1C;
+} LoopPattern;
+
+static void UnrollWhileLoopBody(IRONode *header, IRONode *fnode2, IRONode *fnode3, IROLoop *loop, LoopPattern *pattern, UInt32 unrollFactor) {
+ IRONode *scan;
+ int pass;
+ IROLinear *firstnode;
+ IROLinear *lastnd;
+ IROLinear *nd;
+ IROLinear *nd1;
+ IROLinear *nd2;
+ IROLinear *nd3;
+ IROLinear *nd4;
+ IROLinear *nd5;
+ IROLinear *nd6;
+ IROLinear *nd8;
+ IROLinear *nd7;
+ ENode *expr;
+ IROList list;
+ CInt64 zero;
+ CInt64 shiftval;
+
+ CInt64_SetLong(&zero, 0);
+
+ pass = 0;
+
+ do {
+ firstnode = NULL;
+ for (scan = fnode3; scan && scan != header; scan = scan->nextnode) {
+ IRO_InitList(&list);
+ lastnd = scan->last;
+ nd = scan->first;
+ while (1) {
+ if (nd->stmt)
+ nd->stmt->flags |= StmtFlag_10;
+
+ if (
+ (nd->index < loop->index20 || nd->index > loop->index24) &&
+ nd->type != IROLinearLabel &&
+ nd->type != IROLinearNop &&
+ !(nd->flags & IROLF_Reffed)
+ )
+ {
+ CError_ASSERT(345, nd->nodetype == EORASS || nd->nodetype == EANDASS || nd->nodetype == EXORASS);
+
+ IRO_DuplicateExpr(pattern->nd0, &list);
+ nd1 = list.tail;
+
+ shiftval = cint64_one;
+ shiftval = CInt64_Shl(shiftval, pattern->val1C);
+
+ nd2 = IRO_NewLinear(IROLinearOperand);
+ nd2->index = ++IRO_NumLinear;
+ nd2->rtype = pattern->nd0->rtype;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = pattern->nd0->rtype;
+ CInt64_SetLong(&expr->data.intval, pass * CInt64_GetULong(&shiftval));
+ nd2->u.node = expr;
+ IRO_AddToList(nd2, &list);
+
+ IRO_DuplicateExpr(pattern->nd4, &list);
+
+ nd3 = IRO_NewLinear(IROLinearOp2Arg);
+ nd3->index = ++IRO_NumLinear;
+ nd3->nodetype = EADD;
+ nd3->rtype = pattern->type;
+ nd3->u.diadic.left = list.tail;
+ nd3->u.diadic.right = nd2;
+ IRO_AddToList(nd3, &list);
+
+ nd4 = IRO_NewLinear(IROLinearOp2Arg);
+ nd4->index = ++IRO_NumLinear;
+ nd4->nodetype = EADD;
+ nd4->rtype = pattern->type;
+ nd4->u.diadic.left = nd3;
+ nd4->u.diadic.right = nd1;
+ IRO_AddToList(nd4, &list);
+
+ nd5 = IRO_NewLinear(IROLinearOp1Arg);
+ nd5->index = ++IRO_NumLinear;
+ nd5->nodetype = EINDIRECT;
+ nd5->rtype = nd->rtype;
+ nd5->u.monadic = nd4;
+ IRO_AddToList(nd5, &list);
+
+ nd6 = IRO_NewLinear(IROLinearOp2Arg);
+ *nd6 = *nd;
+ nd6->index = ++IRO_NumLinear;
+ nd6->u.diadic.left = list.tail;
+ nd6->next = NULL;
+
+ nd7 = IRO_NewLinear(IROLinearOperand);
+ nd7->index = ++IRO_NumLinear;
+ nd7->rtype = pattern->ndC->rtype;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = pattern->ndC->rtype;
+ nd7->u.node = expr;
+ nd7->next = NULL;
+ expr->data.intval = pattern->val14;
+
+ if (
+ IS_LINEAR_DIADIC(nd, EANDASS) &&
+ CInt64_Equal(pattern->val14, cint64_zero)
+ )
+ {
+ nd6->nodetype = EASS;
+ } else if (
+ IS_LINEAR_DIADIC(nd, EORASS) &&
+ !CTool_EndianReadWord32(&pattern->val14.hi)
+ )
+ {
+ UInt32 tmp = CInt64_GetULong(&pattern->val14);
+ if (
+ (nd->rtype->size == 1 && tmp == 0xFF) ||
+ (nd->rtype->size == 2 && tmp == 0xFFFF) ||
+ (nd->rtype->size == 4 && tmp == 0xFFFFFFFF)
+ )
+ {
+ nd6->nodetype = EASS;
+ }
+ }
+
+ IRO_AddToList(nd7, &list);
+
+ if (IS_LINEAR_MONADIC(pattern->nd10, ETYPCON)) {
+ nd8 = IRO_NewLinear(IROLinearOp1Arg);
+ *nd8 = *pattern->nd10;
+ nd8->index = ++IRO_NumLinear;
+ nd8->u.monadic = nd7;
+ nd8->next = NULL;
+ IRO_AddToList(nd8, &list);
+ } else {
+ nd8 = nd7;
+ }
+ nd6->u.diadic.right = nd8;
+ IRO_AddToList(nd6, &list);
+
+ if (!firstnode)
+ firstnode = list.head;
+ }
+
+ if (nd == lastnd)
+ break;
+ nd = nd->next;
+ }
+
+ if (list.head && list.tail)
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ }
+ } while (++pass < 8);
+}
+
+static int PatternMatchLoop(IRONode *fnode, IROLoop *loop, IROLoopInd *ind, UInt32 *unrollFactor, SInt32 *result1, SInt32 *result2, LoopPattern *pattern) {
+ IROLinear *scan;
+ IROLinear *varnode;
+ IROLinear *nd1;
+ IROLinear *nd2;
+ IROLinear *left1;
+ IROLinear *left2;
+ IROLinear *right1;
+ IROLinear *right2;
+ Object *obj1;
+ Object *obj2;
+ CInt64 shl;
+ CInt64 val;
+
+ *result1 = 0;
+ *result2 = 0;
+
+ if ((scan = fnode->first)) {
+ while (1) {
+ if (
+ (scan->index < loop->index20 || scan->index > loop->index24) &&
+ !(scan->flags & IROLF_Reffed) &&
+ scan->type != IROLinearNop &&
+ scan->type != IROLinearLabel
+ )
+ {
+ if (IS_LINEAR_DIADIC_3(scan, EORASS, EXORASS, EANDASS)) {
+ (*result2)++;
+ if (IS_LINEAR_MONADIC(scan->u.diadic.left, EINDIRECT)) {
+ varnode = scan->u.diadic.left->u.monadic;
+ if (IS_LINEAR_DIADIC(varnode, EADD)) {
+ pattern->nd4 = varnode->u.diadic.left;
+ pattern->type = varnode->rtype;
+ if (IRO_IsVariable(varnode->u.diadic.left)) {
+ pattern->nd0 = varnode->u.diadic.right;
+ if (
+ IS_LINEAR_DIADIC(pattern->nd0, ESHL) &&
+ IRO_IsConstant(pattern->nd0->u.diadic.right)
+ )
+ {
+ pattern->val1C = pattern->nd0->u.diadic.right->u.node->data.intval;
+ nd1 = pattern->nd0->u.diadic.left;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+
+ pattern->nd10 = scan->u.diadic.right;
+
+ if (IS_LINEAR_MONADIC(pattern->nd10, ETYPCON)) {
+ if (IS_LINEAR_DIADIC(scan, EANDASS)) {
+ if (IS_LINEAR_MONADIC(pattern->nd10->u.monadic, EBINNOT)) {
+ pattern->ndC = pattern->nd10->u.monadic->u.monadic;
+ } else {
+ return 0;
+ }
+ } else {
+ pattern->ndC = pattern->nd10->u.monadic;
+ }
+
+ if (IS_LINEAR_DIADIC(pattern->ndC, ESHL) && IRO_IsConstant(pattern->ndC->u.diadic.left)) {
+ val = pattern->ndC->u.diadic.left->u.node->data.intval;
+ nd2 = pattern->ndC->u.diadic.right;
+ } else {
+ return 0;
+ }
+ } else if (IS_LINEAR_DIADIC(pattern->nd10, ESHL) && IS_LINEAR_DIADIC_2(scan, EORASS, EXORASS)) {
+ pattern->ndC = pattern->nd10;
+ if (IRO_IsConstant(pattern->ndC->u.diadic.left)) {
+ val = pattern->ndC->u.diadic.left->u.node->data.intval;
+ nd2 = pattern->ndC->u.diadic.right;
+ } else {
+ return 0;
+ }
+ } else if (IS_LINEAR_MONADIC(pattern->nd10, EBINNOT) && IS_LINEAR_DIADIC(scan, EANDASS)) {
+ pattern->ndC = pattern->nd10->u.monadic;
+ if (IS_LINEAR_DIADIC(pattern->ndC, ESHL) && IRO_IsConstant(pattern->ndC->u.diadic.left)) {
+ val = pattern->ndC->u.diadic.left->u.node->data.intval;
+ nd2 = pattern->ndC->u.diadic.right;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+
+ if (IS_LINEAR_DIADIC(nd2, EAND) && IS_LINEAR_DIADIC(nd1, ESHR)) {
+ left1 = nd1->u.diadic.left;
+ left2 = nd2->u.diadic.left;
+ obj1 = IRO_IsVariable(left1);
+ obj2 = IRO_IsVariable(left2);
+ if (obj1 == obj2 && obj1 == ind->var->object) {
+ right1 = nd1->u.diadic.right;
+ right2 = nd2->u.diadic.right;
+ if (IRO_IsConstant(right1) && IRO_IsConstant(right2)) {
+ shl = cint64_one;
+ shl = CInt64_Shl(shl, right1->u.node->data.intval);
+ shl = CInt64_Sub(shl, cint64_one);
+ if (CInt64_Equal(shl, right2->u.node->data.intval)) {
+ if (CTool_EndianReadWord32(&shl.hi) == 0) {
+ *unrollFactor = CInt64_GetULong(&shl) + 1;
+ if (CheckConstant(CInt64_Add(shl, cint64_one), val, &pattern->val14)) {
+ (*result1)++;
+ if (IS_LINEAR_DIADIC(scan, EANDASS))
+ pattern->val14 = CInt64_Not(pattern->val14);
+ }
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ if (scan == fnode->last)
+ break;
+ scan = scan->next;
+ }
+ }
+
+ return 1;
+}
+
+static UInt32 UnrollWhileLoop(IRONode *header, IRONode *fnode2, IRONode *fnode3, IROLoop *loop, UInt32 unrollFactor) {
+ IROLoopInd *ind;
+ IRONode *scan;
+ CLabel *lastlabel;
+ IROLinear *lastlabelnode;
+ IROLinear *earlyLoopExitTest;
+ CLabel *earlyLoopExitTestLabel;
+ IROLinear *origIterationCount;
+ IROLinear *unrolledFinalValue;
+ IROLinear *preAlignTemp;
+ IROLinear *newFinalValue;
+ IROLinear *savedHead60;
+ IROLinear *unrolledBodyEntryTest;
+ CLabel *label;
+ IROLinear *savedHead2;
+ IROLinear *loophead25;
+ IROLinear *loopend;
+ IROLinear *loopscan;
+ IROLinear *indvar;
+ IROLinear *less;
+ IROLinear *loopExitTest;
+ IROLinear *saveTail;
+ CLabel *label2;
+ IROLinear *gotond;
+ CLabel *label3;
+ IROLinear *savedHead3;
+ IROLinear *updIndInc;
+ IROLinear *label2nd;
+ IROLinear *less2;
+ IROLinear *saveTail2;
+ IROLinear *less3;
+ IROLinear *wtf;
+ IROLinear *constnd;
+ IROLinear *ass;
+ IROLinear *nd18;
+ IRONode *fn19;
+ IRONode *newfnode1;
+ IRONode *newfnode2;
+ IRONode *newfnode3;
+ IRONode *newfnode4;
+ IRONode *newfnode5;
+ IRONode *newfnode6;
+ IRONode *newfnode7;
+ IRONode *newfnode8;
+ IROLinear *lastnd;
+ ENode *expr;
+ SInt32 result1;
+ SInt32 result2;
+ LoopPattern pattern;
+ IROList list;
+
+ IRO_Dump("while(n--) loop \n");
+
+ if (loop->flags & LoopFlags_800) {
+ IRO_Dump("loop not unrolled because induction used in loop \n");
+ return 0;
+ }
+ if (loop->flags & LoopFlags_1000) {
+ IRO_Dump("loop not unrolled because loop has multiple exits \n");
+ return 0;
+ }
+
+ if (!(loop->flags & LP_HAS_MULTIPLE_INDUCTIONS))
+ return 0;
+
+ for (ind = FirstInd; ind; ind = ind->next) {
+ if ((ind->flags & LoopInd_HasMod) && (ind->flags & LoopInd_HasDiv))
+ break;
+ }
+
+ if (!ind) {
+ IRO_Dump("Could not find loop with and induction with MOD and DIV operation\n");
+ return 0;
+ }
+
+ if (!IRO_IsUnsignedType(ind->nd->rtype))
+ return 0;
+
+ if (ind->nd->type == IROLinearOp2Arg) {
+ if (ind->nd->nodetype == EADDASS && IRO_IsConstant(ind->nd->u.diadic.right)) {
+ if (ind->addConst != 1)
+ return 0;
+ } else if (ind->nd->nodetype == EASS) {
+ if (
+ ind->nd->u.diadic.right->type != IROLinearOp2Arg ||
+ ind->nd->u.diadic.right->nodetype != EADD ||
+ !IRO_IsConstant(ind->nd->u.diadic.right->u.diadic.right)
+ )
+ return 0;
+
+ if (ind->addConst != 1)
+ return 0;
+ } else {
+ return 0;
+ }
+ } else if (ind->nd->type == IROLinearOp1Arg && ind->nd->nodetype != EPREINC && ind->nd->nodetype != EPOSTINC) {
+ return 0;
+ }
+
+ loop->induction = ind;
+ loop->index24 = ind->nd->index;
+ loop->index20 = IRO_FindStart(ind->nd)->index;
+
+ scan = IRO_FirstNode;
+ memset(&pattern, 0, sizeof(pattern));
+ while (scan) {
+ if (Bv_IsBitSet(scan->index, InLoop) && scan != header) {
+ if (!PatternMatchLoop(scan, loop, ind, &unrollFactor, &result1, &result2, &pattern))
+ return 0;
+ }
+ scan = scan->nextnode;
+ }
+
+ if (result1 > 1 || result2 > 1)
+ return 0;
+
+ lastlabel = fnode2->last->u.label.label;
+ lastlabelnode = IRO_FindLabelNode(fnode2->last->u.label.label, fnode2->last);
+
+ IRO_InitList(&list);
+ IRO_DuplicateExprRange(lastlabelnode->next, LoopNode->last->u.label.x4->u.diadic.left, &list);
+ IRO_DuplicateExpr(LoopNode->last->u.label.x4, &list);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ lastlabelnode = list.tail;
+
+ IRO_InitList(&list);
+ earlyLoopExitTest = BuildEarlyLoopExitTest(LoopNode->last->type, &list);
+ earlyLoopExitTestLabel = IRO_NewLabel();
+ earlyLoopExitTest->u.label.label = earlyLoopExitTestLabel;
+ earlyLoopExitTest->u.label.x4 = lastlabelnode;
+ earlyLoopExitTest->u.label.x4->flags |= IROLF_Reffed;
+ earlyLoopExitTest->rtype = LoopNode->last->rtype;
+ IRO_Paste(list.head, list.tail, fnode2->last);
+
+ IRO_InitList(&list);
+ origIterationCount = BuildOrigIterationCount_DoWhile(&list, loop);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ savedHead60 = list.head;
+
+ IRO_InitList(&list);
+ preAlignTemp = BuildPreAlignTemp(ind, unrollFactor, &list);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+
+ IRO_InitList(&list);
+ unrolledFinalValue = BuildUnrolledFinalvalue_DoWhile(origIterationCount, unrollFactor, &list, loop);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+
+ IRO_InitList(&list);
+ newFinalValue = BuildNewFinalvalue_DoWhile(origIterationCount, unrollFactor, &list, loop);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+
+ IRO_InitList(&list);
+ BuildUnrolledBodyEntryTest(&list, origIterationCount, unrollFactor, lastlabel);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ unrolledBodyEntryTest = list.tail;
+
+ IRO_InitList(&list);
+ label = BuildLabel(&list);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+
+ savedHead2 = list.head;
+ loophead25 = NULL;
+ for (scan = fnode3; scan && scan != header; scan = scan->nextnode) {
+ IRO_InitList(&list);
+ loopend = scan->last;
+ loopscan = scan->first;
+ while (1) {
+ if (loopscan->stmt)
+ loopscan->stmt->flags |= StmtFlag_10;
+ if (loopscan->type != IROLinearLabel && !(loopscan->flags & IROLF_Reffed)) {
+ IRO_DuplicateExpr(loopscan, &list);
+ if (!loophead25)
+ loophead25 = list.head;
+ }
+ if (loopscan == loopend)
+ break;
+ loopscan = loopscan->next;
+ }
+
+ if (list.head && list.tail)
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ }
+
+ IRO_InitList(&list);
+
+ if (ind->nd->type == IROLinearOp1Arg)
+ IRO_DuplicateExpr(ind->nd->u.monadic, &list);
+ else
+ IRO_DuplicateExpr(ind->nd->u.diadic.left, &list);
+ list.tail->flags &= ~IROLF_Assigned;
+ indvar = list.tail;
+
+ IRO_DuplicateExpr(preAlignTemp, &list);
+ list.tail->flags &= ~IROLF_Assigned;
+
+ less = IRO_NewLinear(IROLinearOp2Arg);
+ less->nodetype = ELESS;
+ less->rtype = TYPE(&stbool);
+ less->index = ++IRO_NumLinear;
+ less->next = NULL;
+ less->u.diadic.left = indvar;
+ less->u.diadic.right = list.tail;
+ IRO_AddToList(less, &list);
+ less->flags |= IROLF_Reffed;
+
+ loopExitTest = BuildLoopExitTest(LoopNode->last->type, &list);
+ loopExitTest->u.label.label = label;
+ loopExitTest->u.label.x4 = less;
+ loopExitTest->u.label.x4->flags |= IROLF_Reffed;
+ loopExitTest->rtype = LoopNode->last->rtype;
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ saveTail = list.tail;
+
+ IRO_InitList(&list);
+ label2 = IRO_NewLabel();
+ gotond = IRO_NewLinear(IROLinearOp1Arg);
+ gotond->index = ++IRO_NumLinear;
+ gotond->type = IROLinearGoto;
+ gotond->u.label.label = label2;
+ IRO_AddToList(gotond, &list);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+
+ IRO_InitList(&list);
+ label3 = BuildLabel(&list);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ savedHead3 = list.head;
+
+ UnrollWhileLoopBody(header, fnode2, fnode3, loop, &pattern, unrollFactor);
+ updIndInc = UpdateInductionIncrement(loop, 8 * unrollFactor, fnode2->last);
+
+ IRO_InitList(&list);
+ label2nd = IRO_NewLinear(IROLinearLabel);
+ label2nd->index = IRO_NumLinear++;
+ label2nd->u.label.label = label2;
+ label2nd->flags |= IROLF_1;
+ IRO_AddToList(label2nd, &list);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+
+ IRO_InitList(&list);
+
+ if (ind->nd->type == IROLinearOp1Arg)
+ IRO_DuplicateExpr(ind->nd->u.monadic, &list);
+ else
+ IRO_DuplicateExpr(ind->nd->u.diadic.left, &list);
+ list.tail->flags &= ~IROLF_Assigned;
+ indvar = list.tail;
+
+ IRO_DuplicateExpr(unrolledFinalValue, &list);
+ list.tail->flags &= ~IROLF_Assigned;
+
+ less2 = IRO_NewLinear(IROLinearOp2Arg);
+ less2->nodetype = ELESS;
+ less2->rtype = TYPE(&stbool);
+ less2->index = ++IRO_NumLinear;
+ less2->next = NULL;
+ less2->u.diadic.left = indvar;
+ less2->u.diadic.right = list.tail;
+ IRO_AddToList(less2, &list);
+ less2->flags |= IROLF_Reffed;
+
+ loopExitTest = BuildLoopExitTest(LoopNode->last->type, &list);
+ loopExitTest->u.label.label = label3;
+ loopExitTest->u.label.x4 = less2;
+ loopExitTest->u.label.x4->flags |= IROLF_Reffed;
+ loopExitTest->rtype = LoopNode->last->rtype;
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ saveTail2 = list.tail;
+
+ IRO_InitList(&list);
+
+ if (ind->nd->type == IROLinearOp1Arg)
+ IRO_DuplicateExpr(ind->nd->u.monadic, &list);
+ else
+ IRO_DuplicateExpr(ind->nd->u.diadic.left, &list);
+ list.tail->flags &= ~IROLF_Assigned;
+ indvar = list.tail;
+
+ IRO_DuplicateExpr(newFinalValue, &list);
+ list.tail->flags &= ~IROLF_Assigned;
+
+ less3 = IRO_NewLinear(IROLinearOp2Arg);
+ less3->nodetype = ELESS;
+ less3->rtype = TYPE(&stbool);
+ less3->index = ++IRO_NumLinear;
+ less3->next = NULL;
+ less3->u.diadic.left = indvar;
+ less3->u.diadic.right = list.tail;
+ IRO_AddToList(less3, &list);
+ less3->flags |= IROLF_Reffed;
+
+ wtf = LoopNode->last->u.label.x4;
+ IRO_Paste(list.head, list.tail, LoopNode->last);
+ LoopNode->last->u.label.x4 = list.tail;
+
+ IRO_InitList(&list);
+
+ constnd = IRO_NewLinear(IROLinearOperand);
+ constnd->index = ++IRO_NumLinear;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = wtf->u.diadic.left->rtype;
+ expr->data.intval = cint64_zero;
+ constnd->u.node = expr;
+ constnd->rtype = expr->rtype;
+ IRO_AddToList(constnd, &list);
+ constnd->flags |= IROLF_Reffed;
+
+ IRO_DuplicateExpr(wtf->u.diadic.left, &list);
+
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->nodetype = EASS;
+ ass->rtype = list.tail->rtype;
+ ass->index = ++IRO_NumLinear;
+ ass->next = NULL;
+ ass->u.diadic.left = list.tail;
+ ass->u.diadic.right = constnd;
+ IRO_AddToList(ass, &list);
+ ass->flags |= IROLF_Assigned;
+
+ IRO_NopOut(wtf);
+
+ fn19 = fnode2->nextnode;
+ nd18 = fnode2->last;
+ fnode2->last = earlyLoopExitTest;
+
+ newfnode1 = IRO_NewFlowGraphNode();
+ newfnode1->first = savedHead60;
+ newfnode1->last = unrolledBodyEntryTest;
+ fnode2->nextnode = newfnode1;
+
+ newfnode2 = IRO_NewFlowGraphNode();
+ newfnode2->first = savedHead2;
+ newfnode2->last = saveTail;
+ savedHead2->u.label.label->stmt = (Statement *) newfnode2;
+ newfnode1->nextnode = newfnode2;
+
+ newfnode3 = IRO_NewFlowGraphNode();
+ newfnode3->first = gotond;
+ newfnode3->last = gotond;
+ newfnode2->nextnode = newfnode3;
+
+ newfnode4 = IRO_NewFlowGraphNode();
+ newfnode4->first = savedHead3;
+ newfnode4->last = updIndInc;
+ savedHead3->u.label.label->stmt = (Statement *) newfnode4;
+ newfnode3->nextnode = newfnode4;
+
+ newfnode5 = IRO_NewFlowGraphNode();
+ newfnode5->first = label2nd;
+ newfnode5->last = saveTail2;
+ label2nd->u.label.label->stmt = (Statement *) newfnode5;
+ newfnode4->nextnode = newfnode5;
+
+ newfnode6 = IRO_NewFlowGraphNode();
+ newfnode6->first = nd18;
+ newfnode6->last = nd18;
+ newfnode5->nextnode = newfnode6;
+ newfnode6->nextnode = fn19;
+
+ newfnode7 = oalloc(sizeof(IRONode));
+ memset(newfnode7, 0, sizeof(IRONode));
+ newfnode7->index = IRO_NumNodes;
+ IRO_NumNodes++;
+
+ newfnode7->first = list.head;
+ newfnode7->last = list.tail;
+
+ list.tail->next = LoopNode->last->next;
+ LoopNode->last->next = list.head;
+
+ newfnode7->nextnode = LoopNode->nextnode;
+ LoopNode->nextnode = newfnode7;
+
+ newfnode8 = oalloc(sizeof(IRONode));
+ memset(newfnode8, 0, sizeof(IRONode));
+ newfnode8->index = IRO_NumNodes;
+ IRO_NumNodes++;
+
+ lastnd = IRO_NewLinear(IROLinearLabel);
+ lastnd->index = IRO_NumLinear++;
+ lastnd->next = NULL;
+ lastnd->u.label.label = earlyLoopExitTestLabel;
+ lastnd->flags |= IROLF_1;
+ earlyLoopExitTestLabel->stmt = (Statement *) newfnode8;
+
+ newfnode8->first = lastnd;
+ newfnode8->last = lastnd;
+
+ lastnd->next = newfnode7->last->next;
+ newfnode7->last->next = lastnd;
+
+ newfnode8->nextnode = newfnode7->nextnode;
+ newfnode7->nextnode = newfnode8;
+
+ return 1;
+}
+
+void IRO_IterateForLoopBody(IRONode *start, IRONode *end, IROLoop *loop, IROLinear *destnode, SInt32 addConst, CInt64 *val, Boolean funkyFlag) {
+ IROLinear *first = NULL;
+ IROLinear *last = NULL;
+ IRONode *fnode;
+ IROLinear *lastnd;
+ IROLinear *nd;
+ IROList list;
+
+ for (fnode = start; fnode && fnode != end; fnode = fnode->nextnode) {
+ IRO_InitList(&list);
+
+ lastnd = fnode->last;
+ nd = fnode->first;
+ while (1) {
+ if (nd->stmt)
+ nd->stmt->flags |= StmtFlag_10;
+
+ if (
+ (nd->index < loop->index20 || nd->index > loop->index24) &&
+ nd->type != IROLinearLabel &&
+ !(nd->flags & IROLF_Reffed)
+ )
+ {
+ IRO_DuplicateExpr(nd, &list);
+ if (!first)
+ first = list.head;
+ last = list.tail;
+ }
+
+ if (nd == lastnd)
+ break;
+ nd = nd->next;
+ }
+
+ if (list.head && list.tail)
+ IRO_Paste(list.head, list.tail, destnode);
+ }
+
+ if (funkyFlag) {
+ *val = CInt64_Add(*val, IRO_MakeLong(loop->induction->addConst));
+ ChangeInductionReference(first, last, *val, loop);
+ }
+}
+
+void IRO_LinearizeForLoopPostLoop(IRONode *fnode1, IRONode *fnode2, IROLoop *loop, IRONode *fnode3, UInt32 unrollFactor) {
+ IRONode *newfnode;
+ IROLinear *newnd;
+ SInt32 i;
+ CInt64 val;
+
+ newfnode = oalloc(sizeof(IRONode));
+ memset(newfnode, 0, sizeof(IRONode));
+ newfnode->index = IRO_NumNodes;
+ IRO_NumNodes++;
+
+ newnd = IRO_NewLinear(IROLinearNop);
+ newnd->index = IRO_NumLinear++;
+ newnd->next = NULL;
+ newnd->flags |= IROLF_1;
+
+ newfnode->first = newfnode->last = newnd;
+
+ newfnode->nextnode = fnode3->nextnode;
+ fnode3->nextnode = newfnode;
+
+ newnd->next = fnode3->last->next;
+ fnode3->last->next = newnd;
+
+ val = cint64_zero;
+ for (i = 0; i < unrollFactor; i++)
+ IRO_IterateForLoopBody(fnode2, fnode1, loop, newfnode->last, loop->induction->addConst, &val, i > 0);
+ UpdateInductionIncrement(loop, unrollFactor, newfnode->last);
+}
+
+static UInt32 UnrollForLoop(IRONode *header, IRONode *fnode2, IRONode *fnode3, IROLoop *loop, UInt32 unrollFactor) {
+ IROLinear *lastlabelnode;
+ IROLinear *earlyLoopExitTest;
+ IROLinear *origIterationCount;
+ IROLinear *saveHead1;
+ IROLinear *newFinalValue;
+ IROLinear *unrolledBodyEntryTest;
+ IROLinear *gotoNd;
+ IROLinear *saveHead2;
+ IROLinear *updIndInc;
+ IROLinear *labelNd;
+ IROLinear *saveTail2;
+ IROLinear *ndCopy;
+ IROLinear *saveTail3;
+ IROLinear *loopExitTest;
+ IROLinear *lastnd;
+ IROLinear *labelNd2;
+ IROLinear *saveTail4;
+ IROLinear *labelNd3;
+ IROLinear *scan;
+ IRONode *nd18;
+ IRONode *newfnode1;
+ IRONode *newfnode2;
+ IRONode *newfnode3;
+ IRONode *newfnode4;
+ IRONode *newfnode5;
+ IRONode *newfnode6;
+ CLabel *lastlabel;
+ CLabel *earlyLoopExitTestLabel;
+ CLabel *label;
+ CLabel *label2;
+ SInt32 i;
+
+ IROList list;
+ CInt64 iterCount;
+ int isConstant;
+ UInt32 needOrigLoop = 0;
+ UInt32 needUnrollBodyTest = 0;
+ UInt32 resetUnrolledFinalValue = 0;
+ SInt32 leftOver;
+ CInt64 val;
+
+ lastlabelnode = IRO_FindLabelNode(fnode2->last->u.label.label, fnode2->last);
+ lastlabel = IRO_NewLabel();
+
+ IRO_InitList(&list);
+ IRO_DuplicateExprRange(lastlabelnode->next, LoopNode->last->u.label.x4, &list);
+ IRO_DuplicateExpr(LoopNode->last->u.label.x4, &list);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ lastlabelnode = list.tail;
+
+ IRO_InitList(&list);
+ earlyLoopExitTest = BuildEarlyLoopExitTest(LoopNode->last->type, &list);
+ earlyLoopExitTestLabel = IRO_NewLabel();
+ earlyLoopExitTest->u.label.label = earlyLoopExitTestLabel;
+ earlyLoopExitTest->u.label.x4 = lastlabelnode;
+ earlyLoopExitTest->u.label.x4->flags |= IROLF_Reffed;
+ earlyLoopExitTest->rtype = LoopNode->last->rtype;
+ IRO_Paste(list.head, list.tail, fnode2->last);
+
+ isConstant = IsIterationCountConstant(loop, &iterCount);
+ needOrigLoop = 1;
+ needUnrollBodyTest = 1;
+ resetUnrolledFinalValue = 0;
+ if (isConstant)
+ IRO_TestConstantIterationCount(loop, &iterCount, 1, &unrollFactor, &leftOver, &needOrigLoop, &needUnrollBodyTest, &resetUnrolledFinalValue);
+
+ IRO_InitList(&list);
+ origIterationCount = BuildOrigIterationCount(&list, loop);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ saveHead1 = list.head;
+
+ IRO_InitList(&list);
+ newFinalValue = BuildNewFinalvalue(origIterationCount, unrollFactor, &list, loop);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+
+ IRO_InitList(&list);
+ BuildUnrolledBodyEntryTest(&list, origIterationCount, unrollFactor, lastlabel);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ unrolledBodyEntryTest = list.tail;
+
+ label = IRO_NewLabel();
+ IRO_InitList(&list);
+ gotoNd = IRO_NewLinear(IROLinearOp1Arg);
+ gotoNd->index = ++IRO_NumLinear;
+ gotoNd->type = IROLinearGoto;
+ gotoNd->u.label.label = label;
+ IRO_AddToList(gotoNd, &list);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+
+ IRO_InitList(&list);
+ label2 = BuildLabel(&list);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ saveHead2 = list.head;
+
+ val = cint64_zero;
+ for (i = 0; i < unrollFactor; i++)
+ IRO_IterateForLoopBody(fnode3, header, loop, fnode2->last, loop->induction->addConst, &val, i > 0);
+ updIndInc = UpdateInductionIncrement(loop, unrollFactor, fnode2->last);
+
+ IRO_InitList(&list);
+ labelNd = IRO_NewLinear(IROLinearLabel);
+ labelNd->index = IRO_NumLinear++;
+ labelNd->u.label.label = label;
+ labelNd->flags |= IROLF_1;
+ IRO_AddToList(labelNd, &list);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+
+ IRO_InitList(&list);
+
+ IRO_DuplicateExpr(LoopNode->last->u.label.x4->u.diadic.left, &list);
+ saveTail2 = list.tail;
+
+ if (resetUnrolledFinalValue)
+ IRO_DuplicateExpr(loop->nd18->u.diadic.right, &list);
+ else
+ IRO_DuplicateExpr(newFinalValue, &list);
+
+ ndCopy = IRO_NewLinear(LoopNode->last->u.label.x4->type);
+ *ndCopy = *LoopNode->last->u.label.x4;
+ ndCopy->index = ++IRO_NumLinear;
+ ndCopy->next = NULL;
+ ndCopy->expr = NULL;
+ ndCopy->u.diadic.left = saveTail2;
+ ndCopy->u.diadic.right = list.tail;
+ IRO_AddToList(ndCopy, &list);
+
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ saveTail3 = list.tail;
+
+ IRO_InitList(&list);
+ loopExitTest = BuildLoopExitTest(LoopNode->last->type, &list);
+ loopExitTest->u.label.label = label2;
+ loopExitTest->u.label.x4 = saveTail3;
+ loopExitTest->u.label.x4->flags |= IROLF_Reffed;
+ loopExitTest->rtype = LoopNode->last->rtype;
+ IRO_Paste(list.head, list.tail, fnode2->last);
+ saveTail4 = list.tail;
+
+ IRO_InitList(&list);
+ labelNd2 = IRO_NewLinear(IROLinearLabel);
+ labelNd2->index = IRO_NumLinear++;
+ labelNd2->u.label.label = lastlabel;
+ labelNd2->flags |= IROLF_1;
+ IRO_AddToList(labelNd2, &list);
+ IRO_Paste(list.head, list.tail, fnode2->last);
+
+ lastnd = fnode2->last;
+ nd18 = fnode2->nextnode;
+ fnode2->last = earlyLoopExitTest;
+
+ newfnode1 = IRO_NewFlowGraphNode();
+ newfnode1->first = saveHead1;
+ newfnode1->last = unrolledBodyEntryTest;
+ fnode2->nextnode = newfnode1;
+
+ newfnode2 = IRO_NewFlowGraphNode();
+ newfnode2->first = gotoNd;
+ newfnode2->last = gotoNd;
+ newfnode1->nextnode = newfnode2;
+
+ newfnode3 = IRO_NewFlowGraphNode();
+ newfnode3->first = saveHead2;
+ newfnode3->last = updIndInc;
+
+ saveHead2->u.label.label->stmt = (Statement *) newfnode3;
+ if (newfnode2)
+ newfnode2->nextnode = newfnode3;
+ else
+ newfnode1->nextnode = newfnode3;
+
+ newfnode4 = IRO_NewFlowGraphNode();
+ newfnode4->first = labelNd;
+ newfnode4->last = saveTail4;
+ labelNd->u.label.label->stmt = (Statement *) newfnode4;
+ newfnode3->nextnode = newfnode4;
+
+ newfnode5 = IRO_NewFlowGraphNode();
+ newfnode5->first = labelNd2;
+ newfnode5->last = lastnd;
+ newfnode4->nextnode = newfnode5;
+ newfnode5->nextnode = nd18;
+
+ newfnode6 = oalloc(sizeof(IRONode));
+ memset(newfnode6, 0, sizeof(IRONode));
+ newfnode6->index = IRO_NumNodes;
+ IRO_NumNodes++;
+
+ labelNd3 = IRO_NewLinear(IROLinearLabel);
+ labelNd3->index = IRO_NumLinear++;
+ labelNd3->next = NULL;
+ labelNd3->u.label.label = earlyLoopExitTestLabel;
+ labelNd3->flags |= IROLF_1;
+ earlyLoopExitTestLabel->stmt = (Statement *) newfnode6;
+
+ newfnode6->first = labelNd3;
+ newfnode6->last = labelNd3;
+
+ labelNd3->next = LoopNode->last->next;
+ LoopNode->last->next = labelNd3;
+
+ newfnode6->nextnode = LoopNode->nextnode;
+ LoopNode->nextnode = newfnode6;
+
+ if (!needOrigLoop) {
+ NoOpBlock(newfnode5);
+ NoOpBlock(header);
+ NoOpBlock(fnode3);
+ NoOpBlock(loop->induction->fnode);
+ IRO_NopOut(newfnode1->last->u.label.x4);
+ newfnode1->last->type = IROLinearNop;
+ }
+
+ if (!needUnrollBodyTest) {
+ IRO_NopOut(earlyLoopExitTest->u.label.x4);
+ earlyLoopExitTest->type = IROLinearNop;
+
+ IRO_NopOut(newfnode4->last->u.label.x4);
+ newfnode4->last->type = IROLinearNop;
+
+ if (newfnode2)
+ newfnode2->last->type = IROLinearNop;
+
+ for (scan = newfnode1->first; scan; scan = scan->next) {
+ if (!(scan->flags & IROLF_Reffed))
+ IRO_NopOut(scan);
+ if (scan == newfnode1->last)
+ break;
+ }
+ }
+
+ return 1;
+}
+
+static UInt32 UnrollStandardLoop(IRONode *header, IRONode *fnode2, IRONode *fnode3, int count) {
+ IROLoop *loop;
+
+ ConditionalHeaderAtBottom = 1;
+ loop = ExtractLoopInfo(header);
+ loop->xC = fnode2;
+ loop->x10 = fnode3;
+ FindAssignmenttoInductionVar(loop, fnode2);
+
+ if (!IsLoopUnrollable(loop)) {
+ IRO_Dump("LoopUnroll:loop with header %d not unrolled because IsLoopUnrollable failed\n", header->index);
+ return 0;
+ }
+
+ if (loop->flags & LoopFlags_10000)
+ return UnrollWhileLoop(header, fnode2, fnode3, loop, count);
+ else
+ return UnrollForLoop(header, fnode2, fnode3, loop, count);
+}
+
+static void LoopUnroll(int count, IRONode *header) {
+ VarRecord *var;
+ IRONode *tmp;
+ UInt16 i;
+ UInt16 j;
+ IRONode *prevpred;
+ IRONode *prevsucc;
+ int foundpred;
+ UInt32 predcount;
+ UInt32 success = 0;
+
+ LoopNode = header;
+ FindMustReach();
+
+ for (var = IRO_FirstVar; var; var = var->next)
+ var->xA = 1;
+
+ ComputeLoopKills();
+ ComputeLoopInvariance();
+ ComputeLoopInduction();
+
+ LoopNode = header;
+ ConditionalHeaderAtBottom = 0;
+
+ prevpred = NULL;
+ foundpred = 0;
+ for (i = 0; i < LoopNode->numpred; i++) {
+ tmp = IRO_NodeTable[LoopNode->pred[i]];
+ if (!Bv_IsBitSet(tmp->index, InLoop)) {
+ foundpred = 1;
+ if (tmp->nextnode == header) {
+ CError_ASSERT(2101, !prevpred || tmp == prevpred);
+ prevpred = tmp;
+ }
+ }
+ }
+
+ if (!foundpred) {
+ IRO_Dump("No predecessor outside the loop\n");
+ return;
+ }
+
+ if (LoopNode->last->type == IROLinearIf || LoopNode->last->type == IROLinearIfNot) {
+ if (LoopNode->nextnode && !Bv_IsBitSet(LoopNode->nextnode->index, InLoop)) {
+ prevsucc = NULL;
+ for (i = 0; i < LoopNode->numsucc; i++) {
+ tmp = IRO_NodeTable[LoopNode->succ[i]];
+ if (Bv_IsBitSet(tmp->index, InLoop)) {
+ CError_ASSERT(2159, !prevsucc);
+ prevsucc = tmp;
+ }
+ }
+
+ prevpred = NULL;
+ predcount = 0;
+ for (j = 0; j < LoopNode->numpred; j++) {
+ tmp = IRO_NodeTable[LoopNode->pred[j]];
+ if (!Bv_IsBitSet(tmp->index, InLoop)) {
+ prevpred = tmp;
+ predcount++;
+ }
+ }
+
+ if (
+ predcount == 1 &&
+ prevpred->last->type == IROLinearGoto &&
+ prevpred->nextnode == prevsucc &&
+ prevsucc != LoopNode
+ )
+ {
+ success = UnrollStandardLoop(header, prevpred, prevsucc, count);
+ }
+ }
+ } else {
+ IRO_Dump(" LoopUnroll:Loop with header = %d is not a conditional loop\n", header->index);
+ }
+
+ if (!success)
+ return;
+
+ IRO_NodeTable = oalloc(sizeof(IRONode *) * IRO_NumNodes);
+ memset(IRO_NodeTable, 0, sizeof(IRONode *) * IRO_NumNodes);
+ for (tmp = IRO_FirstNode; tmp; tmp = tmp->nextnode)
+ IRO_NodeTable[tmp->index] = tmp;
+ IRO_ComputeSuccPred();
+ IRO_ComputeDom();
+ if (success)
+ IRO_Dump(" LoopUnroll:Loop with header = %d Unrolled\n", header->index);
+}
+
+static int IsLoopUnrollable(IROLoop *loop) {
+ CInt64 tmp;
+
+ if (loop->flags & LP_LOOP_HAS_ASM) {
+ IRO_Dump("IsLoopUnrollable:No due to LP_LOOP_HAS_ASM \n");
+ return 0;
+ }
+ if (loop->flags & LP_IFEXPR_NON_CANONICAL) {
+ IRO_Dump("IsLoopUnrollable:No due to LP_IFEXPR_NON_CANONICAL \n");
+ return 0;
+ }
+ if (loop->flags & LP_LOOP_HAS_CALLS) {
+ IRO_Dump("IsLoopUnrollable:No due to LP_LOOP_HAS_CALLS \n");
+ return 0;
+ }
+ if (loop->flags & LP_LOOP_HAS_CNTRLFLOW) {
+ IRO_Dump("IsLoopUnrollable:No due to LP_LOOP_HAS_CNTRLFLOW \n");
+ return 0;
+ }
+ if (loop->flags & LP_INDUCTION_NOT_FOUND) {
+ IRO_Dump("IsLoopUnrollable:No due to LP_INDUCTION_NOT_FOUND \n");
+ return 0;
+ }
+ if (loop->flags & LP_LOOP_HDR_HAS_SIDEEFFECTS) {
+ IRO_Dump("IsLoopUnrollable:No due to LP_LOOP_HDR_HAS_SIDEEFFECTS \n");
+ return 0;
+ }
+ if (!(loop->flags & LoopFlags_200)) {
+ IRO_Dump("IsLoopUnrollable:No because header does not follow induction update \n");
+ return 0;
+ }
+
+ if (!(loop->flags & LoopFlags_10000)) {
+ IROLinear *upperBound = loop->nd18->u.diadic.right;
+ if (!IRO_IsIntConstant(upperBound) && !(upperBound->flags & IROLF_LoopInvariant)) {
+ IRO_Dump("IsLoopUnrollable:No because Loop Upper Bound is Variant in the loop\n");
+ return 0;
+ }
+ if (!loop->nd14) {
+ IRO_Dump("IsLoopUnrollable:No because there is no initialization of loop index in PreHeader\n");
+ return 0;
+ }
+ if (!IRO_IsVariable(loop->nd14->u.diadic.left)) {
+ IRO_Dump("IsLoopUnrollable:No because initial value of induction stored thru pointer\n");
+ return 0;
+ }
+
+ if (!IRO_IsUnsignedType(loop->nd14->rtype)) {
+ if (IRO_IsIntConstant(loop->nd14->u.diadic.right)) {
+ if (!CInt64_GreaterEqual(loop->nd14->u.diadic.right->u.node->data.intval, cint64_zero)) {
+ IRO_Dump("IsLoopUnrollable:No because initial value of induction is signed but init < 0\n");
+ return 0;
+ }
+ } else if (IsIterationCountConstant(loop, &tmp)) {
+ IRO_Dump("IsLoopUnrollable:Yes, the limits substract out to be constants\n");
+ } else {
+ IRO_Dump("IsLoopUnrollable:No because initial value of induction is signed and not constant\n");
+ return 0;
+ }
+ }
+
+ if (!(loop->flags & LP_LOOP_STEP_ISADD)) {
+ IRO_Dump("IsLoopUnrollable:No because LP_LOOP_STEP_ISADD is not set i.e induciton is not updated by 1\n");
+ return 0;
+ }
+
+ } else {
+ if (!IRO_IsUnsignedType(loop->nd18->u.diadic.left->rtype)) {
+ IRO_Dump("IsLoopUnrollable:No because the while loop induction is signed\n");
+ return 0;
+ }
+ if (!(loop->flags & LoopFlags_2000)) {
+ IRO_Dump("IsLoopUnrollable:No because the while loop operator is not of decrement form\n");
+ return 0;
+ }
+ }
+
+ if (loop->sizeBySomeMeasurement > copts.unrollinstrfactor) {
+ IRO_Dump("IsLoopUnrollable:No because loop size greater than threshold\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+IROLinear *BuildEarlyLoopExitTest(IROLinearType type, IROList *list) {
+ IROLinear *nd = IRO_NewLinear(IROLinearOp1Arg);
+ nd->index = ++IRO_NumLinear;
+ if (type == IROLinearIf)
+ nd->type = IROLinearIfNot;
+ else
+ nd->type = IROLinearIf;
+ IRO_AddToList(nd, list);
+ return nd;
+}
+
+IROLinear *BuildLoopExitTest(IROLinearType type, IROList *list) {
+ IROLinear *nd = IRO_NewLinear(IROLinearOp1Arg);
+ nd->index = ++IRO_NumLinear;
+ nd->type = type;
+ IRO_AddToList(nd, list);
+ return nd;
+}
+
+int IsIterationCountConstant(IROLoop *loop, CInt64 *pval) {
+ IROLinear *lowerBound;
+ IROLinear *upperBound;
+ Type *type;
+ int isUnsigned;
+ IROAddrRecord *lowerRec;
+ IROAddrRecord *upperRec;
+ CInt64 lowerval;
+ CInt64 upperval;
+ CInt64 incval;
+ CInt64 negOne;
+
+ lowerBound = loop->nd14->u.diadic.right;
+ if (loop->flags & LoopFlags_1) {
+ upperBound = loop->nd18->u.diadic.right;
+ type = loop->nd18->u.diadic.right->rtype;
+ } else {
+ upperBound = loop->nd18->u.diadic.left;
+ type = loop->nd18->u.diadic.left->rtype;
+ }
+
+ isUnsigned = IRO_IsUnsignedType(type);
+
+ if (IRO_IsIntConstant(lowerBound) && IRO_IsIntConstant(upperBound)) {
+ lowerval = lowerBound->u.node->data.intval;
+ upperval = upperBound->u.node->data.intval;
+ if (isUnsigned) {
+ if (CInt64_LessEqualU(upperval, lowerval))
+ return 0;
+ } else {
+ if (CInt64_LessEqual(upperval, lowerval))
+ return 0;
+ }
+
+ CInt64_SetLong(&incval, loop->induction->addConst);
+ CInt64_SetLong(&negOne, -1);
+ *pval = CInt64_Sub(upperval, lowerval);
+ *pval = CInt64_Add(*pval, incval);
+
+ if (IS_LINEAR_DIADIC(loop->nd18, ELESS))
+ *pval = CInt64_Add(*pval, negOne);
+
+ CError_ASSERT(2486, !CInt64_IsZero(&incval));
+
+ if (isUnsigned)
+ *pval = CInt64_DivU(*pval, incval);
+ else
+ *pval = CInt64_Div(*pval, incval);
+
+ if (CInt64_Equal(*pval, cint64_zero))
+ return 0;
+
+ if (isUnsigned) {
+ CError_ASSERT(2508, !CInt64_LessEqualU(*pval, cint64_zero));
+ } else {
+ CError_ASSERT(2517, !CInt64_LessEqual(*pval, cint64_zero));
+ }
+
+ return 1;
+ }
+
+ lowerRec = IRO_InitAddrRecordPointer(lowerBound);
+ upperRec = IRO_InitAddrRecordPointer(upperBound);
+
+ if (IS_LINEAR_DIADIC(lowerBound, EADD)) {
+ IRO_DecomposeAddressExpression(lowerBound, lowerRec);
+ } else if (IRO_IsIntConstant(lowerBound)) {
+ lowerRec->numInts++;
+ IRO_AddElmToList(lowerBound, &lowerRec->ints);
+ lowerRec->numObjRefs = 0;
+ lowerRec->numMisc = 0;
+ } else {
+ lowerRec->numMisc++;
+ IRO_AddElmToList(lowerBound, &lowerRec->misc);
+ lowerRec->numObjRefs = 0;
+ lowerRec->numInts = 0;
+ }
+
+ if (IS_LINEAR_DIADIC(upperBound, EADD)) {
+ IRO_DecomposeAddressExpression(upperBound, upperRec);
+ } else if (IRO_IsIntConstant(upperBound)) {
+ upperRec->numInts++;
+ IRO_AddElmToList(upperBound, &upperRec->ints);
+ upperRec->numObjRefs = 0;
+ upperRec->numMisc = 0;
+ } else {
+ upperRec->numMisc++;
+ IRO_AddElmToList(upperBound, &upperRec->misc);
+ upperRec->numObjRefs = 0;
+ upperRec->numInts = 0;
+ }
+
+ if (IsDifferenceOfTermsConstant(lowerRec, upperRec, isUnsigned, pval)) {
+ if (IS_LINEAR_DIADIC(loop->nd18, ELESSEQU))
+ *pval = CInt64_Add(*pval, cint64_one);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int IsDifferenceOfTermsConstant(IROAddrRecord *lowerRec, IROAddrRecord *upperRec, int isUnsigned, CInt64 *pval) {
+ UInt32 i;
+ CInt64 upperval;
+ CInt64 lowerval;
+ IROElmList *el;
+ IROLinear *nd;
+
+ if (upperRec->numObjRefs == lowerRec->numObjRefs && upperRec->numObjRefs != 0)
+ return 0;
+ else if (upperRec->numObjRefs != lowerRec->numObjRefs)
+ return 0;
+
+ if (upperRec->numMisc == lowerRec->numMisc && upperRec->numMisc != 0) {
+ for (i = 0; i < upperRec->numMisc; i++) {
+ // bug? surely this should index on i...?
+ if (!IRO_ExprsSame(lowerRec->misc->element, upperRec->misc->element))
+ return 0;
+ }
+ } else if (upperRec->numMisc != lowerRec->numMisc) {
+ return 0;
+ }
+
+ upperval = cint64_zero;
+ for (el = upperRec->ints; el; el = el->next) {
+ nd = el->element;
+ upperval = CMach_CalcIntDiadic(nd->rtype, upperval, '+', nd->u.node->data.intval);
+ }
+
+ lowerval = cint64_zero;
+ for (el = lowerRec->ints; el; el = el->next) {
+ nd = el->element;
+ lowerval = CMach_CalcIntDiadic(nd->rtype, lowerval, '+', nd->u.node->data.intval);
+ }
+
+ if (CInt64_Equal(upperval, lowerval))
+ return 0;
+
+ if (CInt64_Greater(upperval, lowerval)) {
+ *pval = CInt64_Sub(upperval, lowerval);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void NoOpBlock(IRONode *fnode) {
+ IROLinear *last, *scan;
+
+ for (scan = fnode->first, last = fnode->last; scan; scan = scan->next) {
+ scan->type = IROLinearNop;
+ if (scan == last)
+ break;
+ }
+}
+
+void IRO_TestConstantIterationCount(IROLoop *loop, CInt64 *iterCount, SInt32 vectorStride, UInt32 *unrollFactor, SInt32 *leftOver, UInt32 *needOrigLoop, UInt32 *needUnrollBodyTest, UInt32 *resetUnrolledFinalValue) {
+ UInt32 isUnsigned;
+ CInt64 val;
+ CInt64 val3;
+ CInt64 mod;
+ CInt64 val2;
+ CInt64 loopvar3;
+ CInt64 loopvar1;
+ CInt64 loopvar2;
+ CInt64 strideVal;
+
+ CError_ASSERT(2737, *unrollFactor);
+
+ isUnsigned = IRO_IsUnsignedType(
+ (loop->flags & LoopFlags_1) ? loop->nd18->u.diadic.right->rtype :loop->nd18->u.diadic.left->rtype);
+
+ CError_ASSERT(2756, vectorStride);
+
+ strideVal = IRO_MakeLong(vectorStride);
+ if (isUnsigned ? CInt64_LessU(*iterCount, strideVal) : CInt64_Less(*iterCount, strideVal)) {
+ *needOrigLoop = 1;
+ *needUnrollBodyTest = 0;
+ *unrollFactor = 0;
+ *leftOver = CInt64_GetULong(iterCount);
+ } else {
+ switch (vectorStride) {
+ case 1:
+ val = *iterCount;
+ break;
+ case 2:
+ val = CInt64_ShrU(*iterCount, cint64_one);
+ break;
+ case 4:
+ val = CInt64_ShrU(*iterCount, IRO_MakeLong(2));
+ break;
+ case 8:
+ val = CInt64_ShrU(*iterCount, IRO_MakeLong(3));
+ break;
+ case 16:
+ val = CInt64_ShrU(*iterCount, IRO_MakeLong(4));
+ break;
+ default:
+ val = CInt64_Div(*iterCount, strideVal);
+ }
+
+ if (CInt64_LessU(val, IRO_MakeLong(*unrollFactor)))
+ *unrollFactor = CInt64_GetULong(&val);
+
+ CInt64_SetLong(&val2, *unrollFactor);
+ switch (vectorStride) {
+ case 1:
+ val3 = cint64_zero;
+ break;
+ case 2:
+ val3 = CInt64_And(*iterCount, cint64_one);
+ break;
+ case 4:
+ val3 = CInt64_And(*iterCount, IRO_MakeLong(3));
+ break;
+ case 8:
+ val3 = CInt64_And(*iterCount, IRO_MakeLong(7));
+ break;
+ case 16:
+ val3 = CInt64_And(*iterCount, IRO_MakeLong(15));
+ break;
+ default:
+ val3 = CInt64_Mod(*iterCount, strideVal);
+ }
+
+ if (CInt64_LessEqualU(val, IRO_MakeLong(8))) {
+ *needUnrollBodyTest = vectorStride > 1;
+ *unrollFactor = CInt64_GetULong(&val);
+ *leftOver = CInt64_GetULong(&val3);
+ *needOrigLoop = *leftOver != 0;
+ *resetUnrolledFinalValue = !(*needOrigLoop && *needUnrollBodyTest);
+ } else {
+ loopvar1 = IRO_MakeLong(0x7FFFFFFF);
+ loopvar2 = IRO_MakeLong(0x7FFFFFFF);
+ do {
+ mod = CInt64_Mod(val, val2);
+ loopvar3 = CInt64_Add(CInt64_Mul(mod, strideVal), val3);
+ if (CInt64_Less(loopvar3, loopvar2)) {
+ loopvar2 = loopvar3;
+ loopvar1 = val2;
+ }
+ if (vectorStride > 1)
+ break;
+ val2 = CInt64_Add(val2, cint64_negone);
+ } while (CInt64_GreaterEqualU(CInt64_Mul(val2, val2), val));
+
+ *unrollFactor = CInt64_GetULong(&loopvar1);
+ *leftOver = CInt64_GetULong(&loopvar2);
+ *needOrigLoop = *leftOver != 0;
+ *needUnrollBodyTest = CInt64_Less(loopvar1, val) || vectorStride > 1;
+ *resetUnrolledFinalValue = !(*needOrigLoop && *needUnrollBodyTest);
+ }
+ }
+
+ IRO_Dump(
+ "---- IterCount = %d, VectorStride = %d, UnrollFactor = %d, LeftOver = %d,\n"
+ "\tNeedOrigLoop = %d, NeedUnrollBodyTest = %d, ResetUnrolledFinalValue = %d\n",
+ CInt64_GetULong(iterCount), vectorStride, *unrollFactor, *leftOver,
+ *needOrigLoop, *needUnrollBodyTest, *resetUnrolledFinalValue
+ );
+}
+
+IROLinear *BuildOrigIterationCount(IROList *list, IROLoop *loop) {
+ IROLinear *upperBound;
+ IROLinear *nd29b;
+ IROLinear *lowerBound;
+ IROLinear *finalCount;
+ IROLinear *divisor;
+ Type *type;
+ IROLinear *nd25;
+ IROLinear *tmp;
+ Boolean isZeroBase;
+ Object *tempobj;
+ IROLinear *iterCount;
+ IROLinear *negone;
+ IROLinear *ass;
+ ENode *expr;
+ SInt32 powval;
+
+ isZeroBase = 0;
+ lowerBound = loop->nd14->u.diadic.right;
+ if (IRO_IsIntConstant(lowerBound) && CInt64_Equal(lowerBound->u.node->data.intval, cint64_zero))
+ isZeroBase = 1;
+
+ if (!isZeroBase)
+ lowerBound = IRO_DuplicateExpr(lowerBound, list);
+
+ if (loop->flags & LoopFlags_1) {
+ upperBound = IRO_DuplicateExpr(loop->nd18->u.diadic.right, list);
+ type = loop->nd18->u.diadic.right->rtype;
+ } else {
+ upperBound = IRO_DuplicateExpr(loop->nd18->u.diadic.left, list);
+ type = loop->nd18->u.diadic.left->rtype;
+ }
+
+ CError_ASSERT(2924, loop->induction);
+ CError_ASSERT(2929, loop->induction->addConst);
+
+ divisor = IRO_NewLinear(IROLinearOperand);
+ divisor->index = ++IRO_NumLinear;
+ divisor->rtype = type;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = type;
+ CInt64_SetLong(&expr->data.intval, loop->induction->addConst);
+ divisor->u.node = expr;
+
+ if (isZeroBase) {
+ iterCount = upperBound;
+ } else {
+ iterCount = IRO_NewLinear(IROLinearOp2Arg);
+ iterCount->index = ++IRO_NumLinear;
+ iterCount->nodetype = ESUB;
+ iterCount->u.diadic.left = upperBound;
+ iterCount->u.diadic.right = lowerBound;
+ iterCount->rtype = type;
+ IRO_AddToList(iterCount, list);
+ }
+
+ nd25 = IRO_DuplicateExpr(divisor, list);
+
+ nd29b = IRO_NewLinear(IROLinearOp2Arg);
+ nd29b->index = ++IRO_NumLinear;
+ nd29b->nodetype = EADD;
+ nd29b->u.diadic.left = iterCount;
+ nd29b->u.diadic.right = nd25;
+ nd29b->rtype = type;
+ IRO_AddToList(nd29b, list);
+
+ if (loop->nd18->type == IROLinearOp2Arg && loop->nd18->nodetype == ELESS) {
+ tmp = nd29b;
+
+ negone = IRO_NewLinear(IROLinearOperand);
+ negone->index = ++IRO_NumLinear;
+ negone->rtype = type;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = type;
+ CInt64_SetLong(&expr->data.intval, -1);
+ negone->u.node = expr;
+ IRO_AddToList(negone, list);
+
+ nd29b = IRO_NewLinear(IROLinearOp2Arg);
+ nd29b->index = ++IRO_NumLinear;
+ nd29b->nodetype = EADD;
+ nd29b->u.diadic.left = tmp;
+ nd29b->u.diadic.right = negone;
+ nd29b->rtype = type;
+ IRO_AddToList(nd29b, list);
+ }
+
+ if (CInt64_Equal(divisor->u.node->data.intval, cint64_one)) {
+ finalCount = nd29b;
+ } else {
+ if (divisor->rtype->size <= 4 && IS_TYPE_INT(divisor->rtype) && IRO_IsPow2(divisor, &powval)) {
+ finalCount = IRO_NewLinear(IROLinearOp2Arg);
+ finalCount->index = ++IRO_NumLinear;
+ finalCount->nodetype = ESHL;
+ finalCount->u.diadic.left = nd29b;
+ finalCount->u.diadic.right = divisor;
+ CInt64_SetLong(&divisor->u.node->data.intval, powval);
+ finalCount->rtype = type;
+ IRO_AddToList(divisor, list);
+ IRO_AddToList(finalCount, list);
+ } else {
+ finalCount = IRO_NewLinear(IROLinearOp2Arg);
+ finalCount->index = ++IRO_NumLinear;
+ finalCount->nodetype = EDIV;
+ finalCount->u.diadic.left = nd29b;
+ finalCount->u.diadic.right = divisor;
+ finalCount->rtype = type;
+ IRO_AddToList(divisor, list);
+ IRO_AddToList(finalCount, list);
+ }
+ }
+
+ tempobj = create_temp_object(type);
+ IRO_FindVar(tempobj, 1, 1);
+
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->index = ++IRO_NumLinear;
+ ass->nodetype = EASS;
+ ass->u.diadic.left = IRO_TempReference(tempobj, list);
+ ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind;
+ ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind;
+ ass->u.diadic.right = finalCount;
+ ass->u.diadic.right->flags |= IROLF_Reffed;
+ ass->rtype = type;
+ IRO_AddToList(ass, list);
+
+ return ass->u.diadic.left;
+}
+
+static IROLinear *BuildOrigIterationCount_DoWhile(IROList *list, IROLoop *loop) {
+ IROLinear *finalCount;
+ IROLinear *count;
+ IROLinear *ass;
+ Type *type;
+ Object *tempobj;
+ ENode *expr;
+
+ type = loop->nd18->u.diadic.left->rtype;
+
+ count = IRO_NewLinear(IROLinearOperand);
+ count->index = ++IRO_NumLinear;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = type;
+ expr->data.intval = cint64_one;
+ count->u.node = expr;
+ count->rtype = type;
+ IRO_AddToList(count, list);
+ count->flags |= IROLF_Reffed;
+
+ finalCount = IRO_NewLinear(IROLinearOp2Arg);
+ finalCount->index = ++IRO_NumLinear;
+ finalCount->nodetype = EADD;
+ finalCount->rtype = type;
+ finalCount->u.diadic.left = IRO_DuplicateExpr(loop->nd18->u.diadic.left, list);
+ finalCount->u.diadic.left->flags |= IROLF_Reffed;
+ finalCount->u.diadic.left->flags &= ~IROLF_Assigned;
+ finalCount->u.diadic.left->u.monadic->flags &= ~IROLF_Assigned;
+ finalCount->u.diadic.right = count;
+ IRO_AddToList(finalCount, list);
+
+ tempobj = create_temp_object(type);
+ IRO_FindVar(tempobj, 1, 1);
+
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->index = ++IRO_NumLinear;
+ ass->nodetype = EASS;
+ ass->u.diadic.left = IRO_TempReference(tempobj, list);
+ ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind;
+ ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind;
+ ass->u.diadic.right = finalCount;
+ ass->rtype = type;
+ IRO_AddToList(ass, list);
+
+ return ass->u.diadic.left;
+}
+
+IROLinear *BuildNewFinalvalue(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop) {
+ IROLinear *sub;
+ IROLinear *addvalue;
+ Type *type;
+ IROLinear *ass;
+ IROLinear *dupbound;
+ Object *tempobj;
+ ENode *expr;
+
+ type = iterCount->rtype;
+
+ addvalue = IRO_NewLinear(IROLinearOperand);
+ addvalue->index = ++IRO_NumLinear;
+ addvalue->rtype = type;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = type;
+ CInt64_SetLong(&expr->data.intval, loop->induction->addConst * unrollFactor);
+ addvalue->u.node = expr;
+ IRO_AddToList(addvalue, list);
+
+ if (loop->flags & LoopFlags_1)
+ dupbound = IRO_DuplicateExpr(loop->nd18->u.diadic.right, list);
+ else
+ dupbound = IRO_DuplicateExpr(loop->nd18->u.diadic.left, list);
+
+ sub = IRO_NewLinear(IROLinearOp2Arg);
+ sub->index = ++IRO_NumLinear;
+ sub->nodetype = ESUB;
+ sub->u.diadic.left = dupbound;
+ sub->u.diadic.right = addvalue;
+ sub->rtype = type;
+ IRO_AddToList(sub, list);
+
+ tempobj = create_temp_object(type);
+ IRO_FindVar(tempobj, 1, 1);
+
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->index = ++IRO_NumLinear;
+ ass->nodetype = EASS;
+ ass->u.diadic.left = IRO_TempReference(tempobj, list);
+ ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind;
+ ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind;
+ ass->u.diadic.right = sub;
+ ass->u.diadic.right->flags |= IROLF_Reffed;
+ ass->rtype = type;
+ IRO_AddToList(ass, list);
+
+ return ass->u.diadic.left;
+}
+
+static IROLinear *BuildPreAlignTemp(IROLoopInd *ind, UInt32 unrollFactor, IROList *list) {
+ Type *type;
+ IROLinear *indnd;
+ IROLinear *factornd;
+ IROLinear *div;
+ IROLinear *constnd;
+ IROLinear *add;
+ IROLinear *mul;
+ IROLinear *ass;
+ Object *tempobj;
+ ENode *expr;
+
+ indnd = ind->nd;
+ type = indnd->rtype;
+
+ factornd = IRO_NewLinear(IROLinearOperand);
+ factornd->index = ++IRO_NumLinear;
+ factornd->rtype = type;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = type;
+ CInt64_SetLong(&expr->data.intval, unrollFactor);
+ factornd->u.node = expr;
+ IRO_AddToList(factornd, list);
+
+ if (indnd->type == IROLinearOp1Arg)
+ IRO_DuplicateExpr(indnd->u.monadic, list);
+ else
+ IRO_DuplicateExpr(indnd->u.diadic.left, list);
+
+ list->tail->flags &= ~IROLF_Assigned;
+ list->tail->u.monadic->flags &= ~IROLF_Assigned;
+
+ div = IRO_NewLinear(IROLinearOp2Arg);
+ div->index = ++IRO_NumLinear;
+ div->nodetype = EDIV;
+ div->u.diadic.left = list->tail;
+ div->u.diadic.right = factornd;
+ div->rtype = type;
+ IRO_AddToList(div, list);
+ div->flags |= IROLF_Reffed;
+
+ constnd = IRO_NewLinear(IROLinearOperand);
+ constnd->index = ++IRO_NumLinear;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = type;
+ expr->data.intval = cint64_one;
+ constnd->u.node = expr;
+ constnd->rtype = type;
+ IRO_AddToList(constnd, list);
+ constnd->flags |= IROLF_Reffed;
+
+ add = IRO_NewLinear(IROLinearOp2Arg);
+ add->index = ++IRO_NumLinear;
+ add->nodetype = EADD;
+ add->u.diadic.left = div;
+ add->u.diadic.right = constnd;
+ add->rtype = type;
+ IRO_AddToList(add, list);
+ add->flags |= IROLF_Reffed;
+
+ IRO_DuplicateExpr(factornd, list);
+
+ mul = IRO_NewLinear(IROLinearOp2Arg);
+ mul->index = ++IRO_NumLinear;
+ mul->nodetype = EMUL;
+ mul->u.diadic.left = add;
+ mul->u.diadic.right = list->tail;
+ mul->rtype = type;
+ IRO_AddToList(mul, list);
+ mul->flags |= IROLF_Reffed;
+
+ tempobj = create_temp_object(type);
+ IRO_FindVar(tempobj, 1, 1);
+
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->index = ++IRO_NumLinear;
+ ass->nodetype = EASS;
+ ass->u.diadic.left = IRO_TempReference(tempobj, list);
+ ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind;
+ ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind;
+ ass->u.diadic.right = mul;
+ ass->u.diadic.right->flags |= IROLF_Reffed;
+ ass->rtype = type;
+ IRO_AddToList(ass, list);
+
+ return ass->u.diadic.left;
+}
+
+static IROLinear *BuildNewFinalvalue_DoWhile(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop) {
+ IROLinear *addvalue;
+ IROLinear *add;
+ IROLinear *mul;
+ IROLinear *ass;
+ Type *type;
+ Object *tempobj;
+ ENode *expr;
+
+ type = iterCount->rtype;
+
+ addvalue = IRO_NewLinear(IROLinearOperand);
+ addvalue->index = ++IRO_NumLinear;
+ addvalue->rtype = type;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = type;
+ CInt64_SetLong(&expr->data.intval, loop->induction->addConst);
+ addvalue->u.node = expr;
+ IRO_AddToList(addvalue, list);
+ addvalue->flags |= IROLF_Reffed;
+
+ mul = IRO_NewLinear(IROLinearOp2Arg);
+ mul->index = ++IRO_NumLinear;
+ mul->nodetype = EMUL;
+ mul->u.diadic.left = IRO_DuplicateExpr(iterCount, list);
+ mul->u.diadic.right = addvalue;
+ mul->rtype = type;
+ IRO_AddToList(mul, list);
+ mul->flags |= IROLF_Reffed;
+ mul->u.diadic.left->flags &= ~IROLF_Assigned;
+ mul->u.diadic.left->u.diadic.left->flags &= ~IROLF_Assigned;
+
+ if (loop->induction->nd->type == IROLinearOp1Arg)
+ IRO_DuplicateExpr(loop->induction->nd->u.monadic, list);
+ else
+ IRO_DuplicateExpr(loop->induction->nd->u.diadic.left, list);
+ list->tail->flags &= ~IROLF_Assigned;
+ list->tail->u.diadic.left->flags &= ~IROLF_Assigned;
+
+ add = IRO_NewLinear(IROLinearOp2Arg);
+ add->index = ++IRO_NumLinear;
+ add->nodetype = EADD;
+ add->u.diadic.left = mul;
+ add->u.diadic.right = list->tail;
+ add->rtype = type;
+ IRO_AddToList(add, list);
+ add->flags |= IROLF_Reffed;
+
+ tempobj = create_temp_object(type);
+ IRO_FindVar(tempobj, 1, 1);
+
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->index = ++IRO_NumLinear;
+ ass->nodetype = EASS;
+ ass->u.diadic.left = IRO_TempReference(tempobj, list);
+ ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind;
+ ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind;
+ ass->u.diadic.right = add;
+ ass->u.diadic.right->flags |= IROLF_Reffed;
+ ass->rtype = type;
+ IRO_AddToList(ass, list);
+
+ return ass->u.diadic.left;
+}
+
+static IROLinear *BuildUnrolledFinalvalue_DoWhile(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop) {
+ IROLinear *addvalue_mult;
+ IROLinear *addvalue;
+ IROLinear *mul;
+ IROLinear *sub;
+ IROLinear *add;
+ IROLinear *ass;
+ Type *type;
+ Object *tempobj;
+ ENode *expr;
+
+ type = iterCount->rtype;
+
+ addvalue_mult = IRO_NewLinear(IROLinearOperand);
+ addvalue_mult->index = ++IRO_NumLinear;
+ addvalue_mult->rtype = type;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = type;
+ CInt64_SetLong(&expr->data.intval, loop->induction->addConst * unrollFactor);
+ addvalue_mult->u.node = expr;
+ IRO_AddToList(addvalue_mult, list);
+ addvalue_mult->flags |= IROLF_Reffed;
+
+ addvalue = IRO_NewLinear(IROLinearOperand);
+ addvalue->index = ++IRO_NumLinear;
+ addvalue->rtype = type;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = type;
+ CInt64_SetLong(&expr->data.intval, loop->induction->addConst);
+ addvalue->u.node = expr;
+ IRO_AddToList(addvalue, list);
+ addvalue->flags |= IROLF_Reffed;
+
+ mul = IRO_NewLinear(IROLinearOp2Arg);
+ mul->index = ++IRO_NumLinear;
+ mul->nodetype = EMUL;
+ mul->u.diadic.left = IRO_DuplicateExpr(iterCount, list);
+ mul->u.diadic.right = addvalue;
+ mul->rtype = type;
+ IRO_AddToList(mul, list);
+ mul->flags |= IROLF_Reffed;
+ mul->u.diadic.left->flags &= ~IROLF_Assigned;
+ mul->u.diadic.left->u.diadic.left->flags &= ~IROLF_Assigned;
+
+ sub = IRO_NewLinear(IROLinearOp2Arg);
+ sub->index = ++IRO_NumLinear;
+ sub->nodetype = ESUB;
+ sub->u.diadic.left = mul;
+ sub->u.diadic.right = addvalue_mult;
+ sub->rtype = type;
+ IRO_AddToList(sub, list);
+ sub->flags |= IROLF_Reffed;
+
+ if (loop->induction->nd->type == IROLinearOp1Arg)
+ IRO_DuplicateExpr(loop->induction->nd->u.monadic, list);
+ else
+ IRO_DuplicateExpr(loop->induction->nd->u.diadic.left, list);
+ list->tail->flags &= ~IROLF_Assigned;
+ list->tail->u.diadic.left->flags &= ~IROLF_Assigned;
+
+ add = IRO_NewLinear(IROLinearOp2Arg);
+ add->index = ++IRO_NumLinear;
+ add->nodetype = EADD;
+ add->u.diadic.left = sub;
+ add->u.diadic.right = list->tail;
+ add->rtype = type;
+ IRO_AddToList(add, list);
+ add->flags |= IROLF_Reffed;
+
+ tempobj = create_temp_object(type);
+ IRO_FindVar(tempobj, 1, 1);
+
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->index = ++IRO_NumLinear;
+ ass->nodetype = EASS;
+ ass->u.diadic.left = IRO_TempReference(tempobj, list);
+ ass->u.diadic.left->flags |= IROLF_Assigned | IROLF_Ind;
+ ass->u.diadic.left->u.monadic->flags |= IROLF_Assigned | IROLF_Ind;
+ ass->u.diadic.right = add;
+ ass->u.diadic.right->flags |= IROLF_Reffed;
+ ass->rtype = type;
+ IRO_AddToList(ass, list);
+
+ return ass->u.diadic.left;
+}
+
+void BuildUnrolledBodyEntryTest(IROList *list, IROLinear *iterCount, UInt32 unrollFactor, CLabel *label) {
+ Type *type;
+ IROLinear *ifnot;
+ IROLinear *comp;
+ IROLinear *var;
+ IROLinear *value;
+ ENode *expr;
+
+ type = iterCount->rtype;
+
+ value = IRO_NewLinear(IROLinearOperand);
+ value->index = ++IRO_NumLinear;
+ value->rtype = type;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = type;
+ CInt64_SetLong(&expr->data.intval, unrollFactor);
+ value->u.node = expr;
+ IRO_AddToList(value, list);
+
+ var = IRO_DuplicateExpr(iterCount, list);
+
+ comp = IRO_NewLinear(IROLinearOp2Arg);
+ comp->index = ++IRO_NumLinear;
+ comp->nodetype = EGREATER;
+ comp->u.diadic.left = var;
+ comp->u.diadic.right = value;
+ comp->u.diadic.right->flags |= IROLF_Reffed;
+ comp->rtype = type;
+ IRO_AddToList(comp, list);
+
+ ifnot = IRO_NewLinear(IROLinearOp1Arg);
+ ifnot->index = ++IRO_NumLinear;
+ ifnot->type = IROLinearIfNot;
+ ifnot->u.label.x4 = comp;
+ ifnot->u.label.x4->flags |= IROLF_Reffed;
+ ifnot->rtype = type;
+ ifnot->u.label.label = label;
+ IRO_AddToList(ifnot, list);
+}
+
+void ChangeInductionReference(IROLinear *first, IROLinear *last, CInt64 val, IROLoop *loop) {
+ IROLinear *nd;
+ IROLinear *value;
+ IROLinear *add;
+ UInt32 isUnsigned;
+ IROLinear *father;
+ Boolean flag;
+ IROLinear *father2;
+ IROLinear *father3;
+ Type *tmp;
+ UInt32 flag2;
+ Object *varobj;
+ IROLinear *next;
+ ENode *expr;
+ Type *type;
+
+ CInt64 val2;
+ CInt64 val1;
+ IROList list;
+
+ type = loop->induction->nd->rtype;
+ isUnsigned = IRO_IsUnsignedType(type);
+
+ for (nd = first; nd; nd = next) {
+ next = nd->next;
+
+ varobj = IRO_IsVariable(nd);
+ if (varobj && loop->induction->var->object == varobj) {
+ value = IRO_NewLinear(IROLinearOperand);
+ value->index = ++IRO_NumLinear;
+ value->rtype = type;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = type;
+ expr->data.intval = val;
+ value->u.node = expr;
+
+ add = IRO_NewLinear(IROLinearOp2Arg);
+ add->index = ++IRO_NumLinear;
+ add->nodetype = EADD;
+ add->rtype = type;
+
+ father = IRO_LocateFather(nd);
+ flag = 1;
+ if (father && IS_LINEAR_MONADIC(father, ETYPCON)) {
+ tmp = father->rtype;
+ father = IRO_LocateFather(father);
+ if (tmp->type != nd->rtype->type || tmp->size < nd->rtype->size)
+ flag = 0;
+ }
+
+ flag2 = 0;
+ if (
+ flag &&
+ father &&
+ IS_LINEAR_DIADIC_2(father, ESHL, EMUL) &&
+ IRO_IsIntConstant(father->u.diadic.right) &&
+ (father2 = IRO_LocateFather(father)) &&
+ IS_LINEAR_DIADIC(father2, EADD) &&
+ father2->u.diadic.right == father &&
+ (father3 = IRO_LocateFather(father2))
+ )
+ {
+ IRO_InitList(&list);
+ val2 = father->u.diadic.right->u.node->data.intval;
+ if (father->nodetype == ESHL)
+ val2 = CInt64_Shl(cint64_one, val2);
+
+ val1 = value->u.node->data.intval;
+ if (isUnsigned)
+ val1 = CInt64_MulU(val2, val1);
+ else
+ val1 = CInt64_Mul(val2, val1);
+ value->u.node->data.intval = val1;
+
+ IRO_AddToList(value, &list);
+ IRO_AddToList(add, &list);
+ add->u.diadic.right = value;
+ IRO_Paste(list.head, list.tail, father3);
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(father2, add);
+ add->u.diadic.left = father2;
+ add->rtype = father2->rtype;
+ flag2 = 1;
+ }
+
+ if (!flag2) {
+ add->u.diadic.right = value;
+ add->u.diadic.right->flags |= IROLF_Reffed;
+ value->next = add;
+
+ add->u.diadic.left = nd;
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(nd, add);
+ add->flags |= IROLF_Reffed;
+
+ nd->next = value;
+ add->next = next;
+ }
+ }
+
+ if (nd == last)
+ break;
+ }
+}
+
+IROLinear *UpdateInductionIncrement(IROLoop *loop, SInt32 value, IROLinear *before) {
+ IROLinear *ind_nd;
+ IROLinear *addvalue;
+ IROLinear *ass;
+ Type *type;
+ ENode *expr;
+ IROList list;
+
+ IRO_InitList(&list);
+ ind_nd = loop->induction->nd;
+ type = ind_nd->rtype;
+
+ addvalue = IRO_NewLinear(IROLinearOperand);
+ addvalue->index = ++IRO_NumLinear;
+ addvalue->rtype = type;
+ expr = IRO_NewENode(EINTCONST);
+ expr->rtype = type;
+ CInt64_SetLong(&expr->data.intval, value * loop->induction->addConst);
+ addvalue->u.node = expr;
+ IRO_AddToList(addvalue, &list);
+
+ if (IS_LINEAR_MONADIC_2(ind_nd, EPREINC, EPOSTINC)) {
+ ind_nd = IRO_DuplicateExpr(ind_nd->u.monadic, &list);
+
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->index = ++IRO_NumLinear;
+ ass->nodetype = EADDASS;
+ ass->u.diadic.left = ind_nd;
+ ass->u.diadic.right = addvalue;
+ ass->rtype = type;
+ IRO_AddToList(ass, &list);
+ } else if (IS_LINEAR_MONADIC_2(ind_nd, EPREDEC, EPOSTDEC)) {
+ ind_nd = IRO_DuplicateExpr(ind_nd->u.monadic, &list);
+
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->index = ++IRO_NumLinear;
+ ass->nodetype = ESUBASS;
+ ass->u.diadic.left = ind_nd;
+ ass->u.diadic.right = addvalue;
+ ass->rtype = type;
+ IRO_AddToList(ass, &list);
+ } else if (IS_LINEAR_DIADIC(ind_nd, EADDASS)) {
+ ind_nd = IRO_DuplicateExpr(ind_nd->u.monadic, &list);
+
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->index = ++IRO_NumLinear;
+ ass->nodetype = EADDASS;
+ ass->u.diadic.left = ind_nd;
+ ass->u.diadic.right = addvalue;
+ ass->rtype = type;
+ IRO_AddToList(ass, &list);
+ }
+
+ IRO_Paste(list.head, list.tail, before);
+ return list.tail;
+}
+
+void GenInitialAssignment(IROLoop *loop, Object *var, IROList *list) {
+ Type *type;
+ IROLinear *nd;
+
+ CError_ASSERT(3924, loop->nd14 && loop->nd14->type == IROLinearOp2Arg);
+
+ type = loop->induction->nd->rtype;
+
+ nd = IRO_NewLinear(IROLinearOp2Arg);
+ nd->index = ++IRO_NumLinear;
+ nd->nodetype = EASS;
+ nd->u.diadic.left = IRO_TempReference(var, list);
+ nd->u.diadic.right = IRO_DuplicateExpr(loop->nd14->u.diadic.right, list);
+ nd->rtype = type;
+ IRO_AddToList(nd, list);
+}
+
+void GenNewInduction(void) {
+ CError_FATAL(3941);
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.h b/compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.h
new file mode 100644
index 0000000..fd4972b
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroUnrollLoop.h
@@ -0,0 +1,23 @@
+#ifndef COMPILER_IROUNROLLLOOP_H
+#define COMPILER_IROUNROLLLOOP_H
+
+#include "IrOptimizer.h"
+#include "IroLinearForm.h"
+
+extern void IRO_LoopUnroller(void);
+extern void IRO_IterateForLoopBody(IRONode *start, IRONode *end, IROLoop *loop, IROLinear *destnode, SInt32 addConst, CInt64 *val, Boolean funkyFlag);
+extern void IRO_LinearizeForLoopPostLoop(IRONode *fnode1, IRONode *fnode2, IROLoop *loop, IRONode *fnode3, UInt32 unrollFactor);
+extern IROLinear *BuildEarlyLoopExitTest(IROLinearType type, IROList *list);
+extern IROLinear *BuildLoopExitTest(IROLinearType type, IROList *list);
+extern int IsIterationCountConstant(IROLoop *loop, CInt64 *pval);
+extern void NoOpBlock(IRONode *fnode);
+extern void IRO_TestConstantIterationCount(IROLoop *loop, CInt64 *iterCount, SInt32 vectorStride, UInt32 *unrollFactor, SInt32 *leftOver, UInt32 *needOrigLoop, UInt32 *needUnrollBodyTest, UInt32 *resetUnrolledFinalValue);
+extern IROLinear *BuildOrigIterationCount(IROList *list, IROLoop *loop);
+extern IROLinear *BuildNewFinalvalue(IROLinear *iterCount, UInt32 unrollFactor, IROList *list, IROLoop *loop);
+extern void BuildUnrolledBodyEntryTest(IROList *list, IROLinear *iterCount, UInt32 unrollFactor, CLabel *label);
+extern void ChangeInductionReference(IROLinear *first, IROLinear *last, CInt64 val, IROLoop *loop);
+extern IROLinear *UpdateInductionIncrement(IROLoop *loop, SInt32 value, IROLinear *before);
+extern void GenInitialAssignment(IROLoop *loop, Object *var, IROList *list);
+extern void GenNewInduction(void);
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroUtil.c b/compiler_and_linker/FrontEnd/Optimizer/IroUtil.c
new file mode 100644
index 0000000..7e6321d
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroUtil.c
@@ -0,0 +1,1262 @@
+#include "IroUtil.h"
+#include "IroCSE.h"
+#include "IroDump.h"
+#include "IroFlowgraph.h"
+#include "IroLinearForm.h"
+#include "IroLoop.h"
+#include "IroVars.h"
+#include "compiler/InlineAsmPPC.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/CCompiler.h"
+#include "compiler/CError.h"
+#include "compiler/CException.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/Exceptions.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+#include "cos.h"
+
+static UInt32 IRO_LastUserBreakTick;
+static IROLinear *ExprStart;
+static IROLinear *ExprEnd;
+static IRONode *IRO_Node;
+static SInt32 FuncLevel;
+Object *FunctionName;
+Boolean IRO_IsLeafFunction;
+Boolean IRO_FunctionHasReturn;
+Boolean DisableDueToAsm;
+Boolean LoopOptimizerRun;
+
+Object *IRO_IsVariable(IROLinear *linear) {
+ if (linear->type == IROLinearOp1Arg &&
+ linear->nodetype == EINDIRECT &&
+ linear->u.monadic->type == IROLinearOperand &&
+ linear->u.monadic->u.node->type == EOBJREF)
+ return linear->u.monadic->u.node->data.objref;
+
+ return NULL;
+}
+
+Boolean IRO_IsConstant(IROLinear *linear) {
+ if (linear->type == IROLinearOperand && ENODE_IS3(linear->u.node, EINTCONST, EVECTOR128CONST, EFLOATCONST))
+ return 1;
+ return 0;
+}
+
+Boolean IRO_IsPow2(IROLinear *linear, SInt32 *powvalue) {
+ UInt32 desired;
+ UInt32 value;
+ SInt32 i;
+
+ *powvalue = -1;
+ if (linear->type == IROLinearOperand && linear->u.node->type == EINTCONST) {
+ if (CTool_EndianReadWord32(&linear->u.node->data.intval.hi))
+ return 0;
+
+ desired = CInt64_GetULong(&linear->u.node->data.intval);
+ value = 1;
+ for (i = 0; i < 31; i++) {
+ if (value == desired) {
+ *powvalue = i;
+ return 1;
+ }
+ value += value;
+ }
+ }
+
+ return 0;
+}
+
+Boolean IRO_IsIntConstant(IROLinear *linear) {
+ if (linear->type == IROLinearOperand && ENODE_IS(linear->u.node, EINTCONST))
+ return 1;
+ return 0;
+}
+
+Boolean IRO_IsFloatConstant(IROLinear *linear) {
+ if (linear->type == IROLinearOperand && ENODE_IS(linear->u.node, EFLOATCONST))
+ return 1;
+ return 0;
+}
+
+Boolean IRO_IsVector128Constant(IROLinear *linear) {
+ if (linear->type == IROLinearOperand && ENODE_IS(linear->u.node, EVECTOR128CONST))
+ return 1;
+ return 0;
+}
+
+Boolean IRO_IsAssignment(IROLinear *linear) {
+ if (linear->type == IROLinearOp1Arg || linear->type == IROLinearOp2Arg) {
+ if (IRO_IsAssignOp[linear->nodetype])
+ return 1;
+ }
+ return 0;
+}
+
+static Boolean IRO_OperandsSame(ENode *a, ENode *b) {
+ if (a->type == b->type) {
+ switch (a->type) {
+ case EINTCONST:
+ return CInt64_Equal(a->data.intval, b->data.intval);
+ case ESTRINGCONST:
+ return 0;
+ case EFLOATCONST:
+ return a->data.floatval.value == b->data.floatval.value;
+ case EVECTOR128CONST:
+ return (a->data.vector128val.ul[0] == b->data.vector128val.ul[0]) &&
+ (a->data.vector128val.ul[1] == b->data.vector128val.ul[1]) &&
+ (a->data.vector128val.ul[2] == b->data.vector128val.ul[2]) &&
+ (a->data.vector128val.ul[3] == b->data.vector128val.ul[3]);
+ case EOBJREF:
+ return a->data.objref == b->data.objref;
+ }
+ }
+
+ return 0;
+}
+
+Boolean IRO_TypesEqual(Type *a, Type *b) {
+ if (IS_TYPE_BITFIELD(a)) {
+ if (IS_TYPE_BITFIELD(b)) {
+ if (
+ (TYPE_BITFIELD(a)->bitfieldtype == TYPE_BITFIELD(b)->bitfieldtype) &&
+ (TYPE_BITFIELD(a)->offset == TYPE_BITFIELD(b)->offset) &&
+ (TYPE_BITFIELD(a)->bitlength == TYPE_BITFIELD(b)->bitlength))
+ return 1;
+ }
+ return 0;
+ }
+
+ if (IS_TYPE_POINTER_ONLY(a) && IS_TYPE_POINTER_ONLY(b))
+ return 1;
+
+ return is_typeequal(a, b) != 0;
+}
+
+Type *IRO_UnsignedType(Type *type) {
+ if (IS_TYPE_ENUM(type) || IS_TYPE_POINTER_ONLY(type)) {
+ if (type->size == stunsignedchar.size)
+ return TYPE(&stunsignedchar);
+ if (type->size == stunsignedint.size)
+ return TYPE(&stunsignedint);
+ if (type->size == stunsignedshort.size)
+ return TYPE(&stunsignedshort);
+ if (type->size == stunsignedlong.size)
+ return TYPE(&stunsignedlong);
+ if (type->size == stunsignedlonglong.size)
+ return TYPE(&stunsignedlonglong);
+ CError_FATAL(281);
+ return NULL;
+ }
+
+ if (!IS_TYPE_INT(type)) {
+ CError_FATAL(287);
+ return NULL;
+ }
+
+ if (type == TYPE(&stbool) || type == TYPE(&stwchar))
+ return type;
+
+ if (type == TYPE(&stchar) || type == TYPE(&stsignedchar) || type == TYPE(&stunsignedchar))
+ return TYPE(&stunsignedchar);
+ if (type == TYPE(&stsignedshort) || type == TYPE(&stunsignedshort))
+ return TYPE(&stunsignedshort);
+ if (type == TYPE(&stsignedint) || type == TYPE(&stunsignedint))
+ return TYPE(&stunsignedint);
+ if (type == TYPE(&stsignedlong) || type == TYPE(&stunsignedlong))
+ return TYPE(&stunsignedlong);
+ if (type == TYPE(&stsignedlonglong) || type == TYPE(&stunsignedlonglong))
+ return TYPE(&stunsignedlonglong);
+
+ CError_FATAL(319);
+ return NULL;
+}
+
+Type *IRO_SignedType(Type *type) {
+ if (IS_TYPE_ENUM(type) || IS_TYPE_POINTER_ONLY(type)) {
+ if (type->size == stsignedchar.size)
+ return TYPE(&stsignedchar);
+ if (type->size == stsignedint.size)
+ return TYPE(&stsignedint);
+ if (type->size == stsignedshort.size)
+ return TYPE(&stsignedshort);
+ if (type->size == stsignedlong.size)
+ return TYPE(&stsignedlong);
+ if (type->size == stsignedlonglong.size)
+ return TYPE(&stsignedlonglong);
+ CError_FATAL(357);
+ return NULL;
+ }
+
+ if (!IS_TYPE_INT(type)) {
+ CError_FATAL(363);
+ return NULL;
+ }
+
+ if (type == TYPE(&stbool) && type->size == stsignedchar.size)
+ return TYPE(&stsignedchar);
+
+ if (type == TYPE(&stwchar) && type->size == stsignedshort.size)
+ return TYPE(&stsignedshort);
+
+ if (type == TYPE(&stchar) || type == TYPE(&stsignedchar) || type == TYPE(&stunsignedchar))
+ return TYPE(&stsignedchar);
+ if (type == TYPE(&stsignedshort) || type == TYPE(&stunsignedshort))
+ return TYPE(&stsignedshort);
+ if (type == TYPE(&stsignedint) || type == TYPE(&stunsignedint))
+ return TYPE(&stsignedint);
+ if (type == TYPE(&stsignedlong) || type == TYPE(&stunsignedlong))
+ return TYPE(&stsignedlong);
+ if (type == TYPE(&stsignedlonglong) || type == TYPE(&stunsignedlonglong))
+ return TYPE(&stsignedlonglong);
+
+ CError_FATAL(399);
+ return NULL;
+}
+
+Boolean IRO_is_CPtypeequal(Type *a, Type *b) {
+ if (IS_TYPE_POINTER_ONLY(a) && IS_TYPE_POINTER_ONLY(b))
+ return 1;
+
+ return is_typeequal(a, b) != 0;
+}
+
+Boolean IRO_ExprsSame(IROLinear *a, IROLinear *b) {
+ if (a->type == b->type && IRO_TypesEqual(a->rtype, b->rtype)) {
+ switch (a->type) {
+ case IROLinearOperand:
+ return IRO_OperandsSame(a->u.node, b->u.node);
+ case IROLinearOp1Arg:
+ if (a->nodetype == b->nodetype)
+ return IRO_ExprsSame(a->u.monadic, b->u.monadic);
+ return 0;
+ case IROLinearOp2Arg:
+ if (a->nodetype == b->nodetype)
+ return IRO_ExprsSame(a->u.diadic.left, b->u.diadic.left) &&
+ IRO_ExprsSame(a->u.diadic.right, b->u.diadic.right);
+ return 0;
+ case IROLinearOp3Arg:
+ if (a->nodetype == b->nodetype)
+ return IRO_ExprsSame(a->u.args3.a, b->u.args3.a) &&
+ IRO_ExprsSame(a->u.args3.b, b->u.args3.b) &&
+ IRO_ExprsSame(a->u.args3.c, b->u.args3.c);
+ return 0;
+ case IROLinearFunccall:
+ return 0;
+ default:
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+CLabel *IRO_NewLabel(void) {
+ CLabel *label = newlabel();
+ label->next = Labels;
+ Labels = label;
+ return label;
+}
+
+Boolean IRO_ExprsSameSemantically(IROLinear *a, IROLinear *b) {
+ if (a->type == b->type && IRO_TypesEqual(a->rtype, b->rtype)) {
+ Boolean flag = 0;
+
+ switch (a->type) {
+ case IROLinearOperand:
+ return IRO_OperandsSame(a->u.node, b->u.node);
+ case IROLinearOp1Arg:
+ if (a->nodetype == b->nodetype)
+ return IRO_ExprsSameSemantically(a->u.monadic, b->u.monadic);
+ return 0;
+ case IROLinearOp2Arg:
+ if (a->nodetype == b->nodetype) {
+ switch (a->nodetype) {
+ case EMUL:
+ case EADD:
+ case EAND:
+ case EXOR:
+ case EOR:
+ case ELAND:
+ case ELOR:
+ if (!IRO_HasSideEffect(a)) {
+ flag = IRO_ExprsSameSemantically(a->u.diadic.left, b->u.diadic.right) &&
+ IRO_ExprsSameSemantically(a->u.diadic.right, b->u.diadic.left);
+ }
+ }
+
+ return flag || (IRO_ExprsSameSemantically(a->u.diadic.left, b->u.diadic.left) &&
+ IRO_ExprsSameSemantically(a->u.diadic.right, b->u.diadic.right));
+ }
+ return 0;
+ case IROLinearOp3Arg:
+ if (a->nodetype == b->nodetype)
+ return IRO_ExprsSameSemantically(a->u.args3.a, b->u.args3.a) &&
+ IRO_ExprsSameSemantically(a->u.args3.b, b->u.args3.b) &&
+ IRO_ExprsSameSemantically(a->u.args3.c, b->u.args3.c);
+ return 0;
+ case IROLinearFunccall:
+ return 0;
+ default:
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+IROLinear *IRO_FindPrecedAfter(IROLinear *a, IROLinear *iter) {
+ IROLinear *prev = iter;
+ while (iter && iter != a) {
+ prev = iter;
+ iter = iter->next;
+ }
+
+ if (iter)
+ return prev;
+ return iter;
+}
+
+IROLinear *IRO_FindPreced(IROLinear *a) {
+ IROLinear *iter;
+ IROLinear *prev;
+
+ prev = iter = IRO_FirstLinear;
+ while (iter && iter != a) {
+ prev = iter;
+ iter = iter->next;
+ }
+
+ if (iter)
+ return prev;
+ return iter;
+}
+
+IROLinear *IRO_FindFirst(IROLinear *linear) {
+ short i;
+
+ switch (linear->type) {
+ case IROLinearOperand:
+ return linear;
+ case IROLinearOp1Arg:
+ return IRO_FindFirst(linear->u.monadic);
+ case IROLinearOp2Arg:
+ if (linear->u.diadic.right->index < linear->u.diadic.left->index)
+ return IRO_FindFirst(linear->u.diadic.right);
+ else
+ return IRO_FindFirst(linear->u.diadic.left);
+ case IROLinearOp3Arg:
+ if (linear->u.args3.a->index < linear->u.args3.b->index) {
+ if (linear->u.args3.b->index < linear->u.args3.c->index)
+ return IRO_FindFirst(linear->u.args3.a);
+ else
+ return IRO_FindFirst(linear->u.args3.c);
+ } else {
+ if (linear->u.args3.b->index < linear->u.args3.c->index)
+ return IRO_FindFirst(linear->u.args3.b);
+ else
+ return IRO_FindFirst(linear->u.args3.c);
+ }
+ case IROLinearFunccall:
+ i = linear->u.funccall.argCount - 1;
+ return IRO_FindFirst(linear->u.funccall.args[i]);
+ default:
+ CError_FATAL(641);
+ return NULL;
+ }
+}
+
+void IRO_CutAndPasteAfter(IROLinear *a, IROLinear *b, IROLinear *c) {
+ IROLinear *preced = IRO_FindPreced(a);
+ preced->next = b->next;
+ b->next = c->next;
+ c->next = a;
+}
+
+Boolean IRO_IsConstantZero(IROLinear *linear) {
+ return (IRO_IsIntConstant(linear) && CInt64_IsZero(&linear->u.node->data.intval)) ||
+ (IRO_IsFloatConstant(linear) && CMach_FloatIsZero(linear->u.node->data.floatval));
+}
+
+Boolean IRO_IsConstantOne(IROLinear *linear) {
+ return (IRO_IsIntConstant(linear) && CInt64_IsOne(&linear->u.node->data.intval)) ||
+ (IRO_IsFloatConstant(linear) && CMach_FloatIsOne(linear->u.node->data.floatval));
+}
+
+Boolean IRO_IsConstantNegativeOne(IROLinear *linear) {
+ CInt64 neg = CInt64_Neg(linear->u.node->data.intval);
+ return (IRO_IsIntConstant(linear) && CInt64_IsOne(&neg)) ||
+ (IRO_IsFloatConstant(linear) && CMach_FloatIsNegOne(linear->u.node->data.floatval));
+}
+
+static void ActNop(IROLinear *linear, Boolean isEntry) {
+ if (!isEntry) {
+ linear->type = IROLinearNop;
+ linear->expr = NULL;
+ }
+}
+
+void IRO_NopOut(IROLinear *linear) {
+ IRO_WalkTree(linear, ActNop);
+}
+
+static Boolean NotNoppable(IROLinear *linear) {
+ return (
+ (linear->type == IROLinearFunccall) ||
+ IRO_IsAssignment(linear) ||
+ ((linear->type == IROLinearOperand) && ENODE_IS(linear->u.node, EINSTRUCTION)) ||
+ (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) ||
+ ((linear->type == IROLinearOperand) && ENODE_IS(linear->u.node, EOBJREF) && is_volatile_object(linear->u.node->data.objref))
+ );
+}
+
+static void ActNopNonSideEffects(IROLinear *linear, Boolean isEntry) {
+ if (isEntry) {
+ if (NotNoppable(linear)) {
+ if (!FuncLevel)
+ linear->flags &= ~IROLF_Reffed;
+ FuncLevel++;
+ }
+ } else {
+ if (NotNoppable(linear)) {
+ FuncLevel--;
+ } else if (!FuncLevel) {
+ linear->type = IROLinearNop;
+ }
+ }
+}
+
+void IRO_NopNonSideEffects(IROLinear *linear, SInt32 level) {
+ FuncLevel = level;
+ IRO_WalkTree(linear, ActNopNonSideEffects);
+}
+
+void IRO_BuildList(IROLinear *linear, Boolean isEntry) {
+ if (!isEntry) {
+ linear->next = NULL;
+ IRO_AddToList(linear, &IRO_InitLList);
+ }
+}
+
+void IRO_WalkTree(IROLinear *linear, IROWalkTreeFunc func) {
+ int i;
+
+ func(linear, 1);
+ switch (linear->type) {
+ case IROLinearOperand:
+ break;
+ case IROLinearOp1Arg:
+ IRO_WalkTree(linear->u.monadic, func);
+ break;
+ case IROLinearOp2Arg:
+ IRO_WalkTree(linear->u.diadic.left, func);
+ IRO_WalkTree(linear->u.diadic.right, func);
+ break;
+ case IROLinearOp3Arg:
+ IRO_WalkTree(linear->u.args3.a, func);
+ IRO_WalkTree(linear->u.args3.b, func);
+ IRO_WalkTree(linear->u.args3.c, func);
+ break;
+ case IROLinearFunccall:
+ IRO_WalkTree(linear->u.funccall.linear8, func);
+ for (i = 0; i < linear->u.funccall.argCount; i++)
+ IRO_WalkTree(linear->u.funccall.args[i], func);
+ break;
+ }
+ func(linear, 0);
+}
+
+void IRO_WalkTreeToPropagateFlags(IROLinear *linear, IROWalkTreeFunc func) {
+ int i;
+
+ switch (linear->type) {
+ case IROLinearOperand:
+ break;
+ case IROLinearOp1Arg:
+ IRO_WalkTreeToPropagateFlags(linear->u.monadic, func);
+ break;
+ case IROLinearOp2Arg:
+ IRO_WalkTreeToPropagateFlags(linear->u.diadic.left, func);
+ IRO_WalkTreeToPropagateFlags(linear->u.diadic.right, func);
+ break;
+ case IROLinearOp3Arg:
+ IRO_WalkTreeToPropagateFlags(linear->u.args3.a, func);
+ IRO_WalkTreeToPropagateFlags(linear->u.args3.b, func);
+ IRO_WalkTreeToPropagateFlags(linear->u.args3.c, func);
+ break;
+ case IROLinearFunccall:
+ IRO_WalkTreeToPropagateFlags(linear->u.funccall.linear8, func);
+ for (i = 0; i < linear->u.funccall.argCount; i++)
+ IRO_WalkTreeToPropagateFlags(linear->u.funccall.args[i], func);
+ break;
+ }
+ func(linear, 0);
+}
+
+void IRO_WalkInts(IROLinear *a, IROLinear *b, IROWalkTreeFunc func) {
+ IROLinear *scan;
+
+ for (scan = a; scan; scan = scan->next) {
+ switch (scan->type) {
+ case IROLinearBeginCatch:
+ case IROLinearEndCatch:
+ case IROLinearEndCatchDtor:
+ IRO_WalkTree(scan->u.ctch.linear, func);
+ break;
+ case IROLinearOperand:
+ case IROLinearOp1Arg:
+ case IROLinearOp2Arg:
+ case IROLinearOp3Arg:
+ case IROLinearFunccall:
+ IRO_WalkTree(scan, func);
+ break;
+ case IROLinearIf:
+ case IROLinearIfNot:
+ IRO_WalkTree(scan->u.label.x4, func);
+ break;
+ case IROLinearReturn:
+ if (scan->u.monadic)
+ IRO_WalkTree(scan->u.monadic, func);
+ break;
+ case IROLinearSwitch:
+ IRO_WalkTree(scan->u.swtch.x4, func);
+ break;
+ case IROLinearAsm:
+ func(scan, 1);
+ func(scan, 0);
+ break;
+ case IROLinearEnd:
+ break;
+ }
+
+ if (scan == b)
+ break;
+ }
+}
+
+void IRO_Cut(IROLinear *a, IROLinear *b) {
+ IROLinear *scan;
+ IROLinear *prev;
+ IRONode *node;
+
+ scan = a;
+ while (1) {
+ scan->stmt = NULL;
+ if (scan == b)
+ break;
+ scan = scan->next;
+ }
+
+ prev = NULL;
+ for (scan = IRO_FirstLinear; scan && scan != a; scan = scan->next)
+ prev = scan;
+
+ CError_ASSERT(951, scan);
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (node->first == a) {
+ if (node->last == b) {
+ node->first = node->last = NULL;
+ break;
+ } else {
+ node->first = b->next;
+ break;
+ }
+ } else if (node->last == b) {
+ node->last = prev;
+ break;
+ }
+ }
+
+ if (prev)
+ prev->next = b->next;
+ else
+ IRO_FirstLinear = b->next;
+}
+
+void IRO_Paste(IROLinear *a, IROLinear *b, IROLinear *c) {
+ IROLinear *prev;
+ IROLinear *scan;
+ IRONode *node;
+
+ CError_ASSERT(1002, c && c->type != IROLinearLabel);
+
+ prev = NULL;
+ for (scan = IRO_FirstLinear; scan && scan != c; scan = scan->next)
+ prev = scan;
+
+ CError_ASSERT(1016, scan);
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (node->first == c) {
+ node->first = a;
+ break;
+ }
+ }
+
+ b->next = c;
+ if (prev)
+ prev->next = a;
+ else
+ IRO_FirstLinear = a;
+}
+
+void IRO_PasteAfter(IROLinear *a, IROLinear *b, IROLinear *c) {
+ IRONode *node;
+
+ switch (c->type) {
+ case IROLinearGoto:
+ case IROLinearIf:
+ case IROLinearIfNot:
+ case IROLinearSwitch:
+ CError_FATAL(1060);
+ }
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ if (node->last == c) {
+ node->last = b;
+ break;
+ }
+ }
+
+ b->next = c->next;
+ c->next = a;
+}
+
+static void FindStart(IROLinear *linear, Boolean isEntry) {
+ IROLinear *scan;
+ if (isEntry) {
+ scan = linear;
+ do {
+ if (scan == ExprStart) {
+ ExprStart = linear;
+ return;
+ }
+ if (scan == ExprEnd)
+ return;
+ } while ((scan = scan->next));
+ }
+}
+
+void IRO_ClipExpr(IROExpr *expr) {
+ ExprStart = ExprEnd = expr->linear;
+ IRO_WalkTree(expr->linear, FindStart);
+ IRO_Cut(ExprStart, ExprEnd);
+}
+
+void IRO_ClipExprTree(IROLinear *linear) {
+ ExprStart = ExprEnd = linear;
+ IRO_WalkTree(linear, FindStart);
+ IRO_Cut(ExprStart, ExprEnd);
+}
+
+static void SetNodeNumInExprList(IROLinear *linear, Boolean isEntry) {
+ if (isEntry && linear->expr)
+ linear->expr->node = IRO_Node;
+}
+
+void IRO_MoveExpression(IROExpr *expr, IROLinear *linear) {
+ IRONode *node;
+ IROLinear *scan;
+
+ ExprStart = ExprEnd = expr->linear;
+ IRO_WalkTree(expr->linear, FindStart);
+
+ if (ExprStart != linear) {
+ IRO_Cut(ExprStart, ExprEnd);
+ IRO_Paste(ExprStart, ExprEnd, linear);
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ for (scan = node->first; scan; scan = scan->next) {
+ if (scan == expr->linear) {
+ expr->node = node;
+ break;
+ }
+ if (scan == node->last)
+ break;
+ }
+ }
+
+ IRO_Node = expr->node;
+ IRO_WalkTree(expr->linear, SetNodeNumInExprList);
+ }
+}
+
+void IRO_InitList(IROList *list) {
+ list->head = list->tail = NULL;
+}
+
+void IRO_AddToList(IROLinear *linear, IROList *list) {
+ if (list->head)
+ list->tail->next = linear;
+ else
+ list->head = linear;
+
+ list->tail = linear;
+ while (list->tail->next)
+ list->tail = list->tail->next;
+}
+
+IROLinear *IRO_FindLabelNode(CLabel *label, IROLinear *linear) {
+ IROLinear *scan;
+
+ for (scan = linear; scan; scan = scan->next) {
+ if (scan->type == IROLinearLabel && scan->u.label.label == label)
+ break;
+ }
+
+ CError_ASSERT(1244, scan);
+ return scan;
+}
+
+void IRO_DuplicateExprRange(IROLinear *start, IROLinear *end, IROList *list) {
+ IROLinear *scan;
+
+ for (scan = start; scan; scan = scan->next) {
+ if (scan->type != IROLinearNop && !(scan->flags & IROLF_Reffed))
+ IRO_DuplicateExpr(scan, list);
+ if (scan == end)
+ break;
+ }
+}
+
+IROLinear *IRO_DuplicateExpr(IROLinear *linear, IROList *list) {
+ IROLinear *copy;
+ ENode *copynode;
+ int i;
+
+ copy = IRO_NewLinear(linear->type);
+ *copy = *linear;
+
+ copy->index = ++IRO_NumLinear;
+ copy->next = NULL;
+ copy->expr = NULL;
+
+ switch (copy->type) {
+ case IROLinearOperand:
+ copynode = lalloc(sizeof(ENode));
+ *copynode = *linear->u.node;
+ copy->u.node = copynode;
+ break;
+ case IROLinearOp1Arg:
+ copy->u.monadic = IRO_DuplicateExpr(copy->u.monadic, list);
+ break;
+ case IROLinearOp2Arg:
+ if (linear->flags & IROLF_8000) {
+ copy->u.diadic.right = IRO_DuplicateExpr(copy->u.diadic.right, list);
+ copy->u.diadic.left = IRO_DuplicateExpr(copy->u.diadic.left, list);
+ } else {
+ copy->u.diadic.left = IRO_DuplicateExpr(copy->u.diadic.left, list);
+ copy->u.diadic.right = IRO_DuplicateExpr(copy->u.diadic.right, list);
+ }
+ break;
+ case IROLinearOp3Arg:
+ copy->u.args3.a = IRO_DuplicateExpr(copy->u.args3.a, list);
+ copy->u.args3.b = IRO_DuplicateExpr(copy->u.args3.b, list);
+ copy->u.args3.c = IRO_DuplicateExpr(copy->u.args3.c, list);
+ break;
+ case IROLinearFunccall:
+ copy->u.funccall.linear8 = IRO_DuplicateExpr(copy->u.funccall.linear8, list);
+ copy->u.funccall.args = oalloc(sizeof(IROLinear *) * copy->u.funccall.argCount);
+ for (i = 0; i < copy->u.funccall.argCount; i++) {
+ copy->u.funccall.args[i] = IRO_DuplicateExpr(linear->u.funccall.args[i], list);
+ }
+ break;
+ case IROLinearAsm:
+ copy->u.asm_stmt = CodeGen_CopyAsmStat(linear->u.asm_stmt);
+ break;
+ }
+
+ IRO_AddToList(copy, list);
+ return copy;
+}
+
+IROLinear *IRO_TempReference(Object *obj, IROList *list) {
+ IROLinear *op;
+ IROLinear *ind;
+
+ op = IRO_NewLinear(IROLinearOperand);
+ op->u.node = create_objectrefnode(obj);
+ op->rtype = op->u.node->data.objref->type;
+ op->index = ++IRO_NumLinear;
+ op->flags |= IROLF_Reffed | IROLF_Ind;
+ IRO_AddToList(op, list);
+
+ ind = IRO_NewLinear(IROLinearOp1Arg);
+ ind->nodetype = EINDIRECT;
+ ind->rtype = obj->type;
+ ind->u.monadic = op;
+ ind->index = ++IRO_NumLinear;
+ ind->next = NULL;
+ IRO_AddToList(ind, list);
+
+ return ind;
+}
+
+CW_INLINE IROLinear *LocateFatherHelper(IROLinear *linear, Boolean a, IROLinear ***b) {
+ IROLinear *scan;
+ SInt32 index;
+ int i;
+
+ for (scan = linear->next, index = 0; index < (a ? 2 : 1); index++) {
+ while (scan) {
+ switch (scan->type) {
+ case IROLinearIf:
+ case IROLinearIfNot:
+ if (scan->u.label.x4 == linear) {
+ if (b)
+ *b = &scan->u.label.x4;
+ return scan;
+ }
+ break;
+ case IROLinearReturn:
+ if (scan->u.monadic == linear) {
+ if (b)
+ *b = &scan->u.monadic;
+ return scan;
+ }
+ break;
+ case IROLinearOp1Arg:
+ if (scan->u.monadic == linear) {
+ if (b)
+ *b = &scan->u.monadic;
+ return scan;
+ }
+ break;
+ case IROLinearSwitch:
+ if (scan->u.swtch.x4 == linear) {
+ if (b)
+ *b = &scan->u.swtch.x4;
+ return scan;
+ }
+ break;
+ case IROLinearOp2Arg:
+ if (scan->u.diadic.left == linear) {
+ if (b)
+ *b = &scan->u.diadic.left;
+ return scan;
+ }
+ if (scan->u.diadic.right == linear) {
+ if (b)
+ *b = &scan->u.diadic.right;
+ return scan;
+ }
+ break;
+ case IROLinearOp3Arg:
+ if (scan->u.args3.a == linear) {
+ if (b)
+ *b = &scan->u.args3.a;
+ return scan;
+ }
+ if (scan->u.args3.b == linear) {
+ if (b)
+ *b = &scan->u.args3.b;
+ return scan;
+ }
+ if (scan->u.args3.c == linear) {
+ if (b)
+ *b = &scan->u.args3.c;
+ return scan;
+ }
+ break;
+ case IROLinearFunccall:
+ if (scan->u.funccall.linear8 == linear) {
+ if (b)
+ *b = &scan->u.funccall.linear8;
+ return scan;
+ }
+ for (i = 0; i < scan->u.funccall.argCount; i++) {
+ if (scan->u.funccall.args[i] == linear) {
+ if (b)
+ *b = &scan->u.funccall.args[i];
+ return scan;
+ }
+ }
+ break;
+ case IROLinearNop:
+ case IROLinearOperand:
+ case IROLinearGoto:
+ case IROLinearLabel:
+ case IROLinearEntry:
+ case IROLinearExit:
+ case IROLinearBeginCatch:
+ case IROLinearEndCatch:
+ case IROLinearEndCatchDtor:
+ case IROLinearAsm:
+ case IROLinearEnd:
+ break;
+ default:
+ CError_FATAL(1536);
+ }
+ scan = scan->next;
+ }
+
+ scan = IRO_FirstLinear;
+ }
+
+ if (b)
+ *b = NULL;
+ return NULL;
+}
+
+IROLinear *IRO_LocateFather(IROLinear *linear) {
+ return LocateFatherHelper(linear, 0, NULL);
+}
+
+IROLinear *IRO_LocateFather_Cut_And_Paste(IROLinear *a, IROLinear *b) {
+ IROLinear **p;
+ IROLinear *l = LocateFatherHelper(a, 0, &p);
+ if (l) {
+ CError_ASSERT(1568, p && *p);
+ IRO_NopOut(a);
+ *p = b;
+ }
+ return l;
+}
+
+IROLinear *IRO_LocateFather_Cut_And_Paste_Without_Nopping(IROLinear *a, IROLinear *b) {
+ IROLinear **p;
+ IROLinear *l = LocateFatherHelper(a, 0, &p);
+ if (l) {
+ CError_ASSERT(1585, p && *p);
+ *p = b;
+ }
+ return l;
+}
+
+void IRO_ReplaceReference(IROLinear *a, Object *obj, IROLinear *b) {
+ IROLinear **ptr;
+ IROList list;
+
+ if (LocateFatherHelper(a, 1, &ptr)) {
+ CError_ASSERT(1605, ptr && *ptr);
+ IRO_InitList(&list);
+ *ptr = IRO_TempReference(obj, &list);
+ IRO_PasteAfter(list.head, list.tail, b);
+ if (a->flags & IROLF_LoopInvariant)
+ list.tail->flags |= IROLF_LoopInvariant;
+ } else {
+ IRO_Dump("Oh, oh, did not find reference to replace\n");
+ }
+}
+
+void IRO_ReplaceReferenceWithNode(IROLinear *a, IROLinear *b) {
+ IROLinear **ptr;
+ IROList list;
+
+ if (LocateFatherHelper(a, 1, &ptr)) {
+ CError_ASSERT(1664, ptr && *ptr);
+ *ptr = b;
+ b->flags |= IROLF_Reffed;
+ } else {
+ IRO_Dump("Oh, oh, did not find reference to replace\n");
+ }
+}
+
+VarRecord *IRO_GetTemp(IROExpr *expr) {
+ expr->x8 = create_temp_object(expr->linear->rtype);
+ return IRO_FindVar(expr->x8, 1, 1);
+}
+
+IROLinear *IRO_AssignToTemp(IROExpr *expr) {
+ IROLinear *objref;
+ IROLinear *ind;
+ IROLinear *ass;
+
+ objref = IRO_NewLinear(IROLinearOperand);
+ objref->u.node = create_objectrefnode(expr->x8);
+ objref->rtype = objref->u.node->data.objref->type;
+ objref->index = ++IRO_NumLinear;
+ objref->flags |= IROLF_Reffed | IROLF_Assigned | IROLF_Ind;
+
+ ind = IRO_NewLinear(IROLinearOp1Arg);
+ ind->nodetype = EINDIRECT;
+ ind->rtype = expr->linear->rtype;
+ ind->u.monadic = objref;
+ ind->index = ++IRO_NumLinear;
+ ind->flags |= IROLF_Reffed | IROLF_Assigned;
+
+ ass = IRO_NewLinear(IROLinearOp2Arg);
+ ass->nodetype = EASS;
+ ass->u.diadic.left = ind;
+ ass->u.diadic.right = expr->linear;
+ ass->rtype = expr->linear->rtype;
+ ass->index = ++IRO_NumLinear;
+
+ objref->next = ind;
+ ind->next = ass;
+ IRO_PasteAfter(objref, ass, expr->linear);
+ return ass;
+}
+
+IROLinear *IRO_FindStart(IROLinear *linear) {
+ ExprStart = ExprEnd = linear;
+ IRO_WalkTree(linear, FindStart);
+ return ExprStart;
+}
+
+void IRO_DeleteCommaNode(IROLinear *linear, IROExpr *expr) {
+ IROLinear *scan;
+ for (scan = linear; scan; scan = scan->next) {
+ if (scan->nodetype == ECOMMA) {
+ if (scan != expr->linear) {
+ IRO_NopOut(scan->u.diadic.left);
+ IRO_LocateFather_Cut_And_Paste(scan, scan->u.diadic.right);
+ } else {
+ IRO_NopOut(scan->u.diadic.left);
+ expr->linear = scan->u.diadic.right;
+ }
+ }
+ }
+}
+
+void IRO_RemoveCommaNodeFromIR(void) {
+ IRONode *node;
+ IROLinear *linear;
+
+ for (node = IRO_FirstNode; node; node = node->nextnode) {
+ linear = node->first;
+ do {
+ if (!linear)
+ break;
+ if (linear->nodetype == ECOMMA) {
+ linear->u.diadic.left->flags = linear->u.diadic.left->flags & ~IROLF_Reffed;
+ IRO_LocateFather_Cut_And_Paste_Without_Nopping(linear, linear->u.diadic.right);
+ linear->type = IROLinearNop;
+ }
+ linear = linear->next;
+ } while (linear != node->last);
+ }
+}
+
+IROAddrRecord *IRO_InitAddrRecordPointer(IROLinear *linear) {
+ IROAddrRecord *rec = oalloc(sizeof(IROAddrRecord));
+ rec->numObjRefs = 0;
+ rec->objRefs = NULL;
+ rec->numMisc = 0;
+ rec->misc = NULL;
+ rec->numInts = 0;
+ rec->ints = NULL;
+ rec->x16 = 0;
+ rec->linear = linear;
+ return rec;
+}
+
+IROLinear *IRO_HasSideEffect(IROLinear *linear) {
+ IROLinear *tmp;
+
+ if (!linear)
+ return linear;
+
+ if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS))
+ return linear;
+
+ switch (linear->type) {
+ case IROLinearAsm:
+ return linear;
+ case IROLinearOperand:
+ if (ENODE_IS(linear->u.node, EOBJREF) && is_volatile_object(linear->u.node->data.objref))
+ return linear;
+ return NULL;
+ case IROLinearOp1Arg:
+ if (IRO_IsAssignOp[linear->nodetype])
+ return linear;
+ else
+ return IRO_HasSideEffect(linear->u.monadic);
+ case IROLinearOp2Arg:
+ if (IRO_IsAssignOp[linear->nodetype])
+ return linear;
+ else if ((tmp = IRO_HasSideEffect(linear->u.diadic.left)))
+ return tmp;
+ else
+ return IRO_HasSideEffect(linear->u.diadic.right);
+ case IROLinearOp3Arg:
+ if ((tmp = IRO_HasSideEffect(linear->u.args3.a)))
+ return tmp;
+ else if ((tmp = IRO_HasSideEffect(linear->u.args3.b)))
+ return tmp;
+ else
+ return IRO_HasSideEffect(linear->u.args3.c);
+ case IROLinearFunccall:
+ return linear;
+ default:
+ return linear;
+ }
+}
+
+IROLinear *IRO_CheckSideEffect(IROLinear *linear) {
+ IROLinear *result;
+ IROLinear *tmp;
+ IROLinear *tmp2;
+ IROLinear *tmp3;
+
+ if (!linear)
+ return linear;
+
+ if (linear->rtype && CParser_IsVolatile(linear->rtype, linear->nodeflags & ENODE_FLAG_QUALS)) {
+ linear->flags &= ~IROLF_Reffed;
+ return linear;
+ }
+
+ result = NULL;
+ switch (linear->type) {
+ case IROLinearAsm:
+ linear->flags &= ~IROLF_Reffed;
+ return linear;
+ case IROLinearOperand:
+ if (ENODE_IS(linear->u.node, EOBJREF) && is_volatile_object(linear->u.node->data.objref)) {
+ linear->flags &= ~IROLF_Reffed;
+ return linear;
+ }
+ break;
+ case IROLinearOp1Arg:
+ if (IRO_IsAssignOp[linear->nodetype]) {
+ linear->flags &= ~IROLF_Reffed;
+ return linear;
+ }
+ if ((result = IRO_CheckSideEffect(linear->u.monadic))) {
+ if (linear->nodetype == EINDIRECT && linear->u.monadic->type == IROLinearOperand) {
+ linear->flags &= ~IROLF_Reffed;
+ return linear;
+ }
+ }
+ break;
+ case IROLinearOp2Arg:
+ if (IRO_IsAssignOp[linear->nodetype]) {
+ linear->flags &= ~IROLF_Reffed;
+ return linear;
+ }
+ tmp = IRO_CheckSideEffect(linear->u.diadic.left);
+ tmp2 = IRO_CheckSideEffect(linear->u.diadic.right);
+ if (tmp)
+ result = tmp;
+ else
+ result = tmp2;
+ break;
+ case IROLinearOp3Arg:
+ tmp = IRO_CheckSideEffect(linear->u.args3.a);
+ tmp2 = IRO_CheckSideEffect(linear->u.args3.b);
+ tmp3 = IRO_CheckSideEffect(linear->u.args3.c);
+ result = tmp ? tmp : tmp2 ? tmp2 : tmp3;
+ break;
+ case IROLinearFunccall:
+ linear->flags &= ~IROLF_Reffed;
+ return linear;
+ default:
+ return linear;
+ }
+
+ linear->type = IROLinearNop;
+ IRO_Dump("Nop out with side-effects checking at: %d\n", linear->index);
+ return result;
+}
+
+void IRO_WalkExcActions(ExceptionAction *action, WalkObjFunc func) {
+ while (action) {
+ switch (action->type) {
+ case EAT_DESTROYLOCAL:
+ func(action->data.destroy_local.local);
+ break;
+ case EAT_DESTROYLOCALCOND:
+ func(action->data.destroy_local_cond.local);
+ func(action->data.destroy_local_cond.cond);
+ break;
+ case EAT_DESTROYLOCALOFFSET:
+ func(action->data.destroy_local_offset.local);
+ break;
+ case EAT_DESTROYLOCALPOINTER:
+ func(action->data.destroy_local_pointer.pointer);
+ break;
+ case EAT_DESTROYLOCALARRAY:
+ func(action->data.destroy_local_array.localarray);
+ break;
+ case EAT_DESTROYPARTIALARRAY:
+ func(action->data.destroy_partial_array.arraypointer);
+ func(action->data.destroy_partial_array.arraycounter);
+ func(action->data.destroy_partial_array.element_size);
+ break;
+ case EAT_DESTROYBASE:
+ func(action->data.destroy_member.objectptr); // wrong union?
+ break;
+ case EAT_DESTROYMEMBER:
+ func(action->data.destroy_member.objectptr);
+ break;
+ case EAT_DESTROYMEMBERCOND:
+ func(action->data.destroy_member_cond.objectptr);
+ func(action->data.destroy_member_cond.cond);
+ break;
+ case EAT_DESTROYMEMBERARRAY:
+ func(action->data.destroy_member_array.objectptr);
+ break;
+ case EAT_DELETEPOINTER:
+ func(action->data.delete_pointer.pointerobject);
+ break;
+ case EAT_DELETEPOINTERCOND:
+ func(action->data.delete_pointer_cond.pointerobject);
+ func(action->data.delete_pointer_cond.cond);
+ break;
+ }
+ action = action->prev;
+ }
+}
+
+Boolean IRO_FunctionCallMightThrowException(IROLinear *linear) {
+ Object *obj;
+ if (linear->type == IROLinearFunccall) {
+ obj = NULL;
+ if (linear->u.funccall.linear8->type == IROLinearOperand && ENODE_IS(linear->u.funccall.linear8->u.node, EOBJREF))
+ obj = linear->u.funccall.linear8->u.node->data.objref;
+ if (!obj || CExcept_CanThrowException(obj, obj->datatype == DVFUNC && !(linear->nodeflags & ENODE_FLAG_80)))
+ return 1;
+ }
+ return 0;
+}
+
+IROLinear *IRO_NewIntConst(CInt64 val, Type *type) {
+ ENode *node;
+ IROLinear *linear;
+
+ node = IRO_NewENode(EINTCONST);
+ node->data.intval = val;
+ node->rtype = type;
+
+ linear = IRO_NewLinear(IROLinearOperand);
+ linear->index = ++IRO_NumLinear;
+ linear->rtype = type;
+ linear->u.node = node;
+ return linear;
+}
+
+IROLinear *IRO_NewFloatConst(const Float val, Type *type) {
+ ENode *node;
+ IROLinear *linear;
+
+ node = IRO_NewENode(EFLOATCONST);
+ node->data.floatval = val;
+ node->rtype = type;
+
+ linear = IRO_NewLinear(IROLinearOperand);
+ linear->index = ++IRO_NumLinear;
+ linear->rtype = type;
+ linear->u.node = node;
+ return linear;
+}
+
+Boolean IRO_IsAddressMultiply(IROLinear *linear) {
+ return 0;
+}
+
+void IRO_SetupForUserBreakChecking(void) {
+ IRO_LastUserBreakTick = 0;
+}
+
+void IRO_CheckForUserBreak(void) {
+ if (IRO_LastUserBreakTick + 8 < COS_GetTicks()) {
+ if (CWUserBreak(cparams.context))
+ CError_UserBreak();
+ IRO_LastUserBreakTick = COS_GetTicks();
+ }
+}
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroUtil.h b/compiler_and_linker/FrontEnd/Optimizer/IroUtil.h
new file mode 100644
index 0000000..2661985
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroUtil.h
@@ -0,0 +1,127 @@
+#ifndef COMPILER_IROUTIL_H
+#define COMPILER_IROUTIL_H
+
+#include "IrOptimizer.h"
+#include "compiler/CInt64.h"
+#include "compiler/CParser.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+struct IROList {
+ IROLinear *head;
+ IROLinear *tail;
+};
+
+struct IROListNode {
+ IROList list;
+ IROListNode *nextList;
+};
+
+struct IROElmList {
+ void *element;
+ IROElmList *next;
+};
+
+struct IROAddrRecord {
+ IROLinear *linear;
+ unsigned short numObjRefs;
+ IROElmList *objRefs;
+ unsigned short numMisc;
+ IROElmList *misc;
+ unsigned short numInts;
+ IROElmList *ints;
+ int x16;
+};
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+extern Object *FunctionName;
+extern Boolean IRO_IsLeafFunction;
+extern Boolean IRO_FunctionHasReturn;
+extern Boolean DisableDueToAsm;
+extern Boolean LoopOptimizerRun;
+
+extern Object *IRO_IsVariable(IROLinear *linear);
+extern Boolean IRO_IsConstant(IROLinear *linear);
+extern Boolean IRO_IsPow2(IROLinear *linear, SInt32 *powvalue);
+extern Boolean IRO_IsIntConstant(IROLinear *linear);
+extern Boolean IRO_IsFloatConstant(IROLinear *linear);
+extern Boolean IRO_IsVector128Constant(IROLinear *linear);
+extern Boolean IRO_IsAssignment(IROLinear *linear);
+extern Boolean IRO_TypesEqual(Type *a, Type *b);
+extern Type *IRO_UnsignedType(Type *type);
+extern Type *IRO_SignedType(Type *type);
+extern Boolean IRO_is_CPtypeequal(Type *a, Type *b);
+extern Boolean IRO_ExprsSame(IROLinear *a, IROLinear *b);
+extern CLabel *IRO_NewLabel(void);
+extern Boolean IRO_ExprsSameSemantically(IROLinear *a, IROLinear *b);
+extern IROLinear *IRO_FindPrecedAfter(IROLinear *a, IROLinear *iter);
+extern IROLinear *IRO_FindPreced(IROLinear *a);
+extern IROLinear *IRO_FindFirst(IROLinear *linear);
+extern void IRO_CutAndPasteAfter(IROLinear *a, IROLinear *b, IROLinear *c);
+extern Boolean IRO_IsConstantZero(IROLinear *linear);
+extern Boolean IRO_IsConstantOne(IROLinear *linear);
+extern Boolean IRO_IsConstantNegativeOne(IROLinear *linear);
+extern void IRO_NopOut(IROLinear *linear);
+extern void IRO_NopNonSideEffects(IROLinear *linear, SInt32 level);
+extern void IRO_BuildList(IROLinear *linear, Boolean isEntry);
+typedef void (*IROWalkTreeFunc)(IROLinear *linear, Boolean isEntry);
+extern void IRO_WalkTree(IROLinear *linear, IROWalkTreeFunc func);
+extern void IRO_WalkTreeToPropagateFlags(IROLinear *linear, IROWalkTreeFunc func);
+extern void IRO_WalkInts(IROLinear *a, IROLinear *b, IROWalkTreeFunc func);
+extern void IRO_Cut(IROLinear *a, IROLinear *b);
+extern void IRO_Paste(IROLinear *a, IROLinear *b, IROLinear *c);
+extern void IRO_PasteAfter(IROLinear *a, IROLinear *b, IROLinear *c);
+extern void IRO_ClipExpr(IROExpr *expr);
+extern void IRO_ClipExprTree(IROLinear *linear);
+extern void IRO_MoveExpression(IROExpr *expr, IROLinear *linear);
+extern void IRO_InitList(IROList *list);
+extern void IRO_AddToList(IROLinear *linear, IROList *list);
+extern IROLinear *IRO_FindLabelNode(CLabel *label, IROLinear *linear);
+extern void IRO_DuplicateExprRange(IROLinear *start, IROLinear *end, IROList *list);
+extern IROLinear *IRO_DuplicateExpr(IROLinear *linear, IROList *list);
+extern IROLinear *IRO_TempReference(Object *obj, IROList *list);
+extern IROLinear *IRO_LocateFather(IROLinear *linear);
+extern IROLinear *IRO_LocateFather_Cut_And_Paste(IROLinear *a, IROLinear *b);
+extern IROLinear *IRO_LocateFather_Cut_And_Paste_Without_Nopping(IROLinear *a, IROLinear *b);
+extern void IRO_ReplaceReference(IROLinear *a, Object *obj, IROLinear *b);
+extern void IRO_ReplaceReferenceWithNode(IROLinear *a, IROLinear *b);
+extern VarRecord *IRO_GetTemp(IROExpr *expr);
+extern IROLinear *IRO_AssignToTemp(IROExpr *expr);
+extern IROLinear *IRO_FindStart(IROLinear *linear);
+extern void IRO_DeleteCommaNode(IROLinear *linear, IROExpr *expr);
+extern void IRO_RemoveCommaNodeFromIR(void);
+extern IROAddrRecord *IRO_InitAddrRecordPointer(IROLinear *linear);
+extern IROLinear *IRO_HasSideEffect(IROLinear *linear);
+extern IROLinear *IRO_CheckSideEffect(IROLinear *linear);
+typedef void (*WalkObjFunc)(Object *obj);
+extern void IRO_WalkExcActions(ExceptionAction *action, WalkObjFunc func);
+extern Boolean IRO_FunctionCallMightThrowException(IROLinear *linear);
+extern IROLinear *IRO_NewIntConst(CInt64 val, Type *type);
+extern IROLinear *IRO_NewFloatConst(const Float val, Type *type);
+extern Boolean IRO_IsAddressMultiply(IROLinear *linear);
+extern void IRO_SetupForUserBreakChecking(void);
+extern void IRO_CheckForUserBreak(void);
+
+// TODO is this elsewhere?
+CW_INLINE Boolean IRO_IsUnsignedType(Type *type) {
+ return is_unsigned(type);
+}
+
+// 4B4D40
+CW_INLINE CInt64 IRO_MakeULong(UInt32 i) {
+ CInt64 val;
+ CInt64_SetULong(&val, i);
+ return val;
+}
+
+// 4BAAA0
+CW_INLINE CInt64 IRO_MakeLong(SInt32 i) {
+ CInt64 val;
+ CInt64_SetLong(&val, i);
+ return val;
+}
+
+#endif
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroVars.c b/compiler_and_linker/FrontEnd/Optimizer/IroVars.c
new file mode 100644
index 0000000..b72ba89
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroVars.c
@@ -0,0 +1,1430 @@
+#include "IroVars.h"
+#include "IroDump.h"
+#include "IroFlowgraph.h"
+#include "IroJump.h"
+#include "IroLinearForm.h"
+#include "IroMalloc.h"
+#include "IroPointerAnalysis.h"
+#include "IroUtil.h"
+#include "IROUseDef.h"
+#include "compiler/CClass.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CParser.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/Exceptions.h"
+#include "compiler/objects.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/InlineAsmPPC.h"
+#include "BitVector.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct IndirectRecordMatch {
+ IROLinear *nd;
+ struct IndirectRecordMatch *otherMatches;
+} IndirectRecordMatch;
+
+typedef struct IndirectRecord {
+ IROLinear *linear;
+ unsigned char flags;
+ VarRecord *var;
+ SInt32 addend;
+ SInt32 size;
+ int startbit;
+ int endbit;
+ Type *type;
+ struct IndirectRecord *next;
+ IndirectRecordMatch *matches;
+ IROLinear *x26;
+} IndirectRecord;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static IndirectRecord *IRO_FirstIndirectRecord;
+static IndirectRecord *IRO_LastIndirectRecord;
+static IROLinear *TheBaseTerm;
+VarRecord *IRO_FirstVar;
+VarRecord *IRO_LastVar;
+SInt32 IRO_NumVars;
+Boolean IRO_IsBitField;
+SInt32 IRO_BaseTerms;
+SInt32 IRO_VarTerms;
+Boolean IRO_IsModifyOp[MAXEXPR];
+Boolean IRO_IsAssignOp[MAXEXPR];
+
+// forward decls
+static Boolean CheckAddress(IROLinear *nd, Boolean *resultFlag);
+static Boolean CheckAddressConsistency(IROLinear *nd, VarRecord *var, SInt32 addend, Type *type);
+static void DisableEntries(IndirectRecord *irec);
+static void DisableAddressedEntries(void);
+static UInt32 ObjectIsArg(Object *obj);
+
+void IRO_InitializeIRO_IsModifyOpArray(void) {
+ int i;
+
+ for (i = 0; i < MAXEXPR; i++)
+ IRO_IsModifyOp[i] = 0;
+
+ IRO_IsModifyOp[EPOSTINC] = 1;
+ IRO_IsModifyOp[EPOSTDEC] = 1;
+ IRO_IsModifyOp[EPREINC] = 1;
+ IRO_IsModifyOp[EPREDEC] = 1;
+ IRO_IsModifyOp[EINDIRECT] = 0;
+ IRO_IsModifyOp[EMONMIN] = 0;
+ IRO_IsModifyOp[EBINNOT] = 0;
+ IRO_IsModifyOp[ELOGNOT] = 0;
+ IRO_IsModifyOp[EFORCELOAD] = 0;
+ IRO_IsModifyOp[EMUL] = 0;
+ IRO_IsModifyOp[EMULV] = 0;
+ IRO_IsModifyOp[EDIV] = 0;
+ IRO_IsModifyOp[EMODULO] = 0;
+ IRO_IsModifyOp[EADDV] = 0;
+ IRO_IsModifyOp[ESUBV] = 0;
+ IRO_IsModifyOp[EADD] = 0;
+ IRO_IsModifyOp[ESUB] = 0;
+ IRO_IsModifyOp[ESHL] = 0;
+ IRO_IsModifyOp[ESHR] = 0;
+ IRO_IsModifyOp[ELESS] = 0;
+ IRO_IsModifyOp[EGREATER] = 0;
+ IRO_IsModifyOp[ELESSEQU] = 0;
+ IRO_IsModifyOp[EGREATEREQU] = 0;
+ IRO_IsModifyOp[EEQU] = 0;
+ IRO_IsModifyOp[ENOTEQU] = 0;
+ IRO_IsModifyOp[EAND] = 0;
+ IRO_IsModifyOp[EXOR] = 0;
+ IRO_IsModifyOp[EOR] = 0;
+ IRO_IsModifyOp[ELAND] = 0;
+ IRO_IsModifyOp[ELOR] = 0;
+ IRO_IsModifyOp[EASS] = 0;
+ IRO_IsModifyOp[EMULASS] = 1;
+ IRO_IsModifyOp[EDIVASS] = 1;
+ IRO_IsModifyOp[EMODASS] = 1;
+ IRO_IsModifyOp[EADDASS] = 1;
+ IRO_IsModifyOp[ESUBASS] = 1;
+ IRO_IsModifyOp[ESHLASS] = 1;
+ IRO_IsModifyOp[ESHRASS] = 1;
+ IRO_IsModifyOp[EANDASS] = 1;
+ IRO_IsModifyOp[EXORASS] = 1;
+ IRO_IsModifyOp[EORASS] = 1;
+ IRO_IsModifyOp[ECOMMA] = 0;
+ IRO_IsModifyOp[EPMODULO] = 1;
+ IRO_IsModifyOp[EROTL] = 1;
+ IRO_IsModifyOp[EROTR] = 1;
+ IRO_IsModifyOp[EBCLR] = 1;
+ IRO_IsModifyOp[EBTST] = 1;
+ IRO_IsModifyOp[EBSET] = 1;
+ IRO_IsModifyOp[ETYPCON] = 0;
+ IRO_IsModifyOp[EBITFIELD] = 0;
+ IRO_IsModifyOp[EINTCONST] = 0;
+ IRO_IsModifyOp[EFLOATCONST] = 0;
+ IRO_IsModifyOp[ESTRINGCONST] = 0;
+ IRO_IsModifyOp[ECOND] = 0;
+ IRO_IsModifyOp[EFUNCCALL] = 0;
+ IRO_IsModifyOp[EFUNCCALLP] = 0;
+ IRO_IsModifyOp[EOBJREF] = 0;
+ IRO_IsModifyOp[EMFPOINTER] = 0;
+ IRO_IsModifyOp[ENULLCHECK] = 0;
+ IRO_IsModifyOp[EPRECOMP] = 0;
+ IRO_IsModifyOp[ETEMP] = 0;
+ IRO_IsModifyOp[EARGOBJ] = 0;
+ IRO_IsModifyOp[ELOCOBJ] = 0;
+ IRO_IsModifyOp[ELABEL] = 0;
+ IRO_IsModifyOp[ESETCONST] = 0;
+ IRO_IsModifyOp[ENEWEXCEPTION] = 0;
+ IRO_IsModifyOp[ENEWEXCEPTIONARRAY] = 0;
+ IRO_IsModifyOp[EOBJLIST] = 0;
+ IRO_IsModifyOp[EMEMBER] = 0;
+ IRO_IsModifyOp[ETEMPLDEP] = 0;
+ IRO_IsModifyOp[EINSTRUCTION] = 0;
+ IRO_IsModifyOp[EDEFINE] = 0;
+ IRO_IsModifyOp[EREUSE] = 0;
+ IRO_IsModifyOp[EASSBLK] = 0;
+ IRO_IsModifyOp[EVECTOR128CONST] = 0;
+ IRO_IsModifyOp[ECONDASS] = 1;
+}
+
+void IRO_InitializeIRO_IsAssignOpArray(void) {
+ int i;
+
+ for (i = 0; i < MAXEXPR; i++)
+ IRO_IsAssignOp[i] = 0;
+
+ IRO_IsAssignOp[EPOSTINC] = 1;
+ IRO_IsAssignOp[EPOSTDEC] = 1;
+ IRO_IsAssignOp[EPREINC] = 1;
+ IRO_IsAssignOp[EPREDEC] = 1;
+ IRO_IsAssignOp[EINDIRECT] = 0;
+ IRO_IsAssignOp[EMONMIN] = 0;
+ IRO_IsAssignOp[EBINNOT] = 0;
+ IRO_IsAssignOp[ELOGNOT] = 0;
+ IRO_IsAssignOp[EFORCELOAD] = 0;
+ IRO_IsAssignOp[EMUL] = 0;
+ IRO_IsAssignOp[EMULV] = 0;
+ IRO_IsAssignOp[EDIV] = 0;
+ IRO_IsAssignOp[EMODULO] = 0;
+ IRO_IsAssignOp[EADDV] = 0;
+ IRO_IsAssignOp[ESUBV] = 0;
+ IRO_IsAssignOp[EADD] = 0;
+ IRO_IsAssignOp[ESUB] = 0;
+ IRO_IsAssignOp[ESHL] = 0;
+ IRO_IsAssignOp[ESHR] = 0;
+ IRO_IsAssignOp[ELESS] = 0;
+ IRO_IsAssignOp[EGREATER] = 0;
+ IRO_IsAssignOp[ELESSEQU] = 0;
+ IRO_IsAssignOp[EGREATEREQU] = 0;
+ IRO_IsAssignOp[EEQU] = 0;
+ IRO_IsAssignOp[ENOTEQU] = 0;
+ IRO_IsAssignOp[EAND] = 0;
+ IRO_IsAssignOp[EXOR] = 0;
+ IRO_IsAssignOp[EOR] = 0;
+ IRO_IsAssignOp[ELAND] = 0;
+ IRO_IsAssignOp[ELOR] = 0;
+ IRO_IsAssignOp[EASS] = 1;
+ IRO_IsAssignOp[EMULASS] = 1;
+ IRO_IsAssignOp[EDIVASS] = 1;
+ IRO_IsAssignOp[EMODASS] = 1;
+ IRO_IsAssignOp[EADDASS] = 1;
+ IRO_IsAssignOp[ESUBASS] = 1;
+ IRO_IsAssignOp[ESHLASS] = 1;
+ IRO_IsAssignOp[ESHRASS] = 1;
+ IRO_IsAssignOp[EANDASS] = 1;
+ IRO_IsAssignOp[EXORASS] = 1;
+ IRO_IsAssignOp[EORASS] = 1;
+ IRO_IsAssignOp[ECOMMA] = 0;
+ IRO_IsAssignOp[EPMODULO] = 1;
+ IRO_IsAssignOp[EROTL] = 1;
+ IRO_IsAssignOp[EROTR] = 1;
+ IRO_IsAssignOp[EBCLR] = 1;
+ IRO_IsAssignOp[EBTST] = 1;
+ IRO_IsAssignOp[EBSET] = 1;
+ IRO_IsAssignOp[ETYPCON] = 0;
+ IRO_IsAssignOp[EBITFIELD] = 0;
+ IRO_IsAssignOp[EINTCONST] = 0;
+ IRO_IsAssignOp[EFLOATCONST] = 0;
+ IRO_IsAssignOp[ESTRINGCONST] = 0;
+ IRO_IsAssignOp[ECOND] = 0;
+ IRO_IsAssignOp[EFUNCCALL] = 0;
+ IRO_IsAssignOp[EFUNCCALLP] = 0;
+ IRO_IsAssignOp[EOBJREF] = 0;
+ IRO_IsAssignOp[EMFPOINTER] = 0;
+ IRO_IsAssignOp[ENULLCHECK] = 0;
+ IRO_IsAssignOp[EPRECOMP] = 0;
+ IRO_IsAssignOp[ETEMP] = 0;
+ IRO_IsAssignOp[EARGOBJ] = 0;
+ IRO_IsAssignOp[ELOCOBJ] = 0;
+ IRO_IsAssignOp[ELABEL] = 0;
+ IRO_IsAssignOp[ESETCONST] = 0;
+ IRO_IsAssignOp[ENEWEXCEPTION] = 0;
+ IRO_IsAssignOp[ENEWEXCEPTIONARRAY] = 0;
+ IRO_IsAssignOp[EOBJLIST] = 0;
+ IRO_IsAssignOp[EMEMBER] = 0;
+ IRO_IsAssignOp[ETEMPLDEP] = 0;
+ IRO_IsAssignOp[EINSTRUCTION] = 0;
+ IRO_IsAssignOp[EDEFINE] = 0;
+ IRO_IsAssignOp[EREUSE] = 0;
+ IRO_IsAssignOp[EASSBLK] = 0;
+ IRO_IsAssignOp[EVECTOR128CONST] = 0;
+ IRO_IsAssignOp[ECONDASS] = 1;
+}
+
+VarRecord *IRO_FindVar(Object *object, Boolean flag1, Boolean flag2) {
+ VarRecord *var;
+ VarInfo *vi;
+
+ var = object->varptr;
+ if (!var && flag1) {
+ vi = NULL;
+ if (object->datatype == DLOCAL)
+ vi = object->u.var.info;
+ if (vi)
+ vi->usage = 0;
+ var = oalloc(sizeof(VarRecord));
+ var->object = object;
+ var->index = ++IRO_NumVars;
+ var->x6 = 0;
+ var->xA = 0;
+ var->next = NULL;
+ var->defs = NULL;
+ var->uses = NULL;
+ var->x1A = NULL;
+ var->x1E = NULL;
+ var->xB = 0;
+ if (IRO_FirstVar)
+ IRO_LastVar->next = var;
+ else
+ IRO_FirstVar = var;
+ IRO_LastVar = var;
+ object->varptr = var;
+ }
+
+ if (var && !flag2) {
+ var->xB = 1;
+ if (object->datatype == DLOCAL && object->u.var.info && object->u.var.info->noregister == 0)
+ object->u.var.info->noregister = 2;
+ }
+
+ return var;
+}
+
+static void ResetVars(void) {
+ VarRecord *var;
+
+ for (var = IRO_FirstVar; var; var = var->next) {
+ var->xB = 0;
+ if (var->object && var->object->datatype == DLOCAL && var->object->u.var.info) {
+ if (var->object->u.var.info->noregister == 2)
+ var->object->u.var.info->noregister = 0;
+ }
+ }
+}
+
+static void IRO_HandleExceptionActions(IROLinear *linear) {
+ ExceptionAction *action;
+
+ for (action = linear->stmt->dobjstack; action; action = action->prev) {
+ switch (action->type) {
+ case EAT_DESTROYLOCAL:
+ IRO_FindVar(action->data.destroy_local.local, 1, 0);
+ break;
+ case EAT_DESTROYLOCALCOND:
+ IRO_FindVar(action->data.destroy_local_cond.local, 1, 0);
+ break;
+ case EAT_DESTROYLOCALOFFSET:
+ IRO_FindVar(action->data.destroy_local_offset.local, 1, 0);
+ break;
+ case EAT_DESTROYLOCALARRAY:
+ IRO_FindVar(action->data.destroy_local_array.localarray, 1, 0);
+ break;
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYBASE:
+ IRO_FindVar(action->data.destroy_member.objectptr, 1, 0);
+ break;
+ case EAT_DESTROYMEMBERCOND:
+ IRO_FindVar(action->data.destroy_member_cond.objectptr, 1, 0);
+ break;
+ case EAT_DESTROYMEMBERARRAY:
+ IRO_FindVar(action->data.destroy_member_array.objectptr, 1, 0);
+ break;
+ case EAT_CATCHBLOCK:
+ if (action->data.catch_block.catch_object)
+ IRO_FindVar(action->data.catch_block.catch_object, 1, 0);
+ IRO_FindVar(action->data.catch_block.catch_info_object, 1, 0);
+ break;
+ case EAT_ACTIVECATCHBLOCK:
+ IRO_FindVar(action->data.active_catch_block.catch_info_object, 1, 0);
+ break;
+ }
+ }
+}
+
+void IRO_FindAllVars(void) {
+ IROLinear *linear;
+ VarRecord *var;
+
+ linear = IRO_FirstLinear;
+ IRO_NumVars = 0;
+ IRO_FirstVar = IRO_LastVar = NULL;
+
+ while (linear) {
+ if (IS_LINEAR_ENODE(linear, EOBJREF)) {
+ if (Inline_IsObjectData(linear->u.node->data.objref) || linear->u.node->data.objref->datatype == DLOCAL)
+ IRO_FindVar(linear->u.node->data.objref, 1, (linear->flags & IROLF_Ind) != 0);
+ else
+ linear->u.node->data.objref->varptr = NULL;
+ } else if (linear->type == IROLinearFunccall) {
+ if (linear->stmt && IRO_FunctionCallMightThrowException(linear))
+ IRO_HandleExceptionActions(linear);
+ } else if (linear->type == IROLinearAsm) {
+ IAEffects effects;
+ int i;
+ CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects);
+ for (i = 0; i < effects.numoperands; i++)
+ IRO_FindVar(effects.operands[i].object, 1, effects.operands[i].type != IAEffect_3);
+ }
+ linear = linear->next;
+ }
+
+ var = IRO_FirstVar;
+ Bv_AllocVector(&IRO_FuncKills, IRO_NumVars + 1);
+ Bv_SetBit(0, IRO_FuncKills);
+ while (var) {
+ if (Inline_IsObjectData(var->object) || var->xB)
+ Bv_SetBit(var->index, IRO_FuncKills);
+ var = var->next;
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+void IRO_ZapVarPtrs(void) {
+ VarRecord *var;
+
+ for (var = IRO_FirstVar; var; var = var->next)
+ var->object->varptr = NULL;
+}
+
+void IRO_UpdateVars(void) {
+ IROLinear *linear;
+ VarRecord *var;
+
+ ResetVars();
+
+ for (linear = IRO_FirstLinear; linear; linear = linear->next) {
+ if (IS_LINEAR_ENODE(linear, EOBJREF)) {
+ if (Inline_IsObjectData(linear->u.node->data.objref) || linear->u.node->data.objref->datatype == DLOCAL)
+ IRO_FindVar(linear->u.node->data.objref, 0, (linear->flags & IROLF_Ind) || !(linear->flags & IROLF_Reffed));
+ } else if (linear->type == IROLinearFunccall) {
+ if (linear->stmt && IRO_FunctionCallMightThrowException(linear))
+ IRO_HandleExceptionActions(linear);
+ } else if (linear->type == IROLinearAsm) {
+ IAEffects effects;
+ int i;
+ CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects);
+ for (i = 0; i < effects.numoperands; i++)
+ IRO_FindVar(effects.operands[i].object, 0, effects.operands[i].type != IAEffect_3);
+ }
+ }
+
+ var = IRO_FirstVar;
+ Bv_AllocVector(&IRO_FuncKills, IRO_NumVars + 1);
+ Bv_SetBit(0, IRO_FuncKills);
+ while (var) {
+ if (Inline_IsObjectData(var->object) || var->xB)
+ Bv_SetBit(var->index, IRO_FuncKills);
+ var = var->next;
+ }
+}
+
+void IRO_AddElmToList(IROLinear *linear, IROElmList **list) {
+ IROElmList *l = oalloc(sizeof(IROElmList));
+ l->element = linear;
+ l->next = NULL;
+ if (!*list) {
+ *list = l;
+ } else {
+ l->next = *list;
+ *list = l;
+ }
+}
+
+void IRO_DecomposeAddressExpression(IROLinear *linear, IROAddrRecord *rec) {
+ if (IS_LINEAR_DIADIC(linear->u.diadic.left, EADD)) {
+ IRO_DecomposeAddressExpression(linear->u.diadic.left, rec);
+ } else if (IS_LINEAR_ENODE(linear->u.diadic.left, EINTCONST)) {
+ rec->numInts++;
+ IRO_AddElmToList(linear->u.diadic.left, &rec->ints);
+ } else if (IS_LINEAR_ENODE(linear->u.diadic.left, EOBJREF)) {
+ rec->numObjRefs++;
+ IRO_AddElmToList(linear->u.diadic.left, &rec->objRefs);
+ } else {
+ rec->numMisc++;
+ IRO_AddElmToList(linear->u.diadic.left, &rec->misc);
+ }
+
+ if (IS_LINEAR_DIADIC(linear->u.diadic.right, EADD)) {
+ IRO_DecomposeAddressExpression(linear->u.diadic.right, rec);
+ } else if (IS_LINEAR_ENODE(linear->u.diadic.right, EINTCONST)) {
+ rec->numInts++;
+ IRO_AddElmToList(linear->u.diadic.right, &rec->ints);
+ } else if (IS_LINEAR_ENODE(linear->u.diadic.right, EOBJREF)) {
+ rec->numObjRefs++;
+ IRO_AddElmToList(linear->u.diadic.right, &rec->objRefs);
+ } else {
+ rec->numMisc++;
+ IRO_AddElmToList(linear->u.diadic.right, &rec->misc);
+ }
+}
+
+void IRO_DecomposeAddressExpression_Cheap(IROLinear *linear) {
+ if (IS_LINEAR_DIADIC(linear->u.diadic.left, EADD)) {
+ IRO_DecomposeAddressExpression_Cheap(linear->u.diadic.left);
+ } else if (!IS_LINEAR_ENODE(linear->u.diadic.left, EINTCONST)) {
+ if (IS_LINEAR_ENODE(linear->u.diadic.left, EOBJREF)) {
+ IRO_BaseTerms++;
+ TheBaseTerm = linear->u.diadic.left;
+ } else {
+ IRO_VarTerms++;
+ }
+ }
+
+ if (IS_LINEAR_DIADIC(linear->u.diadic.right, EADD)) {
+ IRO_DecomposeAddressExpression_Cheap(linear->u.diadic.right);
+ } else if (!IS_LINEAR_ENODE(linear->u.diadic.right, EINTCONST)) {
+ if (IS_LINEAR_ENODE(linear->u.diadic.right, EOBJREF)) {
+ IRO_BaseTerms++;
+ TheBaseTerm = linear->u.diadic.right;
+ } else {
+ IRO_VarTerms++;
+ }
+ }
+}
+
+VarRecord *IRO_FindAssigned(IROLinear *linear) {
+ VarRecord *rec;
+
+ IRO_IsBitField = 0;
+ if (linear->type == IROLinearOp2Arg)
+ linear = linear->u.diadic.left;
+ else if (linear->type == IROLinearOp1Arg)
+ linear = linear->u.monadic;
+ else
+ CError_FATAL(818);
+
+ if (IS_LINEAR_MONADIC(linear, EINDIRECT))
+ linear = linear->u.monadic;
+
+ if (IS_LINEAR_MONADIC(linear, EBITFIELD)) {
+ IRO_IsBitField = 1;
+ linear = linear->u.monadic;
+ }
+
+ if (IS_LINEAR_DIADIC(linear, EADD)) {
+ if (IS_LINEAR_ENODE(linear->u.diadic.left, EOBJREF) && IS_LINEAR_ENODE(linear->u.diadic.right, EINTCONST)) {
+ linear = linear->u.diadic.left;
+ } else {
+ IRO_BaseTerms = 0;
+ IRO_DecomposeAddressExpression_Cheap(linear);
+ if (IRO_BaseTerms == 1)
+ linear = TheBaseTerm;
+ }
+ }
+
+ if (!IS_LINEAR_ENODE(linear, EOBJREF))
+ return NULL;
+
+ if ((rec = IRO_FindVar(linear->u.node->data.objref, 0, 1)))
+ return rec;
+ else
+ return NULL;
+}
+
+static void GetKillsByIndirectAssignment(IROLinear *linear) {
+ IROListNode *resultList;
+ IROLinear *nd;
+ IROListNode *list;
+ IROListNode *scan;
+ IROLinear *inner;
+ Boolean result;
+ Boolean foundLinear;
+
+ result = 0;
+
+ if (linear->type == IROLinearOp2Arg)
+ linear = linear->u.diadic.left;
+ else
+ linear = linear->u.monadic;
+
+ if (
+ linear &&
+ linear->type == IROLinearOp1Arg &&
+ linear->nodetype == EINDIRECT &&
+ (inner = linear->u.monadic) &&
+ copts.opt_pointer_analysis &&
+ inner->pointsToFunction &&
+ FunctionName
+ )
+ {
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, inner, &resultList);
+ if ((list = resultList)) {
+ for (scan = list; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ result = 1;
+ break;
+ }
+
+ foundLinear = 0;
+ for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) {
+ if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
+ foundLinear = 1;
+ break;
+ }
+ }
+ if (!foundLinear) {
+ result = 1;
+ break;
+ }
+ }
+
+ if (!result) {
+ while (list) {
+ for (nd = list->list.head; nd != list->list.tail->next; nd = nd->next) {
+ if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
+ Object *obj;
+ VarRecord *var;
+ int index;
+
+ obj = nd->u.node->data.objref;
+ CError_ASSERT(952, obj != NULL);
+
+ var = IRO_FindVar(obj, 1, 1);
+ CError_ASSERT(954, var != NULL);
+
+ index = var->index;
+ CError_ASSERT(956, index != 0);
+
+ Bv_SetBit(index, IRO_VarKills);
+ }
+ }
+
+ list = list->nextList;
+ }
+ }
+
+ while (resultList) {
+ IROListNode *next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ result = 1;
+ }
+ } else {
+ result = 1;
+ }
+
+ if (result)
+ Bv_Or(IRO_FuncKills, IRO_VarKills);
+}
+
+static void GetKillsByFunctionCall(IROLinear *linear) {
+ IROListNode *resultList;
+ IROLinear *nd;
+ IROListNode *list;
+ IROListNode *scan;
+ IROLinear *inner;
+ Boolean result;
+ Boolean foundLinear;
+ Object *obj;
+ ObjectList *killList;
+ ObjectList *olist;
+
+ result = 0;
+
+ if (
+ (inner = linear->u.funccall.linear8) &&
+ copts.opt_pointer_analysis &&
+ inner->pointsToFunction &&
+ FunctionName
+ )
+ {
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, inner, &resultList);
+ if (resultList) {
+ for (scan = resultList; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ result = 1;
+ break;
+ }
+
+ foundLinear = 0;
+ for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) {
+ if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
+ foundLinear = 1;
+ obj = nd->u.node->data.objref;
+ CError_ASSERT(1028, obj != NULL);
+
+ killList = NULL;
+ PointerAnalysis_GetFunctionKills(obj, linear, &killList);
+
+ for (olist = killList; olist; olist = olist->next) {
+ if (!olist->object) {
+ result = 1;
+ break;
+ }
+ }
+
+ while (killList) {
+ ObjectList *next = killList->next;
+ IRO_free(killList);
+ killList = next;
+ }
+
+ if (result)
+ break;
+ }
+ }
+
+ if (!foundLinear)
+ result = 1;
+ if (result)
+ break;
+ }
+
+ if (!result) {
+ for (scan = resultList; scan; scan = scan->nextList) {
+ for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) {
+ if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
+ obj = nd->u.node->data.objref;
+ killList = NULL;
+ PointerAnalysis_GetFunctionKills(obj, linear, &killList);
+
+ for (olist = killList; olist; olist = olist->next) {
+ VarRecord *var;
+ int index;
+
+ var = IRO_FindVar(olist->object, 1, 1);
+ CError_ASSERT(1079, var != NULL);
+
+ index = var->index;
+ CError_ASSERT(1081, index != 0);
+
+ Bv_SetBit(index, IRO_VarKills);
+ }
+
+ while (killList) {
+ ObjectList *next = killList->next;
+ IRO_free(killList);
+ killList = next;
+ }
+ }
+ }
+ }
+ }
+
+ while (resultList) {
+ IROListNode *next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ result = 1;
+ }
+ } else {
+ result = 1;
+ }
+
+ if (result)
+ Bv_Or(IRO_FuncKills, IRO_VarKills);
+}
+
+void IRO_GetKills(IROLinear *linear) {
+ VarRecord *var;
+
+ switch (linear->type) {
+ case IROLinearOp1Arg:
+ case IROLinearOp2Arg:
+ if (IRO_IsAssignOp[linear->nodetype]) {
+ IROLinear *assigned;
+ int index;
+
+ var = IRO_FindAssigned(linear);
+ index = 0;
+ if (var) index = var->index;
+ Bv_SetBit(index, IRO_VarKills);
+
+ if (!index)
+ GetKillsByIndirectAssignment(linear);
+ }
+ break;
+ case IROLinearFunccall:
+ GetKillsByFunctionCall(linear);
+ break;
+ case IROLinearAsm: {
+ IAEffects effects;
+ int i;
+
+ CodeGen_GetAsmEffects(linear->u.asm_stmt, &effects);
+ for (i = 0; i < effects.numoperands; i++) {
+ switch (effects.operands[i].type) {
+ case IAEffect_1:
+ case IAEffect_2:
+ case IAEffect_4:
+ if ((var = IRO_FindVar(effects.operands[i].object, 0, 1)))
+ Bv_SetBit(var->index, IRO_VarKills);
+ break;
+ }
+ }
+
+ if (effects.x1 || effects.x4)
+ Bv_Or(IRO_FuncKills, IRO_VarKills);
+ break;
+ }
+ }
+}
+
+void IRO_CheckInit(void) {
+ IRONode *fnode;
+ IROLinear *nd;
+ VarRecord *var;
+ ObjectList *olist;
+ int flag;
+ int i;
+ BitVector *bv;
+
+ IRO_MakeReachable(IRO_FirstNode);
+ fnode = IRO_FirstNode;
+ Bv_AllocVector(&IRO_VarKills, IRO_NumVars + 1);
+
+ while (fnode) {
+ Bv_AllocVector(&fnode->x16, IRO_NumVars + 1);
+ Bv_AllocVector(&fnode->x1E, IRO_NumVars + 1);
+
+ for (nd = fnode->first; nd; nd = nd->next) {
+ if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
+ if (nd->flags & IROLF_Ind) {
+ if (!(nd->flags & IROLF_Assigned) || (nd->flags & IROLF_Used)) {
+ if ((var = IRO_FindVar(nd->u.node->data.objref, 0, 1))) {
+ if (!Bv_IsBitSet(var->index, fnode->x1E))
+ Bv_SetBit(var->index, fnode->x16);
+ }
+ }
+ } else {
+ if ((var = IRO_FindVar(nd->u.node->data.objref, 0, 0))) {
+ Bv_SetBit(var->index, fnode->x1E);
+ }
+ }
+ } else if (nd->type == IROLinearOp2Arg && nd->nodetype == EASS) {
+ if ((var = IRO_FindAssigned(nd)))
+ Bv_SetBit(var->index, fnode->x1E);
+ } else if (nd->type == IROLinearAsm) {
+ IAEffects effects;
+
+ CodeGen_GetAsmEffects(nd->u.asm_stmt, &effects);
+ for (i = 0; i < effects.numoperands; i++) {
+ var = IRO_FindVar(effects.operands[i].object, 0, 1);
+ switch (effects.operands[i].type) {
+ case IAEffect_1:
+ case IAEffect_2:
+ case IAEffect_4:
+ Bv_SetBit(var->index, fnode->x1E);
+ break;
+ }
+ }
+ }
+
+ if (nd == fnode->last)
+ break;
+ }
+
+ fnode = fnode->nextnode;
+ }
+
+ Bv_AllocVector(&bv, IRO_NumVars + 1);
+
+ do {
+ flag = 0;
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ Bv_Copy(fnode->x1E, bv);
+ for (i = 0; i < fnode->numpred; i++)
+ Bv_Or(IRO_NodeTable[fnode->pred[i]]->x1E, bv);
+ if (!Bv_Compare(bv, fnode->x1E)) {
+ Bv_Copy(bv, fnode->x1E);
+ flag = 1;
+ }
+ }
+ } while (flag);
+
+ Bv_Clear(IRO_VarKills);
+
+ for (fnode = IRO_FirstNode; fnode; fnode = fnode->nextnode) {
+ if (fnode->x36) {
+ Bv_Copy(fnode->x16, bv);
+ for (i = 0; i < fnode->numpred; i++)
+ Bv_Minus(IRO_NodeTable[fnode->pred[i]]->x1E, bv);
+ Bv_Or(bv, IRO_VarKills);
+ }
+ }
+
+ for (olist = locals; olist; olist = olist->next) {
+ if ((var = IRO_FindVar(olist->object, 0, 1)) && Bv_IsBitSet(var->index, IRO_VarKills)) {
+ VarInfo *vi = olist->object->u.var.info;
+ if (!IsTempName(olist->object->name) && !is_volatile_object(olist->object)) {
+ if (!IS_TYPE_CLASS(olist->object->type) || !CClass_IsEmpty(TYPE_CLASS(olist->object->type))) {
+ CError_SetErrorToken(&vi->deftoken);
+ CError_Warning(CErrorStr185, olist->object->name->name);
+ }
+ }
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+static void RewriteIndDec(void) {
+ IROLinear *add;
+ IROLinear *indirect;
+ IROLinear *Int;
+ IROLinear *nd;
+ CInt64 value;
+ IROList list;
+
+ for (nd = IRO_FirstLinear; nd; nd = nd->next) {
+ if (
+ nd->type == IROLinearOp1Arg &&
+ (nd->nodetype == EPOSTINC || nd->nodetype == EPOSTDEC) &&
+ !(nd->flags & IROLF_Reffed)
+ ) {
+ indirect = nd->u.monadic;
+ if (
+ indirect->type == IROLinearOp1Arg &&
+ indirect->nodetype == EINDIRECT &&
+ indirect->u.monadic->type == IROLinearOp1Arg &&
+ indirect->u.monadic->nodetype == EBITFIELD
+ ) {
+ value = IRO_GetSelfAssignmentVal(nd);
+ IRO_InitList(&list);
+
+ nd->type = IROLinearOp2Arg;
+ nd->nodetype = EASS;
+ nd->u.diadic.left = indirect;
+ IRO_DuplicateExpr(indirect, &list);
+
+ Int = IRO_NewIntConst(value, indirect->rtype);
+ Int->flags |= IROLF_Used | IROLF_Reffed;
+
+ add = IRO_NewLinear(IROLinearOp2Arg);
+ add->nodetype = EADD;
+ add->u.diadic.left = list.tail;
+ add->u.diadic.left->flags = 0;
+ add->u.diadic.left->flags |= IROLF_Used | IROLF_Reffed;
+ add->u.diadic.right = Int;
+ add->rtype = indirect->rtype;
+ add->flags = 0;
+ add->flags |= IROLF_Used | IROLF_Reffed;
+
+ nd->u.diadic.right = add;
+
+ IRO_AddToList(Int, &list);
+ IRO_AddToList(add, &list);
+ IRO_PasteAfter(list.head, list.tail, indirect);
+ }
+ }
+ }
+}
+
+void IRO_RewriteBitFieldTemps(void) {
+ IROLinear *nd;
+ IROLinear *expr2;
+ Object *obj;
+ VarRecord *var;
+ IROList list;
+
+ for (nd = IRO_FirstLinear; nd; nd = nd->next) {
+ if ((obj = IRO_IsVariable(nd)) && (nd->flags & IROLF_BitfieldIndirect)) {
+ var = IRO_FindVar(obj, 0, 1);
+ CError_ASSERT(1526, var != NULL);
+
+ expr2 = var->x1E;
+ CError_ASSERT(1532, expr2 != NULL);
+
+ IRO_InitList(&list);
+ IRO_DuplicateExpr(expr2, &list);
+ IRO_NopOut(nd->u.monadic);
+ nd->u.monadic = list.tail;
+ IRO_Paste(list.head, list.tail, nd);
+ }
+ }
+}
+
+static Boolean FunctionCallMightUseOrKillAnyAddressedVar(IROLinear *funccall) {
+ IROLinear *funcnd;
+ IROLinear *nd;
+ IROListNode *scan;
+ IROListNode *resultList;
+ ObjectList *olist;
+ ObjectList *killList;
+ VarRecord *var;
+ Boolean result;
+ Boolean foundObjRef;
+ Object *obj;
+
+ result = 0;
+
+ funcnd = funccall->u.funccall.linear8;
+ if (funcnd && copts.opt_pointer_analysis && funcnd->pointsToFunction && FunctionName) {
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, funcnd, &resultList);
+
+ if (resultList) {
+ for (scan = resultList; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ result = 1;
+ break;
+ }
+
+ foundObjRef = 0;
+ for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) {
+ if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
+ foundObjRef = 1;
+ obj = nd->u.node->data.objref;
+ CError_ASSERT(1592, obj != NULL);
+
+ killList = NULL;
+ PointerAnalysis_GetFunctionKills(obj, funccall, &killList);
+ for (olist = killList; olist; olist = olist->next) {
+ if (!olist->object) {
+ result = 1;
+ } else {
+ var = IRO_FindVar(olist->object, 1, 1);
+ CError_ASSERT(1604, var != NULL);
+ if (var->xB)
+ result = 1;
+ }
+
+ if (result)
+ break;
+ }
+
+ while (killList) {
+ ObjectList *next = killList->next;
+ IRO_free(killList);
+ killList = next;
+ }
+
+ if (!result) {
+ killList = NULL;
+ PointerAnalysis_GetFunctionDependencies(obj, funccall, &killList);
+ for (olist = killList; olist; olist = olist->next) {
+ if (!olist->object) {
+ result = 1;
+ } else {
+ var = IRO_FindVar(olist->object, 1, 1);
+ CError_ASSERT(1632, var != NULL);
+ if (var->xB)
+ result = 1;
+ }
+
+ if (result)
+ break;
+ }
+
+ while (killList) {
+ ObjectList *next = killList->next;
+ IRO_free(killList);
+ killList = next;
+ }
+ }
+
+ if (result)
+ break;
+ }
+ }
+
+ if (!foundObjRef)
+ result = 1;
+ if (result)
+ break;
+ }
+
+ while (resultList) {
+ IROListNode *next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ result = 1;
+ }
+ } else {
+ result = 1;
+ }
+
+ return result;
+}
+
+static Boolean IndirectMightUseOrKillAnyAddressedVar(IROLinear *indirect) {
+ Boolean result;
+ IROLinear *inner;
+ IROLinear *nd;
+ IROListNode *scan;
+ IROListNode *resultList;
+ Boolean foundObjRef;
+ Object *obj;
+ VarRecord *var;
+
+ result = 0;
+
+ if (
+ indirect &&
+ indirect->type == IROLinearOp1Arg &&
+ indirect->nodetype == EINDIRECT &&
+ (inner = indirect->u.monadic) &&
+ copts.opt_pointer_analysis &&
+ inner->pointsToFunction &&
+ FunctionName
+ ) {
+ resultList = NULL;
+ PointerAnalysis_LookupLinearNodePointerExpr(FunctionName, inner, &resultList);
+ if (resultList) {
+ for (scan = resultList; scan; scan = scan->nextList) {
+ if (!scan->list.head || !scan->list.tail) {
+ result = 1;
+ break;
+ }
+
+ foundObjRef = 0;
+ for (nd = scan->list.head; nd != scan->list.tail->next; nd = nd->next) {
+ if (nd->type == IROLinearOperand && nd->u.node->type == EOBJREF) {
+ foundObjRef = 1;
+ obj = nd->u.node->data.objref;
+ CError_ASSERT(1723, obj != NULL);
+ var = IRO_FindVar(obj, 1, 1);
+ CError_ASSERT(1725, var != NULL);
+
+ if (var->xB)
+ result = 1;
+ }
+ }
+
+ if (!foundObjRef)
+ result = 1;
+ if (result)
+ break;
+ }
+
+ while (resultList) {
+ IROListNode *next = resultList->nextList;
+ IRO_free(resultList);
+ resultList = next;
+ }
+ } else {
+ result = 1;
+ }
+ } else {
+ result = 1;
+ }
+
+ return result;
+}
+
+void IRO_ScalarizeClassDataMembers(void) {
+ IROLinear *nd;
+ VarRecord *var;
+ Boolean flag;
+ Object *obj;
+ IndirectRecord *irec;
+ IndirectRecordMatch *match;
+ IROLinear *tmp;
+
+ nd = IRO_FirstLinear;
+ IRO_FirstIndirectRecord = NULL;
+ IRO_LastIndirectRecord = NULL;
+ RewriteIndDec();
+ IRO_DumpAfterPhase("RewriteIndDec", 0);
+ flag = 0;
+
+ while (nd) {
+ if (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT) {
+ CheckAddress(nd, &flag);
+ }
+ if (nd->type == IROLinearAsm) {
+ IAEffects effects;
+ SInt32 i;
+ CodeGen_GetAsmEffects(nd->u.asm_stmt, &effects);
+ for (i = 0; i < effects.numoperands; i++) {
+ if ((var = IRO_FindVar(effects.operands[i].object, 0, 1)))
+ CheckAddressConsistency(nd, var, -1, &stvoid);
+ else
+ CError_FATAL(1823);
+ }
+ }
+ if (nd->type == IROLinearFunccall && !flag)
+ flag = FunctionCallMightUseOrKillAnyAddressedVar(nd);
+
+ nd = nd->next;
+ }
+
+ if (flag)
+ DisableAddressedEntries();
+
+ for (irec = IRO_FirstIndirectRecord; irec; irec = irec->next) {
+ if (!(irec->flags & 1)) {
+ IROList list1;
+ IROList list2;
+
+ obj = create_temp_object(irec->type);
+ var = IRO_FindVar(obj, 1, 1);
+ for (match = irec->matches; match; match = match->otherMatches) {
+ IRO_InitList(&list1);
+ IRO_InitList(&list2);
+ IRO_DuplicateExpr(match->nd, &list1);
+ IRO_DuplicateExpr(match->nd, &list2);
+ if (match->nd->type == IROLinearOperand && match->nd->u.node->type == EOBJREF) {
+ tmp = IRO_LocateFather(match->nd);
+ if (irec->flags & 2) {
+ tmp->flags |= IROLF_BitfieldIndirect;
+ var->x1A = match->nd->rtype;
+ var->x1E = list2.tail;
+ }
+ match->nd->u.node = create_objectrefnode(obj);
+ irec->x26 = list2.tail;
+ } else {
+ tmp = IRO_LocateFather(match->nd);
+ if (irec->flags & 2) {
+ tmp->flags |= IROLF_BitfieldIndirect;
+ var->x1A = match->nd->rtype;
+ var->x1E = list2.tail;
+ }
+ irec->x26 = list2.tail;
+
+ IRO_NopOut(tmp->u.monadic);
+ tmp->u.monadic = IRO_NewLinear(IROLinearOperand);
+ tmp->u.monadic->u.node = create_objectrefnode(obj);
+ tmp->u.monadic->rtype = match->nd->rtype;
+ tmp->u.monadic->index = ++IRO_NumLinear;
+ tmp->u.monadic->flags |= IROLF_Ind | IROLF_Reffed;
+ IRO_NopOut(match->nd);
+ IRO_PasteAfter(tmp->u.monadic, tmp->u.monadic, match->nd);
+ }
+ }
+
+ if (ObjectIsArg(irec->var->object)) {
+ IROLinear *op1;
+ IROLinear *op2;
+ IROLinear *op3;
+ IROLinear *op4;
+ IROLinear *op5;
+
+ op1 = IRO_NewLinear(IROLinearOperand);
+ op1->u.node = create_objectrefnode(obj);
+ op1->rtype = op1->u.node->data.objref->type;
+ op1->index = ++IRO_NumLinear;
+ op1->flags |= IROLF_Ind | IROLF_Assigned;
+
+ op2 = list1.tail;
+
+ op3 = IRO_NewLinear(IROLinearOp1Arg);
+ op3->nodetype = EINDIRECT;
+ op3->rtype = irec->type;
+ op3->u.monadic = op1;
+ op3->index = ++IRO_NumLinear;
+ op3->flags |= IROLF_Assigned;
+
+ op4 = IRO_NewLinear(IROLinearOp1Arg);
+ op4->nodetype = EINDIRECT;
+ op4->rtype = irec->type;
+ op4->u.monadic = op2;
+ op4->index = ++IRO_NumLinear;
+ op4->flags |= IROLF_Reffed;
+
+ op5 = IRO_NewLinear(IROLinearOp2Arg);
+ op5->nodetype = EASS;
+ op5->u.diadic.left = op3;
+ op5->u.diadic.right = op4;
+ op5->rtype = irec->type;
+ op5->index = ++IRO_NumLinear;
+
+ op2->next = op4;
+ op4->next = op1;
+ op1->next = op3;
+ op3->next = op5;
+
+ IRO_PasteAfter(list1.head, op5, IRO_FirstLinear);
+ }
+ }
+ }
+
+ IRO_CheckForUserBreak();
+}
+
+static Boolean CheckAddress(IROLinear *nd, Boolean *resultFlag) {
+ IROLinear *inner;
+ VarRecord *var;
+ Boolean result;
+
+ inner = nd->u.monadic;
+ if (inner->type == IROLinearOp1Arg && inner->nodetype == EBITFIELD)
+ inner = inner->u.monadic;
+
+ result = 0;
+
+ if (inner->type == IROLinearOperand && inner->u.node->type == EOBJREF) {
+ if (IS_TYPE_CLASS(inner->u.node->data.objref->type) || IS_TYPE_STRUCT(inner->u.node->data.objref->type) ||
+ IS_TYPE_ARRAY(inner->u.node->data.objref->type)) {
+ if (inner->u.node->data.objref->datatype == DLOCAL) {
+ var = IRO_FindVar(inner->u.node->data.objref, 0, 1);
+ CError_ASSERT(2240, var != NULL);
+ CheckAddressConsistency(nd, var, 0, nd->rtype);
+ result = 1;
+ }
+ }
+ } else if (
+ inner->type == IROLinearOp2Arg &&
+ inner->nodetype == EADD &&
+ inner->u.diadic.left->type == IROLinearOperand &&
+ inner->u.diadic.left->u.node->type == EOBJREF) {
+ if (
+ inner->u.diadic.right->type == IROLinearOperand &&
+ inner->u.diadic.right->u.node->type == EINTCONST &&
+ inner->u.diadic.right->u.node->data.intval.hi == 0) {
+ if (
+ IS_TYPE_CLASS(inner->u.diadic.left->u.node->data.objref->type) ||
+ IS_TYPE_STRUCT(inner->u.diadic.left->u.node->data.objref->type) ||
+ IS_TYPE_ARRAY(inner->u.diadic.left->u.node->data.objref->type)
+ ) {
+ if (inner->u.diadic.left->u.node->data.objref->datatype == DLOCAL) {
+ var = IRO_FindVar(inner->u.diadic.left->u.node->data.objref, 0, 1);
+ CError_ASSERT(2267, var != NULL);
+ CheckAddressConsistency(nd, var, inner->u.diadic.right->u.node->data.intval.lo, nd->rtype);
+ result = 1;
+ }
+ }
+ } else {
+ if (
+ IS_TYPE_CLASS(inner->u.diadic.left->u.node->data.objref->type) ||
+ IS_TYPE_STRUCT(inner->u.diadic.left->u.node->data.objref->type) ||
+ IS_TYPE_ARRAY(inner->u.diadic.left->u.node->data.objref->type)
+ ) {
+ if (inner->u.diadic.left->u.node->data.objref->datatype == DLOCAL) {
+ var = IRO_FindVar(inner->u.diadic.left->u.node->data.objref, 0, 1);
+ CheckAddressConsistency(nd, var, -1, nd->rtype);
+ result = 1;
+ }
+ }
+ }
+ }
+
+ if (!result && !*resultFlag) {
+ *resultFlag = IndirectMightUseOrKillAnyAddressedVar(nd);
+ }
+
+ return 0;
+}
+
+static Boolean CheckAddressConsistency(IROLinear *nd, VarRecord *var, SInt32 addend, Type *type) {
+ IndirectRecord *rp;
+ IndirectRecordMatch *match;
+ UInt32 flag;
+ IROLinear *inner;
+ UInt32 start_bit;
+ UInt32 end_bit;
+
+ flag = 0;
+ inner = nd->u.monadic;
+ if (inner->type == IROLinearOp1Arg && inner->nodetype == EBITFIELD) {
+ start_bit = TYPE_BITFIELD(inner->rtype)->offset + 8 * addend;
+ end_bit = start_bit + TYPE_BITFIELD(inner->rtype)->bitlength - 1;
+ } else {
+ start_bit = 8 * addend;
+ end_bit = start_bit + 8 * type->size - 1;
+ }
+
+ if (var->xB && !copts.opt_pointer_analysis)
+ return 0;
+
+ if (nd->rtype && CParser_IsVolatile(nd->rtype, nd->nodeflags & ENODE_FLAG_QUALS))
+ addend = -1;
+ if (is_volatile_object(var->object))
+ addend = -1;
+
+ for (rp = IRO_FirstIndirectRecord; rp; rp = rp->next) {
+ if (rp->var->index == var->index) {
+ if (rp->flags & 1)
+ return 0;
+
+ if (addend == -1) {
+ flag = 1;
+ break;
+ }
+
+ if (IRO_TypesEqual(rp->type, type) && rp->startbit == start_bit && rp->endbit == end_bit) {
+ match = oalloc(sizeof(IndirectRecordMatch));
+ match->nd = inner;
+ match->otherMatches = NULL;
+ if (!rp->matches) {
+ rp->matches = match;
+ } else {
+ match->otherMatches = rp->matches;
+ rp->matches = match;
+ }
+
+ IRO_Dump("Exact Match of Type and bits at %d and %d\n", rp->linear->index, nd->index);
+ IRO_Dump("Rp->startbit=%d,Rp->endbit=%d,start_bit=%d,end_bit=%d\n", rp->startbit, rp->endbit, start_bit, end_bit);
+ return 1;
+ }
+
+ if (rp->startbit == start_bit && rp->endbit == end_bit && !IRO_TypesEqual(rp->type, type)) {
+ IRO_Dump("match on bits but mismatch on type %d and %d\n", rp->linear->index, nd->index);
+ IRO_Dump("Rp->startbit=%d,Rp->endbit=%d,start_bit=%d,end_bit=%d\n", rp->startbit, rp->endbit, start_bit, end_bit);
+ flag = 1;
+ break;
+ }
+
+ if (rp->startbit >= start_bit && end_bit >= rp->startbit) {
+ IRO_Dump("Overlap detected --1 %d and %d\n", rp->linear->index, nd->index);
+ IRO_Dump("Rp->startbit=%d,Rp->endbit=%d,start_bit=%d,end_bit=%d\n", rp->startbit, rp->endbit, start_bit, end_bit);
+ flag = 1;
+ break;
+ }
+
+ if (rp->startbit < start_bit && rp->endbit >= start_bit) {
+ IRO_Dump("Overlap detected --2 %d and %d\n", rp->linear->index, nd->index);
+ IRO_Dump("Rp->startbit=%d,Rp->endbit=%d,start_bit=%d,end_bit=%d\n", rp->startbit, rp->endbit, start_bit, end_bit);
+ flag = 1;
+ break;
+ }
+ }
+ }
+
+ if (flag) {
+ DisableEntries(rp);
+ if (addend >= 0)
+ return 0;
+ }
+
+ IRO_Dump("Create Entry at %d\n", nd->index);
+ IRO_Dump("start_bit=%d,end_bit=%d\n", start_bit, end_bit);
+
+ rp = oalloc(sizeof(IndirectRecord));
+ rp->linear = nd;
+ rp->flags = 0;
+ rp->var = var;
+ rp->addend = addend;
+ rp->size = type->size;
+ rp->type = type;
+ rp->next = NULL;
+ rp->matches = oalloc(sizeof(IndirectRecordMatch));
+ rp->matches->nd = inner;
+ rp->matches->otherMatches = NULL;
+ rp->startbit = start_bit;
+ rp->endbit = end_bit;
+
+ if (nd->type == IROLinearOp1Arg && nd->nodetype == EINDIRECT &&
+ nd->u.monadic->type == IROLinearOp1Arg && nd->u.monadic->nodetype == EBITFIELD)
+ rp->flags |= 2;
+
+ if (!(IS_TYPE_FLOAT(type) || IS_TYPE_INT(type) || IS_TYPE_POINTER_ONLY(type)) ||
+ addend == -1 || ((inner->flags & IROLF_4000) && ObjectIsArg(var->object)))
+ rp->flags |= 1;
+
+ if (IRO_FirstIndirectRecord)
+ IRO_LastIndirectRecord->next = rp;
+ else
+ IRO_FirstIndirectRecord = rp;
+ IRO_LastIndirectRecord = rp;
+ return 1;
+}
+
+static void DisableEntries(IndirectRecord *irec) {
+ IndirectRecord *scan;
+
+ for (scan = IRO_FirstIndirectRecord; scan; scan = scan->next) {
+ if (irec->var->index == scan->var->index)
+ scan->flags |= 1;
+ }
+}
+
+static void DisableAddressedEntries(void) {
+ IndirectRecord *scan;
+
+ for (scan = IRO_FirstIndirectRecord; scan; scan = scan->next) {
+ if (scan->var->xB)
+ scan->flags |= 1;
+ }
+}
+
+static UInt32 ObjectIsArg(Object *obj) {
+ ObjectList *scan;
+
+ for (scan = arguments; scan; scan = scan->next) {
+ if (scan->object == obj)
+ return 1;
+ }
+
+ return 0;
+}
+
diff --git a/compiler_and_linker/FrontEnd/Optimizer/IroVars.h b/compiler_and_linker/FrontEnd/Optimizer/IroVars.h
new file mode 100644
index 0000000..2af5b4d
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/Optimizer/IroVars.h
@@ -0,0 +1,51 @@
+#ifndef COMPILER_IROVARS_H
+#define COMPILER_IROVARS_H
+
+#include "IrOptimizer.h"
+#include "compiler/enode.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+struct VarRecord {
+ UInt16 index;
+ Object *object;
+ int x6;
+ Boolean xA;
+ Boolean xB;
+ Boolean xC;
+ VarRecord *next;
+ IRODef *defs;
+ IROUse *uses;
+ Type *x1A; // bitfield-related
+ IROLinear *x1E;
+};
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+extern VarRecord *IRO_FirstVar;
+extern VarRecord *IRO_LastVar;
+extern SInt32 IRO_NumVars;
+extern Boolean IRO_IsBitField;
+extern SInt32 IRO_BaseTerms;
+extern SInt32 IRO_VarTerms;
+extern Boolean IRO_IsModifyOp[MAXEXPR];
+extern Boolean IRO_IsAssignOp[MAXEXPR];
+
+extern void IRO_InitializeIRO_IsModifyOpArray(void);
+extern void IRO_InitializeIRO_IsAssignOpArray(void);
+extern VarRecord *IRO_FindVar(Object *object, Boolean flag1, Boolean flag2);
+extern void IRO_FindAllVars(void);
+extern void IRO_ZapVarPtrs(void);
+extern void IRO_UpdateVars(void);
+extern void IRO_AddElmToList(IROLinear *linear, IROElmList **list);
+extern void IRO_DecomposeAddressExpression(IROLinear *linear, IROAddrRecord *rec);
+extern void IRO_DecomposeAddressExpression_Cheap(IROLinear *linear);
+extern VarRecord *IRO_FindAssigned(IROLinear *linear);
+extern void IRO_GetKills(IROLinear *linear);
+extern void IRO_CheckInit(void);
+extern void IRO_RewriteBitFieldTemps(void);
+extern void IRO_ScalarizeClassDataMembers(void);
+
+#endif