diff options
author | Ash Wolf <ninji@wuffs.org> | 2022-11-20 00:07:22 -0500 |
---|---|---|
committer | Ash Wolf <ninji@wuffs.org> | 2022-11-20 00:07:22 -0500 |
commit | 9d2728a5605f651934fe67a6fe6986b3e4a2c011 (patch) | |
tree | e81e0a3588a0c8d1855bf28316efe27d86b04d66 /compiler_and_linker | |
parent | 9a46dd0e2e80790d9848c0bbd718932a27c23269 (diff) | |
download | MWCC-9d2728a5605f651934fe67a6fe6986b3e4a2c011.tar.gz MWCC-9d2728a5605f651934fe67a6fe6986b3e4a2c011.zip |
add a bunch of code and a ton of stub files for later
Diffstat (limited to 'compiler_and_linker')
90 files changed, 21563 insertions, 312 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CPrep.c b/compiler_and_linker/FrontEnd/C/CPrep.c index 4e3ffea..4b66e88 100644 --- a/compiler_and_linker/FrontEnd/C/CPrep.c +++ b/compiler_and_linker/FrontEnd/C/CPrep.c @@ -46,15 +46,6 @@ static void gotonexttoken(); extern SInt16 *CLT_filesp; extern CPrepFileInfo **CLT_filestack; -//#define OPT_OFFSET(optname) ((short) (((char *) (&copts.optname)) - ((char *) &copts))) -#define OPT_OFFSET(optname) ((short) ( &((COpts *)0)->optname )) -enum { - OPT_OFFSET_MASK = 0x1FFF, - OPT_FLAG_2000 = 0x2000, - OPT_FLAG_4000 = 0x4000, - OPT_FLAG_8000 = 0x8000 -}; - struct CompilerOption { char *name; short bits; diff --git a/compiler_and_linker/unsorted/AddPropagation.c b/compiler_and_linker/unsorted/AddPropagation.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/AddPropagation.c diff --git a/compiler_and_linker/unsorted/Alias.c b/compiler_and_linker/unsorted/Alias.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/Alias.c diff --git a/compiler_and_linker/unsorted/BitVectors.c b/compiler_and_linker/unsorted/BitVectors.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/BitVectors.c diff --git a/compiler_and_linker/unsorted/CABI.c b/compiler_and_linker/unsorted/CABI.c index 0b29b9d..e903797 100644 --- a/compiler_and_linker/unsorted/CABI.c +++ b/compiler_and_linker/unsorted/CABI.c @@ -9,7 +9,7 @@ static void *cabi_pathcur; // TODO type static TypeClass *cabi_loop_class; static Boolean cabi_loop_construct; -short CABI_GetStructResultArgumentIndex(void) { +short CABI_GetStructResultArgumentIndex(TypeFunc *tfunc) { return 0; } diff --git a/compiler_and_linker/unsorted/CBrowse.c b/compiler_and_linker/unsorted/CBrowse.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CBrowse.c diff --git a/compiler_and_linker/unsorted/CClass.c b/compiler_and_linker/unsorted/CClass.c index 7932586..0d2091b 100644 --- a/compiler_and_linker/unsorted/CClass.c +++ b/compiler_and_linker/unsorted/CClass.c @@ -1,4 +1,11 @@ #include "compiler/CClass.h" +#include "compiler/CError.h" +#include "compiler/CInline.h" +#include "compiler/CMangler.h" +#include "compiler/CParser.h" +#include "compiler/CompilerTools.h" +#include "compiler/CodeGen.h" +#include "compiler/objects.h" typedef struct OVClassBase { struct OVClassBase *next; @@ -23,8 +30,17 @@ typedef struct OVClass { Boolean alloced_vtable; } OVClass; +typedef struct ThunkList { + struct ThunkList *next; + Object *thunkobj; + Object *obj; + SInt32 a; + SInt32 b; + SInt32 c; +} ThunkList; + static TypeClass *main_class; -static void *cclass_thunklist; // TODO type +static ThunkList *cclass_thunklist; static TypeClass *cclass_isbase_mostderived; static void *cclass_isbase_foundoffset; // TODO type static Boolean cclass_isambigbase; @@ -45,8 +61,45 @@ static SInt32 cclass_dominator_ooffset; static Object *cclass_dominator_eobject; void CClass_Init(void) {} -void CClass_GenThunks(void) {} -static Object *CClass_ThunkObject(Object *obj, SInt32 a, SInt32 b, SInt32 c) {} + +void CClass_GenThunks(void) { + ThunkList *list; + + for (list = cclass_thunklist; list; list = list->next) { + list->obj->flags |= OBJECT_FLAGS_4; + 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) {} static UInt8 CClass_IsCovariantResult(Type *a, UInt32 qualA, Type *b, UInt32 qualB) {} UInt8 CClass_GetOverrideKind(TypeFunc *a, TypeFunc *b, Boolean errorflag) {} @@ -58,7 +111,7 @@ ENode *CClass_DefaultConstructorCall(TypeClass *a, TypeClass *b, ENode *expr, SI Object *CClass_AssignmentOperator(TypeClass *tclass) {} Object *CClass_CopyConstructor(TypeClass *tclass) {} NameSpaceObjectList *CClass_MemberObject(TypeClass *tclass, HashNameNode *name) {} -Object *CClass_Constructor(TypeClass *tclass) {} +NameSpaceObjectList *CClass_Constructor(TypeClass *tclass) {} Object *CClass_Destructor(TypeClass *tclass) {} Boolean CClass_IsConstructor(Object *obj) {} Boolean CClass_IsDestructor(Object *obj) {} diff --git a/compiler_and_linker/unsorted/CCompiler.c b/compiler_and_linker/unsorted/CCompiler.c index 8339cf6..6159517 100644 --- a/compiler_and_linker/unsorted/CCompiler.c +++ b/compiler_and_linker/unsorted/CCompiler.c @@ -1,9 +1,10 @@ -#include "compiler/common.h" -#include "compiler.h" +#include "compiler/CCompiler.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CompilerTools.h" +#include "compiler/CodeGen.h" #include "compiler/types.h" #include "pref_structs.h" -#include "compiler/CompilerTools.h" -#include "compiler/CPrep.h" Boolean systemHandles; diff --git a/compiler_and_linker/unsorted/CException.c b/compiler_and_linker/unsorted/CException.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CException.c diff --git a/compiler_and_linker/unsorted/CExpr.c b/compiler_and_linker/unsorted/CExpr.c index e73c4bb..9968bab 100644 --- a/compiler_and_linker/unsorted/CExpr.c +++ b/compiler_and_linker/unsorted/CExpr.c @@ -1,123 +1,5057 @@ #include "compiler/CExpr.h" +#include "compiler/CABI.h" +#include "compiler/CClass.h" +#include "compiler/CDecl.h" #include "compiler/CError.h" +#include "compiler/CInit.h" +#include "compiler/CInline.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CInt64.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" -Boolean (*name_obj_check)(void *, Object *); // TODO figure out the right type +Boolean (*name_obj_check)(HashNameNode *, Object *); Boolean disallowgreaterthan; -void CExpr_RewriteConst() {} -void optimizecomm() {} -static void checkadditive() {} -static void CExpr_CompareConvert() {} -static void CExpr_ConstResult() {} -static void makemultnode() {} -static void makedivnode() {} -static void canadd2() {} -void canadd() {} -static void addconst() {} -static void integralpointerpromote() {} -static void padd() {} -static void psub() {} -static void makeaddnode() {} -static void makesubnode() {} -void checkreference() {} -static ENode *pointer_generation2(ENode *expr) {} -ENode *pointer_generation(ENode *expr) {} -void CExpr_PointerGeneration() {} -static void CExpr_ConstPointerCheck() {} -void oldassignmentpromotion() {} -void argumentpromotion() {} -void classargument() {} -ENodeList *CExpr_ScanExpressionList(Boolean flag) {} -static void skipcommaexpr() {} -void CExpr_DoExplicitConversion() {} -static void CExpr_TemplArgDepCast() {} -static void CExpr_ParseExplicitConversion() {} -static void CExpr_MemberVarAccess() {} -static void CExpr_IsTemplateFunc() {} -static void CExpr_ExplicitTemplateArgCheck() {} -void CExpr_MakeNameLookupResultExpr() {} -static void CExpr_NewPTMType() {} -static void CExpr_ParseNameResultExpr() {} -static void CExpr_ParseRotate() {} -static void CExpr_ParseNextArg() {} -static void CExpr_ParseVecStep() {} -static void CExpr_BuiltInComputeAlign() {} -static void CExpr_AtomTypeID() {} -static void CExpr_BuiltInComputeType() {} -static void CExpr_BuiltInClassifyType() {} -static void CExpr_BuiltInComputeVArgType() {} -static void CExpr_ParseTypeExpression() {} -static void CExpr_ParseBuiltin() {} -static void CExpr_ParseBuiltin_isintconst() {} -static void primary_expression() {} -static void CExpr_SimpleExplicitConversion() {} -static void CExpr_NewPTMFCall() {} -static void call_ptmf() {} -static void CExpr_DummyDestr() {} -static void postfix_expression() {} -static void CExpr_ParseSizeof() {} -void scansizeof() {} -static void CExpr_ParseAlignof() {} -void scanalignof() {} -static void logicalexpression() {} -void getnodeaddress() {} -static void CExpr_MakeStaticMemberList() {} -static void CExpr_MakePTDM() {} -void getpointertomemberfunc() {} -static void getpointertomember() {} -void CExpr_New_ELOGNOT_Node() {} -void CExpr_New_EMONMIN_Node() {} -void CExpr_New_EBINNOT_Node() {} -void unary_expression() {} -void do_castnullcheck() {} -void CExpr_SafeClassPointerCast() {} -void PointerToMemberCast() {} -void CExpr_MemberPointerConversion() {} -static void CExpr_MemberPointerCast() {} -void do_typecast() {} -static void isvectorconst() {} -void cast_expression() {} -static void pm_expression() {} -void CExpr_New_EMUL_Node() {} -void CExpr_New_EDIV_Node() {} -void CExpr_New_EMODULO_Node() {} -void CExpr_New_EADD_Node() {} -void CExpr_New_ESUB_Node() {} -void CExpr_New_ESHL_Node() {} -void CExpr_New_ESHR_Node() {} -static void pointercompare() {} -static void unsigncheck() {} -void CExpr_New_ELESS_Node() {} -void CExpr_New_ELESSEQU_Node() {} -void CExpr_New_EGREATER_Node() {} -void CExpr_New_EGREATEREQU_Node() {} -void memberpointercompare() {} -void CExpr_New_EEQU_Node() {} -void CExpr_New_ENOTEQU_Node() {} -void CExpr_New_EAND_Node() {} -void CExpr_New_EXOR_Node() {} -void CExpr_New_EOR_Node() {} -void CExpr_New_ELAND_Node() {} -void CExpr_New_ELOR_Node() {} -void CExpr_NewDyadicNode() {} -static void CExpr_GetDyadicInfo() {} -static void CExpr_ParseDyadicExpression() {} -static void CExpr_IsBlockMoveType() {} -void CExpr_New_ECOND_Node() {} -static void conditional_expression() {} -static void CExpr_MakeOpAssNode() {} -static void makeassignmentnode() {} -static void makepassignmentnode() {} -static void makemulassignmentnode() {} -static void CExpr_TransformOpAssign() {} -ENode *assignment_expression(void) {} -ENode *conv_assignment_expression(void) {} -static void CExpr_HasSideEffect() {} -void CExpr_CheckUnusedExpression() {} -void s_expression() {} -ENode *expression(void) {} -void CExpr_IntegralConstExprType() {} -ENode *CExpr_IntegralConstOrDepExpr(void) {} -void CExpr_IntegralConstExpr() {} -void CExpr_CheckUnwantedAssignment() {} -void CExpr_ParseAsmExpr() {} +// MOVE ME +extern ENode *CIRTrans_TransformOpAss(ENode *); +extern ENode *CTempl_MakeTemplDepExpr(ENode *, ENodeType, ENode *); +extern Boolean CTemplTool_IsTemplateArgumentDependentType(Type *type); +extern Boolean CTemplTool_IsTemplateArgumentDependentExpression(ENode *expr); +extern ENode *CSOM_MemberVarAccess(BClassList *path, ObjMemberVar *var, ENode *expr); +extern TemplArg *CTempl_ParseUncheckTemplArgs(void *a, Boolean flag); +extern Boolean CObjC_IsCompatibleType(Type *a, Type *b); +extern Type *CObjC_GetObjCType_id(Boolean flag); +extern ENode *CExcept_ScanThrowExpression(void); +extern void PPCError_Error(int code, ...); +extern ENode *CObjC_ParseSelectorExpression(void); +extern ENode *CObjC_ParseEncodeExpression(void); +extern ENode *CObjC_ParseProtocolExpression(void); +extern ENode *CObjC_ParseAtExpression(void); +extern ENode *CObjC_ParseMessageExpression(void); +extern ENode *CRTTI_Parse_const_cast(void); +extern ENode *CRTTI_Parse_dynamic_cast(void); +extern ENode *CRTTI_Parse_reinterpret_cast(void); +extern ENode *CRTTI_Parse_static_cast(void); +extern ENode *CRTTI_ParseTypeID(void); +extern Boolean CObjC_IsType_id(Type *type); +extern ENode *CObjC_CheckModernSendMessage(Type *type, ENode *expr); + +// 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_10000) && 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: +#line 105 + CError_FATAL(); + } + } + } + + 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 { +#line 480 + CError_FATAL(); + } + } else { + if (stsignedlong.size == 4) { + type = TYPE(&stsignedlong); + } else if (stsignedint.size == 4) { + type = TYPE(&stsignedint); + } else { +#line 486 + CError_FATAL(); + } + } + } + + 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_FLAGS_2)) + 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(114); + + args = CExpr_ScanExpressionList(1); + if (tk != ')') { + CError_Error(115); + 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; + +#line 1152 + CError_ASSERT(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(CScopeParseResult *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(CScopeParseResult *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(0xDD); + return nullnode(); + default: +#line 1268 + CError_FATAL(); + } + } + + 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; + } + +#line 1278 + CError_FATAL(); + return NULL; +} + +static Type *CExpr_NewPTMType(EMemberInfo *member, Object *obj) { + TypeMemberPointer *ptm; + TypeMethod *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) { +#line 1306 + CError_ASSERT(member->list->object->otype == OT_OBJECT); + obj = OBJECT(member->list->object); +#line 1308 + CError_ASSERT(IS_TYPE_FUNC(obj->type)); + } + + tmethod = galloc(sizeof(TypeMethod)); + memclrw(tmethod, sizeof(TypeMethod)); + *tmethod = *TYPE_METHOD(obj->type); + +#line 1312 + CError_ASSERT(tmethod->args); + + tmethod->args = tmethod->args->next; + CDecl_MakePTMFuncType(TYPE_FUNC(tmethod)); + tmethod->flags &= ~FUNC_FLAGS_2; + + ptm->size = 12; + ptm->ty2 = TYPE(tmethod->theclass); + ptm->ty1 = TYPE(tmethod); + } + + return TYPE(ptm); +} + +static ENode *CExpr_ParseNameResultExpr(CScopeParseResult *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->x8) { + if (copts.cplusplus) { + if (IS_TYPE_TEMPLATE(pr->x8)) { + if (TYPE_TEMPLATE(pr->x8)->dtype == TEMPLDEP_ARGUMENT && TYPE_TEMPLATE(pr->x8)->u.pid.type == TPT_NONTYPE) { + result = CExpr_NewTemplDepENode(TDE_PARAM); + result->data.templdep.u.pid = TYPE_TEMPLATE(pr->x8)->u.pid; + tk = lex(); + return result; + } + if (TYPE_TEMPLATE(pr->x8)->dtype == TEMPLDEP_QUALNAME && !pr->x20) { + result = CExpr_NewTemplDepENode(TDE_QUALNAME); + result->data.templdep.u.qual.type = TYPE_TEMPLATE(pr->x8)->u.qual.type; + result->data.templdep.u.qual.name = TYPE_TEMPLATE(pr->x8)->u.qual.name; + tk = lex(); + return result; + } + } + tk = lex(); + return CExpr_ParseExplicitConversion(pr->x8, pr->xC); + } + 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_FLAGS_100)) { + result = CExpr_NewTemplDepENode(TDE_QUALTEMPL); // not sure this is right tbh + 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(114); + return nullnode(); + } + if ((tk = lex()) != ')') { + CError_Error(115); + return nullnode(); + } + if (!expr && (!cscope_currentfunc || !cscope_currentclass || !cscope_is_member_func)) { + CError_Error(221); + return nullnode(); + } + if (pr->isambig) + CError_Error(188); + + 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_FLAGS_100)) { + 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) { +#line 1521 + CError_ASSERT(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(188); + result = checkreference(CExpr_MemberVarAccess(pr->bcl_18, OBJ_MEMBER_VAR(pr->obj_10), expr)); + tk = lex(); + return result; + } + break; + default: +#line 1552 + CError_FATAL(); + } + + 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))) { +#line 1564 + CError_ASSERT(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))) { +#line 1591 + CError_ASSERT(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.require_prototypes) + CError_Error(178); + + 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); + } + +#line 1711 + CError_FATAL(); + return NULL; +} + +static ENode *CExpr_ParseRotate(Boolean is_right) { + ENode *expr1; + ENode *expr2; + + if (lex() != '(') { + CError_Error(114); + return nullnode(); + } + + tk = lex(); + expr1 = assignment_expression(); + + if (tk != ',') { + CError_Error(116); + return nullnode(); + } + + tk = lex(); + expr2 = assignment_expression(); + + if (tk != ')') { + CError_Error(115); + 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; + CScopeParseResult pr; + ENode *expr; + SInt32 rounded_size; + + if ((tk = lex()) != '(') { + CError_Error(114); + return nullnode(); + } + if ((tk = lex()) != TK_IDENTIFIER) { + CError_Error(0x6B); + return nullnode(); + } + + list = CScope_FindObjectList(&pr, tkidentifier); + if (!list) { + CError_Error(140, tkidentifier->name); + return nullnode(); + } + + if (list->object->otype != OT_OBJECT || OBJECT(list->object)->datatype != DLOCAL) { + CError_Error(140, 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(115); + 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(121); + + if (tk != ')') + CError_ErrorSkip(115); + 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(144); + type = expr->rtype; + } + + CDecl_CompleteType(type); + if (IS_TYPE_VECTOR(type)) { + switch (TYPE_STRUCT(type)->stype) { + case STRUCT_TYPE_4: + case STRUCT_TYPE_5: + case STRUCT_TYPE_6: + value = 16; + break; + case STRUCT_TYPE_7: + case STRUCT_TYPE_8: + case STRUCT_TYPE_9: + case STRUCT_TYPE_E: + value = 8; + break; + default: + value = 4; + } + expr = intconstnode(TYPE(&stsignedint), value); + } else { + PPCError_Error(104, "vec_step", "vec_step", type, 0); + } + } else { + CError_Error(114); + } + + 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: +#line 1976 + CError_FATAL(); + 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(146); + 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(121); + + if (tk != ')') + CError_ErrorSkip(115); + 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(144); + + 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(121); + else + tk = lex(); + + if (ENODE_IS(expression(), EINTCONST)) + CInt64_SetLong(&expr->data.intval, 1); + + if (tk != ')') + CError_ErrorSkip(115); + else + tk = lex(); + + return expr; +} + +static ENode *primary_expression(Boolean flag) { + CScopeParseResult 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(115); + else + tk = lex(); + if (ENODE_IS(expr, EASS)) + 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(141); + 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(114); + + 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(115); + return nullnode(); + } else { +#line 2465 + CError_FATAL(); + 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(115); + 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) { +#line 2568 + CError_ASSERT(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; + CScopeParseResult 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.x8) && tk == TK_COLON_COLON) { + tk = lex(); + nspace = TYPE_CLASS(pr.x8)->nspace; + goto loop; + } else { + if (!is_typesame(pr.x8, expr->rtype)) + CError_Error(146); + 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.x8, expr->rtype)) + CError_Error(146); + 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(146); + 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(146); + goto parsed; + } + } + + CError_Error(141); + return NULL; + +parsed: + if (tk == '(') { + if ((tk = lex()) != ')') + CError_Error(115); + else + tk = lex(); + } else { + CError_Error(114); + } + + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = &stvoid; + return expr; +} + +static ENode *postfix_expression(Boolean flag) { + CScopeParseResult 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(125); + else + tk = lex(); + goto loop; + } + +#line 2753 + CError_ASSERT((expr = conv.left)); + CError_ASSERT((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(148); + goto dont_do_indirect; + } + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TPTR_TARGET(expr->rtype); + dont_do_indirect: + if (tk != ']') + CError_ErrorSkip(125); + else + tk = lex(); + goto loop; + + case '(': + funcexpr = CExpr_PointerGeneration(expr); + if (copts.cplusplus) { + if (CExpr_CheckOperator('(', funcexpr, NULL, &conv)) { +#line 2775 + CError_ASSERT((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(115); + + 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)) { +#line 2810 + CError_ASSERT((subexpr = conv.x0)); + expr = pointer_generation(subexpr); + } + } + + if (!IS_TYPE_POINTER(expr->rtype)) { + CError_ErrorSkip(148); + 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(expr->rtype, expr))) + return subexpr; + + if (!(TYPE_CLASS(expr->rtype)->flags & CLASS_FLAGS_2)) + CError_Error(136, expr->rtype, 0); + + if ((tk = lex()) == TK_TEMPLATE && (tk = lex()) != TK_IDENTIFIER) + CError_Error(107); + + if (CScope_ParseMemberName(TYPE_CLASS(expr->rtype), &pr, 0)) { + if (pr.x1C) { + if ((tk = lex()) == '(') { + if ((tk = lex()) != ')') + CError_Error(115); + else + tk = lex(); + } else { + CError_Error(114); + } + + 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_3) { + if (copts.cplusplus && (subexpr = CExpr_DummyDestr(expr))) + return subexpr; + CError_ErrorSkip(149); + 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(107); + return expr; + } + + member = ismember(TYPE_STRUCT(expr->rtype), tkidentifier); + if (!member) { + if (!expr->rtype->size) + CError_Error(136, expr->rtype, 0); + else + CError_Error(150, tkidentifier->name); + return expr; + } + + if (!IS_TYPE_POINTER(expr->data.monadic->rtype)) { + CError_ErrorSkip(149); + 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; + } +#line 2952 + CError_ASSERT((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; + } +#line 2976 + CError_ASSERT((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(286); + + if (CTemplTool_IsTemplateArgumentDependentType(type)) { + expr = CExpr_NewTemplDepENode(TDE_TYPEEXPR); + expr->data.templdep.u.typeexpr.u.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(136, type, 0); + else + CError_Error(146); + } + + return intconstnode(CABI_GetSizeTType(), type->size); +} + +SInt32 scansizeof(void) { + ENode *expr; + + expr = CExpr_ParseSizeof(); + if (!ENODE_IS(expr, EINTCONST)) { + CError_Error(190); + 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(364); + + if (CTemplTool_IsTemplateArgumentDependentType(type)) { + expr = CExpr_NewTemplDepENode(TDE_unk2); + expr->data.templdep.u.typeexpr.u.type = type; + return expr; + } + + if (type->size == 0) { + if (IS_TYPE_CLASS(type) || IS_TYPE_STRUCT(type)) + CError_Error(136, type, 0); + else + CError_Error(146); + } + + 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(190); + 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(142); + 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(189); + } + + 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(175); + obj->flags |= OBJECT_FLAGS_2; + if (flag && !copts.cplusplus && obj->sclass == TK_REGISTER) + CError_Error(163); + break; + case EFUNCCALL: + if (flag && !IS_TYPE_POINTER_ONLY(result->data.monadic->data.funccall.functype->functype)) + CError_Warning(142); + break; + case EBITFIELD: + CError_Error(144); + 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(331); + 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; + +#line 3414 + CError_ASSERT(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; + TypeMethod *tmethod; + OLinkList *olist; + SInt32 data[3]; + +#line 3442 + CError_ASSERT(ENODE_IS(expr, EMEMBER)); + + if (expr->data.emember->expr && !copts.cpp_extensions) + CError_Error(141); + + if (!copts.cpp_extensions) { + if (!(expr->data.emember->x11 && expr->data.emember->pr_1D)) { + if (type && IS_TYPE_MEMBERPOINTER(type)) + CError_Warning(331); + } + } + + 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(146); + 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; + +#line 3503 + CError_ASSERT(obj->otype == OT_OBJECT && IS_TYPE_NONSTATIC_METHOD(obj->type)); + + if (TYPE_FUNC(obj->type)->flags & FUNC_FLAGS_100000) + CError_Error(190); + + 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->x1E; + 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) { +#line 3554 + CError_ASSERT(ENODE_IS(expr, EMEMBER)); + + if (expr->data.emember->expr) + CError_Error(141); + + 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; +#line 3593 + CError_ASSERT((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(144); + 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; +#line 3652 + CError_ASSERT((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(144); + 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; +#line 3702 + CError_ASSERT((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; +#line 3748 + CError_ASSERT((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; +#line 3776 + CError_ASSERT((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)) { +#line 3809 + CError_ASSERT(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_MONAND); + 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; +#line 3840 + CError_ASSERT((expr = conv.left)); + } + + if (!IS_TYPE_POINTER(expr->rtype)) { + CError_Error(148); + 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; +#line 3852 + CError_ASSERT((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(144); + 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.ANSI_strict) + break; + + if ((tk = lex()) != TK_IDENTIFIER) { + CError_Error(107); + 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; + +#line 3984 + CError_ASSERT(IS_TYPE_CLASS(tm1->ty2)); +#line 3985 + CError_ASSERT(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(188); + + 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(247, 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(164); + 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; + UInt32 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(247, 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, flags, 1); + + if (ENODE_IS(expr, EOBJREF) && IS_TYPE_NONSTATIC_METHOD(expr->data.objref->type)) { + CError_Error(221); + 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(247, 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 |= 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(247, 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(247, 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(247, 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(115); + else + tk = lex(); + + if (di.name) + CError_Error(164); + + if (copts.altivec_model && tk == '(' && IS_TYPE_VECTOR(di.thetype)) { + tk = lex(); + expr = s_expression(); + if (tk != ')') + CError_ErrorSkip(115); + 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.ANSI_strict || 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)) { +#line 4457 + CError_ASSERT((left = conv.x0)); + goto restart; + } + + if (!IS_TYPE_POINTER(left->rtype)) { + CError_Error(148); + 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(142); + return left; + } + common_part: + if (!IS_TYPE_CLASS(left->rtype)) { + CError_Error(149); + return left; + } + if (!IS_TYPE_MEMBERPOINTER(right->rtype)) { + CError_Error(144); + 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(146); + 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 { +#line 4535 + CError_ASSERT(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; +#line 4566 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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; +#line 4592 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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; +#line 4618 + CError_ASSERT((left = conv.left)); + CError_ASSERT((right = conv.right)); + } + + left = integralpromote(left); + right = integralpromote(right); + CExpr_ArithmeticConversion(&left, &right); + + if (iszero(right)) { + if (!no_warning) + CError_Warning(139); + 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; +#line 4665 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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; +#line 4690 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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; +#line 4715 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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; +#line 4752 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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(245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); + } + } else { + CError_Error(245, 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(245, 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(144); +#line 4847 + CError_ASSERT(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(144); +#line 4855 + CError_ASSERT(IS_TYPE_POINTER_ONLY(ltype)); + right->rtype = TYPE(&stunsignedlong); + } else if (!is_typeequal(ltype, rtype)) { + CError_Error(245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); + } + } else { + if (!is_typeequal(ltype, rtype)) + CError_Error(245, 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; +#line 4929 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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; +#line 4976 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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; +#line 5023 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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; +#line 5070 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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(144); + 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(144); + 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; +#line 5201 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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; +#line 5261 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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; +#line 5321 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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; +#line 5360 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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; +#line 5399 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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; +#line 5438 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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(144); + 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(144); + 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; +#line 5543 + CError_ASSERT((left = conv.left)); + CError_ASSERT((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(144); + 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(144); + 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: +#line 5642 + CError_FATAL(); + 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(144); + 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)) { + 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)) { + 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)) { +#line 6246 + CError_ASSERT(!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(188); + 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)) { +#line 6274 + CError_ASSERT(!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(188); + 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(245, 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(144); + return nullnode(); + } + } else { + is_templdep_cond = 1; + } + + tk = lex(); + expr1 = expression(); + if (tk != ':') + CError_ErrorSkip(141); + else + tk = lex(); + + expr2 = (copts.cplusplus && !copts.ARM_conform) ? 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; +#line 6531 + CError_FATAL(); + } + return conv.x0; + } + if (IS_TYPE_CLASS(left->rtype) && CClass_AssignmentOperator(TYPE_CLASS(left->rtype))) + CError_Error(144); + } +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(144); + 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(144); + return left; + } + right = forceintegral(right); + } + if (!IS_TYPE_INT(left->rtype)) { + if (copts.cplusplus) { + CError_Error(144); + return left; + } + left = forceintegral(left); + if (!IS_TYPE_INT(left->rtype)) { + CError_Error(144); + return left; + } + } + return CExpr_MakeOpAssNode(left, right, nt); + } + + if (IS_TYPE_CLASS(left->rtype) && TYPE_CLASS(left->rtype)->sominfo) { + CError_Error(285); + 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; +#line 6625 + CError_FATAL(); + default: +#line 6626 + CError_FATAL(); + } + 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)) { +#line 6669 + CError_ASSERT(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(144); + + switch (left->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEPOINTER: + break; + case TYPEENUM: + if (copts.cplusplus) { + CError_Error(144); + return left; + } + left = forceintegral(left); + break; + default: + CError_Error(144); + 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(144); + 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)) { +#line 6753 + CError_ASSERT(conv.x0); + return conv.x0; + } + if (!IS_TYPE_INT(left->rtype) && !(IS_TYPE_FLOAT(left->rtype) && nt != EMODASS)) { + CError_Error(144); + 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(144); + return nullnode(); + } + + left = CExpr_LValue(left, 1, 1); + tk = lex(); + right = pointer_generation(assignment_expression()); + } + + if (is_array) + CError_Error(144); + + if (IS_TYPE_ENUM(right->rtype)) + right = forceintegral(right); + + if (IS_TYPE_INT(left->rtype) && IS_TYPE_FLOAT(right->rtype) && nt == EMODASS) { + CError_Error(144); + 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(139); + 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(139); + 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 EMYSTERY67: + case EINSTRUCTION: + return 1; + default: +#line 7056 + CError_FATAL(); + 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(208); + return; + } + } + + if (copts.warn_no_side_effect) { + if (!CExpr_HasSideEffect(expr)) { + CError_Warning(369); + 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; +#line 7110 + CError_FATAL(); + default: +#line 7111 + CError_FATAL(); + } + + if (!ENODE_IS(arg->node, ETEMP)) + return; + } + CError_Warning(370); + } + } +} + +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)) { +#line 7143 + CError_ASSERT((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(124); + *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: +#line 7209 + CError_FATAL(); + } + } + + if (CTemplTool_IsTemplateArgumentDependentExpression(expr)) + return expr; + + CError_Error(124); + 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(207); + } +} + +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(199); + *objptr = OBJECT(expr->data.emember->list->object); + while ((*objptr)->datatype == DALIAS) + *objptr = (*objptr)->u.alias.object; + return 1; + } + break; + case EOBJLIST: + CError_Error(199); + return 0; + } + } + + CError_Error(155); + return 0; +} diff --git a/compiler_and_linker/unsorted/CExpr2.c b/compiler_and_linker/unsorted/CExpr2.c index 6679bce..47268ac 100644 --- a/compiler_and_linker/unsorted/CExpr2.c +++ b/compiler_and_linker/unsorted/CExpr2.c @@ -2,18 +2,22 @@ #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/CParser.h" +#include "compiler/CPrepTokenizer.h" #include "compiler/CScope.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 @@ -25,9 +29,18 @@ #endif // TODO MOVE ME +extern ENode *CObjC_New(TypeClass *tclass); +extern Boolean CObjC_IsType_id(Type *type); +extern ENode *CObjC_Delete(TypeClass *tclass, ENode *expr); +extern ENode *CSOM_New(TypeClass *tclass); +extern ENode *CSOM_Delete(TypeClass *tclass, ENode *expr); extern ENode *CSOM_EnvCheck(ENode *, ENodeList *); +extern ENode *CSOM_MethodAccess(BClassList *, Object *, Boolean); extern Boolean CTemplTool_IsTemplateArgumentDependentExpression(ENode *expr); extern ENode *CTemplTool_DeduceDefaultArg(Object *func, ENode *expr); +extern Boolean CTempl_CanDeduceFunc(Object *func, TypeFunc *tfunc, TemplArg *templargs); +extern void CTempl_FuncMatch(NameSpaceObjectList *nsol, TemplArg *templargs, ENodeList *argexprs, Match13 *match, ENode *expr); +extern TemplFuncInstance *CTempl_DeduceFunc(Object *func, TypeFunc *tfunc, TemplArg *templargs, Object *anotherobj, Boolean flag); extern Boolean CObjC_IsCompatibleType(Type *a, Type *b); ENode *assign_node; @@ -43,10 +56,9 @@ static CExprReplaceCB cexpr_rsearch_callback; static Type *cexpr_left_conversion_type; static Type *cexpr_right_conversion_type; -// data objects, need to figure out the types -static void *diadic_arg1; -static void *diadic_arg2; -static void *mon_arg; +static FuncArg mon_arg = {NULL, NULL, NULL, NULL, 0, 0, 0, 0}; +static FuncArg diadic_arg2 = {NULL, NULL, NULL, NULL, 0, 0, 0, 0}; +static FuncArg diadic_arg1 = {&diadic_arg1, NULL, NULL, NULL, 0, 0, 0, 0}; static void CExpr_RecSearchExprTree(ENode *expr) { ENodeList *list; @@ -1147,9 +1159,9 @@ void CExpr_MatchCV(Type *t1, UInt32 q1, Type *t2, UInt32 q2, Match13 *match) { 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->xC--; + match->anotherm5.x8--; if ((TYPE_POINTER(t1)->qual & Q_VOLATILE) != (TYPE_POINTER(t2)->qual & Q_VOLATILE)) - match->xC--; + match->anotherm5.x8--; } t2 = TYPE_POINTER(t2)->target; t1 = TYPE_POINTER(t1)->target; @@ -1157,9 +1169,9 @@ void CExpr_MatchCV(Type *t1, UInt32 q1, Type *t2, UInt32 q2, Match13 *match) { } if ((q1 & Q_CONST) != (q2 & Q_CONST)) - match->xC--; + match->anotherm5.x8--; if ((q1 & Q_VOLATILE) != (q2 & Q_VOLATILE)) - match->xC--; + match->anotherm5.x8--; } Boolean CExpr_MatchAssign(Type *type, UInt32 qual, ENode *expr, Match13 *match) { @@ -1167,14 +1179,14 @@ Boolean CExpr_MatchAssign(Type *type, UInt32 qual, ENode *expr, Match13 *match) case CheckResult0: return 0; case CheckResult1: - match->x4++; + match->anotherm5.x0++; break; case CheckResult2: - match->x6++; + match->anotherm5.x2++; break; case CheckResult3: - match->x8++; - match->xA += assign_value; + match->anotherm5.x4++; + match->anotherm5.x6 += assign_value; break; case CheckResult4: match->xE++; @@ -1216,7 +1228,35 @@ static short CExpr_StdMatchCompare(Match5 *a, Match5 *b, Boolean flag) { } static short CExpr2_MemberPointerConversion(Type *type, ENode *expr, Boolean flag1) { - // returns CheckResult + ENode *newnode; + short depth; + + newnode = lalloc(sizeof(ENode)); + *newnode = *expr; + if (!IS_TYPE_MEMBERPOINTER(newnode->rtype)) { + newnode = CExpr_MemberPointerConversion(newnode, type, flag1); + if (iscpp_typeequal(newnode->rtype, type)) { + if (flag1) + assign_node = newnode; + return CheckResult3; + } + } + + if (IS_TYPE_MEMBERPOINTER(newnode->rtype)) { +#line 1656 + CError_ASSERT(IS_TYPE_CLASS(TYPE_MEMBER_POINTER(type)->ty2)); +#line 1657 + CError_ASSERT(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) { @@ -1347,6 +1387,75 @@ ENode *CExpr_GetClassAccessNode(BClassList *a, BClassList *b, ENode *expr, Objec } 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_FLAGS_100000)) { + if (!found_non_template_func && CTempl_CanDeduceFunc(obj, TYPE_FUNC(type), templargs)) { + instance = CTempl_DeduceFunc(obj, TYPE_FUNC(type), templargs, NULL, 0); +#line 1861 + CError_ASSERT(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_FLAGS_UNUSED; + if (used_obj->datatype == DINLINEFUNC) + CError_Error(CErrorStr175); + } + return CheckResult1; + } else { + return CheckResult0; + } } ENode *CExpr_ConvertToBool(ENode *expr, Boolean flag) { @@ -1702,7 +1811,225 @@ restart: return NULL; } -void user_assign_check() {} +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; + TypeMethod *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; + +#line 2378 + CError_ASSERT(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); +#line 2419 + CError_ASSERT(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_FLAGS_20) && !(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); +#line 2537 + CError_ASSERT(r13->flags & FUNC_FLAGS_METHOD); + r15b = create_objectrefnode(r26); + r26->flags |= OBJECT_FLAGS_UNUSED; + 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_FLAGS_20) { + 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) { @@ -1723,16 +2050,332 @@ ENode *CExpr_ConvertToCondition(ENode *expr) { } } -void CExpr_ConvertToIntegral() {} -void CExpr_CheckArithmConversion() {} -void get_address_of_temp_copy() {} +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; +#line 2772 + CError_ASSERT(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: +#line 2857 + CError_FATAL(); + } + 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; } -void CExpr_MatchCompare() {} -static void MatchOverloadFunc() {} -void CExpr_GetFuncMatchArgs() {} +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_FLAGS_100000)) { + 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_FLAGS_METHOD)) { + result->exprs = argexprs; + result->args = TYPE_FUNC(obj->type)->args; + return 1; + } + + if (TYPE_METHOD(obj->type)->x26) { + result->exprs = argexprs; + result->args = TYPE_FUNC(obj->type)->args; + return 1; + } + + if (TYPE_FUNC(obj->type)->flags & FUNC_FLAGS_1000) { + 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; @@ -1753,7 +2396,45 @@ static NameSpaceObjectList *CExpr_CopyNameSpaceObjectList(NameSpaceObjectList *l return first; } -static void CExpr_MatchArgList() {} +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_FLAGS_100000)) { + 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; @@ -1860,24 +2541,870 @@ ENode *CExpr_VarArgPromotion(ENode *expr, Boolean flag) { return expr; } -void CExpr_GenericFuncCall() {} -void CExpr_GenericPtmfCall() {} -static void CExpr_ConvertEMember() {} -void CExpr_MakeFunctionCall() {} -static void accept_conversion_type() {} -static void CExpr_OperatorConversion() {} -static void wild_conversion_check() {} -static void monadic_conversion_check() {} -static void is_legal_type_combination() {} -static void match_class_type_conversion() {} -static void match_type_class_conversion() {} -static void match_class_class_conversion() {} -void CExpr_CheckOperatorConversion() {} -void CExpr_CheckOperator() {} +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)->x26) { + 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._59 && !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_FLAGS_8) && + cscope_currentfunc && + (TYPE_FUNC(cscope_currentfunc->type)->flags & (FUNC_FLAGS_1000 | FUNC_FLAGS_2000)) && + 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_FLAGS_1000 | FUNC_FLAGS_2000))) + 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_FLAGS_METHOD) { +#line 3599 + CError_ASSERT(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_FLAGS_200) && + (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_FLAGS_200)) { + 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: +#line 3912 + CError_FATAL(); + 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: +#line 4132 + CError_FATAL(); + 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; + CScopeParseResult pr; + CScopeParseResult 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 { +#line 4371 + CError_FATAL(); + } + } + 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 { +#line 4439 + CError_FATAL(); + } + } + 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 { +#line 4470 + CError_ASSERT(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; - Object *ctor; + NameSpaceObjectList *ctorlist; + BClassList path; #line 4595 CError_ASSERT(IS_TYPE_POINTER_ONLY(addr_expr->rtype)); @@ -1894,14 +3421,23 @@ ENode *CExpr_ConstructObject(TypeClass *tclass, ENode *addr_expr, ENodeList *arg return expr; } - if ((ctor = CClass_Constructor(tclass))) { + if ((ctorlist = CClass_Constructor(tclass))) { if (tclass->flags & CLASS_FLAGS_20) { ENodeList *list = lalloc(sizeof(ENodeList)); list->next = args; args = list; list->node = intconstnode(TYPE(&stsignedshort), flag2 != 0); } - // TODO: 12CE80 call to genericfunccall + 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)) { @@ -1916,19 +3452,796 @@ ENode *CExpr_ConstructObject(TypeClass *tclass, ENode *addr_expr, ENodeList *arg } } -static void CExpr_DeleteFuncCall() {} -static void CExpr_CopyPlacementNewArg() {} -static void CExpr_PlacementDeleteCall() {} -static void scan_type_name() {} -static void cv_qualifier_list() {} -static void scan_new_declarator() {} -static void scan_new_type_name() {} -static void CExpr_NewAlloc() {} -static void CExpr_NewExceptionSafeAlloc() {} -static void CExpr_NewExceptionSafeInit() {} -static void CExpr_NewArray() {} -static void CExpr_NewSimpleClass() {} -static void CExpr_NewClass() {} -void scannew() {} -static void CExpr_DeleteArray() {} -void scandelete() {} +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_FLAGS_UNUSED; + + 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: +#line 4726 + CError_FATAL(); + 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; + +#line 4752 + CError_ASSERT(ENODE_IS(expr, EFUNCCALL) && ENODE_IS(expr->data.funccall.funcref, EOBJREF)); + + funcobj = expr->data.funccall.funcref->data.objref; +#line 4756 + CError_ASSERT(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_FLAGS_UNUSED; + + list = lalloc(sizeof(ENodeList)); + list->node = create_objectnode(obj); + result->data.funccall.args = list; + +#line 4780 + CError_ASSERT((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) { + CScopeParseResult 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; + CScopeParseResult 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); +#line 4935 + CError_ASSERT(list || obj); + found = 1; + } else if (TYPE_CLASS(type)->flags & CLASS_FLAGS_1) { +#line 4942 + CError_ASSERT(!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 = EMYSTERY67; + 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 EMYSTERY67: + expr->data.itc.tryexpr = tryexpr; + break; + default: +#line 5056 + CError_FATAL(); + } + 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_FLAGS_UNUSED; + } else { + ctor = CClass_DummyDefaultConstructor(TYPE_CLASS(innertype)); + if (!ctor) + CError_Error(CErrorStr203); + } + } + + dtor = CClass_Destructor(TYPE_CLASS(innertype)); + if (dtor) + dtor = CABI_GetDestructorObject(dtor, 1); + + 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_FLAGS_2) && 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 { +#line 5650 + CError_ASSERT(!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_FLAGS_UNUSED; + } + + 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/unsorted/CIRTransform.c b/compiler_and_linker/unsorted/CIRTransform.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CIRTransform.c diff --git a/compiler_and_linker/unsorted/CInline.c b/compiler_and_linker/unsorted/CInline.c index bd2e46c..1f11b61 100644 --- a/compiler_and_linker/unsorted/CInline.c +++ b/compiler_and_linker/unsorted/CInline.c @@ -84,7 +84,7 @@ static void CInline_ForceReverseSearch(ENode *) {} static ENode *CInline_ForceReverseEvaluation(ENode *expr) {} static void CInline_ExportCheck(ENode *expr) {} static void CInline_Expand(Statement *stmt) {} -SInt32 CInline_GetStatementNumber(Statement *first, Statement *stmt) {} +SInt16 CInline_GetStatementNumber(Statement *first, Statement *stmt) {} static CI_Switch *CInline_PackSwitch(Statement *s1, Statement *s2) {} static Boolean CInline_CanInline(Object *obj, Statement *stmt) {} static ExceptionAction *CInline_PackActions(Statement *s1, Statement *s2) {} diff --git a/compiler_and_linker/unsorted/CMachine.c b/compiler_and_linker/unsorted/CMachine.c index fd4aafc..0c1ac0d 100644 --- a/compiler_and_linker/unsorted/CMachine.c +++ b/compiler_and_linker/unsorted/CMachine.c @@ -1337,7 +1337,7 @@ Boolean CMach_PassResultInHiddenArg(Type *type) { } } -const char *CMach_GetCPU() { +char *CMach_GetCPU() { switch (copts.cpu) { case CPU_PPC401: return "__PPC401__"; case CPU_PPC403: return "__PPC403__"; diff --git a/compiler_and_linker/unsorted/CObjC.c b/compiler_and_linker/unsorted/CObjC.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CObjC.c diff --git a/compiler_and_linker/unsorted/CObjCModern.c b/compiler_and_linker/unsorted/CObjCModern.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CObjCModern.c diff --git a/compiler_and_linker/unsorted/COptimizer.c b/compiler_and_linker/unsorted/COptimizer.c new file mode 100644 index 0000000..38b203f --- /dev/null +++ b/compiler_and_linker/unsorted/COptimizer.c @@ -0,0 +1,1781 @@ +#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 "compiler/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.optimize_for_size) { + if (ENODE_IS3(cse->expr, EMUL, EDIV, EMODULO)) + cost = 2; + } + //cost = (!copts.optimize_for_size && ENODE_IS3(cse->expr, EMUL, EDIV, EMODULO)) ? 2 : 1; + return cse_cost(cse->left) + cse_cost(cse->right) + cost; + //return + // ((!copts.optimize_for_size && ENODE_IS3(cse->expr, EMUL, EDIV, EMODULO)) ? 2 : 1) + + // cse_cost(cse->left) + + // cse_cost(cse->right); + } + + 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); +#line 348 + CError_ASSERT(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) { +#line 390 + CError_FATAL(); + } 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) { +#line 524 + CError_ASSERT(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) { +#line 552 + CError_ASSERT(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) { +#line 581 + CError_ASSERT(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)) { +#line 612 + CError_ASSERT(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; +#line 672 + CError_ASSERT(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; +#line 816 + CError_ASSERT(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: +#line 887 + CError_ASSERT(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: +#line 948 + CError_FATAL(); + + default: +#line 951 + CError_FATAL(); + 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; + } +} + +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: +#line 1332 + CError_FATAL(); + } + } +} + +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.global_optimizer) { + 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_GOTO: + 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; + } + } + +#line 1602 + CError_ASSERT(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; + } + } +} + +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) { +} + +static void optimizeswitch(Statement *stmt) { + SwitchInfo *info; + SwitchCase *swcase; + + info = (SwitchInfo *) stmt->label; +#line 1746 + CError_ASSERT(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 |= StmtFlag_1; + } else if (action->type == EAT_SPECIFICATION) { + action->data.specification.unexp_label->stmt->marked = 1; + 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; +#line 1875 + CError_ASSERT(obj->datatype != DALIAS); + + if (obj->datatype == DLOCAL || obj->datatype == DNONLAZYPTR) { + vi = obj->u.var.info; + vi->used = 1; + if (!copts.global_optimizer) { + if (copts.optimize_for_size) + 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: +#line 1998 + CError_FATAL(); + } + } +} + +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: +#line 2096 + CError_FATAL(); + } + 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) { +#line 2195 + CError_ASSERT(expr->data.label->stmt && expr->data.label->stmt->type == ST_LABEL); + 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.global_optimizer) + 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/unsorted/CPreprocess.c b/compiler_and_linker/unsorted/CPreprocess.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CPreprocess.c diff --git a/compiler_and_linker/unsorted/CRTTI.c b/compiler_and_linker/unsorted/CRTTI.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CRTTI.c diff --git a/compiler_and_linker/unsorted/CSOM.c b/compiler_and_linker/unsorted/CSOM.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CSOM.c diff --git a/compiler_and_linker/unsorted/CTemplateClass.c b/compiler_and_linker/unsorted/CTemplateClass.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CTemplateClass.c diff --git a/compiler_and_linker/unsorted/CTemplateFunc.c b/compiler_and_linker/unsorted/CTemplateFunc.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CTemplateFunc.c diff --git a/compiler_and_linker/unsorted/CTemplateNew.c b/compiler_and_linker/unsorted/CTemplateNew.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CTemplateNew.c diff --git a/compiler_and_linker/unsorted/CTemplateTools.c b/compiler_and_linker/unsorted/CTemplateTools.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CTemplateTools.c diff --git a/compiler_and_linker/unsorted/CodeGen.c b/compiler_and_linker/unsorted/CodeGen.c index 0867270..d87d80f 100644 --- a/compiler_and_linker/unsorted/CodeGen.c +++ b/compiler_and_linker/unsorted/CodeGen.c @@ -1,13 +1,63 @@ -#include "compiler.h" +#include "compiler/CodeGen.h" +#include "compiler/CCompiler.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/CMangler.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/InstrSelection.h" +#include "compiler/Operands.h" #include "compiler/PCode.h" #include "compiler/PCodeInfo.h" #include "compiler/PCodeUtilities.h" +#include "compiler/RegisterInfo.h" +#include "compiler/StackFrame.h" +#include "compiler/TOC.h" +#include "compiler/CompilerTools.h" #include "compiler/enode.h" #include "compiler/objects.h" +#include "compiler/scopes.h" #include "compiler/tokens.h" #include "compiler/types.h" +// TODO: MOVE ME +extern void Intrinsics_SetupRuntimeObjects(void); +extern void Intrinsics_ReInitRuntimeObjects(Boolean); +extern Boolean Intrinsics_IsPublicRuntimeObject(Object *); +extern ENode *Intrinsics_HandleIntrinsicCall(Object *func, ENodeList *arg_exprs); +extern void PPCError_Error(int, ...); +extern void PPCError_Warning(int, ...); +extern void PPCError_Message(char *, ...); +extern void globallyoptimizepcode(Object *); +extern void pclistblocks(char *, char *); +extern void pclistblocks_start_scheduler(char *, char *); +extern void pclistblocks_end_scheduler(); +extern void scheduleinstructions(Boolean); +extern void peepholemergeblocks(Object *, Boolean); +extern void peepholeoptimizeforward(Object *); +extern void peepholeoptimizepcode(Object *); +extern void colorinstructions(Object *); +extern void removecommonsubexpressions(Object *, Boolean); +extern int removedcommonsubexpressions; +extern SInt32 assemblefunction(Object *, void *); +extern void dumpswitchtables(Object *); +extern void ObjGen_DeclareInitFunction(Object *); +extern void *switchtables; +extern void initializeexceptiontables(); +extern void dumpexceptiontables(Object *, SInt32); +extern void switchstatement(ENode *, CLabel *); +extern void DumpIR(Statement **, Object *); +extern void InlineAsm_TranslateIRtoPCode(Statement *stmt); +typedef struct WeirdInlineAsmThing { + UInt8 x0, x1, x2; +} WeirdInlineAsmThing; +extern Statement **COpt_Optimizer(Object *, Statement **); + static Macro powcM; static Macro __powcM; static Macro ppc_cpu; @@ -29,8 +79,8 @@ static Macro dynM; static Macro ppcM; Object *gFunction; static ObjectList *temps; -PCodeLabel *returnlabel; -PCodeLabel *cleanreturnlabel; +CLabel *returnlabel; +CLabel *cleanreturnlabel; Boolean needs_cleanup; Statement *current_statement; int has_catch_blocks; @@ -60,7 +110,7 @@ Object *rt_cvt_sll_dbl; Object *rt_cvt_ull_flt; Object *rt_cvt_sll_flt; Object *rt_cvt_dbl_usll; -static void *saveheaperror; +static heaperror_t saveheaperror; enum { GPRLimit = 10, @@ -68,6 +118,9 @@ enum { VRLimit = 13 }; +// forward decls +static void CodeGen_heaperror(void); + VarInfo *CodeGen_GetNewVarInfo(void) { VarInfo *vi; @@ -601,10 +654,11 @@ static void load_TOC_pointers(void) { Object *obj; ObjectList *list; PCode *pc; + Operand opnd; if (uses_globals && pic_base_reg) { pic_base_pcodelabel = makepclabel(); - pc = makepcode(PC_BC, 20, 7, 3); + pc = makepcode(PC_BC, 20, 7, 3, pic_base_pcodelabel); pcsetlinkbit(pc); pcsetsideeffects(pc); appendpcode(pclastblock, pc); @@ -614,24 +668,52 @@ static void load_TOC_pointers(void) { emitpcode(PC_MFLR, pic_base_reg); } - // TODO: depends on Operands + memclrw(&opnd, sizeof(Operand)); for (list = toclist; list; list = list->next) { - + obj = list->object; + if ((vi = Registers_GetVarInfo(obj)) && (vi->flags & VarInfoFlag2)) { + switch (obj->datatype) { + case DNONLAZYPTR: + symbol_operand(&opnd, obj); + opnd.optype = OpndType_IndirectSymbol; + if (opnd.optype) + Coerce_to_register(&opnd, TYPE(&void_ptr), vi->reg); + if (opnd.reg != vi->reg) + emitpcode(PC_MR, vi->reg, opnd.reg); + break; + default: +#line 1206 + CError_FATAL(); + } + } } } -static Boolean has_vararglist(Object *funcobj) { +static int has_vararglist(Object *funcobj) { FuncArg *arg; arg = TYPE_FUNC(funcobj->type)->args; while (arg && arg != &elipsis) arg = arg->next; - return arg == &elipsis; + return (arg == &elipsis); } -void assign_labels() { - // TODO +void assign_labels(Statement *stmt) { + Statement *last; + + last = NULL; + while (stmt) { + if (stmt->type == ST_LABEL && !stmt->label->pclabel) { + if (last && last->type == ST_LABEL) + stmt->label->pclabel = last->label->pclabel; + else + stmt->label->pclabel = makepclabel(); + } + + last = stmt; + stmt = stmt->next; + } } static Boolean islaststatement(Statement *stmt) { @@ -642,7 +724,7 @@ static Boolean islaststatement(Statement *stmt) { return 1; } -static void newstatement(SInt32 sourceoffset, UInt16 value, int flag) { +static void newstatement(SInt32 sourceoffset, SInt32 value, int flag) { PCodeBlock *block = pclastblock; pcloopweight = value; @@ -657,41 +739,1685 @@ static void newstatement(SInt32 sourceoffset, UInt16 value, int flag) { } static void expressionstatement(ENode *expr) { + Operand opnd; + + memclrw(&opnd, sizeof(Operand)); + cgdispatch[expr->type](expr, 0, 0, &opnd); + + if (ENODE_IS(expr, EINDIRECT) && (opnd.flags & OpndFlags_Volatile)) { + if (TYPE_FITS_IN_REGISTER_2(expr->rtype)) { + if (opnd.optype != OpndType_GPR) + Coerce_to_register(&opnd, expr->rtype, 0); + } else if (IS_TYPE_FLOAT(expr->rtype)) { + if (opnd.optype != OpndType_FPR) + Coerce_to_fp_register(&opnd, expr->rtype, 0); + } else if (IS_TYPE_VECTOR(expr->rtype)) { + if (opnd.optype != OpndType_VR) + Coerce_to_v_register(&opnd, expr->rtype, 0); + } + } +} + +static void labelstatement(CLabel *label) { + if (!label->pclabel) + label->pclabel = makepclabel(); + if (!label->pclabel->resolved) + branch_label(label->pclabel); + free_temporaries(); +} + +static void gotostatement(CLabel *label) { + if (!label->pclabel) + label->pclabel = makepclabel(); + branch_always(label->pclabel); + free_temporaries(); +} + +static void gotoexpression(ENode *expr) { + Operand opnd; + CodeLabelList *list; + + memclrw(&opnd, sizeof(Operand)); + cgdispatch[expr->type](expr, 0, 0, &opnd); + + if (opnd.optype != OpndType_GPR) + Coerce_to_register(&opnd, TYPE(&void_ptr), 0); +#line 1397 + CError_ASSERT(opnd.optype == OpndType_GPR); + + for (list = codelabellist; list; list = list->next) + pcbranch(pclastblock, list->label->pclabel); + + emitpcode(PC_MTCTR, opnd.reg); + branch_indirect(NULL); +} + +static void conditionalstatement(ENode *cond, CLabel *label, short truthy) { + Operand opnd; + memclrw(&opnd, sizeof(Operand)); + + cond = evaluate_and_skip_comma(cond); + if (!label->pclabel) + label->pclabel = makepclabel(); + + if (TYPE_IS_8BYTES(cond->data.diadic.right->rtype) || TYPE_IS_8BYTES(cond->data.diadic.left->rtype)) + I8_gen_condition(cond, &opnd, 0); + else + gen_condition(cond, &opnd); + + branch_conditional(opnd.reg, opnd.regOffset, truthy, label->pclabel); + free_temporaries(); +} + +static void returnstatement(ENode *expr, Boolean dont_branch) { + Operand opnd; + Type *type; + memclrw(&opnd, sizeof(Operand)); + + if (expr) { + type = expr->rtype; + if (TYPE_FITS_IN_REGISTER(type)) { + if (TYPE_IS_8BYTES(type)) { + cgdispatch[expr->type](expr, low_reg, high_reg, &opnd); + coerce_to_register_pair(&opnd, type, low_reg, high_reg); + } else { + cgdispatch[expr->type](expr, 3, 0, &opnd); + if (opnd.optype != OpndType_GPR) + Coerce_to_register(&opnd, type, 3); + if (opnd.reg != 3) + emitpcode(PC_MR, 3, opnd.reg); + } + } else if (IS_TYPE_FLOAT(type)) { + cgdispatch[expr->type](expr, 1, 0, &opnd); + if (opnd.optype != OpndType_FPR) + Coerce_to_fp_register(&opnd, type, 1); + if (opnd.reg != 1) + emitpcode(PC_FMR, 1, opnd.reg); + } else if (IS_TYPE_VECTOR(type)) { + cgdispatch[expr->type](expr, 2, 0, &opnd); + if (opnd.optype != OpndType_VR) + Coerce_to_v_register(&opnd, type, 2); + if (opnd.reg != 2) + emitpcode(PC_VMR, 2, opnd.reg); + } else { + cgdispatch[expr->type](expr, 0, 0, &opnd); + } + } + + if (!dont_branch) { + if (!returnlabel->pclabel) + returnlabel->pclabel = makepclabel(); + branch_always(returnlabel->pclabel); + free_temporaries(); + } +} + +static void capturestackpointer(Object *obj) { + branch_label(makepclabel()); +#line 1568 + CError_ASSERT(obj->datatype == DLOCAL); + + load_store_register(PC_STW, 1, local_base_register(obj), obj, 20); + branch_label(makepclabel()); +} + +static void resetstackpointer(Object *obj) { + PCode *pc; + +#line 1595 + CError_ASSERT(obj->datatype == DLOCAL); + + branch_label(makepclabel()); + + load_store_register(PC_LWZ, 0, 1, NULL, 0); + + pc = makepcode(PC_LWZ, 1, local_base_register(obj), obj, 20); + pcsetsideeffects(pc); + appendpcode(pclastblock, pc); + + load_store_register(PC_STW, 0, 1, NULL, 0); + + branch_label(makepclabel()); +} + +static void callprofiler(char *name) { + UInt32 masks[RegClassMax] = {0, 0, 0, 0, 0}; + load_store_register(PC_LWZ, 3, 1, NULL, 0); + load_store_register(PC_LWZ, 3, 3, NULL, 8); + masks[RegClass_GPR] |= (1 << 3); + branch_subroutine(rt_profile_entry, 1, masks); +} + +static void exitprofiler(void) { +} + +void CodeGen_Generator(Statement **statements, Object *func, UInt8 mysteryFlag, Boolean callOnModuleBind) { + Statement *stmt; + Boolean has_varargs; + PCodeBlock *tmp; + Object *obj; + SInt32 size; + + CodeGen_InitialSanityCheck(); + if (!saveheaperror) { + saveheaperror = getheaperror(); + setheaperror(CodeGen_heaperror); + } + + if (cparamblkptr->isPrecompiling == 1) + CError_Error(180); + + if (!func) { + func = createstaticinitobject(); + } else if (func && func->name) { + PrintProgressFunction(func->name->name); + } + + gFunction = func; + has_varargs = has_vararglist(func); + init_endian(); + init_stack_globals(func); + assign_arguments_to_memory(func, mysteryFlag, has_varargs); + + needs_cleanup = 0; + disable_optimizer = 0; + has_catch_blocks = 0; + current_statement = NULL; + current_linenumber = 0; + precomputedoperands = NULL; + switchtables = NULL; + temps = NULL; + initializeexceptiontables(); + returnlabel = cleanreturnlabel = newlabel(); + + if (copts.debuglisting) + DumpIR(statements, func); + + statements = COpt_Optimizer(func, statements); + if (copts.debuglisting) + DumpIR(statements, func); + + resetTOCvarinfo(); + init_registers(); + expandTOCreferences(statements); + if (copts.debuglisting) + DumpIR(statements, func); + + if (copts.profile) { + makes_call = 1; + requires_frame = 1; + } + + initpcode(); + + pclabel(prologue = makepcblock(), makepclabel()); + prologue->flags |= fPCBlockFlag1; + + pclabel(tmp = makepcblock(), makepclabel()); + pcbranch(prologue, tmp->labels); + + init_frame_sizes(has_varargs); + allocate_locals(); + process_arguments(move_assigned_argument, has_varargs); + + if (copts.schedule_mode || copts.altivec_model) + branch_label(makepclabel()); + + load_TOC_pointers(); + + if (copts.profile) + callprofiler(CMangler_GetLinkName(func)->name); + + assign_labels(*statements); + open_temp_registers(); + + for (stmt = *statements; stmt; stmt = stmt->next) { + current_statement = stmt; + current_linenumber = stmt->sourceoffset; + switch (stmt->type) { + case ST_NOP: + break; + case ST_EXPRESSION: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + expressionstatement(stmt->expr); + break; + case ST_LABEL: + labelstatement(stmt->label); + break; + case ST_IFGOTO: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + conditionalstatement(stmt->expr, stmt->label, 1); + break; + case ST_IFNGOTO: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + conditionalstatement(stmt->expr, stmt->label, 0); + break; + case ST_GOTOEXPR: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + gotoexpression(stmt->expr); + break; + case ST_GOTO: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + gotostatement(stmt->label); + break; + case ST_RETURN: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + returnstatement(stmt->expr, islaststatement(stmt)); + break; + case ST_SWITCH: + newstatement(stmt->sourceoffset, stmt->value, (stmt->flags & StmtFlag_10) != 0); + switchstatement(stmt->expr, stmt->label); + break; + case ST_BEGINCATCH: + capturestackpointer(stmt->expr->data.objref); + break; + case ST_ENDCATCHDTOR: +#line 2056 + CError_ASSERT(stmt->expr->data.objref->datatype == DLOCAL); + obj = stmt->expr->data.objref; + add_immediate(3, local_base_register(obj), obj, 0); + { + UInt32 masks[RegClassMax] = {0, 0, 0, 0, 0}; + masks[RegClass_GPR] |= 1 << 3; + branch_subroutine(Xecth_func, 1, masks); + } + case ST_ENDCATCH: + resetstackpointer(stmt->expr->data.objref); + break; + case ST_ASM: + if (stmt->expr) { + // ... will need to understand inline ASM properly for this ... + if (((WeirdInlineAsmThing *) stmt->expr)->x2 & 1) { +#line 2076 + CError_FATAL(); + } else { + branch_label(makepclabel()); + InlineAsm_TranslateIRtoPCode(stmt); + } + } + break; + case ST_BEGINLOOP: +#line 2086 + CError_FATAL(); + break; + case ST_ENDLOOP: +#line 2090 + CError_FATAL(); + break; + default: +#line 2094 + CError_FATAL(); + } + check_temp_registers(); + } + + close_temp_registers(); + labelstatement(returnlabel); + + current_statement = NULL; + + epilogue = pclastblock; + pclastblock->flags |= fPCBlockFlag2; + + pccomputepredecessors(); + deleteunreachableblocks(); + + if (copts.report_heap_info > 0) + CodeGen_reportheapinfo(0, CMangler_GetLinkName(func)->name, "before optimization"); + + if (copts.optimizationlevel > 0 && !disable_optimizer) + globallyoptimizepcode(func); + else + pclistblocks(CMangler_GetLinkName(func)->name, "INITIAL CODE"); + + if (copts.schedule_mode == 2) { + if (copts.peephole) + peepholemergeblocks(func, 0); + if (copts.debuglisting) + pclistblocks_start_scheduler(CMangler_GetLinkName(func)->name, "BEFORE SCHEDULING"); + scheduleinstructions(0); + if (copts.debuglisting) + pclistblocks_end_scheduler(); + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER INSTRUCTION SCHEDULING"); + } + + if (copts.peephole) { + if (copts.schedule_mode == 0 && copts.optimizationlevel > 1) + peepholemergeblocks(func, 0); + peepholeoptimizeforward(func); + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER PEEPHOLE FORWARD"); + } + + allocate_temporaries(); + colorinstructions(func); + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER REGISTER COLORING"); + + if (copts.optimizationlevel > 1 && !disable_optimizer) { + removecommonsubexpressions(func, 1); + if (removedcommonsubexpressions && copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER VALUE NUMBERING (POST COLORING)"); + } + + compute_frame_sizes(); + generate_prologue(prologue, has_varargs); + if (copts.profile) + exitprofiler(); + generate_epilogue(epilogue, 1); + + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER GENERATING EPILOGUE, PROLOGUE"); + + if (copts.peephole) { + if (copts.schedule_mode) { + peepholemergeblocks(func, 1); + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER MERGING EPILOGUE, PROLOGUE"); + } + peepholeoptimizepcode(func); + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "AFTER PEEPHOLE OPTIMIZATION"); + } + + if (copts.schedule_mode) { + if (copts.debuglisting) + pclistblocks_start_scheduler(CMangler_GetLinkName(func)->name, "BEFORE SCHEDULING"); + scheduleinstructions(1); + if (copts.debuglisting) + pclistblocks_end_scheduler(); + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "FINAL CODE AFTER INSTRUCTION SCHEDULING"); + } else { + if (copts.debuglisting) + pclistblocks(CMangler_GetLinkName(func)->name, "FINAL CODE"); + } + + size = assemblefunction(func, NULL); + dumpswitchtables(func); + dumpcodelabels(func); + if (callOnModuleBind) + ObjGen_DeclareInitFunction(func); + + pic_base_pcodelabel = NULL; + pic_base_reg = 0; + if (copts.exceptions && requires_frame) + dumpexceptiontables(func, size); + + if (copts.report_heap_info > 0) + CodeGen_reportheapinfo(0, CMangler_GetLinkName(func)->name, "finished"); + + if (saveheaperror) + setheaperror(saveheaperror); +} + +enum { + reg3 = 3, + reg4 = 4 +}; + +void CodeGen_GenVDispatchThunk(Object *thunkobj, Object *obj, SInt32 a, SInt32 b, SInt32 c) { + Boolean save_debug; + Boolean save_peephole; + Boolean save_traceback; + char reg; + + save_debug = copts.isGeneratingDebugInfo; + save_peephole = copts.peephole; + save_traceback = copts.traceback; + + CodeGen_InitialSanityCheck(); +#line 2270 + CError_ASSERT(b == 0); + + initpcode(); + makepcblock(); + + if (a) { + reg = CMach_PassResultInHiddenArg(TYPE_FUNC(obj->type)->functype) ? reg4 : reg3; + + if (c >= 0) { + if (!FITS_IN_SHORT(c)) { + emitpcode(PC_ADDIS, 11, 0, 0, HIGH_PART(c)); + if (c) + emitpcode(PC_ADDI, 11, 11, 0, LOW_PART(c)); + } else { + emitpcode(PC_ADDI, 11, 0, 0, c); + } + emitpcode(PC_LWZX, 11, reg, 11); + emitpcode(PC_ADD, reg, reg, 11); + } + + if (!FITS_IN_SHORT(a)) { + emitpcode(PC_ADDIS, reg, reg, 0, HIGH_PART(a)); + if (a) + emitpcode(PC_ADDI, reg, reg, 0, LOW_PART(a)); + } else { + emitpcode(PC_ADDI, reg, reg, 0, a); + } + } + + emitpcode(PC_B, 0, obj); + + copts.isGeneratingDebugInfo = 0; + copts.peephole = 0; + copts.traceback = 0; + assemblefunction(thunkobj, NULL); + copts.isGeneratingDebugInfo = save_debug; + copts.peephole = save_peephole; + copts.traceback = save_traceback; +} + +void CodeGen_SetupRuntimeObjects(void) { + setupaddressing(); + dyld_stub_binding_helper = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_cvt_fp2unsigned = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_profile_entry = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_profile_exit = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_div2i = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_div2u = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_mod2i = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_mod2u = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_shr2i = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_shr2u = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_shl2i = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_cvt_ull_dbl = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_cvt_sll_dbl = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_cvt_ull_flt = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_cvt_sll_flt = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + rt_cvt_dbl_usll = CParser_NewRTFunc(&stvoid, NULL, 2, 0); + Intrinsics_SetupRuntimeObjects(); } -static void labelstatement() {} -static void gotostatement() {} -static void gotoexpression() {} -static void conditionalstatement() {} -static void returnstatement() {} -static void capturestackpointer() {} -static void resetstackpointer() {} -static void callprofiler() {} -static void exitprofiler() {} -void CodeGen_Generator() {} -void CodeGen_GenVDispatchThunk() {} -void CodeGen_SetupRuntimeObjects() {} -Boolean CodeGen_ReInitRuntimeObjects(Boolean is_precompiler) {} -Boolean CodeGen_IsPublicRuntimeObject(Object *obj) {} -void CodeGen_SOMStub() {} -void CodeGen_ParseDeclSpec() {} -static void CodeGen_EOLCheck() {} -static void schedule_for() {} -static void pragma_scheduling() {} -static void CodeGen_ParseLongIntegerORonORoff() {} -void CodeGen_ParsePragma(HashNameNode *name) {} -void CodeGen_UpdateObject(Object *object) {} -void CodeGen_UpdateBackEndOptions() {} -void CodeGen_objc_method_self_offset() {} -void CodeGen_objc_method_sel_offset() {} -void CodeGen_objc_method_arg_offset() {} -void CodeGen_objc_method_args_size() {} -void CodeGen_HandleIntrinsicCall() {} -void CodeGen_HandleTypeCast() {} -void CodeGen_AssignCheck() {} -void CodeGen_CollapseVectorExpression() {} -void CodeGen_InsertSpecialMacros() {} -char *CodeGen_ExpandSpecialMacro(Macro *macro) {} -void CodeGen_reportheapinfo() {} -static void CodeGen_heaperror() {} -void CodeGen_InitialSanityCheck() {} +Boolean CodeGen_ReInitRuntimeObjects(Boolean is_precompiler) { + dyld_stub_binding_helper->name = GetHashNameNodeExport("dyld_stub_binding_helper"); + dyld_stub_binding_helper->u.func.linkname = dyld_stub_binding_helper->name; + + rt_cvt_fp2unsigned->name = GetHashNameNodeExport("__cvt_fp2unsigned"); + + rt_profile_entry->name = GetHashNameNodeExport("mcount"); + rt_profile_entry->u.func.linkname = rt_profile_entry->name; + + rt_profile_exit->name = GetHashNameNodeExport("profile_exit"); + + rt_div2i->name = GetHashNameNodeExport("__div2i"); + rt_div2u->name = GetHashNameNodeExport("__div2u"); + rt_mod2i->name = GetHashNameNodeExport("__mod2i"); + rt_mod2u->name = GetHashNameNodeExport("__mod2u"); + rt_shr2i->name = GetHashNameNodeExport("__shr2i"); + rt_shr2u->name = GetHashNameNodeExport("__shr2u"); + rt_shl2i->name = GetHashNameNodeExport("__shl2i"); + + rt_cvt_ull_dbl->name = GetHashNameNodeExport("__cvt_ull_dbl"); + rt_cvt_sll_dbl->name = GetHashNameNodeExport("__cvt_sll_dbl"); + rt_cvt_ull_flt->name = GetHashNameNodeExport("__cvt_ull_flt"); + rt_cvt_sll_flt->name = GetHashNameNodeExport("__cvt_sll_flt"); + rt_cvt_dbl_usll->name = GetHashNameNodeExport("__cvt_dbl_usll"); + + CMach_ReInitRuntimeObjects(); + Intrinsics_ReInitRuntimeObjects(is_precompiler); +} + +Boolean CodeGen_IsPublicRuntimeObject(Object *obj) { + return Intrinsics_IsPublicRuntimeObject(obj); +} + +void CodeGen_SOMStub(Object *a, Object *b, Object *c, SInt32 offset) { + Boolean save_debug; + Boolean save_peephole; + Boolean save_traceback; + Object *tmp; + Operand opnd; + + save_debug = copts.isGeneratingDebugInfo; + save_peephole = copts.peephole; + save_traceback = copts.traceback; + + CodeGen_InitialSanityCheck(); + memclrw(&opnd, sizeof(Operand)); +#line 2528 + CError_ASSERT(offset <= 0x7FFF); + + initpcode(); + makepcblock(); + + tmp = createIndirect(c, 1, 1); + if (tmp) { + opnd.optype = OpndType_Symbol; + opnd.object = tmp; + indirect(&opnd, NULL); + } else { + opnd.optype = OpndType_Symbol; + opnd.object = c; + } + + if (opnd.optype != OpndType_GPR) + Coerce_to_register(&opnd, TYPE(&void_ptr), 12); + + if (opnd.optype != OpndType_GPR) { +#line 2562 + CError_FATAL(); + } else if (opnd.reg != 12) { + emitpcode(PC_MR, 12, opnd.reg); + } + + load_store_register(PC_LWZ, 12, 12, NULL, (short) offset); + emitpcode(PC_B, 0, b); + + copts.isGeneratingDebugInfo = 0; + copts.peephole = 0; + copts.traceback = 0; + assemblefunction(a, NULL); + copts.isGeneratingDebugInfo = save_debug; + copts.peephole = save_peephole; + copts.traceback = save_traceback; +} + +void CodeGen_ParseDeclSpec(HashNameNode *identifier, DeclInfo *declinfo) { + if (!strcmp(identifier->name, "private_extern")) { + declinfo->storageclass = TK_EXTERN; + declinfo->exportflags = EXPORT_FLAGS_INTERNAL; + } else { + CError_Error(176); + } +} + +static void CodeGen_EOLCheck(void) { + short t; + + if (plex() != TK_NEG7) { + CPrep_Error(113); + do { + t = plex(); + } while (t != TK_NEG7 && t != 0); + } +} + +static void schedule_for(int what) { + CPrep_PushOption(OPT_OFFSET(schedule_cpu), what); + if (copts.schedule_mode == 0) + CPrep_PushOption(OPT_OFFSET(schedule_mode), 2); +} + +static void pragma_scheduling(void) { + Boolean *flag; + int cpu; + + tk = plex(); + if (tk == TK_IDENTIFIER) { + flag = &copts.altivec_model; + if (!strcmp(tkidentifier->name, "vger")) { + schedule_for(10); + return; + } else if (!strcmp(tkidentifier->name, "altivec")) { + schedule_for(7); + return; + } else if (!strcmp(tkidentifier->name, "reset")) { + CPrep_PopOption(OPT_OFFSET(schedule_cpu)); + CPrep_PopOption(OPT_OFFSET(schedule_mode)); + return; + } else if (!strcmp(tkidentifier->name, "off")) { + CPrep_PushOption(OPT_OFFSET(schedule_mode), 0); + return; + } else if (!strcmp(tkidentifier->name, "once")) { + CPrep_PushOption(OPT_OFFSET(schedule_mode), 1); + return; + } else if (!strcmp(tkidentifier->name, "twice")) { + CPrep_PushOption(OPT_OFFSET(schedule_mode), 2); + return; + } else if (!strcmp(tkidentifier->name, "on")) { + CPrep_PushOption(OPT_OFFSET(schedule_mode), 2); + return; + } else if (!*flag) { + if (!strcmp(tkidentifier->name, "603e")) { + schedule_for(5); + return; + } else if (!strcmp(tkidentifier->name, "604e")) { + schedule_for(6); + return; + } else if (!strcmp(tkidentifier->name, "PPC603e")) { + schedule_for(5); + return; + } else if (!strcmp(tkidentifier->name, "PPC604e")) { + schedule_for(6); + return; + } + } else { + PPCError_Error(115); + return; + } + CPrep_Error(186); + return; + } + + if (tk == TK_INTCONST) { + switch (CInt64_GetULong(&tkintconst)) { + case 601: + cpu = 1; + break; + case 603: + cpu = 2; + break; + case 604: + cpu = 3; + break; + case 750: + cpu = 4; + break; + case 7400: + cpu = 7; + break; + case 7450: + cpu = 10; + break; + case 8240: + case 8260: + cpu = 5; + break; + case 801: + case 821: + case 823: + case 850: + case 860: + cpu = 9; + break; + default: + CPrep_Error(186); + return; + } + schedule_for(cpu); + return; + } + + if (copts.warn_illpragma) + CPrep_Warning(186); +} + +static SInt32 CodeGen_ParseLongIntegerORonORoff(void) { + SInt32 result; + short t; + + result = 0; + t = plex(); + if (t == TK_INTCONST) { + if (!tkintconst.hi) + result = CInt64_GetULong(&tkintconst); + else + CPrep_Error(154); + CodeGen_EOLCheck(); + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "on")) { + CodeGen_EOLCheck(); + return 1; + } + if (!strcmp(tkidentifier->name, "off")) { + CodeGen_EOLCheck(); + return 0; + } + if (copts.warn_illpragma) + CPrep_Warning(186); + return 0; + } else { + if (copts.warn_illpragma) + CPrep_Warning(186); + } + + return result; +} + +void CodeGen_ParsePragma(HashNameNode *name) { + short t; + SInt32 value; + char *str; + NameSpace *nspace; + NameSpaceObjectList *list; + + if (!strcmp(name->name, "debuglisting")) { + copts.debuglisting = CodeGen_ParseLongIntegerORonORoff(); + return; + } + + if (!strcmp(name->name, "report_heap_info")) { + t = plex(); + if (t == TK_INTCONST) { + copts.report_heap_info = CInt64_GetULong(&tkintconst); + if (copts.report_heap_info < 0) { + copts.report_heap_info = 0; + CError_Error(186); + } + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.report_heap_info = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.report_heap_info = 1; + } else { + CError_Error(186); + return; + } + } else { + CError_Error(186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "scheduling")) { + pragma_scheduling(); + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "ppc_unroll_speculative")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.ppc_unroll_speculative = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.ppc_unroll_speculative = 1; + } else { + CError_Error(186); + return; + } + } else { + CError_Error(186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "ppc_unroll_instructions_limit")) { + t = plex(); + if (t == TK_INTCONST) { + copts.ppc_unroll_instructions_limit = CInt64_GetULong(&tkintconst); + if (copts.ppc_unroll_instructions_limit < 0) { + copts.ppc_unroll_instructions_limit = 0; + CError_Error(186); + } + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.ppc_unroll_instructions_limit = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.ppc_unroll_instructions_limit = 70; + } else { + CError_Error(186); + return; + } + } else { + CError_Error(186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "gen_fsel")) { + t = plex(); + if (t == TK_INTCONST) { + value = CInt64_GetULong(&tkintconst); + if (value < 0) { + copts.gen_fsel = 0; + CError_Error(186); + } else if (value > 255) { + copts.gen_fsel = 255; + CError_Error(186); + } else { + copts.gen_fsel = value; + } + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.gen_fsel = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.gen_fsel = 10; + } else if (!strcmp(tkidentifier->name, "always")) { + copts.gen_fsel = 255; + } else { + CError_Error(186); + return; + } + } else { + CError_Error(186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "ppc_unroll_factor_limit")) { + t = plex(); + if (t == TK_INTCONST) { + copts.ppc_unroll_factor_limit = CInt64_GetULong(&tkintconst); + if (copts.ppc_unroll_factor_limit < 0) { + copts.ppc_unroll_factor_limit = 0; + CError_Error(186); + } + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.ppc_unroll_factor_limit = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.ppc_unroll_factor_limit = 10; + } else { + CError_Error(186); + return; + } + } else { + CError_Error(186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "altivec_model")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.altivec_model = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.altivec_model = 1; + } else { + CError_Error(186); + return; + } + } else { + CError_Error(186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "altivec_vrsave")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + CPrep_PushOption(OPT_OFFSET(altivec_vrsave), 0); + } else if (!strcmp(tkidentifier->name, "on")) { + CPrep_PushOption(OPT_OFFSET(altivec_vrsave), 1); + } else if (!strcmp(tkidentifier->name, "allon")) { + CPrep_PushOption(OPT_OFFSET(altivec_vrsave), 2); + } else if (!strcmp(tkidentifier->name, "reset")) { + CPrep_PopOption(OPT_OFFSET(altivec_vrsave)); + } else { + CError_Error(186); + return; + } + } else { + CError_Error(186); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "function_align")) { + t = plex(); + if (t == TK_INTCONST) { + value = CInt64_GetULong(&tkintconst); + switch (value) { + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + CPrep_PushOption(OPT_OFFSET(code_alignment), value); + break; + default: + PPCError_Warning(161); + CodeGen_EOLCheck(); + return; + } + } else if (t == TK_IDENTIFIER && !strcmp(tkidentifier->name, "reset")) { + CPrep_PopOption(OPT_OFFSET(code_alignment)); + } else { + PPCError_Warning(161); + } + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "processor")) { + if (cscope_currentfunc) { + PPCError_Warning(156, "pragma processor"); + return; + } + t = plex(); + if (t == TK_INTCONST) { + switch (CInt64_GetULong(&tkintconst)) { + case 401: + copts.cpu = 0; + break; + case 403: + copts.cpu = 1; + break; + case 505: + copts.cpu = 2; + break; + case 509: + copts.cpu = 3; + break; + case 555: + copts.cpu = 4; + break; + case 556: + copts.cpu = 25; + break; + case 565: + copts.cpu = 26; + break; + case 601: + copts.cpu = 5; + break; + case 602: + copts.cpu = 6; + break; + case 8240: + copts.cpu = 18; + break; + case 8260: + copts.cpu = 19; + break; + case 603: + copts.cpu = 7; + break; + case 604: + copts.cpu = 9; + break; + case 740: + copts.cpu = 11; + break; + case 750: + copts.cpu = 12; + break; + case 801: + copts.cpu = 13; + break; + case 821: + copts.cpu = 14; + break; + case 823: + copts.cpu = 15; + break; + case 850: + copts.cpu = 16; + break; + case 860: + copts.cpu = 17; + break; + case 7400: + copts.cpu = 21; + break; + default: + PPCError_Warning(208); + CodeGen_EOLCheck(); + return; + } + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "generic")) + copts.cpu = 20; + else if (!strcmp(tkidentifier->name, "603e")) + copts.cpu = 8; + else if (!strcmp(tkidentifier->name, "604e")) + copts.cpu = 10; + else if (!strcmp(tkidentifier->name, "PPC603e")) + copts.cpu = 8; + else if (!strcmp(tkidentifier->name, "PPC604e")) + copts.cpu = 10; + else + PPCError_Warning(208); + } else { + PPCError_Warning(208); + } + + if ((str = CMach_GetCPU())) + CPrep_InsertSpecialMacro(&ppc_cpu, str); + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "min_struct_alignment")) { + t = plex(); + if (t == TK_INTCONST) { + value = CInt64_GetULong(&tkintconst); + switch (value) { + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + CPrep_PushOption(OPT_OFFSET(some_alignment), value); + break; + default: + PPCError_Warning(191); + CodeGen_EOLCheck(); + return; + } + } else if (t == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "reset")) + CPrep_PopOption(OPT_OFFSET(some_alignment)); + else if (!strcmp(tkidentifier->name, "on")) + CPrep_PushOption(OPT_OFFSET(some_alignment), 4); + else if (!strcmp(tkidentifier->name, "off")) + CPrep_PushOption(OPT_OFFSET(some_alignment), 1); + } else { + PPCError_Warning(161); + } + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "tvectors")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + no_descriptors = 1; + } else if (!strcmp(tkidentifier->name, "on")) { + no_descriptors = 0; + } else { + CError_Error(186); + return; + } + } else { + CError_Error(186); + } + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "dynamic")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.codegen_dynamic = 0; + copts.codegen_pic = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.codegen_dynamic = 1; + } else { + CError_Error(186); + return; + } + } else { + CError_Error(186); + } + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "pic")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.codegen_pic = 0; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.codegen_pic = 1; + if (!copts.codegen_dynamic) { + PPCError_Error(189); + copts.codegen_pic = 0; + } + } else { + CError_Error(186); + return; + } + } else { + CError_Error(186); + } + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "implicit_templates")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.no_implicit_templates = 1; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.no_implicit_templates = 0; + } else { + CError_Error(186); + return; + } + } else { + CError_Error(186); + } + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "common")) { + if (plex() == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "off")) { + copts.no_common = 1; + } else if (!strcmp(tkidentifier->name, "on")) { + copts.no_common = 0; + } else { + CError_Error(186); + return; + } + } else { + CError_Error(186); + } + + CodeGen_EOLCheck(); + return; + } + + if (!strcmp(name->name, "CALL_ON_MODULE_BIND")) { + if (plex() == TK_IDENTIFIER) { + for (nspace = cscope_current; nspace; nspace = nspace->parent) { + list = CScope_GetLocalObject(nspace, tkidentifier); + if (list && list->object->otype == OT_OBJECT && OBJECT(list->object)->datatype == DFUNC) { + ObjGen_DeclareInitFunction(OBJECT(list->object)); + break; + } + } + } else { + CError_Error(186); + } + + CodeGen_EOLCheck(); + return; + } + + if (copts.warn_illpragma) + CPrep_Warning(186); + + if (plex() != TK_NEG7) { + do { + t = plex(); + } while (t != TK_NEG7 && t != 0); + } +} + +void CodeGen_UpdateObject(Object *object) { + if (object->datatype == DDATA && object->section == SECT_DEFAULT && object == rt_ptmf_null) + object->sclass = TK_EXTERN; +} + +void CodeGen_UpdateBackEndOptions(void) { + copts.global_optimizer = 1; +} + +void CodeGen_objc_method_self_offset() { + // TODO objc +} + +void CodeGen_objc_method_sel_offset() { + // TODO objc +} + +void CodeGen_objc_method_arg_offset() { + // TODO objc +} + +void CodeGen_objc_method_args_size() { + // TODO objc +} + +ENode *CodeGen_HandleIntrinsicCall(Object *func, ENodeList *arg_exprs) { + return Intrinsics_HandleIntrinsicCall(func, arg_exprs); +} + +ENode *CodeGen_HandleTypeCast(ENode *expr, Type *type, UInt32 qual) { + short flags; + + if (copts.altivec_model) { + flags = qual & ENODE_FLAG_QUALS; + if (IS_TYPE_STRUCT(type) && IS_TYPE_STRUCT(expr->rtype) && expr->flags == flags) { + switch (TYPE_STRUCT(type)->stype) { + case STRUCT_TYPE_4: + case STRUCT_TYPE_5: + case STRUCT_TYPE_6: + case STRUCT_TYPE_7: + case STRUCT_TYPE_8: + case STRUCT_TYPE_9: + case STRUCT_TYPE_A: + case STRUCT_TYPE_B: + case STRUCT_TYPE_C: + case STRUCT_TYPE_D: + case STRUCT_TYPE_E: + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = type; + expr->flags = flags; + return expr; + } + } + } + + return NULL; +} + +short CodeGen_AssignCheck(ENode *expr, Type *type, Boolean flag1, Boolean flag2) { + short result; + Type *exprtype = expr->rtype; + + if (copts.altivec_model && IS_TYPE_VECTOR(type) && IS_TYPE_VECTOR(exprtype) && TYPE_STRUCT(type)->stype == TYPE_STRUCT(exprtype)->stype) + result = CheckResult3; + else + result = CheckResult0; + return result; +} + +Boolean CodeGen_CollapseVectorExpression(ENode *expr, MWVector128 *vec, Type *type) { + // this function is a mess and needs lots of fixing + Boolean result; + //int count; + int i; + ENode *escan; + + result = 0; + for (i = 0; i < 4; i++) + vec->ul[i] = 0; + + if (ENODE_IS(expr, ECOMMA)) { + i = 0; + escan = expr; + while (ENODE_IS(escan, ECOMMA)) { + i++; + escan = escan->data.diadic.left; + } + switch (TYPE_STRUCT(type)->stype) { + case STRUCT_TYPE_4: + case STRUCT_TYPE_5: + case STRUCT_TYPE_6: + if (i < 15) { + PPCError_Error(110, type, 0); + } else if (i > 15) { + PPCError_Error(111, type, 0); + } else { + escan = expr; + i = 15; + while (ENODE_IS(escan, ECOMMA)) { + CInt64 v; + expr = escan->data.diadic.right; + v = expr->data.intval; + if (!ENODE_IS(expr, EINTCONST)) { + PPCError_Error(112); + break; + } + + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_4) { + if (!CInt64_IsInURange(v, 1)) + PPCError_Warning(113, type, 0); + } else { + if (!CInt64_IsInRange(v, 1)) + PPCError_Warning(113, type, 0); + } + } + + vec->uc[i--] = (UInt8) v.lo; + escan = escan->data.diadic.left; + } + + if (ENODE_IS(escan, EINTCONST)) { + CInt64 v = escan->data.intval; + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_4) { + if (!CInt64_IsInURange(v, 1)) + PPCError_Warning(113, type, 0); + } else { + if (!CInt64_IsInRange(v, 1)) + PPCError_Warning(113, type, 0); + } + } + vec->uc[0] = (UInt8) v.lo; + } else { + PPCError_Error(112); + break; + } + result = 1; + } + break; + + case STRUCT_TYPE_7: + case STRUCT_TYPE_8: + case STRUCT_TYPE_9: + case STRUCT_TYPE_E: + if (i < 7) { + PPCError_Error(110, type, 0); + } else if (i > 7) { + PPCError_Error(111, type, 0); + } else { + escan = expr; + i = 7; + while (ENODE_IS(escan, ECOMMA)) { + ENode *e = escan->data.diadic.right; + CInt64 v = e->data.intval; + if (!ENODE_IS(e, EINTCONST)) { + PPCError_Error(112); + break; + } + + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_7 || TYPE_STRUCT(type)->stype == STRUCT_TYPE_E) { + if (!CInt64_IsInURange(v, 2)) + PPCError_Warning(113, type, 0); + } else { + if (!CInt64_IsInRange(v, 2)) + PPCError_Warning(113, type, 0); + } + } + + vec->us[i--] = (UInt16) e->data.intval.lo; + escan = escan->data.diadic.left; + } + + if (ENODE_IS(escan, EINTCONST)) { + CInt64 v = escan->data.intval; + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_7 || TYPE_STRUCT(type)->stype == STRUCT_TYPE_E) { + if (!CInt64_IsInURange(v, 2)) + PPCError_Warning(113, type, 0); + } else { + if (!CInt64_IsInRange(v, 2)) + PPCError_Warning(113, type, 0); + } + } + vec->us[0] = (UInt16) v.lo; + } else { + PPCError_Error(112); + break; + } + result = 1; + } + break; + + case STRUCT_TYPE_A: + case STRUCT_TYPE_B: + case STRUCT_TYPE_C: + if (i < 3) { + PPCError_Error(110, type, 0); + } else if (i > 3) { + PPCError_Error(111, type, 0); + } else { + escan = expr; + i = 3; + while (ENODE_IS(escan, ECOMMA)) { + CInt64 v; + expr = escan->data.diadic.right; + v = expr->data.intval; + if (!ENODE_IS(expr, EINTCONST)) { + PPCError_Error(112); + break; + } + + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_A) { + if (!CInt64_IsInURange(v, 4)) + PPCError_Warning(113, type, 0); + } else { + if (!CInt64_IsInRange(v, 4)) + PPCError_Warning(113, type, 0); + } + } + + vec->ul[i--] = expr->data.intval.lo; + escan = escan->data.diadic.left; + } + + if (ENODE_IS(escan, EINTCONST)) { + CInt64 v = escan->data.intval; + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_A) { + if (!CInt64_IsInURange(v, 4)) + PPCError_Warning(113, type, 0); + } else { + if (!CInt64_IsInRange(v, 4)) + PPCError_Warning(113, type, 0); + } + } + vec->ul[0] = v.lo; + } else { + PPCError_Error(112); + break; + } + result = 1; + } + break; + + case STRUCT_TYPE_D: + if (i < 3) { + PPCError_Error(110, type, 0); + } else if (i > 3) { + PPCError_Error(111, type, 0); + } else { + Float fv; + escan = expr; + i = 3; + while (ENODE_IS(escan, ECOMMA)) { + expr = escan->data.diadic.right; + if (ENODE_IS(expr, EFLOATCONST)) { + fv = expr->data.floatval; + } else if (ENODE_IS(escan->data.diadic.right, EINTCONST)) { + fv = CMach_CalcFloatConvertFromInt(expr->rtype, + expr->data.intval); + } else { + PPCError_Error(112); + break; + } + + CMach_InitFloatMem(TYPE(&stfloat), fv, &vec->f[i]); + i--; + escan = escan->data.diadic.left; + } + + if (ENODE_IS(escan, EFLOATCONST)) { + fv = escan->data.floatval; + } else if (ENODE_IS(escan, EINTCONST)) { + fv = CMach_CalcFloatConvertFromInt(escan->rtype, escan->data.intval); + } else { + PPCError_Error(112); + break; + } + + CMach_InitFloatMem(TYPE(&stfloat), fv, &vec->f[0]); + result = 1; + } + break; + } + } else if (ENODE_IS(expr, EINTCONST)) { + int i = 0; + switch (TYPE_STRUCT(type)->stype) { + case STRUCT_TYPE_4: + case STRUCT_TYPE_5: + case STRUCT_TYPE_6: + { + CInt64 v = expr->data.intval; + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_4) { + if (!CInt64_IsInURange(v, 1)) + PPCError_Warning(113, type, 0); + } else { + if (!CInt64_IsInRange(v, 1)) + PPCError_Warning(113, type, 0); + } + } + while (i < 16) + vec->uc[i++] = (UInt8) v.lo; + result = 1; + break; + } + case STRUCT_TYPE_7: + case STRUCT_TYPE_8: + case STRUCT_TYPE_9: + case STRUCT_TYPE_E: + { + CInt64 v = expr->data.intval; + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_7 || TYPE_STRUCT(type)->stype == STRUCT_TYPE_E) { + if (!CInt64_IsInURange(v, 2)) + PPCError_Warning(113, type, 0); + } else { + if (!CInt64_IsInRange(v, 2)) + PPCError_Warning(113, type, 0); + } + } + while (i < 8) + vec->us[i++] = (UInt16) v.lo; + result = 1; + break; + } + case STRUCT_TYPE_A: + case STRUCT_TYPE_B: + case STRUCT_TYPE_C: + { + CInt64 v = expr->data.intval; + if (copts.pedantic) { + if (TYPE_STRUCT(type)->stype == STRUCT_TYPE_A) { + if (!CInt64_IsInURange(v, 4)) + PPCError_Warning(113, type, 0); + } else { + if (!CInt64_IsInRange(v, 4)) + PPCError_Warning(113, type, 0); + } + } + while (i < 4) + vec->ul[i++] = v.lo; + result = 1; + break; + } + case STRUCT_TYPE_D: + { + Float fv; + if (!CInt64_IsInRange(expr->data.intval, 4)) { + PPCError_Error(112); + break; + } + fv = CMach_CalcFloatConvertFromInt(expr->rtype, expr->data.intval); + for (; i < 4; i++) + CMach_InitFloatMem(TYPE(&stfloat), fv, &vec->f[i]); + result = 1; + break; + } + default: + PPCError_Error(112); + } + } else if (ENODE_IS(expr, EFLOATCONST)) { + switch (TYPE_STRUCT(type)->stype) { + default: + PPCError_Error(112); + break; + case STRUCT_TYPE_D: + { + Float fv; + i = 0; + fv = expr->data.floatval; + CMach_InitFloatMem(TYPE(&stfloat), fv, &vec->f[0]); + while (i < 4) + CMach_InitFloatMem(TYPE(&stfloat), fv, &vec->f[i++]); + result = 1; + break; + } + } + } else if (ENODE_IS2(expr, EINDIRECT, EFUNCCALL)) { + if (!IS_TYPE_STRUCT(expr->rtype)) + PPCError_Error(112); + } else if (!ENODE_IS(expr, EVECTOR128CONST)) { + PPCError_Error(112); + } + + return result; +} + +void CodeGen_InsertSpecialMacros(void) { + char *str; + + CPrep_InsertSpecialMacro(&vecM, "__VEC__"); + CPrep_InsertSpecialMacro(&altivecM, "__ALTIVEC__"); + CPrep_InsertSpecialMacro(&powcM, "powerc"); + CPrep_InsertSpecialMacro(&__powcM, "__powerc"); + CPrep_InsertSpecialMacro(&hostM, "__POWERPC__"); + CPrep_InsertSpecialMacro(&_ppc_M, "__ppc__"); + + CPrep_InsertSpecialMacro(&bendM, "__BIG_ENDIAN__"); + + if ((str = CMach_GetCPU())) + CPrep_InsertSpecialMacro(&ppc_cpu, str); + + CPrep_InsertSpecialMacro(&profM, "__profile__"); + CPrep_InsertSpecialMacro(&longI, "__fourbyteints__"); + CPrep_InsertSpecialMacro(&IEEED, "__IEEEdoubles__"); + CPrep_InsertSpecialMacro(&macM2, "__MACOS__"); + CPrep_InsertSpecialMacro(&appleM, "__APPLE__"); + CPrep_InsertSpecialMacro(&_machM, "__MACH__"); + CPrep_InsertSpecialMacro(&archM, "__ARCHITECTURE__"); + + if (copts.optimizationlevel > 0) + CPrep_InsertSpecialMacro(&optM, "__OPTIMIZE__"); + + if (copts.codegen_dynamic) + CPrep_InsertSpecialMacro(&dynM, "__DYNAMIC__"); + if (!copts.codegen_dynamic) + CPrep_InsertSpecialMacro(&dynM, "__STATIC__"); + + if (copts.oldalignment && copts.align_mode == AlignMode2_PPC) + CPrep_InsertSpecialMacro(&alignM, "__NATURAL_ALIGNMENT__"); + + if (!copts.ANSI_strict) + CPrep_InsertSpecialMacro(&ppcM, "ppc"); +} + +char *CodeGen_ExpandSpecialMacro(Macro *macro) { + if (macro == &vecM) return "10205"; + if (macro == &altivecM) return "100000000"; + if (macro == &powcM) return "1"; + if (macro == &__powcM) return "1"; + if (macro == &hostM) return "1"; + if (macro == &bendM) return "1"; + if (macro == &_ppc_M) return "1"; + if (CMach_GetCPU() && macro == &ppc_cpu) return "1"; + if (macro == &profM) return copts.profile ? "1" : "0"; + if (macro == &longI) return "1"; + if (macro == &IEEED) return "1"; + if (macro == &macM2) return "1"; + if (macro == &appleM) return "1"; + if (macro == &alignM) return "1"; + + if (macro == &optM) { + switch (copts.optimizationlevel) { + case 1: return "1"; + case 2: return "2"; + case 3: return "3"; + case 4: return "4"; + case 0: return "0"; + default: return "9"; + } + } + + if (macro == &_machM) return "1"; + if (macro == &archM) return "ppc"; + if (macro == &dynM) return "1"; + if (!copts.ANSI_strict && macro == &ppcM) return "1"; + if (macro == &_ppc_M) return "1"; + +#line 4801 + CError_FATAL(); + return "0"; +} + +void CodeGen_reportheapinfo(Boolean release_flag, char *name, char *text) { + HeapInfo o; + HeapInfo all; + + CTool_GetHeapInfo(&o, 3); + CTool_GetHeapInfo(&all, 5); + + if (release_flag) + releaseoheap(); + + PPCError_Message( + "%n:%u HEAP STATUS\n" + " optimizer: %i blocks, used: %i, free: %i, total: %i, largest free: %i\n" + " all: %i blocks, used: %i, free: %i, total: %i, largest free: %i", + name, text, + o.blocks, o.total_size - o.total_free, o.total_free, o.total_size, o.largest_free_block, + all.blocks, all.total_size - all.total_free, all.total_free, all.total_size, all.largest_free_block + ); +} + +static void CodeGen_heaperror(void) { + CodeGen_reportheapinfo(1, "?", "out of memory"); + if (saveheaperror) { + setheaperror(saveheaperror); + saveheaperror(); + } +} + +void CodeGen_InitialSanityCheck(void) { +} diff --git a/compiler_and_linker/unsorted/CodeGenOptPPC.c b/compiler_and_linker/unsorted/CodeGenOptPPC.c new file mode 100644 index 0000000..5723395 --- /dev/null +++ b/compiler_and_linker/unsorted/CodeGenOptPPC.c @@ -0,0 +1,17 @@ +#include "compiler/CodeGenOptPPC.h" +#include "compiler/InstrSelection.h" + +void CodeGen_InitCompiler(void) { + init_cgdispatch(); +} + +void CodeGen_TermCompiler(void) { + +} + +void CodeGen_InitBackEndOptions(void) { + // TODO +} + +void Test_Version_Numbers(void) { +} diff --git a/compiler_and_linker/unsorted/CodeMotion.c b/compiler_and_linker/unsorted/CodeMotion.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CodeMotion.c diff --git a/compiler_and_linker/unsorted/Coloring.c b/compiler_and_linker/unsorted/Coloring.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/Coloring.c diff --git a/compiler_and_linker/unsorted/ConstantPropagation.c b/compiler_and_linker/unsorted/ConstantPropagation.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/ConstantPropagation.c diff --git a/compiler_and_linker/unsorted/CopyPropagation.c b/compiler_and_linker/unsorted/CopyPropagation.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/CopyPropagation.c diff --git a/compiler_and_linker/unsorted/Exceptions.c b/compiler_and_linker/unsorted/Exceptions.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/Exceptions.c diff --git a/compiler_and_linker/unsorted/FuncLevelAsmPPC.c b/compiler_and_linker/unsorted/FuncLevelAsmPPC.c new file mode 100644 index 0000000..d054191 --- /dev/null +++ b/compiler_and_linker/unsorted/FuncLevelAsmPPC.c @@ -0,0 +1,22 @@ +#include "compiler/FuncLevelAsmPPC.h" + +void setup_assembly_argument(Object *obj, short i) { +} + +void assign_local_addresses() { +} + +static void FuncAsm_PreScanDirectives() { +} + +static void FuncAsm_AddEntryPoint() { +} + +void Assembler() { +} + +void SetupAssembler() { +} + +void CleanupAssembler() { +} diff --git a/compiler_and_linker/unsorted/FunctionCalls.c b/compiler_and_linker/unsorted/FunctionCalls.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/FunctionCalls.c diff --git a/compiler_and_linker/unsorted/GCCInlineAsm.c b/compiler_and_linker/unsorted/GCCInlineAsm.c new file mode 100644 index 0000000..9bceb19 --- /dev/null +++ b/compiler_and_linker/unsorted/GCCInlineAsm.c @@ -0,0 +1,33 @@ +#include "compiler/GCCInlineAsm.h" + +Statement *first_ST_ASM; + +void InlineAsm_SkipComment() { +} + +static void gcc_parse_attribute() { +} + +static void gcc_parse_name() { +} + +static void gcc_parse_expression() { +} + +static void gcc_parse_input() { +} + +static void gcc_parse_output() { +} + +static void gcc_parse_killed() { +} + +static void gcc_replace_arg_st_asm() { +} + +static void gcc_replace_arg() { +} + +void InlineAsm_gcc_parse(void) { +} diff --git a/compiler_and_linker/unsorted/GenStabs.c b/compiler_and_linker/unsorted/GenStabs.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/GenStabs.c diff --git a/compiler_and_linker/unsorted/GlobalOptimizer.c b/compiler_and_linker/unsorted/GlobalOptimizer.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/GlobalOptimizer.c diff --git a/compiler_and_linker/unsorted/IROUseDef.c b/compiler_and_linker/unsorted/IROUseDef.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IROUseDef.c diff --git a/compiler_and_linker/unsorted/InlineAsm.c b/compiler_and_linker/unsorted/InlineAsm.c new file mode 100644 index 0000000..ae73d91 --- /dev/null +++ b/compiler_and_linker/unsorted/InlineAsm.c @@ -0,0 +1,681 @@ +#include "compiler/InlineAsm.h" +#include "compiler/InlineAsmPPC.h" +#include "compiler/GCCInlineAsm.h" +#include "compiler/CompilerTools.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/CMachine.h" +#include "compiler/COptimizer.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CScope.h" +#include "compiler/PCode.h" +#include "compiler/Registers.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/types.h" + +int allow_array_expressions = 1; + +int backtracking; +jmp_buf backtrack; +jmp_buf InlineAsm_assemblererror; +static int ASMstmtnb; + +void AssemblerError(void) { + longjmp(InlineAsm_assemblererror, 1); +} + +void InlineAsm_SyntaxError(short code) { + if (backtracking) + longjmp(backtrack, 1); + + if (tk == TK_NEG7 || tk == ';') + code = CErrorStr112; + CError_Error(code); +} + +CLabel *InlineAsm_LookupLabel(HashNameNode *name) { + CLabel *label; + + for (label = Labels; label; label = label->next) { + if (name == label->name) + break; + } + + return label; +} + +CLabel *InlineAsm_DeclareLabel(HashNameNode *name) { + CLabel *label = newlabel(); + label->name = name; + label->next = Labels; + Labels = label; + return label; +} + +static void InlineAsm_DefineLabel(HashNameNode *name) { + CLabel *label; + Statement *stmt; + + label = InlineAsm_LookupLabel(name); + if (!label) { + label = InlineAsm_DeclareLabel(name); + } else { + if (label->stmt) + CError_Error(CErrorStr171, name->name); + } + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label; + label->stmt = stmt; +} + +Boolean InlineAsm_LookupSymbolOrTag(HashNameNode *name, IALookupResult *result, Boolean allow_tag) { + ObjBase *obj; + NameSpace *nspace; + NameSpaceObjectList *list; + + result->name = name; + result->object = NULL; + result->label = NULL; + result->type = NULL; + result->has_value = 0; + + if ((result->label = InlineAsm_LookupLabel(name))) + return 1; + + for (nspace = cscope_current; nspace; nspace = nspace->parent) { + if ((list = CScope_FindName(nspace, name))) { + obj = list->object; + switch (obj->otype) { + case OT_ENUMCONST: + result->has_value = 1; + result->value = OBJ_ENUM_CONST(list->object)->val.lo; + return 1; + case OT_OBJECT: + if (OBJECT(obj)->datatype == DABSOLUTE) { + result->has_value = 1; + result->value = OBJECT(obj)->u.address; + } else { + if (OBJECT(obj)->datatype == DDATA && (OBJECT(obj)->qual & Q_10000)) + CInit_ExportConst(OBJECT(obj)); + result->object = OBJECT(obj); + } + return 1; + case OT_TYPE: + result->type = OBJ_TYPE(obj)->type; + return 1; + case OT_TYPETAG: + if (allow_tag) { + result->type = OBJ_TYPE_TAG(obj)->type; + return 1; + } + case OT_NAMESPACE: + case OT_MEMBERVAR: + return 0; + default: +#line 245 + CError_FATAL(); + } + } + } + + return 0; +} + +Boolean InlineAsm_LookupSymbol(HashNameNode *name, IALookupResult *result) { + return InlineAsm_LookupSymbolOrTag(name, result, 0); +} + +static ObjMemberVar *isclassmember(TypeClass *tclass, HashNameNode *name) { + NameSpaceObjectList *list; + + list = CScope_FindName(tclass->nspace, name); + return (list && list->object->otype == OT_MEMBERVAR) ? OBJ_MEMBER_VAR(list->object) : NULL; +} + +SInt32 InlineAsm_StructMemberOffset(Type *type) { + StructMember *member; + ObjMemberVar *ivar; + SInt32 offset = 0; + + do { + if (IS_TYPE_STRUCT(type)) { + tk = lex(); + if (tk != TK_IDENTIFIER) + InlineAsm_SyntaxError(CErrorStr107); + member = ismember(TYPE_STRUCT(type), tkidentifier); + if (!member) + CError_Error(CErrorStr150, tkidentifier->name); + offset += member->offset; + type = member->type; + tk = lex(); + } else if (IS_TYPE_CLASS(type)) { + tk = lex(); + if (tk != TK_IDENTIFIER) + InlineAsm_SyntaxError(CErrorStr107); + ivar = isclassmember(TYPE_CLASS(type), tkidentifier); + if (!ivar) + CError_Error(CErrorStr150, tkidentifier->name); + offset += ivar->offset; + type = ivar->type; + tk = lex(); + } else { + CError_Error(CErrorStr149); + } + } while (tk == '.'); + + return offset; +} + +SInt32 InlineAsm_StructArrayMemberOffset(Type *type) { + StructMember *member; + ObjMemberVar *ivar; + SInt32 offset = 0; + + do { + if (tk == '.') { + if (IS_TYPE_STRUCT(type)) { + tk = lex(); + if (tk != TK_IDENTIFIER) + InlineAsm_SyntaxError(CErrorStr107); + member = ismember(TYPE_STRUCT(type), tkidentifier); + if (!member) + CError_Error(CErrorStr150, tkidentifier->name); + offset += member->offset; + type = member->type; + tk = lex(); + } else if (IS_TYPE_CLASS(type)) { + tk = lex(); + if (tk != TK_IDENTIFIER) + InlineAsm_SyntaxError(CErrorStr107); + ivar = isclassmember(TYPE_CLASS(type), tkidentifier); + if (!ivar) + CError_Error(CErrorStr150, tkidentifier->name); + offset += ivar->offset; + type = ivar->type; + tk = lex(); + } else { + CError_Error(CErrorStr149); + } + } else { + if (IS_TYPE_ARRAY(type)) { + type = TPTR_TARGET(type); + tk = lex(); + offset += type->size * InlineAsm_ConstantExpression(); + if (tk != ']') + InlineAsm_SyntaxError(125); + tk = lex(); + } else { + CError_Error(CErrorStr148); + } + } + } while (tk == '.' || tk == '['); + + return offset; +} + +SInt32 InlineAsm_StructPointerMemberOffset(Type *type) { + StructMember *member; + ObjMemberVar *ivar; + SInt32 offset; + + tk = lex(); + if (tk != TK_IDENTIFIER) + InlineAsm_SyntaxError(107); + + if (IS_TYPE_STRUCT(type)) { + member = ismember(TYPE_STRUCT(type), tkidentifier); + if (!member) + CError_Error(CErrorStr150, tkidentifier->name); + offset = member->offset; + type = member->type; + } else { + ivar = isclassmember(TYPE_CLASS(type), tkidentifier); + if (!ivar) + CError_Error(CErrorStr150, tkidentifier->name); + offset = ivar->offset; + type = ivar->type; + } + + tk = lex(); + if (tk == '.' || tk == '[') + offset += InlineAsm_StructArrayMemberOffset(type); + + return offset; +} + +static SInt32 DiadicOperator(SInt32 left, short op, SInt32 right) { + CInt64 left64; + CInt64 right64; + CInt64_SetLong(&left64, left); + CInt64_SetLong(&right64, right); + right64 = CMach_CalcIntDiadic(TYPE(&stsignedint), left64, op, right64); + return CInt64_GetULong(&right64); +} + +static SInt32 PrimaryExpression(void) { + IALookupResult result; + SInt32 value; + + switch (tk) { + case TK_IDENTIFIER: + if (InlineAsm_LookupSymbol(tkidentifier, &result)) { + if (result.has_value) { + tk = lex(); + return result.value; + } + + if (result.type && (IS_TYPE_STRUCT(result.type) || IS_TYPE_CLASS(result.type))) { + tk = lex(); + if (tk != '.') + InlineAsm_SyntaxError(120); + if (allow_array_expressions) + return InlineAsm_StructArrayMemberOffset(result.type); + else + return InlineAsm_StructMemberOffset(result.type); + } else { + InlineAsm_SyntaxError(124); + } + } else { + InlineAsm_SyntaxError(124); + } + break; + case TK_INTCONST: + value = tkintconst.lo; + tk = lex(); + return value; + case TK_SIZEOF: + return scansizeof(); + case '+': + tk = lex(); + return PrimaryExpression(); + case '-': + tk = lex(); + return -PrimaryExpression(); + case '!': + tk = lex(); + return PrimaryExpression() == 0; + case '~': + tk = lex(); + return ~PrimaryExpression(); + case '(': + tk = lex(); + value = InlineAsm_ConstantExpression(); + if (tk != ')') + InlineAsm_SyntaxError(115); + tk = lex(); + return value; + default: + InlineAsm_SyntaxError(120); + } + + return 0; +} + +static SInt32 ConstantExpressionTail(SInt32 value) { + SInt32 right; + short left_token; + short right_prec; + + while (1) { + left_token = tk; + tk = lex(); + right = PrimaryExpression(); + + right_prec = GetPrec(tk); + if (right_prec == 0) + return DiadicOperator(value, left_token, right); + + if (GetPrec(left_token) >= right_prec) { + value = DiadicOperator(value, left_token, right); + } else { + value = DiadicOperator(value, left_token, ConstantExpressionTail(right)); + if (GetPrec(tk) == 0) + return value; + } + } +} + +SInt32 InlineAsm_ConstantExpression(void) { + SInt32 value = PrimaryExpression(); + + if (GetPrec(tk) == 0) + return value; + else + return ConstantExpressionTail(value); +} + +HashNameNode *MakeLocalLabel(CInt64 num) { + char buf[80]; + sprintf(buf, "@%i_%i", ASMstmtnb, CInt64_GetULong(&num)); + return GetHashNameNodeExport(buf); +} + +static void ScanOptionalLabel() { + if (tk == TK_INTCONST) { + if (lookahead() == ':') { + InlineAsm_DefineLabel(MakeLocalLabel(tkintconst)); + tk = lex(); + tk = lex(); + } + } else { + if (tkidentifier->name[0] == '@') { + InlineAsm_DefineLabel(tkidentifier); + tk = lex(); + if (tk == ':') + tk = lex(); + } else { + HashNameNode *name = tkidentifier; + short t = lookahead(); + tkidentifier = name; + if (t == ':') { + InlineAsm_DefineLabel(name); + tk = lex(); + tk = lex(); + } + } + } +} + +static void ScanStatements(volatile short endToken, UInt8 mode) { + if (setjmp(InlineAsm_assemblererror)) { + while (tk != TK_NEG7 && tk != endToken && tk != '}' && tk) + tk = lex(); + if (tk == ';' || tk == TK_NEG7) + tk = lex(); + } else { + InlineAsm_Initialize(mode); + InlineAsm_gccmode = 0; + if (setjmp(InlineAsm_assemblererror)) { + while (tk != ';' && tk != TK_NEG7 && tk != endToken && tk != '}' && tk) + tk = lex(); + if (tk == ';' || tk == TK_NEG7) + tk = lex(); + } + + while (tk && tk != endToken) { + backtracking = 0; + sourceoffset = CPrep_GetFileOffsetInfo(&cparser_fileoffset); + if (tk == '"') { + if (InlineAsm_gccmode) { + tk = lex(); + InlineAsm_gcc_parse(); + } else { + InlineAsm_gccmode = 1; + copts.cplusplus = 0; + copts.asmpoundcomment = 1; + tk = lex(); + } + } + + if (tk == '.') { + InlineAsm_ScanAssemblyDirective(); + } else if (tk == TK_IDENTIFIER) { + ScanOptionalLabel(); + if (tk == TK_IDENTIFIER) + InlineAsm_ScanAssemblyInstruction(); + } else if (tk == TK_INTCONST) { + ScanOptionalLabel(); + if (tk == TK_IDENTIFIER) + InlineAsm_ScanAssemblyInstruction(); + } + + if (InlineAsm_gccmode && tk == '"') { + tk = lex(); + InlineAsm_gcc_parse(); + } + + if (tk == ';' || tk == TK_NEG7) { + CPrep_TokenStreamFlush(); + tk = lex(); + } else if (tk != endToken) { + if (endToken == ')') + CError_Error(CErrorStr115); + else + CError_Error(CErrorStr113); + } + } + } +} + +void InlineAsm_ScanStatements(volatile short endToken) { + ScanStatements(endToken, 0); +} + +void InlineAsm_ScanFunction(volatile short endToken) { + ScanStatements(endToken, 1); +} + +void InlineAsm_Assemble(void) { + short token = (tk == '(') ? ')' : '}'; + char save_pc = copts.asmpoundcomment; + char save_cpp = copts.cplusplus; + + cprep_nostring = 1; + CFunc_AppendStatement(ST_NOP); + first_ST_ASM = curstmt; + ASMstmtnb++; + + cprep_eoltokens = 1; + in_assembler = 1; + tk = lex(); + InlineAsm_ScanStatements(token); + in_assembler = 0; + cprep_eoltokens = 0; + cprep_nostring = 0; + + copts.asmpoundcomment = save_pc; + copts.cplusplus = save_cpp; +} + +void InlineAsm_PackAsmStatement(Statement *stmt, Statement *first, void **output, SInt32 *outsize) { + InlineAsm *src; + InlineAsm *dest; + IAOperand *op; + SInt32 i; + SInt32 size; + + src = (InlineAsm *) stmt->expr; + size = sizeof(InlineAsm) + sizeof(IAOperand) * src->argcount; + dest = galloc(size); + memcpy(dest, src, size); + + for (i = 0, op = dest->args; i < dest->argcount; i++, op++) { + switch (op->type) { + case IAOpnd_0: + break; + case IAOpnd_Reg: + case IAOpnd_4: + op->u.reg.object = (Object *) CInline_GetLocalID(op->u.reg.object); + break; + case IAOpnd_Lab: + op->u.lab.label = (CLabel *) CInline_GetStatementNumber(first, op->u.lab.label->stmt); + break; + case IAOpnd_LabDiff: + op->u.labdiff.label1 = (CLabel *) CInline_GetStatementNumber(first, op->u.labdiff.label1->stmt); + op->u.labdiff.label2 = (CLabel *) CInline_GetStatementNumber(first, op->u.labdiff.label2->stmt); + break; + } + } + + *output = dest; + *outsize = size; +} + +void InlineAsm_UnpackAsmStatement(Statement *stmt, CLabel **labelArray, Boolean flag, void *data, SInt32 size) { + InlineAsm *ia; + IAOperand *op; + SInt32 i; + + ia = galloc(size); + memcpy(ia, data, size); + + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + switch (op->type) { + case IAOpnd_0: + break; + case IAOpnd_Reg: + case IAOpnd_4: + op->u.reg.object = CInline_GetLocalObj((SInt32) op->u.reg.object, flag); + break; + case IAOpnd_Lab: + op->u.lab.label = labelArray[(SInt16) op->u.lab.label]; + break; + case IAOpnd_LabDiff: + op->u.labdiff.label1 = labelArray[(SInt16) op->u.labdiff.label1]; + op->u.labdiff.label2 = labelArray[(SInt16) op->u.labdiff.label2]; + break; + } + } + + stmt->expr = (ENode *) ia; +} + +void InlineAsm_CheckLocalUsage(Statement *stmt) { + InlineAsm *ia = (InlineAsm *) stmt->expr; + IAOperand *op; + SInt32 i; + + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + switch (op->type) { + case IAOpnd_Reg: + if (op->u.reg.object) + SetVarUsage(op->u.reg.object, 0); + break; + case IAOpnd_4: + SetVarUsage(op->u.obj.obj, 1); + break; + } + } +} + +CLabel *InlineAsm_GetReferencedLabel(Statement *stmt) { + InlineAsm *ia = (InlineAsm *) stmt->expr; + IAOperand *op; + SInt32 i; + + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + if (op->type == IAOpnd_Lab) + return op->u.lab.label; + if (op->type == IAOpnd_LabDiff) + return op->u.labdiff.label1; + } + + return NULL; +} + +CLabel *InlineAsm_GetReferencedLabel2(Statement *stmt) { + InlineAsm *ia = (InlineAsm *) stmt->expr; + IAOperand *op; + SInt32 i; + + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + if (op->type == IAOpnd_LabDiff) + return op->u.labdiff.label2; + } + + return NULL; +} + +Object *InlineAsm_GetObjectOffset(InlineAsm *ia, SInt32 index, SInt32 *offset) { + IAOperand *op; + SInt32 i; + SInt32 counter; + + for (i = 0, counter = 0, op = ia->args; i < ia->argcount; i++, op++) { + if (op->type == IAOpnd_3) { + if (counter++ == index) { + *offset = ((SInt32) &op->u.obj.obj) - ((SInt32) ia); + return op->u.obj.obj; + } + } + } + + return NULL; +} + +char *InlineAsm_DumpStatement(Statement *stmt) { + static char buffer[1024]; + InlineAsm *ia; + IAOperand *arg; + int i; + char ch; + SInt32 offset; + + ia = (InlineAsm *) stmt->expr; + + strcpy(buffer, "\""); + strcat(buffer, InlineAsm_GetMnemonic(ia)); + strcat(buffer, "\""); + + for (i = 0, arg = ia->args; i < ia->argcount; i++, arg++) { + char argbuf[1024]; + + switch (arg->type) { + case IAOpnd_Imm: + sprintf(argbuf, " imm(%ld)", arg->u.imm.value); + break; + case IAOpnd_Reg: + ch = ' '; + if (arg->u.reg.effect & EffectWrite) { + if (arg->u.reg.effect & EffectRead) + ch = '+'; + else + ch = '='; + } else { + if (!(arg->u.reg.effect & EffectRead)) + ch = '0'; + } + + if (arg->u.reg.object) { + sprintf(argbuf, + "%creg(%s)", + ch, + arg->u.reg.object->name->name); + } else { + sprintf(argbuf, + "%creg(%s%d)", + ch, + register_class_name[arg->u.reg.rclass], + arg->u.reg.num); + } + break; + + case IAOpnd_3: + case IAOpnd_4: + if (arg->u.obj.offset > 0) + sprintf(argbuf, " obj(%s+%ld)", arg->u.obj.obj->name->name, arg->u.obj.offset); + else if (arg->u.obj.offset < 0) + sprintf(argbuf, " obj(%s-%ld)", arg->u.obj.obj->name->name, -arg->u.obj.offset); + else + sprintf(argbuf, " obj(%s)", arg->u.obj.obj->name->name); + break; + + case IAOpnd_Lab: + sprintf(argbuf, " lab(%s)", arg->u.lab.label->uniquename->name); + break; + + case IAOpnd_LabDiff: + offset = !arg->negated ? 0 : arg->u.labdiff.offset; + sprintf(argbuf, + " labdiff(%s-%s%c%d)", + arg->u.labdiff.label1->uniquename->name, + arg->u.labdiff.label2->uniquename->name, + (arg->negated == 1) ? '-' : '+', + offset + ); + break; + } + + strcat(buffer, argbuf); + } + + return buffer; +} diff --git a/compiler_and_linker/unsorted/InlineAsmMnemonicsPPC.c b/compiler_and_linker/unsorted/InlineAsmMnemonicsPPC.c new file mode 100644 index 0000000..07d7d2c --- /dev/null +++ b/compiler_and_linker/unsorted/InlineAsmMnemonicsPPC.c @@ -0,0 +1,1036 @@ +#include "compiler/InlineAsmMnemonicsPPC.h" +#include "compiler/InlineAsm.h" +#include "compiler/CompilerTools.h" + +static IAMnemonic mnemonics[] = { + "abs", 0x000001A7, "=r,r", 0x00000001, 0x7C0002D0, + "abs.", 0x000001A7, "=r,r;=Z", 0x00000001, 0x7C0002D1, + "abso", 0x000001A7, "=r,r;+X", 0x00000001, 0x7C0006D0, + "abso.", 0x000001A7, "=r,r;+X=Z", 0x00000001, 0x7C0006D1, + "add", 0x0000003C, "=r,r,r", 0x000FFFFF, 0x7C000214, + "add.", 0x0000003C, "=r,r,r;=Z", 0x000FFFFF, 0x7C000215, + "addo", 0x0000003C, "=r,r,r;+X", 0x000FFFFF, 0x7C000614, + "addo.", 0x0000003C, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C000615, + "addc", 0x0000003D, "=r,r,r;+X", 0x000FFFFF, 0x7C000014, + "addc.", 0x0000003D, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C000015, + "addco", 0x0000003D, "=r,r,r;+X", 0x000FFFFF, 0x7C000414, + "addco.", 0x0000003D, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C000415, + "adde", 0x0000003E, "=r,r,r;+X", 0x000FFFFF, 0x7C000114, + "adde.", 0x0000003E, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C000115, + "addeo", 0x0000003E, "=r,r,r;+X", 0x000FFFFF, 0x7C000514, + "addeo.", 0x0000003E, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C000515, + "addi", 0x0000003F, "=r,b,m;p", 0x000FFFFF, 0x38000000, + "addic", 0x00000040, "=r,r,i;+X", 0x000FFFFF, 0x30000000, + "addic.", 0x00000041, "=r,r,i;+X=Z", 0x000FFFFF, 0x34000000, + "addis", 0x00000042, "=r,b,M", 0x000FFFFF, 0x3C000000, + "addme", 0x00000043, "=r,r;+X", 0x000FFFFF, 0x7C0001D4, + "addme.", 0x00000043, "=r,r;+X=Z", 0x000FFFFF, 0x7C0001D5, + "addmeo", 0x00000043, "=r,r;+X", 0x000FFFFF, 0x7C0005D4, + "addmeo.", 0x00000043, "=r,r;+X=Z", 0x000FFFFF, 0x7C0005D5, + "addze", 0x00000044, "=r,r;+X", 0x000FFFFF, 0x7C000194, + "addze.", 0x00000044, "=r,r;+X=Z", 0x000FFFFF, 0x7C000195, + "addzeo", 0x00000044, "=r,r;+X", 0x000FFFFF, 0x7C000594, + "addzeo.", 0x00000044, "=r,r;+X=Z", 0x000FFFFF, 0x7C000595, + "and", 0x0000005C, "=r,r,r", 0x000FFFFF, 0x7C000038, + "and.", 0x0000005C, "=r,r,r;=Z", 0x000FFFFF, 0x7C000039, + "andc", 0x00000062, "=r,r,r", 0x000FFFFF, 0x7C000078, + "andc.", 0x00000062, "=r,r,r;=Z", 0x000FFFFF, 0x7C000079, + "andi.", 0x00000056, "=r,r,x;=Z", 0x000FFFFF, 0x70000000, + "andis.", 0x00000057, "=r,r,x;=Z", 0x000FFFFF, 0x74000000, + "b", 0x00000000, "l;p", 0x000FFFFF, 0x48000000, + "ba", 0x00000000, "l;p", 0x000FFFFF, 0x48000002, + "bc", 0x00000002, "B,Q,l;p", 0x000FFFFF, 0x40000000, + "bca", 0x00000002, "B,Q,l;p", 0x000FFFFF, 0x40000002, + "bcla", 0x00000002, "B,Q,l;=L", 0x000FFFFF, 0x40000003, + "bcctr", 0x00000004, "B,Q;Cp", 0x000FFFFF, 0x4C000420, + "bcctrl", 0x00000004, "B,Q;C=L", 0x000FFFFF, 0x4C000421, + "bcl", 0x00000002, "B,Q,l;=L", 0x000FFFFF, 0x40000001, + "bclr", 0x00000003, "B,Q;L", 0x000FFFFF, 0x4C000020, + "bclrl", 0x00000003, "B,Q;+L", 0x000FFFFF, 0x4C000021, + "bl", 0x00000001, "l;=L", 0x000FFFFF, 0x48000001, + "bla", 0x00000001, "l;=L", 0x000FFFFF, 0x48000003, + "clcs", 0x000001A8, "=r,r", 0x00000001, 0x7C000426, + "cmp", 0x00000053, "=?c,Or,r", 0x000FFFFF, 0x7C000000, + "cmpi", 0x00000052, "=?c,Or,i", 0x000FFFFF, 0x2C000000, + "cmpl", 0x00000055, "=?c,Or,r", 0x000FFFFF, 0x7C000040, + "cmpli", 0x00000054, "=?c,Or,u", 0x000FFFFF, 0x28000000, + "cntlzw", 0x00000066, "=r,r", 0x000FFFFF, 0x7C000034, + "cntlzw.", 0x00000066, "=r,r;=Z", 0x000FFFFF, 0x7C000035, + "crand", 0x0000006E, "=Q,Q,Q", 0x000FFFFF, 0x4C000202, + "crandc", 0x0000006F, "=Q,Q,Q", 0x000FFFFF, 0x4C000102, + "creqv", 0x00000070, "=Q,Q,Q", 0x000FFFFF, 0x4C000242, + "crnand", 0x00000071, "=Q,Q,Q", 0x000FFFFF, 0x4C0001C2, + "crnor", 0x00000072, "=Q,Q,Q", 0x000FFFFF, 0x4C000042, + "cror", 0x00000073, "=Q,Q,Q", 0x000FFFFF, 0x4C000382, + "crorc", 0x00000074, "=Q,Q,Q", 0x000FFFFF, 0x4C000342, + "crxor", 0x00000075, "=Q,Q,Q", 0x000FFFFF, 0x4C000182, + "dcbf", 0x00000037, "b,r", 0x080FFFFF, 0x7C0000AC, + "dcbst", 0x00000038, "b,r", 0x080FFFFF, 0x7C00006C, + "dcbt", 0x00000039, "b,r", 0x080FFFFF, 0x7C00022C, + "dcbtst", 0x0000003A, "b,r", 0x080FFFFF, 0x7C0001EC, + "dcba", 0x000000EB, "b,r", 0x00004000, 0x7C0005EC, + "dcbz", 0x0000003B, "b,r", 0x080FFFFF, 0x7C0007EC, + "dccci", 0x000000DE, "b,r", 0x000007C0, 0x7C00038C, + "dcread", 0x000000DF, "=r,(b,r)", 0x000007C0, 0x7C0003CC, + "dcbi", 0x000000C3, "b,r", 0x080FFFFF, 0x7C0003AC, + "icbi", 0x000000C4, "b,r", 0x000FEFFF, 0x7C0007AC, + "icbt", 0x000000E0, "b,r", 0x000007C0, 0x7C00020C, + "iccci", 0x000000E1, "b,r", 0x000007C0, 0x7C00078C, + "icread", 0x000000E2, "b,r", 0x000007C0, 0x7C0007CC, + "div", 0x000001A2, "=r,r,r", 0x00000001, 0x7C000296, + "div.", 0x000001A2, "=r,r,r;=Z", 0x00000001, 0x7C000297, + "divo", 0x000001A2, "=r,r,r;+X", 0x00000001, 0x7C000696, + "divo.", 0x000001A2, "=r,r,r;+X=Z", 0x00000001, 0x7C000697, + "divs", 0x000001A3, "=r,r,r", 0x00000001, 0x7C0002D6, + "divs.", 0x000001A3, "=r,r,r;=Z", 0x00000001, 0x7C0002D7, + "divso", 0x000001A3, "=r,r,r;+X", 0x00000001, 0x7C0006D6, + "divso.", 0x000001A3, "=r,r,r;+X=Z", 0x00000001, 0x7C0006D7, + "divw", 0x00000045, "=r,r,r", 0x000FFFFF, 0x7C0003D6, + "divw.", 0x00000045, "=r,r,r;=Z", 0x000FFFFF, 0x7C0003D7, + "divwo", 0x00000045, "=r,r,r;+X", 0x000FFFFF, 0x7C0007D6, + "divwo.", 0x00000045, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C0007D7, + "divwu", 0x00000046, "=r,r,r", 0x000FFFFF, 0x7C000396, + "divwu.", 0x00000046, "=r,r,r;=Z", 0x000FFFFF, 0x7C000397, + "divwuo", 0x00000046, "=r,r,r;+X", 0x000FFFFF, 0x7C000796, + "divwuo.", 0x00000046, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C000797, + "doz", 0x000001A4, "=r,r,r", 0x00000001, 0x7C000210, + "doz.", 0x000001A4, "=r,r,r;=Z", 0x00000001, 0x7C000211, + "dozo", 0x000001A4, "=r,r,r;+X", 0x00000001, 0x7C000610, + "dozo.", 0x000001A4, "=r,r,r;+X=Z", 0x00000001, 0x7C000611, + "dozi", 0x000001A9, "=r,r,x", 0x00000001, 0x24000000, + "dsa", 0x000000DC, "", 0x00000002, 0x7C0004E8, + "esa", 0x000000DD, "", 0x00000002, 0x7C0004A8, + "eciwx", 0x000000C1, "=r,(b,r)", 0x020FFFFF, 0x7C00026C, + "ecowx", 0x000000C2, "r,(b,r)", 0x020FFFFF, 0x7C00036C, + "eieio", 0x00000085, "", 0x000FFFFF, 0x7C0006AC, + "eqv", 0x00000061, "=r,r,r", 0x000FFFFF, 0x7C000238, + "eqv.", 0x00000061, "=r,r,r;=Z", 0x000FFFFF, 0x7C000239, + "extsb", 0x00000064, "=r,r", 0x000FFFFF, 0x7C000774, + "extsb.", 0x00000064, "=r,r;=Z", 0x000FFFFF, 0x7C000775, + "extsh", 0x00000065, "=r,r", 0x000FFFFF, 0x7C000734, + "extsh.", 0x00000065, "=r,r;=Z", 0x000FFFFF, 0x7C000735, + "fabs", 0x0000009F, "=f,f", 0x800FFFFF, 0xFC000210, + "fabs.", 0x0000009F, "=f,f;=Z", 0x800FFFFF, 0xFC000211, + "fadd", 0x000000A2, "=f,f,f", 0x800FFFFF, 0xFC00002A, + "fadd.", 0x000000A2, "=f,f,f;=Z", 0x800FFFFF, 0xFC00002B, + "fadds", 0x000000A3, "=f,f,f", 0x800FFFFF, 0xEC00002A, + "fadds.", 0x000000A3, "=f,f,f;=Z", 0x800FFFFF, 0xEC00002B, + "fcmpo", 0x000000B9, "=?c,f,f", 0x800FFFFF, 0xFC000040, + "fcmpu", 0x000000B8, "=?c,f,f", 0x800FFFFF, 0xFC000000, + "fctiw", 0x000000B6, "=f,f", 0x800FFFFF, 0xFC00001C, + "fctiw.", 0x000000B6, "=f,f;=Z", 0x800FFFFF, 0xFC00001D, + "fctiwz", 0x000000B7, "=f,f", 0x800FFFFF, 0xFC00001E, + "fctiwz.", 0x000000B7, "=f,f;=Z", 0x800FFFFF, 0xFC00001F, + "fdiv", 0x000000A8, "=f,f,f", 0x800FFFFF, 0xFC000024, + "fdiv.", 0x000000A8, "=f,f,f;=Z", 0x800FFFFF, 0xFC000025, + "fdivs", 0x000000A9, "=f,f,f", 0x800FFFFF, 0xEC000024, + "fdivs.", 0x000000A9, "=f,f,f;=Z", 0x800FFFFF, 0xEC000025, + "fmadd", 0x000000AA, "=f,f,f,f", 0x800FFFFF, 0xFC00003A, + "fmadd.", 0x000000AA, "=f,f,f,f;=Z", 0x800FFFFF, 0xFC00003B, + "fmadds", 0x000000AB, "=f,f,f,f", 0x800FFFFF, 0xEC00003A, + "fmadds.", 0x000000AB, "=f,f,f,f;=Z", 0x800FFFFF, 0xEC00003B, + "fmr", 0x0000009E, "=f,f", 0x800FFFFF, 0xFC000090, + "fmr.", 0x0000009E, "=f,f;=Z", 0x800FFFFF, 0xFC000091, + "fmsub", 0x000000AC, "=f,f,f,f", 0x800FFFFF, 0xFC000038, + "fmsub.", 0x000000AC, "=f,f,f,f;=Z", 0x800FFFFF, 0xFC000039, + "fmsubs", 0x000000AD, "=f,f,f,f", 0x800FFFFF, 0xEC000038, + "fmsubs.", 0x000000AD, "=f,f,f,f;=Z", 0x800FFFFF, 0xEC000039, + "fmul", 0x000000A6, "=f,f,f", 0x800FFFFF, 0xFC000032, + "fmul.", 0x000000A6, "=f,f,f;=Z", 0x800FFFFF, 0xFC000033, + "fmuls", 0x000000A7, "=f,f,f", 0x800FFFFF, 0xEC000032, + "fmuls.", 0x000000A7, "=f,f,f;=Z", 0x800FFFFF, 0xEC000033, + "fnabs", 0x000000A1, "=f,f", 0x800FFFFF, 0xFC000110, + "fnabs.", 0x000000A1, "=f,f;=Z", 0x800FFFFF, 0xFC000111, + "fneg", 0x000000A0, "=f,f", 0x800FFFFF, 0xFC000050, + "fneg.", 0x000000A0, "=f,f;=Z", 0x800FFFFF, 0xFC000051, + "fnmadd", 0x000000AE, "=f,f,f,f", 0x800FFFFF, 0xFC00003E, + "fnmadd.", 0x000000AE, "=f,f,f,f;=Z", 0x800FFFFF, 0xFC00003F, + "fnmadds", 0x000000AF, "=f,f,f,f", 0x800FFFFF, 0xEC00003E, + "fnmadds.", 0x000000AF, "=f,f,f,f;=Z", 0x800FFFFF, 0xEC00003F, + "fnmsub", 0x000000B0, "=f,f,f,f", 0x800FFFFF, 0xFC00003C, + "fnmsub.", 0x000000B0, "=f,f,f,f;=Z", 0x800FFFFF, 0xFC00003D, + "fnmsubs", 0x000000B1, "=f,f,f,f", 0x800FFFFF, 0xEC00003C, + "fnmsubs.", 0x000000B1, "=f,f,f,f;=Z", 0x800FFFFF, 0xEC00003D, + "fres", 0x000000B2, "=f,f", 0x808FFFFF, 0xEC000030, + "fres.", 0x000000B2, "=f,f;=Z", 0x808FFFFF, 0xEC000031, + "frsp", 0x000000B5, "=f,f", 0x800FFFFF, 0xFC000018, + "frsp.", 0x000000B5, "=f,f;=Z", 0x800FFFFF, 0xFC000019, + "frsqrte", 0x000000B3, "=f,f", 0x808FFFFF, 0xFC000034, + "frsqrte.", 0x000000B3, "=f,f;=Z", 0x808FFFFF, 0xFC000035, + "fsel", 0x000000B4, "=f,f,f,f", 0x808FFFFF, 0xFC00002E, + "fsel.", 0x000000B4, "=f,f,f,f;=Z", 0x808FFFFF, 0xFC00002F, + "fsqrt", 0x000000D0, "=f,f", 0x80000000, 0xFC00002C, + "fsqrt.", 0x000000D0, "=f,f;=Z", 0x80000000, 0xFC00002D, + "fsqrts", 0x000000D1, "=f,f", 0x80000000, 0xEC00002C, + "fsqrts.", 0x000000D1, "=f,f;=Z", 0x80000000, 0xEC00002D, + "fsub", 0x000000A4, "=f,f,f", 0x800FFFFF, 0xFC000028, + "fsub.", 0x000000A4, "=f,f,f;=Z", 0x800FFFFF, 0xFC000029, + "fsubs", 0x000000A5, "=f,f,f", 0x800FFFFF, 0xEC000028, + "fsubs.", 0x000000A5, "=f,f,f;=Z", 0x800FFFFF, 0xEC000029, + "isync", 0x00000086, "", 0x000FFFFF, 0x4C00012C, + "lbz", 0x00000015, "=r,d(b)", 0x000FFFFF, 0x88000000, + "lbzu", 0x00000016, "=r,d(+b)", 0x000FFFFF, 0x8C000000, + "lbzx", 0x00000017, "=r,(b,r)", 0x000FFFFF, 0x7C0000AE, + "lbzux", 0x00000018, "=r,(+b,r)", 0x000FFFFF, 0x7C0000EE, + "lfd", 0x00000092, "=f,d(b)", 0x800FFFFF, 0xC8000000, + "lfdu", 0x00000093, "=f,d(+b)", 0x800FFFFF, 0xCC000000, + "lfdx", 0x00000094, "=f,(b,r)", 0x800FFFFF, 0x7C0004AE, + "lfdux", 0x00000095, "=f,(+b,r)", 0x800FFFFF, 0x7C0004EE, + "lfs", 0x0000008E, "=f,d(b)", 0x800FFFFF, 0xC0000000, + "lfsu", 0x0000008F, "=f,d(+b)", 0x800FFFFF, 0xC4000000, + "lfsx", 0x00000090, "=f,(b,r)", 0x800FFFFF, 0x7C00042E, + "lfsux", 0x00000091, "=f,(+b,r)", 0x800FFFFF, 0x7C00046E, + "lha", 0x0000001D, "=r,d(b)", 0x000FFFFF, 0xA8000000, + "lhau", 0x0000001E, "=r,d(+b)", 0x000FFFFF, 0xAC000000, + "lhaux", 0x00000020, "=r,(+b,r)", 0x000FFFFF, 0x7C0002EE, + "lhax", 0x0000001F, "=r,(b,r)", 0x000FFFFF, 0x7C0002AE, + "lhbrx", 0x00000021, "=r,(b,r)", 0x000FFFFF, 0x7C00062C, + "lhz", 0x00000019, "=r,d(b)", 0x000FFFFF, 0xA0000000, + "lhzu", 0x0000001A, "=r,d(+b)", 0x000FFFFF, 0xA4000000, + "lhzux", 0x0000001C, "=r,(+b,r)", 0x000FFFFF, 0x7C00026E, + "lhzx", 0x0000001B, "=r,(b,r)", 0x000FFFFF, 0x7C00022E, + "lmw", 0x00000027, "=r,d(b)", 0x000FFFFF, 0xB8000000, + "lscbx", 0x000001A1, "=r,(b,r)", 0x00000001, 0x7C00022A, + "lscbx.", 0x000001A1, "=r,(b,r);=Z", 0x00000001, 0x7C00022B, + "lswi", 0x000000BB, "=r,b,N", 0x000FFFFF, 0x7C0004AA, + "lswx", 0x000000BC, "=r,(b,r)", 0x000FFFFF, 0x7C00042A, + "lwarx", 0x000000BA, "=r,(b,r)", 0x000FFFFF, 0x7C000028, + "lwbrx", 0x00000026, "=r,(b,r)", 0x000FFFFF, 0x7C00042C, + "lwz", 0x00000022, "=r,d(b)", 0x000FFFFF, 0x80000000, + "lwzu", 0x00000023, "=r,d(+b)", 0x000FFFFF, 0x84000000, + "lwzux", 0x00000025, "=r,(+b,r)", 0x000FFFFF, 0x7C00006E, + "lwzx", 0x00000024, "=r,(b,r)", 0x000FFFFF, 0x7C00002E, + "maskg", 0x0000019F, "=r,r,r", 0x00000001, 0x7C00003A, + "maskg.", 0x0000019F, "=r,r,r;=Z", 0x00000001, 0x7C00003B, + "maskir", 0x000001A0, "=r,r,r", 0x00000001, 0x7C00043A, + "maskir.", 0x000001A0, "=r,r,r;=Z", 0x00000001, 0x7C00043B, + "mcrf", 0x00000076, "=c,c", 0x000FFFFF, 0x4C000000, + "mcrfs", 0x000000C5, "=c,x3", 0x800FFFFF, 0xFC000080, + "mcrxr", 0x000000C6, "=c;+X", 0x000FFFFF, 0x7C000400, + "mfcr", 0x00000082, "=r;Y", 0x000FFFFF, 0x7C000026, + "mfdcr", 0x000000E9, "=r,D", 0x000007C0, 0x7C000286, + "mffs", 0x00000083, "=f", 0x800FFFFF, 0xFC00048E, + "mffs.", 0x00000083, "=f;=Z", 0x800FFFFF, 0xFC00048F, + "mfmsr", 0x0000007D, "=r", 0x000FFFFF, 0x7C0000A6, + "mfrom", 0x000000DB, "=r,r", 0x00000002, 0x7C000212, + "mfspr", 0x0000007E, "=r,s", 0x000FFFFF, 0x7C0002A6, + "mfsr", 0x000000C8, "=r,u4", 0x010FFFFF, 0x7C0004A6, + "mfsrin", 0x000000CA, "=r,r", 0x010FFFFF, 0x7C000526, + "mtcrf", 0x0000007A, "x8,r;=Y", 0x000FFFFF, 0x7C000120, + "mtdcr", 0x000000EA, "D,r", 0x000007C0, 0x7C000386, + "mtfsb0", 0x000000CC, "u5", 0x000FFFFF, 0xFC00008C, + "mtfsb0.", 0x000000CC, "u5;=Z", 0x000FFFFF, 0xFC00008D, + "mtfsb1", 0x000000CD, "u5", 0x000FFFFF, 0xFC00004C, + "mtfsb1.", 0x000000CD, "u5;=Z", 0x000FFFFF, 0xFC00004D, + "mtfsf", 0x00000084, "x8,f", 0x800FFFFF, 0xFC00058E, + "mtfsf.", 0x00000084, "x8,f;=Z", 0x800FFFFF, 0xFC00058F, + "mtfsfi", 0x000000CE, "c,x4", 0x000FFFFF, 0xFC00010C, + "mtfsfi.", 0x000000CE, "c,x4;=Z", 0x000FFFFF, 0xFC00010D, + "mtmsr", 0x0000007B, "r", 0x000FFFFF, 0x7C000124, + "mtspr", 0x0000007C, "=s,r", 0x000FFFFF, 0x7C0003A6, + "mtsr", 0x000000C9, "u4,r", 0x010FFFFF, 0x7C0001A4, + "mtsrin", 0x000000CB, "r,r", 0x010FFFFF, 0x7C0001E4, + "mul", 0x000001A5, "=r,r,r", 0x00000001, 0x7C0000D6, + "mul.", 0x000001A5, "=r,r,r;=Z", 0x00000001, 0x7C0000D7, + "mulo", 0x000001A5, "=r,r,r;+X", 0x00000001, 0x7C0004D6, + "mulo.", 0x000001A5, "=r,r,r;+X=Z", 0x00000001, 0x7C0004D7, + "mulhw", 0x00000047, "=r,r,r", 0x000FFFFF, 0x7C000096, + "mulhw.", 0x00000047, "=r,r,r;=Z", 0x000FFFFF, 0x7C000097, + "mulhwu", 0x00000048, "=r,r,r", 0x000FFFFF, 0x7C000016, + "mulhwu.", 0x00000048, "=r,r,r;=Z", 0x000FFFFF, 0x7C000017, + "mulli", 0x00000049, "=r,r,i", 0x000FFFFF, 0x1C000000, + "mullw", 0x0000004A, "=r,r,r", 0x000FFFFF, 0x7C0001D6, + "mullw.", 0x0000004A, "=r,r,r;=Z", 0x000FFFFF, 0x7C0001D7, + "mullwo", 0x0000004A, "=r,r,r;+X", 0x000FFFFF, 0x7C0005D6, + "mullwo.", 0x0000004A, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C0005D7, + "nabs", 0x000001A6, "=r,r", 0x00000001, 0x7C0003D0, + "nabs.", 0x000001A6, "=r,r;=Z", 0x00000001, 0x7C0003D1, + "nabso", 0x000001A6, "=r,r;+X", 0x00000001, 0x7C0007D0, + "nabso.", 0x000001A6, "=r,r;+X=Z", 0x00000001, 0x7C0007D1, + "nand", 0x0000005F, "=r,r,r", 0x000FFFFF, 0x7C0003B8, + "nand.", 0x0000005F, "=r,r,r;=Z", 0x000FFFFF, 0x7C0003B9, + "neg", 0x0000004B, "=r,r", 0x000FFFFF, 0x7C0000D0, + "neg.", 0x0000004B, "=r,r;=Z", 0x000FFFFF, 0x7C0000D1, + "nego", 0x0000004B, "=r,r;+X", 0x000FFFFF, 0x7C0004D0, + "nego.", 0x0000004B, "=r,r;+X=Z", 0x000FFFFF, 0x7C0004D1, + "nor", 0x00000060, "=r,r,r", 0x000FFFFF, 0x7C0000F8, + "nor.", 0x00000060, "=r,r,r;=Z", 0x000FFFFF, 0x7C0000F9, + "or", 0x0000005D, "=r,r,r;pp", 0x000FFFFF, 0x7C000378, + "or.", 0x0000005D, "=r,r,r;pp=Z", 0x000FFFFF, 0x7C000379, + "orc", 0x00000063, "=r,r,r", 0x000FFFFF, 0x7C000338, + "orc.", 0x00000063, "=r,r,r;=Z", 0x000FFFFF, 0x7C000339, + "ori", 0x00000058, "=r,r,m", 0x000FFFFF, 0x60000000, + "oris", 0x00000059, "=r,r,M", 0x000FFFFF, 0x64000000, + "rfci", 0x000000E3, "", 0x000007C0, 0x4C000066, + "rfi", 0x00000088, "", 0x000FFFFF, 0x4C000064, + "rlmi", 0x000001AA, "+r,r,r,u5,u5", 0x00000001, 0x58000000, + "rlmi.", 0x000001AA, "+r,r,r,u5,u5;=Z", 0x00000001, 0x58000001, + "rlwimi", 0x00000069, "+r,r,u5,u5,u5", 0x000FFFFF, 0x50000000, + "rlwimi.", 0x00000069, "+r,r,u5,u5,u5;=Z", 0x000FFFFF, 0x50000001, + "rlwinm", 0x00000067, "=r,r,u5,u5,u5", 0x000FFFFF, 0x54000000, + "rlwinm.", 0x00000067, "=r,r,u5,u5,u5;=Z", 0x000FFFFF, 0x54000001, + "rlwnm", 0x00000068, "=r,r,r,u5,u5", 0x000FFFFF, 0x5C000000, + "rlwnm.", 0x00000068, "=r,r,r,u5,u5;=Z", 0x000FFFFF, 0x5C000001, + "rrib", 0x000001AB, "=r,r,r", 0x00000001, 0x7C000432, + "rrib.", 0x000001AB, "=r,r,r;=Z", 0x00000001, 0x7C000433, + "sc", 0x000000CF, "", 0x000FFFFF, 0x44000002, + "sle", 0x00000190, "=r,r,r", 0x00000001, 0x7C000132, + "sle.", 0x00000190, "=r,r,r;=Z", 0x00000001, 0x7C000133, + "sleq", 0x00000191, "=r,r,r", 0x00000001, 0x7C0001B2, + "sleq.", 0x00000191, "=r,r,r;=Z", 0x00000001, 0x7C0001B3, + "sliq", 0x00000192, "=r,r,u5", 0x00000001, 0x7C000170, + "sliq.", 0x00000192, "=r,r,u5;=Z", 0x00000001, 0x7C000171, + "slliq", 0x00000193, "=r,r,u5", 0x00000001, 0x7C0001F0, + "slliq.", 0x00000193, "=r,r,u5;=Z", 0x00000001, 0x7C0001F1, + "sllq", 0x00000194, "=r,r,r", 0x00000001, 0x7C0001B0, + "sllq.", 0x00000194, "=r,r,r;=Z", 0x00000001, 0x7C0001B1, + "slq", 0x00000195, "=r,r,r", 0x00000001, 0x7C000130, + "slq.", 0x00000195, "=r,r,r;=Z", 0x00000001, 0x7C000131, + "slw", 0x0000006A, "=r,r,r", 0x000FFFFF, 0x7C000030, + "slw.", 0x0000006A, "=r,r,r;=Z", 0x000FFFFF, 0x7C000031, + "sraiq", 0x00000196, "=r,r,u5", 0x00000001, 0x7C000770, + "sraiq.", 0x00000196, "=r,r,u5;=Z", 0x00000001, 0x7C000771, + "sraq", 0x00000197, "=r,r,r", 0x00000001, 0x7C000730, + "sraq.", 0x00000197, "=r,r,r;=Z", 0x00000001, 0x7C000731, + "sraw", 0x0000006D, "=r,r,r;+X", 0x000FFFFF, 0x7C000630, + "sraw.", 0x0000006D, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C000631, + "srawi", 0x0000006C, "=r,r,u5;+X", 0x000FFFFF, 0x7C000670, + "srawi.", 0x0000006C, "=r,r,u5;+X=Z", 0x000FFFFF, 0x7C000671, + "sre", 0x00000198, "=r,r,r", 0x00000001, 0x7C000532, + "sre.", 0x00000198, "=r,r,r;=Z", 0x00000001, 0x7C000533, + "srea", 0x00000199, "=r,r,r", 0x00000001, 0x7C000732, + "srea.", 0x00000199, "=r,r,r;=Z", 0x00000001, 0x7C000733, + "sreq", 0x0000019A, "=r,r,r", 0x00000001, 0x7C0005B2, + "sreq.", 0x0000019A, "=r,r,r;=Z", 0x00000001, 0x7C0005B3, + "sriq", 0x0000019B, "=r,r,u5", 0x00000001, 0x7C000570, + "sriq.", 0x0000019B, "=r,r,u5;=Z", 0x00000001, 0x7C000571, + "srliq", 0x0000019C, "=r,r,u5", 0x00000001, 0x7C0005F0, + "srliq.", 0x0000019C, "=r,r,u5;=Z", 0x00000001, 0x7C0005F1, + "srlq", 0x0000019D, "=r,r,r", 0x00000001, 0x7C0005B0, + "srlq.", 0x0000019D, "=r,r,r;=Z", 0x00000001, 0x7C0005B1, + "srq", 0x0000019E, "=r,r,r", 0x00000001, 0x7C000530, + "srq.", 0x0000019E, "=r,r,r;=Z", 0x00000001, 0x7C000531, + "srw", 0x0000006B, "=r,r,r", 0x000FFFFF, 0x7C000430, + "srw.", 0x0000006B, "=r,r,r;=Z", 0x000FFFFF, 0x7C000431, + "stb", 0x00000028, "r,d(b)", 0x000FFFFF, 0x98000000, + "stbu", 0x00000029, "r,d(+b)", 0x000FFFFF, 0x9C000000, + "stbux", 0x0000002B, "r,(+b,r)", 0x000FFFFF, 0x7C0001EE, + "stbx", 0x0000002A, "r,(b,r)", 0x000FFFFF, 0x7C0001AE, + "stfd", 0x0000009A, "f,d(b)", 0x800FFFFF, 0xD8000000, + "stfdu", 0x0000009B, "f,d(+b)", 0x800FFFFF, 0xDC000000, + "stfdux", 0x0000009D, "f,(+b,r)", 0x800FFFFF, 0x7C0005EE, + "stfdx", 0x0000009C, "f,(b,r)", 0x800FFFFF, 0x7C0005AE, + "stfiwx", 0x000000BD, "f,(b,r)", 0x800FFFFE, 0x7C0007AE, + "stfs", 0x00000096, "f,d(b)", 0x800FFFFF, 0xD0000000, + "stfsu", 0x00000097, "f,d(+b)", 0x800FFFFF, 0xD4000000, + "stfsux", 0x00000099, "f,(+b,r)", 0x800FFFFF, 0x7C00056E, + "stfsx", 0x00000098, "f,(b,r)", 0x800FFFFF, 0x7C00052E, + "sth", 0x0000002C, "r,d(b)", 0x000FFFFF, 0xB0000000, + "sthbrx", 0x00000030, "r,(b,r)", 0x000FFFFF, 0x7C00072C, + "sthu", 0x0000002D, "r,d(+b)", 0x000FFFFF, 0xB4000000, + "sthux", 0x0000002F, "r,(+b,r)", 0x000FFFFF, 0x7C00036E, + "sthx", 0x0000002E, "r,(b,r)", 0x000FFFFF, 0x7C00032E, + "stmw", 0x00000036, "r,d(b)", 0x000FFFFF, 0xBC000000, + "stswi", 0x000000BE, "r,b,N", 0x000FFFFF, 0x7C0005AA, + "stswx", 0x000000BF, "r,(b,r)", 0x000FFFFF, 0x7C00052A, + "stw", 0x00000031, "r,d(b)", 0x000FFFFF, 0x90000000, + "stwbrx", 0x00000035, "r,(b,r)", 0x000FFFFF, 0x7C00052C, + "stwcx.", 0x000000C0, "r,(b,r);=Z", 0x000FFFFF, 0x7C00012D, + "stwu", 0x00000032, "r,d(+b)", 0x000FFFFF, 0x94000000, + "stwux", 0x00000034, "r,(+b,r)", 0x000FFFFF, 0x7C00016E, + "stwx", 0x00000033, "r,(b,r)", 0x000FFFFF, 0x7C00012E, + "subf", 0x0000004C, "=r,r,r", 0x000FFFFF, 0x7C000050, + "subf.", 0x0000004C, "=r,r,r;=Z", 0x000FFFFF, 0x7C000051, + "subfo", 0x0000004C, "=r,r,r;+X", 0x000FFFFF, 0x7C000450, + "subfo.", 0x0000004C, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C000451, + "subfc", 0x0000004D, "=r,r,r;+X", 0x000FFFFF, 0x7C000010, + "subfc.", 0x0000004D, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C000011, + "subfco", 0x0000004D, "=r,r,r;+X", 0x000FFFFF, 0x7C000410, + "subfco.", 0x0000004D, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C000411, + "subfe", 0x0000004E, "=r,r,r;+X", 0x000FFFFF, 0x7C000110, + "subfe.", 0x0000004E, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C000111, + "subfeo", 0x0000004E, "=r,r,r;+X", 0x000FFFFF, 0x7C000510, + "subfeo.", 0x0000004E, "=r,r,r;+X=Z", 0x000FFFFF, 0x7C000511, + "subfic", 0x0000004F, "=r,r,i;+X", 0x000FFFFF, 0x20000000, + "subfme", 0x00000050, "=r,r;+X", 0x000FFFFF, 0x7C0001D0, + "subfme.", 0x00000050, "=r,r;+X=Z", 0x000FFFFF, 0x7C0001D1, + "subfmeo", 0x00000050, "=r,r;+X", 0x000FFFFF, 0x7C0005D0, + "subfmeo.", 0x00000050, "=r,r;+X=Z", 0x000FFFFF, 0x7C0005D1, + "subfze", 0x00000051, "=r,r;+X", 0x000FFFFF, 0x7C000190, + "subfze.", 0x00000051, "=r,r;+X=Z", 0x000FFFFF, 0x7C000191, + "subfzeo", 0x00000051, "=r,r;+X", 0x000FFFFF, 0x7C000590, + "subfzeo.", 0x00000051, "=r,r;+X=Z", 0x000FFFFF, 0x7C000591, + "sync", 0x00000087, "", 0x000FFFFF, 0x7C0004AC, + "tlbia", 0x000000D2, "", 0x00000230, 0x7C0002E4, + "tlbie", 0x000000D3, "r", 0x040FFFFF, 0x7C000264, + "tlbld", 0x000000D4, "r", 0x00010006, 0x7C0007A4, + "tlbli", 0x000000D5, "r", 0x00010006, 0x7C0007E4, + "tlbsync", 0x000000D6, "", 0x040FFFFE, 0x7C00046C, + "tlbre", 0x000000E4, "=r,r,u1", 0x00000200, 0x7C000764, + "tlbrehi", 0x000000E4, "=r,r;%0", 0x00000200, 0x7C000764, + "tlbrelo", 0x000000E4, "=r,r;%1", 0x00000200, 0x7C000F64, + "tlbsx", 0x000000E5, "=r,(b,r)", 0x00000200, 0x7C000724, + "tlbsx.", 0x000000E5, "=r,(b,r);=Z", 0x00000200, 0x7C000725, + "tlbwe", 0x000000E6, "r,b,u1", 0x00000200, 0x7C0007A4, + "tlbwehi", 0x000000E6, "r,b;%0", 0x00000200, 0x7C0007A4, + "tlbwelo", 0x000000E6, "r,b;%1", 0x00000200, 0x7C000FA4, + "tw", 0x000000D7, "u5,r,r", 0x000FFFFF, 0x7C000008, + "twi", 0x000000D9, "u5,r,m", 0x000FFFFF, 0x0C000000, + "wrtee", 0x000000E7, "r", 0x000007C0, 0x7C000106, + "wrteei", 0x000000E8, "u1", 0x000007C0, 0x7C000146, + "xor", 0x0000005E, "=r,r,r", 0x000FFFFF, 0x7C000278, + "xor.", 0x0000005E, "=r,r,r;=Z", 0x000FFFFF, 0x7C000279, + "xori", 0x0000005A, "=r,r,x", 0x000FFFFF, 0x68000000, + "xoris", 0x0000005B, "=r,r,x", 0x000FFFFF, 0x6C000000, + "cmpw", 0x00000053, "=?c,r,r", 0x000FFFFF, 0x7C000000, + "cmpwi", 0x00000052, "=?c,r,i", 0x000FFFFF, 0x2C000000, + "cmplw", 0x00000055, "=?c,r,r", 0x000FFFFF, 0x7C000040, + "cmplwi", 0x00000054, "=?c,r,u", 0x000FFFFF, 0x28000000, + "la", 0x0000003F, "=r,d(b)", 0x000FFFFF, 0x38000000, + "las", 0x00000042, "=r,d(b)", 0x000FFFFF, 0x3C000000, + "li", 0x00000089, "=r,n", 0x000FFFFF, 0x38000000, + "lis", 0x0000008A, "=r,M", 0x000FFFFF, 0x3C000000, + "mr", 0x0000008B, "=r,r;p", 0x000FFFFF, 0x7C000378, + "mr.", 0x0000008B, "=r,r;p=Z", 0x000FFFFF, 0x7C000379, + "nop", 0x0000008C, "", 0x000FFFFF, 0x60000000, + "not", 0x0000008D, "=r,r", 0x000FFFFF, 0x7C0000F8, + "not.", 0x0000008D, "=r,r;=Z", 0x000FFFFF, 0x7C0000F9, + "sub", 0x0000004C, "=r,r,r/", 0x000FFFFF, 0x7C000050, + "sub.", 0x0000004C, "=r,r,r/;=Z", 0x000FFFFF, 0x7C000051, + "subo", 0x0000004C, "=r,r,r/;+X", 0x000FFFFF, 0x7C000450, + "subo.", 0x0000004C, "=r,r,r/;+X=Z", 0x000FFFFF, 0x7C000451, + "subc", 0x0000004D, "=r,r,r/;+X", 0x000FFFFF, 0x7C000010, + "subc.", 0x0000004D, "=r,r,r/;+X=Z", 0x000FFFFF, 0x7C000011, + "subco", 0x0000004D, "=r,r,r/;+X", 0x000FFFFF, 0x7C000410, + "subco.", 0x0000004D, "=r,r,r/;+X=Z", 0x000FFFFF, 0x7C000411, + "subi", 0x0000003F, "=r,b,-i;p", 0x000FFFFF, 0x38000000, + "subic", 0x00000040, "=r,r,-i;+X", 0x000FFFFF, 0x30000000, + "subic.", 0x00000041, "=r,r,-i;+X=Z", 0x000FFFFF, 0x34000000, + "subis", 0x00000042, "=r,b,-i", 0x000FFFFF, 0x3C000000, + "bctr", 0x00000012, ";Cpp", 0x000FFFFF, 0x4E800420, + "bctrl", 0x00000013, ";C=L", 0x000FFFFF, 0x4E800421, + "bdnzf", 0x0000000D, "Q,l;Cp", 0x000FFFFF, 0x40000000, + "bdnzfl", 0x0000000D, "Q,l;C=L", 0x000FFFFF, 0x40000001, + "bdnzfa", 0x0000000D, "Q,l;Cp", 0x000FFFFF, 0x40000002, + "bdnzfla", 0x0000000D, "Q,l;C=L", 0x000FFFFF, 0x40000003, + "bdnzflr", 0x00000003, "%0Q;CL", 0x000FFFFF, 0x4C000020, + "bdnzflrl", 0x00000003, "%0Q;C+L", 0x000FFFFF, 0x4C000021, + "bdnz", 0x0000000B, "l;Cp", 0x000FFFFF, 0x42000000, + "bdnzl", 0x0000000B, "l;C=L", 0x000FFFFF, 0x42000001, + "bdnza", 0x0000000B, "l;Cp", 0x000FFFFF, 0x42000002, + "bdnzla", 0x0000000B, "l;C=L", 0x000FFFFF, 0x42000003, + "bdnzlr", 0x00000003, ";%16%0%0CL", 0x000FFFFF, 0x4E000020, + "bdnzlrl", 0x00000003, ";%16%0%0C+L", 0x000FFFFF, 0x4E000021, + "bdnzt", 0x0000000C, "Q,l;Cp", 0x000FFFFF, 0x41000000, + "bdnztl", 0x0000000C, "Q,l;C=L", 0x000FFFFF, 0x41000001, + "bdnzta", 0x0000000C, "Q,l;Cp", 0x000FFFFF, 0x41000002, + "bdnztla", 0x0000000C, "Q,l;C=L", 0x000FFFFF, 0x41000003, + "bdnztlr", 0x00000003, "%8Q;CL", 0x000FFFFF, 0x4D000020, + "bdnztlrl", 0x00000003, "%8Q;C+L", 0x000FFFFF, 0x4D000021, + "bdzf", 0x00000010, "Q,l;Cp", 0x000FFFFF, 0x40400000, + "bdzfl", 0x00000010, "Q,l;C=L", 0x000FFFFF, 0x40400001, + "bdzfa", 0x00000010, "Q,l;Cp", 0x000FFFFF, 0x40400002, + "bdzfla", 0x00000010, "Q,l;C=L", 0x000FFFFF, 0x40400003, + "bdzflr", 0x00000003, "%2Q;CL", 0x000FFFFF, 0x4C400020, + "bdzflrl", 0x00000003, "%2Q;C+L", 0x000FFFFF, 0x4C400021, + "bdz", 0x0000000E, "l;Cp", 0x000FFFFF, 0x42400000, + "bdzl", 0x0000000E, "l;C=L", 0x000FFFFF, 0x42400001, + "bdza", 0x0000000E, "l;Cp", 0x000FFFFF, 0x42400002, + "bdzla", 0x0000000E, "l;C=L", 0x000FFFFF, 0x42400003, + "bdzlr", 0x00000003, ";%18%0%0CL", 0x000FFFFF, 0x4E400020, + "bdzlrl", 0x00000003, ";%18%0%0C+L", 0x000FFFFF, 0x4E400021, + "bdzt", 0x0000000F, "Q,l;Cp", 0x000FFFFF, 0x41400000, + "bdztl", 0x0000000F, "Q,l;C=L", 0x000FFFFF, 0x41400001, + "bdzta", 0x0000000F, "Q,l;Cp", 0x000FFFFF, 0x41400002, + "bdztla", 0x0000000F, "Q,l;C=L", 0x000FFFFF, 0x41400003, + "bdztlr", 0x00000003, "%10Q;CL", 0x000FFFFF, 0x4D400020, + "bdztlrl", 0x00000003, "%10Q;C+L", 0x000FFFFF, 0x4D400021, + "bf", 0x00000008, "Q,l;p", 0x000FFFFF, 0x40800000, + "bfl", 0x00000008, "Q,l;=L", 0x000FFFFF, 0x40800001, + "bfa", 0x00000008, "Q,l;p", 0x000FFFFF, 0x40800002, + "bfla", 0x00000008, "Q,l;=L", 0x000FFFFF, 0x40800003, + "bfctr", 0x0000000A, "Q;Cp", 0x000FFFFF, 0x4C800420, + "bfctrl", 0x0000000A, "Q;C=L", 0x000FFFFF, 0x4C800421, + "bflr", 0x00000009, "Q;L", 0x000FFFFF, 0x4C800020, + "bflrl", 0x00000009, "Q;+L", 0x000FFFFF, 0x4C800021, + "blr", 0x00000011, ";L", 0x000FFFFF, 0x4E800020, + "blrl", 0x00000014, ";+L", 0x000FFFFF, 0x4E800021, + "bt", 0x00000005, "Q,l;p", 0x000FFFFF, 0x41800000, + "btl", 0x00000005, "Q,l;=L", 0x000FFFFF, 0x41800001, + "bta", 0x00000005, "Q,l;p", 0x000FFFFF, 0x41800002, + "btla", 0x00000005, "Q,l;=L", 0x000FFFFF, 0x41800003, + "btctr", 0x00000007, "Q;Cp", 0x000FFFFF, 0x4D800420, + "btctrl", 0x00000007, "Q;C=L", 0x000FFFFF, 0x4D800421, + "btlr", 0x00000006, "Q;L", 0x000FFFFF, 0x4D800020, + "btlrl", 0x00000006, "Q;+L", 0x000FFFFF, 0x4D800021, + "beq", 0x00000005, "?c,%2l;p", 0x000FFFFF, 0x41820000, + "beql", 0x00000005, "?c,%2l;=L", 0x000FFFFF, 0x41820001, + "beqa", 0x00000005, "?c,%2l;p", 0x000FFFFF, 0x41820002, + "beqla", 0x00000005, "?c,%2l;=L", 0x000FFFFF, 0x41820003, + "beqctr", 0x00000007, "?c;%2Cp", 0x000FFFFF, 0x4D820420, + "beqctrl", 0x00000007, "?c;%2C=L", 0x000FFFFF, 0x4D820421, + "beqlr", 0x00000006, "?c;%2L", 0x000FFFFF, 0x4D820020, + "beqlrl", 0x00000006, "?c;%2+L", 0x000FFFFF, 0x4D820021, + "bge", 0x00000008, "?c,%0l;p", 0x000FFFFF, 0x40800000, + "bgel", 0x00000008, "?c,%0l;=L", 0x000FFFFF, 0x40800001, + "bgea", 0x00000008, "?c,%0l;p", 0x000FFFFF, 0x40800002, + "bgela", 0x00000008, "?c,%0l;=L", 0x000FFFFF, 0x40800003, + "bgectr", 0x0000000A, "?c;%0Cp", 0x000FFFFF, 0x4C800420, + "bgectrl", 0x0000000A, "?c;%0C=L", 0x000FFFFF, 0x4C800421, + "bgelr", 0x00000009, "?c;%0L", 0x000FFFFF, 0x4C800020, + "bgelrl", 0x00000009, "?c;%0+L", 0x000FFFFF, 0x4C800021, + "bgt", 0x00000005, "?c,%1l;p", 0x000FFFFF, 0x41810000, + "bgtl", 0x00000005, "?c,%1l;=L", 0x000FFFFF, 0x41810001, + "bgta", 0x00000005, "?c,%1l;p", 0x000FFFFF, 0x41810002, + "bgtla", 0x00000005, "?c,%1l;=L", 0x000FFFFF, 0x41810003, + "bgtctr", 0x00000007, "?c;%1Cp", 0x000FFFFF, 0x4D810420, + "bgtctrl", 0x00000007, "?c;%1C=L", 0x000FFFFF, 0x4D810421, + "bgtlr", 0x00000006, "?c;%1L", 0x000FFFFF, 0x4D810020, + "bgtlrl", 0x00000006, "?c;%1+L", 0x000FFFFF, 0x4D810021, + "ble", 0x00000008, "?c,%1l;p", 0x000FFFFF, 0x40810000, + "blel", 0x00000008, "?c,%1l;=L", 0x000FFFFF, 0x40810001, + "blea", 0x00000008, "?c,%1l;p", 0x000FFFFF, 0x40810002, + "blela", 0x00000008, "?c,%1l;=L", 0x000FFFFF, 0x40810003, + "blectr", 0x0000000A, "?c;%1Cp", 0x000FFFFF, 0x4C810420, + "blectrl", 0x0000000A, "?c;%1C=L", 0x000FFFFF, 0x4C810421, + "blelr", 0x00000009, "?c;%1L", 0x000FFFFF, 0x4C810020, + "blelrl", 0x00000009, "?c;%1+L", 0x000FFFFF, 0x4C810021, + "blt", 0x00000005, "?c,%0l;p", 0x000FFFFF, 0x41800000, + "bltl", 0x00000005, "?c,%0l;=L", 0x000FFFFF, 0x41800001, + "blta", 0x00000005, "?c,%0l;p", 0x000FFFFF, 0x41800002, + "bltla", 0x00000005, "?c,%0l;=L", 0x000FFFFF, 0x41800003, + "bltctr", 0x00000007, "?c;%0Cp", 0x000FFFFF, 0x4D800420, + "bltctrl", 0x00000007, "?c;%0C=L", 0x000FFFFF, 0x4D800421, + "bltlr", 0x00000006, "?c;%0L", 0x000FFFFF, 0x4D800020, + "bltlrl", 0x00000006, "?c;%0+L", 0x000FFFFF, 0x4D800021, + "bne", 0x00000008, "?c,%2l;p", 0x000FFFFF, 0x40820000, + "bnel", 0x00000008, "?c,%2l;=L", 0x000FFFFF, 0x40820001, + "bnea", 0x00000008, "?c,%2l;p", 0x000FFFFF, 0x40820002, + "bnela", 0x00000008, "?c,%2l;=L", 0x000FFFFF, 0x40820003, + "bnectr", 0x0000000A, "?c;%2Cp", 0x000FFFFF, 0x4C820420, + "bnectrl", 0x0000000A, "?c;%2C=L", 0x000FFFFF, 0x4C820421, + "bnelr", 0x00000009, "?c;%2L", 0x000FFFFF, 0x4C820020, + "bnelrl", 0x00000009, "?c;%2+L", 0x000FFFFF, 0x4C820021, + "bng", 0x00000008, "?c,%1l;p", 0x000FFFFF, 0x40810000, + "bngl", 0x00000008, "?c,%1l;=L", 0x000FFFFF, 0x40810001, + "bnga", 0x00000008, "?c,%1l;p", 0x000FFFFF, 0x40810002, + "bngla", 0x00000008, "?c,%1l;=L", 0x000FFFFF, 0x40810003, + "bngctr", 0x0000000A, "?c;%1Cp", 0x000FFFFF, 0x4C810420, + "bngctrl", 0x0000000A, "?c;%1C=L", 0x000FFFFF, 0x4C810421, + "bnglr", 0x00000009, "?c;%1L", 0x000FFFFF, 0x4C810020, + "bnglrl", 0x00000009, "?c;%1+L", 0x000FFFFF, 0x4C810021, + "bnl", 0x00000008, "?c,%0l;p", 0x000FFFFF, 0x40800000, + "bnll", 0x00000008, "?c,%0l;=L", 0x000FFFFF, 0x40800001, + "bnla", 0x00000008, "?c,%0l;p", 0x000FFFFF, 0x40800002, + "bnlla", 0x00000008, "?c,%0l;=L", 0x000FFFFF, 0x40800003, + "bnlctr", 0x0000000A, "?c;%0Cp", 0x000FFFFF, 0x4C800420, + "bnlctrl", 0x0000000A, "?c;%0C=L", 0x000FFFFF, 0x4C800421, + "bnllr", 0x00000009, "?c;%0L", 0x000FFFFF, 0x4C800020, + "bnllrl", 0x00000009, "?c;%0+L", 0x000FFFFF, 0x4C800021, + "bns", 0x00000008, "?c,%3l;p", 0x000FFFFF, 0x40830000, + "bnsl", 0x00000008, "?c,%3l;=L", 0x000FFFFF, 0x40830001, + "bnsa", 0x00000008, "?c,%3l;p", 0x000FFFFF, 0x40830002, + "bnsla", 0x00000008, "?c,%3l;=L", 0x000FFFFF, 0x40830003, + "bnsctr", 0x0000000A, "?c;%3Cp", 0x000FFFFF, 0x4C830420, + "bnsctrl", 0x0000000A, "?c;%3C=L", 0x000FFFFF, 0x4C830421, + "bnslr", 0x00000009, "?c;%3L", 0x000FFFFF, 0x4C830020, + "bnslrl", 0x00000009, "?c;%3+L", 0x000FFFFF, 0x4C830021, + "bnu", 0x00000008, "?c,%3l;p", 0x000FFFFF, 0x40830000, + "bnul", 0x00000008, "?c,%3l;=L", 0x000FFFFF, 0x40830001, + "bnua", 0x00000008, "?c,%3l;p", 0x000FFFFF, 0x40830002, + "bnula", 0x00000008, "?c,%3l;=L", 0x000FFFFF, 0x40830003, + "bnuctr", 0x0000000A, "?c;%3Cp", 0x000FFFFF, 0x4C830420, + "bnuctrl", 0x0000000A, "?c;%3C=L", 0x000FFFFF, 0x4C830421, + "bnulr", 0x00000009, "?c;%3L", 0x000FFFFF, 0x4C830020, + "bnulrl", 0x00000009, "?c;%3+L", 0x000FFFFF, 0x4C830021, + "bso", 0x00000005, "?c,%3l;p", 0x000FFFFF, 0x41830000, + "bsol", 0x00000005, "?c,%3l;=L", 0x000FFFFF, 0x41830001, + "bsoa", 0x00000005, "?c,%3l;p", 0x000FFFFF, 0x41830002, + "bsola", 0x00000005, "?c,%3l;=L", 0x000FFFFF, 0x41830003, + "bsoctr", 0x00000007, "?c;%3Cp", 0x000FFFFF, 0x4D830420, + "bsoctrl", 0x00000007, "?c;%3C=L", 0x000FFFFF, 0x4D830421, + "bsolr", 0x00000006, "?c;%3L", 0x000FFFFF, 0x4D830020, + "bsolrl", 0x00000006, "?c;%3+L", 0x000FFFFF, 0x4D830021, + "bun", 0x00000005, "?c,%3l;p", 0x000FFFFF, 0x41830000, + "bunl", 0x00000005, "?c,%3l;=L", 0x000FFFFF, 0x41830001, + "buna", 0x00000005, "?c,%3l;p", 0x000FFFFF, 0x41830002, + "bunla", 0x00000005, "?c,%3l;=L", 0x000FFFFF, 0x41830003, + "bunctr", 0x00000007, "?c;%3Cp", 0x000FFFFF, 0x4D830420, + "bunctrl", 0x00000007, "?c;%3C=L", 0x000FFFFF, 0x4D830421, + "bunlr", 0x00000006, "?c;%3L", 0x000FFFFF, 0x4D830020, + "bunlrl", 0x00000006, "?c;%3+L", 0x000FFFFF, 0x4D830021, + "mfxer", 0x0000007F, "=r;X", 0x000FFFFF, 0x7C0102A6, + "mflr", 0x00000081, "=r;L", 0x000FFFFF, 0x7C0802A6, + "mfctr", 0x00000080, "=r;C", 0x000FFFFF, 0x7C0902A6, + "mftb", 0x000000C7, "=r?T", 0x100FFFFF, 0x7C0C42E6, + "mftbu", 0x000000C7, "=r;S285", 0x100FFFFF, 0x7C0D42E6, + "mttbl", 0x0000007C, "=S284r", 0x100FFFFF, 0x7C1C43A6, + "mttbu", 0x0000007C, "=S285r", 0x100FFFFF, 0x7C1D43A6, + "mtxer", 0x00000077, "r;=X", 0x000FFFFF, 0x7C0103A6, + "mtctr", 0x00000078, "r;=C", 0x000FFFFF, 0x7C0903A6, + "mtlr", 0x00000079, "r;=L", 0x000FFFFF, 0x7C0803A6, + "mfdec", 0x0000007E, "=r;S22", 0x000FF83F, 0x7C1602A6, + "mfmq", 0x0000007E, "=r;S0", 0x00000001, 0x7C0002A6, + "mfrtcl", 0x0000007E, "=r;S5", 0x00000001, 0x7C0502A6, + "mfrtcu", 0x0000007E, "=r;S4", 0x00000001, 0x7C0402A6, + "mfdar", 0x0000007E, "=r;S19", 0x000FF83F, 0x7C1302A6, + "mfdbatl", 0x0000007E, "=r,P*2|537", 0x000FFFFF, 0x7C1982A6, + "mfdbatu", 0x0000007E, "=r,P*2|536", 0x000FFFFF, 0x7C1882A6, + "mfdsisr", 0x0000007E, "=r;S18", 0x000FF83F, 0x7C1202A6, + "mfear", 0x0000007E, "=r;S282", 0x000FFFCF, 0x7C1A42A6, + "mfibatl", 0x0000007E, "=r,P*2|529", 0x000FFFFF, 0x7C1182A6, + "mfibatu", 0x0000007E, "=r,P*2|528", 0x000FFFFF, 0x7C1082A6, + "mfpvr", 0x0000007E, "=r;S287", 0x000FFFFF, 0x7C1F42A6, + "mfsdr1", 0x0000007E, "=r;S25", 0x000FE00F, 0x7C1902A6, + "mfsprg", 0x0000007E, "=r,P|272", 0x000FFFFF, 0x7C1042A6, + "mfsrr0", 0x0000007E, "=r;S26", 0x000FFFFF, 0x7C1A02A6, + "mfsrr1", 0x0000007E, "=r;S27", 0x000FFFFF, 0x7C1B02A6, + "mtcr", 0x0000007A, "%255r;Y", 0x000FFFFF, 0x7C0FF120, + "mtfs", 0x00000084, "%255f", 0x800FFFFF, 0xFDFE058E, + "mtfs.", 0x00000084, "%255f;=Z", 0x800FFFFF, 0xFDFE058F, + "mtmq", 0x0000007C, "=S0r", 0x00000001, 0x7C0003A6, + "mtdar", 0x0000007C, "=S19r", 0x000FF83F, 0x7C1303A6, + "mtdbatl", 0x0000007C, "=P*2|537,r", 0x000FFFFF, 0x7C1983A6, + "mtdbatu", 0x0000007C, "=P*2|536,r", 0x000FFFFF, 0x7C1883A6, + "mtdec", 0x0000007C, "=S22r", 0x000FF83F, 0x7C1603A6, + "mtdsisr", 0x0000007C, "=S18r", 0x000FF83F, 0x7C1203A6, + "mtear", 0x0000007C, "=S282r", 0x000FFFCF, 0x7C1A43A6, + "mtibatl", 0x0000007C, "=P*2|529,r", 0x000FFFFF, 0x7C1183A6, + "mtibatu", 0x0000007C, "=P*2|528,r", 0x000FFFFF, 0x7C1083A6, + "mtsdr1", 0x0000007C, "=S25r", 0x000FE00F, 0x7C1903A6, + "mtsprg", 0x0000007C, "=P|272,r", 0x000FFFFF, 0x7C1043A6, + "mtsrr0", 0x0000007C, "=S26r", 0x000FFFFF, 0x7C1A03A6, + "mtsrr1", 0x0000007C, "=S27r", 0x000FFFFF, 0x7C1B03A6, + "mfcdbcr", 0x0000007E, "=r;S983", 0x000007C0, 0x7C17F2A6, + "mfdac1", 0x0000007E, "=r;S1014", 0x000007C0, 0x7C16FAA6, + "mfdac2", 0x0000007E, "=r;S1015", 0x00000080, 0x7C17FAA6, + "mfdbcr", 0x0000007E, "=r;S1010", 0x000007C0, 0x7C12FAA6, + "mfdbsr", 0x0000007E, "=r;S1008", 0x000007C0, 0x7C10FAA6, + "mfdccr", 0x0000007E, "=r;S1018", 0x000007C0, 0x7C1AFAA6, + "mfdcwr", 0x0000007E, "=r;S954", 0x00000240, 0x7C1AEAA6, + "mfdear", 0x0000007E, "=r;S981", 0x000007C0, 0x7C15F2A6, + "mfesr", 0x0000007E, "=r;S980", 0x000007C0, 0x7C14F2A6, + "mfevpr", 0x0000007E, "=r;S982", 0x000007C0, 0x7C16F2A6, + "mfiac1", 0x0000007E, "=r;S1012", 0x000007C0, 0x7C14FAA6, + "mfiac2", 0x0000007E, "=r;S1013", 0x00000080, 0x7C15FAA6, + "mficcr", 0x0000007E, "=r;S1019", 0x000007C0, 0x7C1BFAA6, + "mficdbdr", 0x0000007E, "=r;S979", 0x000007C0, 0x7C13F2A6, + "mfpid", 0x0000007E, "=r;S945", 0x00000200, 0x7C11EAA6, + "mfpit", 0x0000007E, "=r;S987", 0x000007C0, 0x7C1BF2A6, + "mfpbl1", 0x0000007E, "=r;S1020", 0x00000080, 0x7C1CFAA6, + "mfpbl2", 0x0000007E, "=r;S1022", 0x00000080, 0x7C1EFAA6, + "mfpbu1", 0x0000007E, "=r;S1021", 0x00000080, 0x7C1DFAA6, + "mfpbu2", 0x0000007E, "=r;S1023", 0x00000080, 0x7C1FFAA6, + "mfsgr", 0x0000007E, "=r;S953", 0x00000240, 0x7C19EAA6, + "mfsler", 0x0000007E, "=r;S955", 0x00000040, 0x7C1BEAA6, + "mfsprg0", 0x0000007E, "=r;S272", 0x000FFFFF, 0x7C1042A6, + "mfsprg1", 0x0000007E, "=r;S273", 0x000FFFFF, 0x7C1142A6, + "mfsprg2", 0x0000007E, "=r;S274", 0x000FFFFF, 0x7C1242A6, + "mfsprg3", 0x0000007E, "=r;S275", 0x000FFFFF, 0x7C1342A6, + "mfsrr2", 0x0000007E, "=r;S990", 0x000007C0, 0x7C1EF2A6, + "mfsrr3", 0x0000007E, "=r;S991", 0x000007C0, 0x7C1FF2A6, + "mftbhi", 0x0000007E, "=r;S988", 0x000007C0, 0x7C1CF2A6, + "mftbhu", 0x0000007E, "=r;S972", 0x00000240, 0x7C0CF2A6, + "mftblo", 0x0000007E, "=r;S989", 0x000007C0, 0x7C1DF2A6, + "mftblu", 0x0000007E, "=r;S973", 0x00000240, 0x7C0DF2A6, + "mftcr", 0x0000007E, "=r;S986", 0x000007C0, 0x7C1AF2A6, + "mftsr", 0x0000007E, "=r;S984", 0x000007C0, 0x7C18F2A6, + "mfzpr", 0x0000007E, "=r;S944", 0x00000200, 0x7C10EAA6, + "mtcdbcr", 0x0000007C, "=S983r", 0x000007C0, 0x7C17F3A6, + "mtdac1", 0x0000007C, "=S1014r", 0x000007C0, 0x7C16FBA6, + "mtdac2", 0x0000007C, "=S1015r", 0x00000080, 0x7C17FBA6, + "mtdbcr", 0x0000007C, "=S1010r", 0x000007C0, 0x7C12FBA6, + "mtdbsr", 0x0000007C, "=S1008r", 0x000007C0, 0x7C10FBA6, + "mtdccr", 0x0000007C, "=S1018r", 0x000007C0, 0x7C1AFBA6, + "mtdcwr", 0x0000007C, "=S954r", 0x00000240, 0x7C1AEBA6, + "mtdear", 0x0000007C, "=S981r", 0x000007C0, 0x7C15F3A6, + "mtesr", 0x0000007C, "=S980r", 0x000007C0, 0x7C14F3A6, + "mtevpr", 0x0000007C, "=S982r", 0x000007C0, 0x7C16F3A6, + "mtiac1", 0x0000007C, "=S1012r", 0x000007C0, 0x7C14FBA6, + "mtiac2", 0x0000007C, "=S1013r", 0x00000080, 0x7C15FBA6, + "mticcr", 0x0000007C, "=S1019r", 0x000007C0, 0x7C1BFBA6, + "mticdbdr", 0x0000007C, "=S979r", 0x000007C0, 0x7C13F3A6, + "mtpid", 0x0000007C, "=S945r", 0x00000200, 0x7C11EBA6, + "mtpit", 0x0000007C, "=S987r", 0x000007C0, 0x7C1BF3A6, + "mtpbl1", 0x0000007C, "=S1020r", 0x00000080, 0x7C1CFBA6, + "mtpbl2", 0x0000007C, "=S1022r", 0x00000080, 0x7C1EFBA6, + "mtpbu1", 0x0000007C, "=S1021r", 0x00000080, 0x7C1DFBA6, + "mtpbu2", 0x0000007C, "=S1023r", 0x00000080, 0x7C1FFBA6, + "mtsgr", 0x0000007C, "=S953r", 0x00000240, 0x7C19EBA6, + "mtsler", 0x0000007C, "=S955r", 0x00000040, 0x7C1BEBA6, + "mtsprg0", 0x0000007C, "=S272r", 0x000FFFFF, 0x7C1043A6, + "mtsprg1", 0x0000007C, "=S273r", 0x000FFFFF, 0x7C1143A6, + "mtsprg2", 0x0000007C, "=S274r", 0x000FFFFF, 0x7C1243A6, + "mtsprg3", 0x0000007C, "=S275r", 0x000FFFFF, 0x7C1343A6, + "mtsrr2", 0x0000007C, "=S990r", 0x000007C0, 0x7C1EF3A6, + "mtsrr3", 0x0000007C, "=S991r", 0x000007C0, 0x7C1FF3A6, + "mttbhi", 0x0000007C, "=S988r", 0x000007C0, 0x7C1CF3A6, + "mttblo", 0x0000007C, "=S989r", 0x000007C0, 0x7C1DF3A6, + "mttcr", 0x0000007C, "=S986r", 0x000007C0, 0x7C1AF3A6, + "mttsr", 0x0000007C, "=S984r", 0x000007C0, 0x7C18F3A6, + "mtzpr", 0x0000007C, "=S944r", 0x00000200, 0x7C10EBA6, + "mfbear", 0x000000E9, "=r;%144", 0x000007C0, 0x7C102286, + "mfbesr", 0x000000E9, "=r;%145", 0x00000080, 0x7C112286, + "mfbesr0", 0x000000E9, "=r;%145", 0x00000040, 0x7C112286, + "mfbr0", 0x000000E9, "=r;%128", 0x00000080, 0x7C002286, + "mfbrcr0", 0x000000E9, "=r;%128", 0x00000040, 0x7C002286, + "mfbr1", 0x000000E9, "=r;%129", 0x00000080, 0x7C012286, + "mfbrcr1", 0x000000E9, "=r;%129", 0x00000040, 0x7C012286, + "mfbr2", 0x000000E9, "=r;%130", 0x00000080, 0x7C022286, + "mfbrcr2", 0x000000E9, "=r;%130", 0x00000040, 0x7C022286, + "mfbr3", 0x000000E9, "=r;%131", 0x00000080, 0x7C032286, + "mfbrcr3", 0x000000E9, "=r;%131", 0x00000040, 0x7C032286, + "mfbr4", 0x000000E9, "=r;%132", 0x00000080, 0x7C042286, + "mfbrcr4", 0x000000E9, "=r;%132", 0x00000040, 0x7C042286, + "mfbr5", 0x000000E9, "=r;%133", 0x00000080, 0x7C052286, + "mfbrcr5", 0x000000E9, "=r;%133", 0x00000040, 0x7C052286, + "mfbr6", 0x000000E9, "=r;%134", 0x00000080, 0x7C062286, + "mfbrcr6", 0x000000E9, "=r;%134", 0x00000040, 0x7C062286, + "mfbr7", 0x000000E9, "=r;%135", 0x00000080, 0x7C072286, + "mfbrcr7", 0x000000E9, "=r;%135", 0x00000040, 0x7C072286, + "mfdmacc0", 0x000000E9, "=r;%196", 0x00000080, 0x7C043286, + "mfdmacc1", 0x000000E9, "=r;%204", 0x00000080, 0x7C0C3286, + "mfdmacc2", 0x000000E9, "=r;%212", 0x00000080, 0x7C143286, + "mfdmacc3", 0x000000E9, "=r;%220", 0x00000080, 0x7C1C3286, + "mfdmacr0", 0x000000E9, "=r;%192", 0x00000080, 0x7C003286, + "mfdmacr1", 0x000000E9, "=r;%200", 0x00000080, 0x7C083286, + "mfdmacr2", 0x000000E9, "=r;%208", 0x00000300, 0x7C103286, + "mfdmacr3", 0x000000E9, "=r;%216", 0x00000300, 0x7C183286, + "mfdmact0", 0x000000E9, "=r;%193", 0x00000080, 0x7C013286, + "mfdmact1", 0x000000E9, "=r;%201", 0x00000080, 0x7C093286, + "mfdmact2", 0x000000E9, "=r;%209", 0x00000300, 0x7C113286, + "mfdmact3", 0x000000E9, "=r;%217", 0x00000300, 0x7C193286, + "mfdmada0", 0x000000E9, "=r;%194", 0x00000080, 0x7C023286, + "mfdmada1", 0x000000E9, "=r;%202", 0x00000080, 0x7C0A3286, + "mfdmada2", 0x000000E9, "=r;%210", 0x00000300, 0x7C123286, + "mfdmada3", 0x000000E9, "=r;%218", 0x00000300, 0x7C1A3286, + "mfdmasa0", 0x000000E9, "=r;%195", 0x00000080, 0x7C033286, + "mfdmasa1", 0x000000E9, "=r;%203", 0x00000080, 0x7C0B3286, + "mfdmasa2", 0x000000E9, "=r;%211", 0x00000300, 0x7C133286, + "mfdmasa3", 0x000000E9, "=r;%219", 0x00000300, 0x7C1B3286, + "mfdmasr", 0x000000E9, "=r;%224", 0x00000080, 0x7C003A86, + "mfexisr", 0x000000E9, "=r;%64", 0x00000080, 0x7C001286, + "mfexier", 0x000000E9, "=r;%66", 0x00000080, 0x7C021286, + "mfiocr", 0x000000E9, "=r;%160", 0x000007C0, 0x7C002A86, + "mfpmcr0", 0x000000E9, "=r;%161", 0x00000040, 0x7C012A86, + "mtbear", 0x000000EA, "%144r", 0x000007C0, 0x7C102386, + "mtbesr", 0x000000EA, "%145r", 0x00000080, 0x7C112386, + "mtbesr0", 0x000000EA, "%145r", 0x00000080, 0x7C112386, + "mtbr0", 0x000000EA, "%128r", 0x00000080, 0x7C002386, + "mtbrcr0", 0x000000EA, "%128r", 0x00000040, 0x7C002386, + "mtbr1", 0x000000EA, "%129r", 0x00000080, 0x7C012386, + "mtbrcr1", 0x000000EA, "%129r", 0x00000040, 0x7C012386, + "mtbr2", 0x000000EA, "%130r", 0x00000080, 0x7C022386, + "mtbrcr2", 0x000000EA, "%130r", 0x00000040, 0x7C022386, + "mtbr3", 0x000000EA, "%131r", 0x00000080, 0x7C032386, + "mtbrcr3", 0x000000EA, "%131r", 0x00000040, 0x7C032386, + "mtbr4", 0x000000EA, "%132r", 0x00000080, 0x7C042386, + "mtbrcr4", 0x000000EA, "%132r", 0x00000040, 0x7C042386, + "mtbr5", 0x000000EA, "%133r", 0x00000080, 0x7C052386, + "mtbrcr5", 0x000000EA, "%133r", 0x00000040, 0x7C052386, + "mtbr6", 0x000000EA, "%134r", 0x00000080, 0x7C062386, + "mtbrcr6", 0x000000EA, "%134r", 0x00000040, 0x7C062386, + "mtbr7", 0x000000EA, "%135r", 0x00000080, 0x7C072386, + "mtbrcr7", 0x000000EA, "%135r", 0x00000040, 0x7C072386, + "mtdmacc0", 0x000000EA, "%196r", 0x00000080, 0x7C043386, + "mtdmacc1", 0x000000EA, "%204r", 0x00000080, 0x7C0C3386, + "mtdmacc2", 0x000000EA, "%212r", 0x00000300, 0x7C143386, + "mtdmacc3", 0x000000EA, "%220r", 0x00000300, 0x7C1C3386, + "mtdmacr0", 0x000000EA, "%192r", 0x00000080, 0x7C003386, + "mtdmacr1", 0x000000EA, "%200r", 0x00000080, 0x7C083386, + "mtdmacr2", 0x000000EA, "%208r", 0x00000300, 0x7C103386, + "mtdmacr3", 0x000000EA, "%216r", 0x00000300, 0x7C183386, + "mtdmact0", 0x000000EA, "%193r", 0x00000080, 0x7C013386, + "mtdmact1", 0x000000EA, "%201r", 0x00000080, 0x7C093386, + "mtdmact2", 0x000000EA, "%209r", 0x00000300, 0x7C113386, + "mtdmact3", 0x000000EA, "%217r", 0x00000300, 0x7C193386, + "mtdmada0", 0x000000EA, "%194r", 0x00000080, 0x7C023386, + "mtdmada1", 0x000000EA, "%202r", 0x00000080, 0x7C0A3386, + "mtdmada2", 0x000000EA, "%210r", 0x00000300, 0x7C123386, + "mtdmada3", 0x000000EA, "%218r", 0x00000300, 0x7C1A3386, + "mtdmasa0", 0x000000EA, "%195r", 0x00000080, 0x7C033386, + "mtdmasa1", 0x000000EA, "%203r", 0x00000080, 0x7C0B3386, + "mtdmasa2", 0x000000EA, "%211r", 0x00000300, 0x7C133386, + "mtdmasa3", 0x000000EA, "%219r", 0x00000300, 0x7C1B3386, + "mtdmasr", 0x000000EA, "%224r", 0x00000080, 0x7C003B86, + "mtexisr", 0x000000EA, "%64r", 0x00000080, 0x7C001386, + "mtexier", 0x000000EA, "%66r", 0x00000080, 0x7C021386, + "mtiocr", 0x000000EA, "%160r", 0x000007C0, 0x7C002B86, + "mtpmcr0", 0x000000EA, "%161r", 0x00000040, 0x7C012B86, + "trap", 0x000000D8, "", 0x000FFFFF, 0x7FE00008, + "tweq", 0x000000D7, "%4r,r", 0x000FFFFF, 0x7C800008, + "tweqi", 0x000000D9, "%4r,i", 0x000FFFFF, 0x0C800000, + "twge", 0x000000D7, "%12r,r", 0x000FFFFF, 0x7D800008, + "twgei", 0x000000D9, "%12r,i", 0x000FFFFF, 0x0D800000, + "twgt", 0x000000D7, "%8r,r", 0x000FFFFF, 0x7D000008, + "twgti", 0x000000D9, "%8r,i", 0x000FFFFF, 0x0D000000, + "twle", 0x000000D7, "%20r,r", 0x000FFFFF, 0x7E800008, + "twlei", 0x000000D9, "%20r,i", 0x000FFFFF, 0x0E800000, + "twlge", 0x000000D7, "%5r,r", 0x000FFFFF, 0x7CA00008, + "twlgei", 0x000000D9, "%5r,i", 0x000FFFFF, 0x0CA00000, + "twlgt", 0x000000D7, "%1r,r", 0x000FFFFF, 0x7C200008, + "twlgti", 0x000000D9, "%1r,i", 0x000FFFFF, 0x0C200000, + "twlle", 0x000000D7, "%6r,r", 0x000FFFFF, 0x7CC00008, + "twllei", 0x000000D9, "%6r,i", 0x000FFFFF, 0x0CC00000, + "twllt", 0x000000D7, "%2r,r", 0x000FFFFF, 0x7C400008, + "twllti", 0x000000D9, "%2r,i", 0x000FFFFF, 0x0C400000, + "twlng", 0x000000D7, "%6r,r", 0x000FFFFF, 0x7CC00008, + "twlngi", 0x000000D9, "%6r,i", 0x000FFFFF, 0x0CC00000, + "twlnl", 0x000000D7, "%5r,r", 0x000FFFFF, 0x7CA00008, + "twlnli", 0x000000D9, "%5r,i", 0x000FFFFF, 0x0CA00000, + "twlt", 0x000000D7, "%16r,r", 0x000FFFFF, 0x7E000008, + "twlti", 0x000000D9, "%16r,i", 0x000FFFFF, 0x0E000000, + "twne", 0x000000D7, "%24r,r", 0x000FFFFF, 0x7F000008, + "twnei", 0x000000D9, "%24r,i", 0x000FFFFF, 0x0F000000, + "twng", 0x000000D7, "%20r,r", 0x000FFFFF, 0x7E800008, + "twngi", 0x000000D9, "%20r,i", 0x000FFFFF, 0x0E800000, + "twnl", 0x000000D7, "%12r,r", 0x000FFFFF, 0x7D800008, + "twnli", 0x000000D9, "%12r,i", 0x000FFFFF, 0x0D800000, + "rotlwi", 0x00000067, "=r,r,u5;%0;%31", 0x000FFFFF, 0x5400003E, + "rotlwi.", 0x00000067, "=r,r,u5;%0;%31;=Z", 0x000FFFFF, 0x5400003F, + "rotrwi", 0x00000067, "=r,r,u5<31;%0;%31", 0x000FFFFF, 0x5400003E, + "rotrwi.", 0x00000067, "=r,r,u5<31;%0;%31;=Z", 0x000FFFFF, 0x5400003F, + "clrlslwi", 0x00000067, "=r,r,u5&,u5>p/<31", 0x000FFFFF, 0x54000000, + "clrlslwi.", 0x00000067, "=r,r,u5&,u5>p/<31;=Z", 0x000FFFFF, 0x54000001, + "clrlwi", 0x00000067, "=r,r,u5;%0/%31", 0x000FFFFF, 0x5400003E, + "clrlwi.", 0x00000067, "=r,r,u5;%0/%31=Z", 0x000FFFFF, 0x5400003F, + "clrrwi", 0x00000067, "=r,r,u5;%0;%0/2<31", 0x000FFFFF, 0x54000000, + "clrrwi.", 0x00000067, "=r,r,u5;%0;%0/2<31=Z", 0x000FFFFF, 0x54000001, + "extlwi", 0x00000067, "=r,r,u5,u5/>1%0/", 0x000FFFFF, 0x54000000, + "extlwi.", 0x00000067, "=r,r,u5,u5/>1%0/;=Z", 0x000FFFFF, 0x54000001, + "extrwi", 0x00000067, "=r,r,u5,u5|p/<32;%31", 0x000FFFFF, 0x5400003E, + "extrwi.", 0x00000067, "=r,r,u5,u5|p/<32;%31;=Z", 0x000FFFFF, 0x5400003F, + "slwi", 0x00000067, "=r,r,u5&<31%0/", 0x000FFFFF, 0x54000000, + "slwi.", 0x00000067, "=r,r,u5&<31%0/;=Z", 0x000FFFFF, 0x54000001, + "srwi", 0x00000067, "=r,r,u5&<32/%31", 0x000FFFFF, 0x5400003E, + "srwi.", 0x00000067, "=r,r,u5&<32/%31;=Z", 0x000FFFFF, 0x5400003F, + "rotlw", 0x00000068, "=r,r,r;%0%31", 0x000FFFFF, 0x5C00003E, + "rotlw.", 0x00000068, "=r,r,r;%0%31=Z", 0x000FFFFF, 0x5C00003F, + "inslwi", 0x00000069, "+r,r,u5,u5&<32/2|p>1", 0x000FFFFF, 0x50000000, + "inslwi.", 0x00000069, "+r,r,u5,u5&<32/2|p>1;=Z", 0x000FFFFF, 0x50000001, + "insrwi", 0x00000069, "+r,r,u5,u5/|p&<32/2/>1", 0x000FFFFF, 0x50000000, + "insrwi.", 0x00000069, "+r,r,u5,u5/|p&<32/2/>1;=Z", 0x000FFFFF, 0x50000001, + "crset", 0x00000070, "=Q&2&2", 0x000FFFFF, 0x4C000242, + "crnot", 0x00000072, "=Q,Q&2", 0x000FFFFF, 0x4C000042, + "crmove", 0x00000073, "=Q,Q&2", 0x000FFFFF, 0x4C000382, + "crclr", 0x00000075, "=Q&2&2", 0x000FFFFF, 0x4C000182, + "opword", 0x000000DA, "w", 0x000FFFFF, 0x00000000, + "dss", 0x000000EC, "u2?u2", 0x400FFFFF, 0x7C00066C, + "dssall", 0x000000ED, "", 0x400FFFFF, 0x7E00066C, + "dst", 0x000000EE, "r,r,u2?u2", 0x400FFFFF, 0x7C0002AC, + "dstt", 0x000000EF, "r,r,u2", 0x400FFFFF, 0x7E0002AC, + "dstst", 0x000000F0, "r,r,u2?u2", 0x400FFFFF, 0x7C0002EC, + "dststt", 0x000000F1, "r,r,u2", 0x400FFFFF, 0x7E0002EC, + "lvebx", 0x000000F2, "=v,(b,r)", 0x400FFFFF, 0x7C00000E, + "lvehx", 0x000000F3, "=v,(b,r)", 0x400FFFFF, 0x7C00004E, + "lvewx", 0x000000F4, "=v,(b,r)", 0x400FFFFF, 0x7C00008E, + "lvsl", 0x000000F5, "=v,(b,r)", 0x400FFFFF, 0x7C00000C, + "lvsr", 0x000000F6, "=v,(b,r)", 0x400FFFFF, 0x7C00004C, + "lvx", 0x000000F7, "=v,(b,r)", 0x400FFFFF, 0x7C0000CE, + "lvxl", 0x000000F8, "=v,(b,r)", 0x400FFFFF, 0x7C0002CE, + "mfvscr", 0x000000FE, "=v", 0x400FFFFF, 0x10000C08, + "mtvscr", 0x000000FF, "v", 0x400FFFFF, 0x10000C88, + "stvebx", 0x000000F9, "v,(b,r)", 0x400FFFFF, 0x7C00010E, + "stvehx", 0x000000FA, "v,(b,r)", 0x400FFFFF, 0x7C00014E, + "stvewx", 0x000000FB, "v,(b,r)", 0x400FFFFF, 0x7C00018E, + "stvx", 0x000000FC, "v,(b,r)", 0x400FFFFF, 0x7C0001CE, + "stvxl", 0x000000FD, "v,(b,r)", 0x400FFFFF, 0x7C0003CE, + "vaddcuw", 0x00000100, "=v,v,v", 0x400FFFFF, 0x10000180, + "vaddfp", 0x00000101, "=v,v,v", 0x400FFFFF, 0x1000000A, + "vaddsbs", 0x00000102, "=v,v,v", 0x400FFFFF, 0x10000300, + "vaddshs", 0x00000103, "=v,v,v", 0x400FFFFF, 0x10000340, + "vaddsws", 0x00000104, "=v,v,v", 0x400FFFFF, 0x10000380, + "vaddubm", 0x00000105, "=v,v,v", 0x400FFFFF, 0x10000000, + "vaddubs", 0x00000106, "=v,v,v", 0x400FFFFF, 0x10000200, + "vadduhm", 0x00000107, "=v,v,v", 0x400FFFFF, 0x10000040, + "vadduhs", 0x00000108, "=v,v,v", 0x400FFFFF, 0x10000240, + "vadduwm", 0x00000109, "=v,v,v", 0x400FFFFF, 0x10000080, + "vadduws", 0x0000010A, "=v,v,v", 0x400FFFFF, 0x10000280, + "vand", 0x0000010B, "=v,v,v", 0x400FFFFF, 0x10000404, + "vandc", 0x0000010C, "=v,v,v", 0x400FFFFF, 0x10000444, + "vavgsb", 0x0000010D, "=v,v,v", 0x400FFFFF, 0x10000502, + "vavgsh", 0x0000010E, "=v,v,v", 0x400FFFFF, 0x10000542, + "vavgsw", 0x0000010F, "=v,v,v", 0x400FFFFF, 0x10000582, + "vavgub", 0x00000110, "=v,v,v", 0x400FFFFF, 0x10000402, + "vavguh", 0x00000111, "=v,v,v", 0x400FFFFF, 0x10000442, + "vavguw", 0x00000112, "=v,v,v", 0x400FFFFF, 0x10000482, + "vcfsx", 0x00000113, "=v,v,u5", 0x400FFFFF, 0x1000034A, + "vcfux", 0x00000114, "=v,v,u5", 0x400FFFFF, 0x1000030A, + "vcmpbfp", 0x00000115, "=v,v,v", 0x400FFFFF, 0x100003C6, + "vcmpbfp.", 0x00000115, "=v,v,v;=Z", 0x400FFFFF, 0x100007C6, + "vcmpeqfp", 0x00000116, "=v,v,v", 0x400FFFFF, 0x100000C6, + "vcmpeqfp.", 0x00000116, "=v,v,v;=Z", 0x400FFFFF, 0x100004C6, + "vcmpequb", 0x00000117, "=v,v,v", 0x400FFFFF, 0x10000006, + "vcmpequb.", 0x00000117, "=v,v,v;=Z", 0x400FFFFF, 0x10000406, + "vcmpequh", 0x00000118, "=v,v,v", 0x400FFFFF, 0x10000046, + "vcmpequh.", 0x00000118, "=v,v,v;=Z", 0x400FFFFF, 0x10000446, + "vcmpequw", 0x00000119, "=v,v,v", 0x400FFFFF, 0x10000086, + "vcmpequw.", 0x00000119, "=v,v,v;=Z", 0x400FFFFF, 0x10000486, + "vcmpgefp", 0x0000011A, "=v,v,v", 0x400FFFFF, 0x100001C6, + "vcmpgefp.", 0x0000011A, "=v,v,v;=Z", 0x400FFFFF, 0x100005C6, + "vcmpgtfp", 0x0000011B, "=v,v,v", 0x400FFFFF, 0x100002C6, + "vcmpgtfp.", 0x0000011B, "=v,v,v;=Z", 0x400FFFFF, 0x100006C6, + "vcmpgtsb", 0x0000011C, "=v,v,v", 0x400FFFFF, 0x10000306, + "vcmpgtsb.", 0x0000011C, "=v,v,v;=Z", 0x400FFFFF, 0x10000706, + "vcmpgtsh", 0x0000011D, "=v,v,v", 0x400FFFFF, 0x10000346, + "vcmpgtsh.", 0x0000011D, "=v,v,v;=Z", 0x400FFFFF, 0x10000746, + "vcmpgtsw", 0x0000011E, "=v,v,v", 0x400FFFFF, 0x10000386, + "vcmpgtsw.", 0x0000011E, "=v,v,v;=Z", 0x400FFFFF, 0x10000786, + "vcmpgtub", 0x0000011F, "=v,v,v", 0x400FFFFF, 0x10000206, + "vcmpgtub.", 0x0000011F, "=v,v,v;=Z", 0x400FFFFF, 0x10000606, + "vcmpgtuh", 0x00000120, "=v,v,v", 0x400FFFFF, 0x10000246, + "vcmpgtuh.", 0x00000120, "=v,v,v;=Z", 0x400FFFFF, 0x10000646, + "vcmpgtuw", 0x00000121, "=v,v,v", 0x400FFFFF, 0x10000286, + "vcmpgtuw.", 0x00000121, "=v,v,v;=Z", 0x400FFFFF, 0x10000686, + "vctsxs", 0x00000122, "=v,v,u5", 0x400FFFFF, 0x100003CA, + "vctuxs", 0x00000123, "=v,v,u5", 0x400FFFFF, 0x1000038A, + "vexptefp", 0x00000124, "=v,v", 0x400FFFFF, 0x1000018A, + "vlogefp", 0x00000125, "=v,v", 0x400FFFFF, 0x100001CA, + "vmaxfp", 0x00000126, "=v,v,v", 0x400FFFFF, 0x1000040A, + "vmaxsb", 0x00000127, "=v,v,v", 0x400FFFFF, 0x10000102, + "vmaxsh", 0x00000128, "=v,v,v", 0x400FFFFF, 0x10000142, + "vmaxsw", 0x00000129, "=v,v,v", 0x400FFFFF, 0x10000182, + "vmaxub", 0x0000012A, "=v,v,v", 0x400FFFFF, 0x10000002, + "vmaxuh", 0x0000012B, "=v,v,v", 0x400FFFFF, 0x10000042, + "vmaxuw", 0x0000012C, "=v,v,v", 0x400FFFFF, 0x10000082, + "vminfp", 0x0000012D, "=v,v,v", 0x400FFFFF, 0x1000044A, + "vminsb", 0x0000012E, "=v,v,v", 0x400FFFFF, 0x10000302, + "vminsh", 0x0000012F, "=v,v,v", 0x400FFFFF, 0x10000342, + "vminsw", 0x00000130, "=v,v,v", 0x400FFFFF, 0x10000382, + "vminub", 0x00000131, "=v,v,v", 0x400FFFFF, 0x10000202, + "vminuh", 0x00000132, "=v,v,v", 0x400FFFFF, 0x10000242, + "vminuw", 0x00000133, "=v,v,v", 0x400FFFFF, 0x10000282, + "vmrghb", 0x00000134, "=v,v,v", 0x400FFFFF, 0x1000000C, + "vmrghh", 0x00000135, "=v,v,v", 0x400FFFFF, 0x1000004C, + "vmrghw", 0x00000136, "=v,v,v", 0x400FFFFF, 0x1000008C, + "vmrglb", 0x00000137, "=v,v,v", 0x400FFFFF, 0x1000010C, + "vmrglh", 0x00000138, "=v,v,v", 0x400FFFFF, 0x1000014C, + "vmrglw", 0x00000139, "=v,v,v", 0x400FFFFF, 0x1000018C, + "vmulesb", 0x0000013A, "=v,v,v", 0x400FFFFF, 0x10000308, + "vmulesh", 0x0000013B, "=v,v,v", 0x400FFFFF, 0x10000348, + "vmuleub", 0x0000013C, "=v,v,v", 0x400FFFFF, 0x10000208, + "vmuleuh", 0x0000013D, "=v,v,v", 0x400FFFFF, 0x10000248, + "vmulosb", 0x0000013E, "=v,v,v", 0x400FFFFF, 0x10000108, + "vmulosh", 0x0000013F, "=v,v,v", 0x400FFFFF, 0x10000148, + "vmuloub", 0x00000140, "=v,v,v", 0x400FFFFF, 0x10000008, + "vmulouh", 0x00000141, "=v,v,v", 0x400FFFFF, 0x10000048, + "vnor", 0x00000142, "=v,v,v", 0x400FFFFF, 0x10000504, + "vnot", 0x00000142, "=v,v&", 0x400FFFFF, 0x10000504, + "vor", 0x00000143, "=v,v,v", 0x400FFFFF, 0x10000484, + "vpkpx", 0x00000144, "=v,v,v", 0x400FFFFF, 0x1000030E, + "vpkshss", 0x00000145, "=v,v,v", 0x400FFFFF, 0x1000018E, + "vpkshus", 0x00000146, "=v,v,v", 0x400FFFFF, 0x1000010E, + "vpkswss", 0x00000147, "=v,v,v", 0x400FFFFF, 0x100001CE, + "vpkswus", 0x00000148, "=v,v,v", 0x400FFFFF, 0x1000014E, + "vpkuhum", 0x00000149, "=v,v,v", 0x400FFFFF, 0x1000000E, + "vpkuhus", 0x0000014A, "=v,v,v", 0x400FFFFF, 0x1000008E, + "vpkuwum", 0x0000014B, "=v,v,v", 0x400FFFFF, 0x1000004E, + "vpkuwus", 0x0000014C, "=v,v,v", 0x400FFFFF, 0x100000CE, + "vrefp", 0x0000014D, "=v,v", 0x400FFFFF, 0x1000010A, + "vrfim", 0x0000014E, "=v,v", 0x400FFFFF, 0x100002CA, + "vrfin", 0x0000014F, "=v,v", 0x400FFFFF, 0x1000020A, + "vrfip", 0x00000150, "=v,v", 0x400FFFFF, 0x1000028A, + "vrfiz", 0x00000151, "=v,v", 0x400FFFFF, 0x1000024A, + "vrlb", 0x00000152, "=v,v,v", 0x400FFFFF, 0x10000004, + "vrlh", 0x00000153, "=v,v,v", 0x400FFFFF, 0x10000044, + "vrlw", 0x00000154, "=v,v,v", 0x400FFFFF, 0x10000084, + "vrsqrtefp", 0x00000155, "=v,v", 0x400FFFFF, 0x1000014A, + "vsl", 0x00000156, "=v,v,v", 0x400FFFFF, 0x100001C4, + "vslb", 0x00000157, "=v,v,v", 0x400FFFFF, 0x10000104, + "vslh", 0x00000158, "=v,v,v", 0x400FFFFF, 0x10000144, + "vslo", 0x00000159, "=v,v,v", 0x400FFFFF, 0x1000040C, + "vslw", 0x0000015A, "=v,v,v", 0x400FFFFF, 0x10000184, + "vspltb", 0x0000015B, "=v,v,u5", 0x400FFFFF, 0x1000020C, + "vsplth", 0x0000015C, "=v,v,u5", 0x400FFFFF, 0x1000024C, + "vspltw", 0x0000015D, "=v,v,u5", 0x400FFFFF, 0x1000028C, + "vspltisb", 0x0000015E, "=v,i5", 0x400FFFFF, 0x1000030C, + "vspltish", 0x0000015F, "=v,i5", 0x400FFFFF, 0x1000034C, + "vspltisw", 0x00000160, "=v,i5", 0x400FFFFF, 0x1000038C, + "vsr", 0x00000161, "=v,v,v", 0x400FFFFF, 0x100002C4, + "vsrab", 0x00000162, "=v,v,v", 0x400FFFFF, 0x10000304, + "vsrah", 0x00000163, "=v,v,v", 0x400FFFFF, 0x10000344, + "vsraw", 0x00000164, "=v,v,v", 0x400FFFFF, 0x10000384, + "vsrb", 0x00000165, "=v,v,v", 0x400FFFFF, 0x10000204, + "vsrh", 0x00000166, "=v,v,v", 0x400FFFFF, 0x10000244, + "vsro", 0x00000167, "=v,v,v", 0x400FFFFF, 0x1000044C, + "vsrw", 0x00000168, "=v,v,v", 0x400FFFFF, 0x10000284, + "vsubcuw", 0x00000169, "=v,v,v", 0x400FFFFF, 0x10000580, + "vsubfp", 0x0000016A, "=v,v,v", 0x400FFFFF, 0x1000004A, + "vsubsbs", 0x0000016B, "=v,v,v", 0x400FFFFF, 0x10000700, + "vsubshs", 0x0000016C, "=v,v,v", 0x400FFFFF, 0x10000740, + "vsubsws", 0x0000016D, "=v,v,v", 0x400FFFFF, 0x10000780, + "vsububm", 0x0000016E, "=v,v,v", 0x400FFFFF, 0x10000400, + "vsububs", 0x0000016F, "=v,v,v", 0x400FFFFF, 0x10000600, + "vsubuhm", 0x00000170, "=v,v,v", 0x400FFFFF, 0x10000440, + "vsubuhs", 0x00000171, "=v,v,v", 0x400FFFFF, 0x10000640, + "vsubuwm", 0x00000172, "=v,v,v", 0x400FFFFF, 0x10000480, + "vsubuws", 0x00000173, "=v,v,v", 0x400FFFFF, 0x10000680, + "vsumsws", 0x00000174, "=v,v,v", 0x400FFFFF, 0x10000788, + "vsum2sws", 0x00000175, "=v,v,v", 0x400FFFFF, 0x10000688, + "vsum4sbs", 0x00000176, "=v,v,v", 0x400FFFFF, 0x10000708, + "vsum4shs", 0x00000177, "=v,v,v", 0x400FFFFF, 0x10000648, + "vsum4ubs", 0x00000178, "=v,v,v", 0x400FFFFF, 0x10000608, + "vupkhpx", 0x00000179, "=v,v", 0x400FFFFF, 0x1000034E, + "vupkhsb", 0x0000017A, "=v,v", 0x400FFFFF, 0x1000020E, + "vupkhsh", 0x0000017B, "=v,v", 0x400FFFFF, 0x1000024E, + "vupklpx", 0x0000017C, "=v,v", 0x400FFFFF, 0x100003CE, + "vupklsb", 0x0000017D, "=v,v", 0x400FFFFF, 0x1000028E, + "vupklsh", 0x0000017E, "=v,v", 0x400FFFFF, 0x100002CE, + "vxor", 0x0000017F, "=v,v,v", 0x400FFFFF, 0x100004C4, + "vmaddfp", 0x00000180, "=v,v,v,v", 0x400FFFFF, 0x1000002E, + "vmhaddshs", 0x00000181, "=v,v,v,v", 0x400FFFFF, 0x10000020, + "vmhraddshs", 0x00000182, "=v,v,v,v", 0x400FFFFF, 0x10000021, + "vmladduhm", 0x00000183, "=v,v,v,v", 0x400FFFFF, 0x10000022, + "vmsummbm", 0x00000184, "=v,v,v,v", 0x400FFFFF, 0x10000025, + "vmsumshm", 0x00000185, "=v,v,v,v", 0x400FFFFF, 0x10000028, + "vmsumshs", 0x00000186, "=v,v,v,v", 0x400FFFFF, 0x10000029, + "vmsumubm", 0x00000187, "=v,v,v,v", 0x400FFFFF, 0x10000024, + "vmsumuhm", 0x00000188, "=v,v,v,v", 0x400FFFFF, 0x10000026, + "vmsumuhs", 0x00000189, "=v,v,v,v", 0x400FFFFF, 0x10000027, + "vnmsubfp", 0x0000018A, "=v,v,v,v", 0x400FFFFF, 0x1000002F, + "vperm", 0x0000018B, "=v,v,v,v", 0x400FFFFF, 0x1000002B, + "vsel", 0x0000018C, "=v,v,v,v", 0x400FFFFF, 0x1000002A, + "vsldoi", 0x0000018D, "=v,v,v,u4", 0x400FFFFF, 0x1000002C, + "vmr", 0x0000018E, "=v,v", 0x400FFFFF, 0x10000484, + "vmrp", 0x0000018F, "=v,v", 0x400FFFFF, 0x1000002C, + "mtvrsave", 0x0000007C, "=S256r", 0x400FFFFF, 0x7C0043A6, + "mfvrsave", 0x0000007E, "=r;S256", 0x400FFFFF, 0x7C0042A6, + NULL, 0, NULL, 0, 0 +}; + +typedef struct HashedMnemonic { + struct HashedMnemonic *next; + IAMnemonic *mnemonic; +} HashedMnemonic; + +HashedMnemonic *hashedmnemonics[1024]; + +void InlineAsm_InitializeMnemonicsPPC(void) { + SInt32 i; + IAMnemonic *mnemonic; + HashedMnemonic **ptr; + HashedMnemonic *entry; + + for (i = 0; i < 1024; i++) + hashedmnemonics[i] = NULL; + + for (mnemonic = mnemonics; mnemonic->name; mnemonic++) { + ptr = hashedmnemonics + (CHash(mnemonic->name) & 1023); + entry = lalloc(sizeof(HashedMnemonic)); + entry->mnemonic = mnemonic; + entry->next = *ptr; + *ptr = entry; + } +} + +IAMnemonic *InlineAsm_LookupMnemonicPPC(char *name) { + HashedMnemonic *entry; + + for (entry = hashedmnemonics[CHash(name) & 1023]; entry; entry = entry->next) { + IAMnemonic *mnemonic = entry->mnemonic; + if (!strcmp(mnemonic->name, name)) + return mnemonic; + } + + return NULL; +} diff --git a/compiler_and_linker/unsorted/InlineAsmPPC.c b/compiler_and_linker/unsorted/InlineAsmPPC.c new file mode 100644 index 0000000..ead84d7 --- /dev/null +++ b/compiler_and_linker/unsorted/InlineAsmPPC.c @@ -0,0 +1,2624 @@ +#include "compiler/InlineAsmPPC.h" +#include "compiler/CError.h" +#include "compiler/CInt64.h" +#include "compiler/CFunc.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/TOC.h" +#include "compiler/FuncLevelAsmPPC.h" +#include "compiler/InlineAsm.h" +#include "compiler/InlineAsmMnemonicsPPC.h" +#include "compiler/InlineAsmRegisters.h" +#include "compiler/InlineAsmRegistersPPC.h" +#include "compiler/CodeGen.h" +#include "compiler/CodeGenOptPPC.h" +#include "compiler/PPCError.h" +#include "compiler/RegisterInfo.h" +#include "compiler/objects.h" +#include "compiler/CExpr.h" +#include "compiler/PCode.h" +#include "compiler/PCodeUtilities.h" +#include "compiler/StackFrame.h" +#include "compiler/CompilerTools.h" + +// TODO: move me +extern int countexceptionactionregisters(ExceptionAction *); +extern void noteexceptionactionregisters(ExceptionAction *, PCodeArg *); +extern void *make_alias(Object *obj, SInt32 offset, SInt32 size); + +char asm_alloc_flags[10]; +unsigned char sm_section; +UInt32 cpu; +SInt32 fralloc_parameter_area_size; +Boolean user_responsible_for_frame; +Boolean supports_hardware_fpu; +UInt32 assembledinstructions; +UInt8 assembler_type; +char volatileasm; +Boolean InlineAsm_gccmode; +Boolean InlineAsm_labelref; +CLabel *pic_base_label; + +enum { + NO_REG = 0, + INVALID_PIC_REG = -2 +}; + +// forward decls +static SInt32 InlineAsm_ConstantExpressionPPC(SInt32 value); +static Object *isvariableoperand(void); +static Object *isregisterstructpointeroperand(void); +static void registeroperand(IAOperand *op, char rclass, short effect); +static void DiadicOperatorPPC(IAExpr *left, short token, IAExpr *right); +static void InlineAsm_ExpressionPPC(IAExpr *expr, SInt32 value); +static void savepicbase(short reg, HashNameNode *name); + +inline SInt32 ExtractValue(CInt64 value) { + return (SInt32) CInt64_GetULong(&value); +} + +static void IllegalObjectOperator(HashNameNode *name1, HashNameNode *name2, short token) { + char *opstr; + switch (token) { + case '*': opstr = "*"; break; + case '/': opstr = "/"; break; + case '%': opstr = "%"; break; + case '+': opstr = "+"; break; + case '-': opstr = "-"; break; + case TK_SHL: opstr = "<<"; break; + case TK_SHR: opstr = ">>"; break; + case '<': opstr = "<"; break; + case '>': opstr = ">"; break; + case TK_LESS_EQUAL: opstr = "<="; break; + case TK_GREATER_EQUAL: opstr = ">="; break; + case TK_LOGICAL_EQ: opstr = "=="; break; + case TK_LOGICAL_NE: opstr = "!="; break; + case '&': opstr = "&"; break; + case '^': opstr = "^"; break; + case '|': opstr = "|"; break; + case TK_LOGICAL_AND: opstr = "&&"; break; + case TK_LOGICAL_OR: opstr = "||"; break; + default: opstr = "???"; + } + + if (!name2) { + PPCError_Error(119, opstr, name1->name); + } else if (!name1) { + PPCError_Error(120, opstr, name2->name); + } else { + PPCError_Error(118, name1->name, opstr, name2->name); + } +} + +static void IllegalObjectInConst(IAExpr *expr) { + if (expr->xC) { + PPCError_Error(122, expr->xC->name->name); + } else if (expr->object) { + PPCError_Error(122, expr->object->name->name); + } else if (expr->label) { + PPCError_Error(166, expr->label->name->name); + } +} + +static void NotInRegisterError(char *name, char rclass) { + PPCError_Error(167, name, register_class_name[rclass]); +} + +static int isregisteroperand(char rclass) { + IARegister *reg; + + return (tk == TK_IDENTIFIER && (reg = InlineAsm_LookupRegisterPPCName(tkidentifier)) && reg->rclass == rclass); +} + +static SInt32 getcroperand(char rclass) { + SInt32 value; + IARegister *reg; + + value = 0; + if (tk == TK_IDENTIFIER && (reg = InlineAsm_LookupRegisterPPCName(tkidentifier)) && reg->rclass == rclass) { + value = reg->num; + } else { + PPCError_Error(167, tkidentifier->name); + } + + tk = lex(); + return value; +} + +static SInt32 getimmediateoperand(SInt32 minimum, SInt32 maximum) { + SInt32 value = InlineAsm_ConstantExpressionPPC(0); + if (value < minimum || value > maximum) + CError_Error(CErrorStr154); + return value; +} + +static void PrimaryExpressionPPC(IAExpr *expr, SInt32 value) { + Object *obj; + IALookupResult result; + IAExpr subexpr; + IAExprType type = IAExpr_0; + SInt32 v; + + switch (tk) { + case TK_IDENTIFIER: + if ((obj = isregisterstructpointeroperand())) { + tk = lex(); + InlineAsm_InitExpr5(expr, InlineAsm_StructPointerMemberOffset(TPTR_TARGET(obj->type))); + expr->object = obj; + return; + } + + if ((obj = isvariableoperand())) { + short reg; + InlineAsm_InitExpr5(expr, 0); + expr->xC = obj; + + if (obj->datatype == DLOCAL) + reg = 1; + else + reg = pic_base_reg; + + tk = lex(); + if (tk == '.' || tk == '[') { + InlineAsm_InitExpr5(&subexpr, InlineAsm_StructArrayMemberOffset(obj->type)); + DiadicOperatorPPC(expr, '+', &subexpr); + } + + if (tk == '+') { + tk = lex(); + InlineAsm_ExpressionPPC(&subexpr, value); + DiadicOperatorPPC(expr, '+', &subexpr); + } else if (tk == '-') { + tk = lex(); + InlineAsm_ExpressionPPC(&subexpr, value); + DiadicOperatorPPC(expr, '-', &subexpr); + } else if (!strcmp(tkidentifier->name, "@loword")) { + tk = lex(); + if (low_offset) { + InlineAsm_InitExpr5(&subexpr, low_offset); + DiadicOperatorPPC(expr, '+', &subexpr); + } + } else if (!strcmp(tkidentifier->name, "@hiword")) { + tk = lex(); + if (high_offset) { + InlineAsm_InitExpr5(&subexpr, high_offset); + DiadicOperatorPPC(expr, '+', &subexpr); + } + } + expr->reg = reg; + return; + } + + if (InlineAsm_LookupSymbolOrTag(tkidentifier, &result, 1)) { + if (result.has_value) { + tk = lex(); + InlineAsm_InitExpr5(expr, result.value); + return; + } + + if (result.type && (IS_TYPE_STRUCT(result.type) || IS_TYPE_CLASS(result.type))) { + tk = lex(); + if (tk != '.') + CError_Error(CErrorStr120); + + if (allow_array_expressions) { + InlineAsm_InitExpr5(expr, InlineAsm_StructArrayMemberOffset(result.type)); + return; + } + + InlineAsm_InitExpr5(expr, InlineAsm_StructMemberOffset(result.type)); + return; + } + + if (result.object && result.object->datatype == DABSOLUTE) { + tk = lex(); + InlineAsm_InitExpr5(expr, result.object->u.address); + return; + } + } else if (value) { + if (isregisteroperand(RegClass_CRFIELD)) { + InlineAsm_InitExpr5(expr, getcroperand(RegClass_CRFIELD)); + return; + } + if (isregisteroperand(RegClass_6)) { + InlineAsm_InitExpr5(expr, getcroperand(RegClass_6)); + return; + } + if (strlen(tkidentifier->name) == 6 && !strncmp(tkidentifier->name, "cr", 2) && tkidentifier->name[3] == '_') { + IARegister *reg; + char regname[4]; + regname[0] = tkidentifier->name[0]; + regname[1] = tkidentifier->name[1]; + regname[2] = tkidentifier->name[2]; + regname[3] = 0; + if ((reg = InlineAsm_LookupRegisterPPC(regname)) && reg->rclass == RegClass_CRFIELD) { + SInt32 v = reg->num * 4; + regname[0] = tkidentifier->name[4]; + regname[1] = tkidentifier->name[5]; + regname[2] = 0; + if ((reg = InlineAsm_LookupRegisterPPC(regname)) && reg->rclass == RegClass_6) { + tk = lex(); + InlineAsm_InitExpr5(expr, v + reg->num); + return; + } + } + } + } + + if (!strcmp("ha16", tkidentifier->name)) + type = IAExpr_8; + else if (!strcmp("hi16", tkidentifier->name)) + type = IAExpr_7; + else if (!strcmp("lo16", tkidentifier->name)) + type = IAExpr_6; + + if (type != IAExpr_0) { + tk = lex(); + if (tk == '(') { + SInt32 v; + tk = lex(); + PrimaryExpressionPPC(expr, value); + expr->type = type; + if (tk != ')') + CError_Error(CErrorStr115); + + tk = lex(); + if (InlineAsm_CheckExpr(expr)) { + expr->value = InlineAsm_GetExprValue(expr); + expr->type = IAExpr_5; + } + return; + } + + CError_Error(CErrorStr114); + } else { + if (!result.label) + result.label = InlineAsm_DeclareLabel(tkidentifier); + + InlineAsm_InitExpr5(expr, 0); + expr->flags |= IAFlag1; + expr->label = result.label; + tk = lex(); + return; + } + break; + + case TK_INTCONST: + v = CInt64_GetULong(&tkintconst); + tk = lex(); + InlineAsm_InitExpr5(expr, v); + return; + + case TK_SIZEOF: + InlineAsm_InitExpr5(expr, scansizeof()); + return; + + case '+': + tk = lex(); + PrimaryExpressionPPC(expr, value); + return; + + case '-': + tk = lex(); + PrimaryExpressionPPC(expr, value); + if (InlineAsm_CheckExpr(expr)) + expr->value = -expr->value; + else + CError_Error(CErrorStr124); + return; + + case '!': + tk = lex(); + PrimaryExpressionPPC(expr, value); + if (InlineAsm_CheckExpr(expr)) + expr->value = !expr->value; + else + CError_Error(CErrorStr124); + return; + + case '~': + tk = lex(); + PrimaryExpressionPPC(expr, value); + if (InlineAsm_CheckExpr(expr)) + expr->value = ~expr->value; + else + CError_Error(CErrorStr124); + return; + + case '(': + tk = lex(); + InlineAsm_ExpressionPPC(expr, value); + if (tk != ')') + CError_Error(CErrorStr115); + tk = lex(); + return; + + default: + CError_Error(CErrorStr120); + } + + InlineAsm_InitExpr5(expr, 0); +} + +static void DiadicOperatorPPC(IAExpr *left, short token, IAExpr *right) { + CInt64 leftval; + CInt64 rightval; + + CInt64_SetLong(&leftval, left->value); + CInt64_SetLong(&rightval, right->value); + rightval = CMach_CalcIntDiadic(TYPE(&stsignedint), leftval, token, rightval); + + if (left->xC) { + if (right->label) + PPCError_Error(124, left->xC->name->name, right->label->name->name); + + if (right->xC) { + if (left->x10) { + PPCError_Error(121, left->xC->name->name, left->x10->name->name, right->xC->name->name); + } else if (right->x10) { + PPCError_Error(121, left->xC->name->name, right->xC->name->name, right->x10->name->name); + } else if (token == '-') { + left->value = CInt64_GetULong(&rightval); + left->x10 = right->xC; + } else { + IllegalObjectOperator(left->xC->name, right->xC->name, token); + } + } else if (token == '-' || token == '+') { + left->value = CInt64_GetULong(&rightval); + } else { + IllegalObjectOperator(left->xC->name, NULL, token); + } + } else if (right->xC) { + if (right->label) + PPCError_Error(124, right->xC->name->name, right->label->name->name); + + if (token == '+') { + left->xC = right->xC; + left->x10 = right->x10; + left->value = CInt64_GetULong(&rightval); + } else { + IllegalObjectOperator(NULL, right->xC->name, token); + } + } else if (left->label) { + if (left->xC) + PPCError_Error(124, left->label->name->name, left->xC->name->name); + + if (right->label) { + if (left->x18) { + PPCError_Error(121, left->label->name->name, left->x18->name->name, right->label->name->name); + } else if (right->x18) { + PPCError_Error(121, left->label->name->name, right->label->name->name, right->x18->name->name); + } else if (token == '-') { + left->value = CInt64_GetULong(&rightval); + left->x18 = right->label; + } else { + IllegalObjectOperator(left->label->name, right->label->name, token); + } + } else if (token == '+' || token == '-') { + left->value = CInt64_GetULong(&rightval); + } else { + IllegalObjectOperator(NULL, left->label->name, token); + } + } else if (right->label) { + if (token == '+') { + left->label = right->label; + left->x18 = right->x18; + left->value = CInt64_GetULong(&rightval); + } else { + IllegalObjectOperator(NULL, right->label->name, token); + } + } else { + left->value = CInt64_GetULong(&rightval); + } + + left->flags |= right->flags; + if (left->type == IAOpnd_Lab) { + if (right->type != IAOpnd_Lab) + left->type = right->type; + } else { + if (right->type != IAOpnd_Lab && right->type != left->type) + PPCError_Error(126); + } +} + +static void ExpressionTailPPC(IAExpr *left, SInt32 value) { + IAExpr right; + short left_tk; + short right_prec; + + while (1) { + left_tk = tk; + tk = lex(); + + PrimaryExpressionPPC(&right, value); + right_prec = GetPrec(tk); + if (right_prec == 0) { + DiadicOperatorPPC(left, left_tk, &right); + break; + } + + if (GetPrec(left_tk) >= right_prec) { + DiadicOperatorPPC(left, left_tk, &right); + } else { + ExpressionTailPPC(&right, value); + DiadicOperatorPPC(left, left_tk, &right); + if (GetPrec(tk) == 0) + break; + } + } +} + +static void immediateoperand(IAOperand *op, SInt32 minval, SInt32 maxval) { + SInt32 value; + if (InlineAsm_gccmode && tk == '%') { + tk = lex(); + if (tk != TK_INTCONST) { + CError_Error(CErrorStr144); + } else { + CInt64 c = tkintconst; + value = CInt64_GetULong(&c); + if (value < 0) + CError_Error(CErrorStr144); + } + op->type = IAOpnd_7; + op->u.unk7.value = value; + op->u.unk7.unk1 = 1; + op->u.unk7.unk2 = 0; + op->u.unk7.unk3 = 0; + tk = lex(); + } else { + value = InlineAsm_ConstantExpressionPPC(0); + if (value < minval || value > maxval) + CError_Error(CErrorStr154); + op->type = IAOpnd_Imm; + op->u.imm.value = value; + } +} + +static SInt32 immediatevalue(IAOperand *op, SInt32 minval, SInt32 maxval) { + SInt32 value; + if (InlineAsm_gccmode && tk == '%') { + CError_Error(CErrorStr144); + return 0; + } else { + value = InlineAsm_ConstantExpressionPPC(0); + if (value < minval || value > maxval) + CError_Error(CErrorStr154); + op->type = IAOpnd_Imm; + op->u.imm.value = value; + return value; + } +} + +static void InlineAsm_ExpressionPPC(IAExpr *expr, SInt32 value) { + PrimaryExpressionPPC(expr, value); + if (GetPrec(tk)) + ExpressionTailPPC(expr, value); + if (GetPrec(tk)) + ExpressionTailPPC(expr, value); + + if (expr->type == IAExpr_5 && tk == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "@l")) { + expr->type = IAExpr_6; + tk = lex(); + } else if (!strcmp(tkidentifier->name, "@ha")) { + expr->type = IAExpr_8; + tk = lex(); + } else if (!strcmp(tkidentifier->name, "@h")) { + expr->type = IAExpr_7; + tk = lex(); + } + } +} + +static SInt32 InlineAsm_ConstantExpressionPPC(SInt32 value) { + IAExpr expr; + + InlineAsm_ExpressionPPC(&expr, value); + if (!InlineAsm_CheckExpr(&expr)) { + IllegalObjectInConst(&expr); + return 0; + } else { + return InlineAsm_GetExprValue(&expr); + } +} + +static SInt32 crbitoperand(void) { + SInt32 value = InlineAsm_ConstantExpressionPPC(1); + if (value < 0 || value > 31) + CError_Error(CErrorStr154); + return value; +} + +static void floatoperand(IAOperand *op, InlineAsm *ia, Type *type) { + Object *obj; + + obj = createfloatconstant(type, &tkfloatconst); + op[0].type = IAOpnd_Reg; + op[0].u.reg.rclass = RegClass_GPR; + op[0].u.reg.object = NULL; + op[0].u.reg.effect = EffectRead; + op[0].u.reg.num = pic_base_reg; + + ia->argcount++; + op[1].type = IAOpnd_4; + op[1].u.obj.obj = obj; + PPCError_Error(179); + op[1].u.obj.unk = IAExpr_2; + op[1].u.obj.offset = 0; + tk = lex(); +} + +static Object *isvariableoperand(void) { + IALookupResult result; + Object *obj; + + if (tk == TK_IDENTIFIER) { + InlineAsm_LookupSymbol(tkidentifier, &result); + if ((obj = result.object)) { + if (obj->datatype == DLOCAL) { + if (OBJECT_REG(obj)) + return NULL; + return obj; + } + + if (obj->datatype == DFUNC || obj->datatype == DVFUNC) + return obj; + + if (obj->datatype == DDATA) { + createIndirect(obj, 0, 0); + return obj; + } + } + } + + return NULL; +} + +static Object *isregisterstructpointeroperand(void) { + IALookupResult result; + Object *obj; + + if (tk != TK_IDENTIFIER) + return NULL; + + InlineAsm_LookupSymbol(tkidentifier, &result); + if ((obj = result.object)) { + if (obj->datatype != DLOCAL) + return NULL; + if (!OBJECT_REG(obj) && !is_register_object(obj)) + return NULL; + if (!IS_TYPE_POINTER(obj->type)) + return NULL; + if (!IS_TYPE_STRUCT(TPTR_TARGET(obj->type)) && !IS_TYPE_CLASS(TPTR_TARGET(obj->type))) + return NULL; + return obj; + } + + return NULL; +} + +static void memoryoperand(IAOperand *op, InlineAsm *ia, Boolean flag, short effect) { + IAExpr expr; + + InlineAsm_ExpressionPPC(&expr, 0); + if (expr.object) { + if (!flag) + CError_Error(CErrorStr155); + if (expr.xC) + PPCError_Error(122, expr.xC); + + op[0].type = IAOpnd_Reg; + op[0].u.reg.rclass = RegClass_GPR; + op[0].u.reg.object = expr.object; + op[0].u.reg.num = 0; + op[0].u.reg.effect = effect; + if (expr.object || expr.reg) + op[0].u.reg.effect = effect; + else + op[0].u.reg.effect = 0; + + ia->argcount++; + op[1].type = IAOpnd_Imm; + switch (expr.type) { + case IAExpr_5: + expr.type = IAExpr_6; + if (expr.object->datatype != DLOCAL || !OBJECT_REG(expr.object)) + PPCError_Error(180); + case IAExpr_2: + case IAExpr_6: + case IAExpr_7: + case IAExpr_8: + op[1].u.imm.value = InlineAsm_GetExprValue(&expr); + break; + default: + CError_Error(CErrorStr155); + } + + expr.object->flags |= OBJECT_FLAGS_UNUSED; + return; + } + + if (expr.xC) { + if (expr.x10) + PPCError_Error(123, expr.xC->name->name, expr.x10->name->name); + + if (flag) { + if (tk == '(') { + if (flag) { + tk = lex(); + registeroperand(op, RegClass_GPR, effect); + if ((expr.type == IAExpr_8 || expr.type == IAExpr_7) && copts.codegen_pic && pic_base_reg) + CError_Error(CErrorStr155); + if (tk != ')') + CError_Error(CErrorStr115); + tk = lex(); + } + } else { + op[0].type = IAOpnd_Reg; + op[0].u.reg.rclass = RegClass_GPR; + op[0].u.reg.object = expr.object; + op[0].u.reg.num = expr.reg; + } + + if (expr.object || expr.reg) + op[0].u.reg.effect = effect; + else + op[0].u.reg.effect = 0; + + ia->argcount++; + op++; + } + + if (expr.xC->datatype == DLOCAL) { + op[0].type = IAOpnd_4; + op[0].u.obj.unk = IAExpr_1; + } else { + op[0].type = IAOpnd_3; + if (expr.type == IAExpr_5) { + expr.type = IAExpr_6; + PPCError_Error(180); + } + op[0].u.obj.unk = expr.type; + } + + op[0].u.obj.obj = expr.xC; + op[0].u.obj.offset = expr.value; + expr.xC->flags |= OBJECT_FLAGS_UNUSED; + return; + } + + if (flag) { + if (tk == '(') { + tk = lex(); + registeroperand(op, RegClass_GPR, effect); + ia->argcount++; + op++; + if (tk != ')') + CError_Error(CErrorStr115); + tk = lex(); + } else { + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_GPR; + op->u.reg.object = expr.object; + op->u.reg.num = expr.reg; + ia->argcount++; + op++; + } + } + + if (expr.label) { + if (expr.x18) { + op->type = IAOpnd_LabDiff; + op->negated = 0; + op->u.labdiff.label1 = expr.label; + op->u.labdiff.label2 = expr.x18; + op->u.labdiff.offset = expr.value; + } else { + PPCError_Error(125, expr.label->name->name); + } + } else { + op->type = IAOpnd_Imm; + op->u.imm.value = InlineAsm_GetExprValue(&expr); + } +} + +static void registeroperand(IAOperand *op, char rclass, short effect) { + IARegister *reg; + Object *obj; + + if (tk == TK_IDENTIFIER && (reg = InlineAsm_LookupRegisterPPCName(tkidentifier)) && reg->rclass == rclass) { + SInt32 num; + obj = reg->object; + num = reg->num; + op->type = IAOpnd_Reg; + op->u.reg.rclass = rclass; + op->u.reg.object = obj; + op->u.reg.num = num; + op->u.reg.effect = effect; + if (obj) { + reg->object->flags |= OBJECT_FLAGS_UNUSED; + Registers_GetVarInfo(obj)->flags |= VarInfoFlag40; + } + } else if (rclass == RegClass_CRFIELD) { + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_CRFIELD; + op->u.reg.object = NULL; + op->u.reg.num = getimmediateoperand(0, 7); + op->u.reg.effect = effect; + return; + } else if (rclass == RegClass_SPR) { + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.object = NULL; + op->u.reg.num = getimmediateoperand(0, 1024); + op->u.reg.effect = effect; + return; + } else if (tk == '%' && InlineAsm_gccmode) { + SInt32 num; + tk = lex(); + if (tk != TK_INTCONST) { + CError_Error(CErrorStr144); + } else { + num = ExtractValue(tkintconst); + if (num < 0) + CError_Error(CErrorStr144); + } + + op->type = IAOpnd_6; + op->u.unk6.num = num; + op->u.unk6.unk4 = 2; + op->u.unk6.effect = effect; + op->u.unk6.rclass = rclass; + tk = lex(); + return; + } else if (tk == TK_IDENTIFIER) { + NotInRegisterError(tkidentifier->name, rclass); + } else { + PPCError_Error(171); + } + + tk = lex(); + if (!strcmp(tkidentifier->name, "@loword")) { + tk = lex(); + } else if (!strcmp(tkidentifier->name, "@hiword")) { + if (reg->object) + op->u.reg.num = 1; + else + PPCError_Error(168); + tk = lex(); + } else if (rclass == RegClass_GPR) { + if (reg->object && reg->object->type->size == 8) { + HashNameNode *name = reg->object->name; + PPCError_Error(127, name->name, name->name, name->name); + } + } +} + +static void cr0_operand(IAOperand *op, short effect) { + IARegister *reg; + + if ((reg = InlineAsm_LookupRegisterPPC("cr0"))) { + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_CRFIELD; + op->u.reg.object = reg->object; + op->u.reg.num = reg->num; + op->u.reg.effect = effect; + } else { + NotInRegisterError("cr0", RegClass_CRFIELD); + } +} + +static void r0_operand(IAOperand *op) { + IARegister *reg; + + if ((reg = InlineAsm_LookupRegisterPPC("r0"))) { + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_GPR; + op->u.reg.object = reg->object; + op->u.reg.num = reg->num; + op->u.reg.effect = 0; + tk = lex(); + } else { + NotInRegisterError("r0", RegClass_GPR); + } +} + +static void labeloperand(InlineAsm *ia, IAOperand *op, Boolean flag1, Boolean flag2, Boolean flag3) { + IALookupResult result; + + if (tk == TK_IDENTIFIER) { + if (!InlineAsm_LookupSymbol(tkidentifier, &result)) + result.label = InlineAsm_DeclareLabel(tkidentifier); + + if (result.label) { + op->type = IAOpnd_Lab; + op->u.lab.label = result.label; + } else if (result.object && result.object->datatype == DFUNC) { + if (flag3) + ia->flags |= IAFlag2; + op->type = IAOpnd_3; + op->u.obj.obj = result.object; + op->u.obj.offset = 0; + + if (flag1) { + op->u.obj.unk = IAExpr_4; + if (flag2) + CError_Error(CErrorStr261); + } else { + op->u.obj.unk = IAExpr_2; + if (flag2) + op->u.obj.unk = IAExpr_10; + op->u.obj.unk = IAExpr_6; + PPCError_Error(180); + } + } else { + CError_Error(CErrorStr144); + } + + tk = lex(); + } else if (tk == '*') { + if (!flag2) { + tk = lex(); + if (tk == '+') { + tk = lex(); + if (flag1) + immediateoperand(op, -0x2000000, 0x1FFFFFF); + else + immediateoperand(op, -0x8000, 0xFFFF); + } else if (tk == '-') { + tk = lex(); + op->u.imm.value = flag1 ? -immediatevalue(op, -0x1FFFFFF, 0x2000000) : -immediatevalue(op, -0x7FFF, 0x10000); + } else { + CError_Error(CErrorStr144); + } + } else { + CError_Error(CErrorStr144); + } + } else { + if (flag2) { + if (flag1) + immediateoperand(op, -0x2000000, 0x1FFFFFF); + else + immediateoperand(op, -0x8000, 0xFFFF); + } else { + CError_Error(CErrorStr144); + } + } +} + +static void imm_or_labeldiff_operand(InlineAsm *ia, IAOperand *op, SInt32 minimum, SInt32 maximum, Boolean negate) { + IAExpr expr; + Object *obj; + SInt32 value; + + InlineAsm_ExpressionPPC(&expr, 0); + + if ((obj = expr.xC) && !expr.x10 && expr.type == IAExpr_5 && obj->datatype == DDATA && IS_TYPE_INT_OR_ENUM(obj->type) && (obj->qual & Q_10000)) { + switch (ia->opcode) { + case PC_ADDI: + case PC_ADDIC: + case PC_ADDICR: + case PC_ADDIS: + case PC_ORI: + case PC_ORIS: + if (ia->args[1].u.imm.value) { + SInt32 cmp; + if (obj->datatype != DLOCAL) { + cmp = copts.codegen_pic ? INVALID_PIC_REG : NO_REG; + } else { + cmp = local_base_register(obj); + } + if (ia->args[1].u.imm.value == cmp) + break; + } + case PC_LI: + case PC_LIS: + case PC_TWI: + case PC_OPWORD: + InlineAsm_InitExpr5(&expr, expr.value + CInt64_GetULong(&obj->u.data.u.intconst)); + break; + } + } + + if (expr.label) { + if (expr.x18) { + op->type = IAOpnd_LabDiff; + if (negate) + op->negated = 1; + else + op->negated = 0; + op->u.labdiff.label1 = expr.label; + op->u.labdiff.label2 = expr.x18; + op->u.labdiff.offset = expr.value; + } else { + PPCError_Error(125, expr.label->name->name); + } + return; + } + + if (expr.xC) { + if (!expr.x10) { + if (ia->opcode != PC_OPWORD && expr.type == IAExpr_5) { + IllegalObjectInConst(&expr); + return; + } + + if (expr.xC->datatype == DLOCAL) { + op->type = IAOpnd_4; + op->u.obj.unk = IAExpr_1; + } else { + op->type = IAOpnd_3; + if (expr.type == IAExpr_5) { + expr.type = IAExpr_6; + PPCError_Error(180); + } + op->u.obj.unk = expr.type; + } + op->u.obj.obj = expr.xC; + op->u.obj.offset = expr.value; + } else { + PPCError_Error(123, expr.xC->name->name, expr.x10->name->name); + } + return; + } + + value = InlineAsm_GetExprValue(&expr); + if (value < minimum || value > maximum) + CError_Error(CErrorStr154); + + op->type = IAOpnd_Imm; + if (negate) + op->u.imm.value = -value; + else + op->u.imm.value = value; +} + +static void eatcommatoken(void) { + if (tk == ',') + tk = lex(); + else + CError_Error(CErrorStr116); +} + +static InlineAsm *InlineAsm_ScanAssemblyOperands(IAMnemonic *mnemonic) { + OpcodeInfo *info; + InlineAsm *ia; + SInt32 buffersize; + IAOperand *op; + int argcount; + char *format; + IARegister *reg; + + char code; + short effect; + Boolean has_excl; + Boolean has_question; + Boolean negate; + UInt32 t; + + info = &opcodeinfo[mnemonic->x4]; + argcount = info->x8; + if (PCODE_FLAG_SET_F(info) & fPCodeFlag8000000) + argcount++; + if (!(PCODE_FLAG_SET_F(info) & fPCodeFlag10000000) && (PCODE_FLAG_SET_F(info) & fPCodeFlag4000000)) + argcount++; + if (PCODE_FLAG_SET_T(info) & fPCodeFlag2000000) + argcount++; + + buffersize = sizeof(InlineAsm) + sizeof(IAOperand) * argcount; + ia = galloc(buffersize); + memset(ia, 0, buffersize); + + ia->opcode = mnemonic->x4; + ia->flags = 0; + ia->argcount = 0; + + op = ia->args; + for (format = mnemonic->format; *format; format++) { +#line 1664 + CError_ASSERT(ia->argcount < argcount); + + if (*format == ',') { + eatcommatoken(); + format++; + } else if (*format == ';') { + format++; + } + + if (*format == '[' || *format == '(') + format++; + + effect = EffectRead; + has_excl = 0; + has_question = 0; + negate = 0; + if (*format == '=') { + effect = EffectWrite; + format++; + } else if (*format == '+') { + effect = EffectRead | EffectWrite; + format++; + } + + if (*format == '-') { + negate = 1; + format++; + } + + if (*format == '?') { + has_question = 1; + format++; + } + + if (*format == '!') { + has_excl = 1; + format++; + } + + switch (*format) { + case 'p': + continue; + case '&': + if (format[1] == '2') { + op[0] = op[-2]; + format++; + if (op->type == IAOpnd_Reg) + op->u.reg.effect = effect; + ia->argcount++; + + op[1] = op[-1]; + op++; + if (op->type == IAOpnd_Reg) + op->u.reg.effect = effect; + } else { + op[0] = op[-1]; + if (op->type == IAOpnd_Reg) + op->u.reg.effect = effect; + } + break; + + case '%': { + SInt32 value; + format += pcode_const_from_format(format + 1, &value); + op->type = IAOpnd_Imm; + op->u.imm.value = value; + break; + } + + case 'b': + if (!isregisteroperand(RegClass_GPR)) { + if (tk == TK_INTCONST && tkintconst.lo == 0) + r0_operand(op); + } else { + registeroperand(op, RegClass_GPR, effect); + if (op->u.reg.object == NULL && op->u.reg.num == 0) + op->u.reg.effect = 0; + } + break; + + case 'r': + registeroperand(op, RegClass_GPR, effect); + break; + + case 'B': + case 'a': + case 'i': + case 't': + case 'u': + case 'x': + { + SInt32 value, hi, lo; + code = *format; + value = 16; + if (code == 'a') { + if (isdigit(format[1])) { + code = *(++format); + } else { +#line 1804 + CError_FATAL(); + } + } + + if (isdigit(format[1])) { + format += pcode_const_from_format(format + 1, &value); + } else if (code == 't' || code == 'B') { + code = 'u'; + value = 5; + } + + pcode_get_hi_lo(value, code, &hi, &lo); + if (!has_question || tk == ',') { + if (has_question) + tk = lex(); + if (has_excl) + getimmediateoperand(lo, hi); + else + immediateoperand(op, lo, hi); + } else { + op->type = IAOpnd_Imm; + op->u.imm.value = 0; + } + + if (code == 'i' && value == 16) + op->u.imm.value = (short) op->u.imm.value; + if (negate) + op->u.imm.value = -op->u.imm.value; + + if (pcode_check_imm_bits(op->u.imm.value, value, code)) { +#line 1838 + CError_FATAL(); + } + + break; + } + + case 'O': + if (tk == TK_INTCONST && tkintconst.lo == 0) { + getimmediateoperand(0, 0); + eatcommatoken(); + } + continue; + + case 'f': + registeroperand(op, RegClass_FPR, effect); + break; + + case 'v': + registeroperand(op, RegClass_VR, effect); + break; + + case 'T': + if (!has_question || tk == ',') { + if (has_question) + tk = lex(); + + immediateoperand(op, 268, 269); + if (op->u.reg.num == 268) + op->u.reg.num = 284; + else + op->u.reg.num = 285; + } else { + op->u.reg.num = 284; + } + + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.effect = effect; + break; + + case 'S': + { + SInt32 value; + format += pcode_const_from_format(format + 1, &value); + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.num = value; + op->u.reg.effect = effect; + break; + } + + case 'c': + if (has_question) { + if (isregisteroperand(RegClass_CRFIELD) || tk == TK_INTCONST) { + registeroperand(op, RegClass_CRFIELD, effect); + } else { + cr0_operand(op, effect); + if (format[1] == ',') + format++; + } + } else { + registeroperand(op, RegClass_CRFIELD, effect); + } + break; + + case 'l': + switch (ia->opcode) { + case PC_B: + case PC_BL: + labeloperand(ia, op, 1, mnemonic->x10 & 2, mnemonic->x10 & 1); + break; + default: + labeloperand(ia, op, 0, mnemonic->x10 & 2, mnemonic->x10 & 1); + break; + } + break; + + case 'w': + imm_or_labeldiff_operand(ia, op, -0x80000000, 0x7FFFFFFF, negate); + break; + + case 'M': + case 'm': + case 'n': + imm_or_labeldiff_operand(ia, op, -0x8000, 0xFFFF, negate); + break; + + case 'Q': + { + SInt32 cr = crbitoperand(); + op->type = IAOpnd_Reg; + op->u.reg.num = cr >> 2; + op->u.reg.rclass = RegClass_CRFIELD; + op->u.reg.effect = effect; + + ia->argcount++; + op[1].type = IAOpnd_Imm; + op[1].u.imm.value = cr % 4; + op++; + break; + } + + case 'd': { + short effect2; +#line 1971 + CError_ASSERT(format[1] == '('); + format++; + effect2 = EffectRead; + if (format[1] == '=') { + effect2 = EffectWrite; + format++; + } else if (format[1] == '+') { + effect2 = EffectRead | EffectWrite; + format++; + } + +#line 1983 + CError_ASSERT(format[1] == 'b'); +#line 1985 + CError_ASSERT(format[2] == ')'); + format += 2; + + switch (ia->opcode) { + case PC_LFS: + if (tk == TK_FLOATCONST) + floatoperand(op, ia, TYPE(&stfloat)); + else + memoryoperand(op, ia, 1, effect2); + break; + case PC_LFD: + if (tk == TK_FLOATCONST) + floatoperand(op, ia, TYPE(&stdouble)); + else + memoryoperand(op, ia, 1, effect2); + break; + default: + memoryoperand(op, ia, 1, effect2); + } + + break; + } + + case 'N': + immediateoperand(op, 1, 32); + break; + + case 's': + registeroperand(op, RegClass_SPR, effect); + break; + + case 'D': + if (tk == TK_IDENTIFIER && (reg = InlineAsm_LookupDCRRegister(tkidentifier->name))) { + op->type = IAOpnd_Imm; + op->u.imm.value = reg->num; + } else { + immediateoperand(op, 0, 1023); + } + break; + + case 'Y': + { + SInt32 mask = 255; + SInt32 i; + if (ia->opcode == PC_MTCRF) { + if (ia->args[0].type != IAOpnd_Imm) + CError_Error(CErrorStr144); + mask = ia->args[0].u.imm.value; + } + for (i = 0; i < 8; i++) { + if ((0x80 >> i) & mask) { + op->type = IAOpnd_Reg; + op->u.reg.num = i; + op->u.reg.rclass = RegClass_CRFIELD; + op->u.reg.effect = effect; + ia->argcount++; + op++; + } + } + ia->argcount--; + op--; + break; + } + + case 'P': + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.object = NULL; + if (format[1] == '3') { + format++; + op->u.reg.num = getimmediateoperand(0, 7); + } else { + op->u.reg.num = getimmediateoperand(0, 3); + } + op->u.reg.effect = effect; + break; + + case 'C': + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.object = NULL; + op->u.reg.num = 9; + op->u.reg.effect = effect; + break; + + case 'L': + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.object = NULL; + op->u.reg.num = 8; + op->u.reg.effect = effect; + break; + + case 'X': + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.object = NULL; + op->u.reg.num = 1; + op->u.reg.effect = effect; + break; + + case 'Z': + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_CRFIELD; + op->u.reg.object = NULL; + t = info->flags & 0xC0000000; + if (t == 0x40000000) { + op->u.reg.num = 1; + } else if (t == 0xC0000000) { + op->u.reg.num = 6; + } else { + op->u.reg.num = 0; + } + op->u.reg.effect = effect; + break; + + default: +#line 2266 + CError_FATAL(); + } + + while (format[1] && strchr("/<>|*", format[1])) { + int index; + SInt32 value; + SInt32 value2; + IAOperand tmp; + switch ((code = *(++format))) { + case '/': + index = -1; + if (format[1] == '2') { + index = -2; + format++; + } + + tmp = op[index]; + op[index] = op[0]; + op[0] = tmp; + break; + case '*': + case '<': + case '>': + case '|': + if (op->type == IAOpnd_Imm) { + value = op->u.imm.value; + } else if (op->type == IAOpnd_Reg) { + value = op->u.reg.num; + } else { +#line 2312 + CError_FATAL(); + } + + if (format[1] == 'p') { + format++; + if (op[-1].type == IAOpnd_Imm) { + value2 = op[-1].u.imm.value; + } else if (op[-1].type == IAOpnd_Reg) { + value2 = op[-1].u.reg.num; + } else { +#line 2322 + CError_FATAL(); + } + } else if (isdigit(format[1])) { + format += pcode_const_from_format(format + 1, &value2); + } else { +#line 2327 + CError_FATAL(); + } + + switch (code) { + case '<': + value = value2 - value; + break; + case '>': + value = value - value2; + break; + case '|': + value = value + value2; + break; + case '*': + value = value * value2; + break; + default: +#line 2348 + CError_FATAL(); + } + + if (op->type == IAOpnd_Imm) { + op->u.imm.value = value; + } else if (op->type == IAOpnd_Reg) { + op->u.reg.num = value; + } else { +#line 2355 + CError_FATAL(); + } + break; + } + } + + ia->argcount++; + op++; + if (format[1] == ']' || format[1] == ')') + format++; + } + + return ia; +} + +static int mnemonic_has_overflow(char *buf) { + int result = 0; + + if (buf[strlen(buf) - 1] == 'o') { + if (!strcmp(buf, "bso")) + return 0; + if (!strcmp(buf, "fcmpo")) + return 0; + if (!strcmp(buf, "eieio")) + return 0; + if (!strcmp(buf, "vslo")) + return 0; + if (!strcmp(buf, "vsro")) + return 0; + result = 1; + } + + return result; +} + +static int mnemonic_has_absolute(char *buf) { + int result = 0; + char last = buf[strlen(buf) - 1]; + + if (buf[0] == 'b' && last == 'a') + result = 1; + + return result; +} + +static int mnemonic_has_linkregister(char *buf) { + int result = 0; + char last = buf[strlen(buf) - 1]; + + if (buf[0] == 'b' && last == 'l') + result = 1; + + return result; +} + +static int mnemonic_has_record(char *buf) { + int result = 0; + + if (lookahead() == '.') { + tk = lex(); + result = 1; + strcat(buf, "."); + } + + return result; +} + +static void installregistervariables(void) { +} + +void InlineAsm_InitializePPC(void) { + Test_Version_Numbers(); + allow_array_expressions = 1; + supports_hardware_fpu = 1; + assembledinstructions = 0; + + switch (copts.cpu) { + case CPU_PPC401: cpu = CPUMask_401; break; + case CPU_PPC403: cpu = CPUMask_403; break; + case CPU_PPC505: cpu = CPUMask_50x; break; + case CPU_PPC509: cpu = CPUMask_50x; break; + case CPU_PPC555: cpu = CPUMask_55x_56x; break; + case CPU_PPC556: cpu = CPUMask_55x_56x; break; + case CPU_PPC565: cpu = CPUMask_55x_56x; break; + case CPU_PPC601: cpu = CPUMask_601; break; + case CPU_PPC602: cpu = CPUMask_602; break; + case CPU_PPC8240: cpu = CPUMask_8240; break; + case CPU_PPC8260: cpu = CPUMask_8260; break; + case CPU_PPC603: cpu = CPUMask_603; break; + case CPU_PPC603e: cpu = CPUMask_603; break; + case CPU_PPC604: cpu = CPUMask_604; break; + case CPU_PPC604e: cpu = CPUMask_604; break; + case CPU_PPC740: cpu = CPUMask_740_750; break; + case CPU_PPC750: cpu = CPUMask_740_750; break; + case CPU_PPC801: cpu = CPUMask_801_821_860; break; + case CPU_PPC821: cpu = CPUMask_801_821_860; break; + case CPU_PPC823: cpu = CPUMask_823_850; break; + case CPU_PPC850: cpu = CPUMask_823_850; break; + case CPU_PPC860: cpu = CPUMask_801_821_860; break; + case CPU_PPC7400: case CPU_PPC7450: cpu = CPUMask_74xx; break; + case CPU_Generic: cpu = CPUMask_Generic; break; + default: +#line 2613 + CError_FATAL(); + } + + if (copts.altivec_model) + cpu |= 0x40000000; +} + +void InlineAsm_Initialize(UInt8 assemblertype) { + assembler_type = assemblertype; + + if (assembler_type == 0) { + InlineAsm_InitializePPC(); + pic_base_reg = INVALID_PIC_REG; + } else { + pic_base_reg = 0; + pic_base_label = NULL; + } + + InlineAsm_InitializeMnemonicsPPC(); + InlineAsm_InitializeRegisters(); + InlineAsm_InitializeRegistersPPC(); + + if (assembler_type == 0) { + installregistervariables(); + } else { + process_arguments(setup_assembly_argument, 0); + assign_local_addresses(); + } +} + +static IAEntryPoint *InlineAsm_CreateEntryPoint(HashNameNode *name, Boolean flag) { + Object *obj; + IAEntryPoint *ep; + IALookupResult result; + + if (InlineAsm_LookupSymbol(name, &result) && (obj = result.object)) { + if (!(obj->datatype == DFUNC && !(obj->flags & OBJECT_FLAGS_4))) + CError_Error(CErrorStr122, name->name); + + obj->flags |= OBJECT_FLAGS_4; + obj->sclass = flag ? TK_STATIC : TK_EXTERN; + + ep = lalloc(sizeof(IAEntryPoint)); + memclrw(ep, sizeof(IAEntryPoint)); + ep->x0 = IADirective_Entry; + ep->x2 = 1; + ep->x8 = obj; + ep->size = assembledinstructions * 4; + } else { + CError_Error(CErrorStr140, name->name); + } + + return ep; +} + +static InlineAsm *InlineAsm_CreateFrFree(void) { + InlineAsm *ia = lalloc(sizeof(InlineAsm)); + memclrw(ia, sizeof(InlineAsm)); + ia->opcode = IADirective_FrFree; + ia->flags = IAFlag1; + return ia; +} + +SInt32 InlineAsm_IsDirective(UInt8 assemblertype) { + char *name; + SInt32 directive = IADirective_Null; + + if (tk == '.') + tk = lex(); + + if (tk == TK_IDENTIFIER) { + name = tkidentifier->name; + if (!strcmp(name, "machine")) { + directive = IADirective_Machine; + } else if (assemblertype == 1) { + if (!strcmp(name, "entry")) { + directive = IADirective_Entry; + } else if (!strcmp(name, "fralloc")) { + directive = IADirective_FrAlloc; + } else if (!strcmp(name, "nofralloc")) { + directive = IADirective_NoFrAlloc; + } else if (!strcmp(name, "frfree")) { + directive = IADirective_FrFree; + } else if (!strcmp(name, "smclass")) { + directive = IADirective_SmClass; + } else if (!strcmp(name, "picbase")) { + directive = IADirective_PicBase; + } else { + directive = IADirective_Null; + } + } + } + + return directive; +} + +void InlineAsm_ProcessDirective(SInt32 directive) { + Boolean flag; + Statement *stmt; + IAOperand op; + + switch (directive) { + case IADirective_Entry: + flag = 0; + tk = lex(); + if (tk == TK_STATIC) { + flag = 1; + tk = lex(); + } else if (tk == TK_EXTERN) { + tk = lex(); + } + + if (tk != TK_IDENTIFIER) + CError_Error(CErrorStr107); + + stmt = CFunc_AppendStatement(ST_ASM); + stmt->expr = NULL; + stmt->expr = (ENode *) InlineAsm_CreateEntryPoint(tkidentifier, flag); + stmt->sourceoffset = -1; + tk = lex(); + break; + + case IADirective_FrAlloc: + if (assembledinstructions) + CError_Error(CErrorStr166); + if (asm_alloc_flags[0]) + CError_Error(CErrorStr165); + if (asm_alloc_flags[1] || asm_alloc_flags[2]) + CError_Error(CErrorStr166); + + tk = lex(); + if (tk != TK_NEG7 && tk != ';') + fralloc_parameter_area_size = getimmediateoperand(0x20, 0x7FFE); + + requires_frame = 1; + asm_alloc_flags[0] = 1; + break; + + case IADirective_NoFrAlloc: + if (asm_alloc_flags[0] || asm_alloc_flags[1]) + CError_Error(CErrorStr165); + if (asm_alloc_flags[2]) + CError_Error(CErrorStr166); + if (assembledinstructions) + CError_Error(CErrorStr166); + tk = lex(); + + asm_alloc_flags[1] = 1; + user_responsible_for_frame = 1; + break; + + case IADirective_FrFree: + if (asm_alloc_flags[1] || asm_alloc_flags[2]) + CError_Error(CErrorStr166); + + asm_alloc_flags[2] = 1; + stmt = CFunc_AppendStatement(ST_ASM); + stmt->expr = NULL; + stmt->expr = (ENode *) InlineAsm_CreateFrFree(); + if (copts.isGeneratingDebugInfo) + stmt->sourceoffset = CPrep_GetFileOffsetInfo(&cparser_fileoffset); + else + stmt->sourceoffset = -1; + tk = lex(); + break; + + case IADirective_Machine: + tk = lex(); + if (tk == TK_INTCONST) { + switch (tkintconst.lo) { + case 401: cpu = CPUMask_401; break; + case 403: cpu = CPUMask_403; break; + case 505: cpu = CPUMask_50x; break; + case 509: cpu = CPUMask_50x; break; + case 555: cpu = CPUMask_55x_56x; break; + case 556: cpu = CPUMask_55x_56x; break; + case 565: cpu = CPUMask_55x_56x; break; + case 601: cpu = CPUMask_601; break; + case 602: cpu = CPUMask_602; break; + case 8240: cpu = CPUMask_8240; break; + case 8260: cpu = CPUMask_8260; break; + case 603: cpu = CPUMask_603; break; + case 604: cpu = CPUMask_604; break; + case 740: cpu = CPUMask_740_750; break; + case 750: cpu = CPUMask_740_750; break; + case 801: cpu = CPUMask_801_821_860; break; + case 821: cpu = CPUMask_801_821_860; break; + case 823: cpu = CPUMask_823_850; break; + case 850: cpu = CPUMask_823_850; break; + case 860: cpu = CPUMask_801_821_860; break; + case 7400: cpu = CPUMask_74xx; break; + default: + CError_Error(CErrorStr144); + } + } else if (tk == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "all")) { + cpu = CPUMask_All; + } else if (!strcmp(tkidentifier->name, "generic")) { + cpu = CPUMask_Generic; + } else if (!strcmp(tkidentifier->name, "603e")) { + cpu = CPUMask_603; + } else if (!strcmp(tkidentifier->name, "604e")) { + cpu = CPUMask_604; + } else if (!strcmp(tkidentifier->name, "PPC603e")) { + cpu = CPUMask_603; + } else if (!strcmp(tkidentifier->name, "PPC604e")) { + cpu = CPUMask_604; + } else if (!strcmp(tkidentifier->name, "altivec")) { + cpu = CPUMask_74xx; + } else { + CError_Error(CErrorStr144); + } + } else { + CError_Error(CErrorStr144); + } + tk = lex(); + break; + + case IADirective_SmClass: + tk = lex(); + if (tk == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "PR")) + sm_section = 1; + else + CError_Error(CErrorStr144); + } else { + CError_Error(CErrorStr144); + } + tk = lex(); + break; + + case IADirective_PicBase: + tk = lex(); + registeroperand(&op, RegClass_GPR, EffectRead); + + if (!(op.type == IAOpnd_Reg && op.u.reg.object == NULL)) + CError_Error(CErrorStr144); + + tk = lex(); + if (tk == TK_IDENTIFIER) { + savepicbase(op.u.reg.num, tkidentifier); + tk = lex(); + } else { + CError_Error(CErrorStr144); + } + break; + + default: + CError_Error(CErrorStr261); + } +} + +void InlineAsm_ScanAssemblyDirective(void) { + SInt32 directive; + + if ((directive = InlineAsm_IsDirective(assembler_type)) != IADirective_Null) + InlineAsm_ProcessDirective(directive); +} + +void InlineAsm_ScanAssemblyInstruction(void) { + Statement *stmt; + InlineAsm *ia; + IAMnemonic *mnemonic; + Boolean record_flag; + Boolean flag3; + Boolean flag4; + Boolean flag5; + Boolean flag1; + Boolean flag2; + SInt32 directive; + char buf[20]; + + flag1 = 0; + flag2 = 0; + if ((directive = InlineAsm_IsDirective(assembler_type)) != IADirective_Null) { + InlineAsm_ProcessDirective(directive); + return; + } + + stmt = CFunc_AppendStatement(ST_ASM); + stmt->expr = NULL; + if (copts.isGeneratingDebugInfo) + stmt->sourceoffset = CPrep_GetFileOffsetInfo(&cparser_fileoffset); + else + stmt->sourceoffset = -1; + + strncpy(buf, tkidentifier->name, sizeof(buf)); + record_flag = mnemonic_has_record(buf); + mnemonic = InlineAsm_LookupMnemonicPPC(buf); + if (!mnemonic) + CError_Error(CErrorStr261); + + flag3 = (FLAG_SET_F(opcodeinfo[mnemonic->x4].flags) & fPCodeFlag4000000) && (mnemonic->x10 & 0x400); + flag4 = (FLAG_SET_T(opcodeinfo[mnemonic->x4].flags) & fPCodeFlag20000000) && (mnemonic->x10 & 2); + flag5 = (FLAG_SET_T(opcodeinfo[mnemonic->x4].flags) & fPCodeFlag2000000) && (mnemonic->x10 & 1); + + if ((cpu == CPUMask_Generic) && (cpu & CPUFLAG_LOW_MASK) != ((cpu & mnemonic->cpu) & CPUFLAG_LOW_MASK)) { + CError_Error(CErrorStr152); + } else if (((cpu & mnemonic->cpu) & CPUFLAG_LOW_MASK) == 0) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_10000000) && !(cpu & CPUFLAG_10000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_8000000) && !(cpu & CPUFLAG_8000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_2000000) && !(cpu & CPUFLAG_2000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_4000000) && !(cpu & CPUFLAG_4000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_1000000) && !(cpu & CPUFLAG_1000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_40000000) && !(cpu & CPUFLAG_40000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_20000000) && !(cpu & CPUFLAG_20000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_800000) && !(cpu & CPUFLAG_800000)) { + CError_Error(CErrorStr152); + } + + tk = lex(); + if (tk == '+' || tk == '-') { + if ( + ((OPCODE_PART_1(mnemonic->x10) == 16) && (OPCODE_PART_2(mnemonic->x10) != 20)) || + ((OPCODE_PART_1(mnemonic->x10) == 19) && (OPCODE_PART_3(mnemonic->x10) == 528) && (OPCODE_PART_2(mnemonic->x10) != 20)) || + ((OPCODE_PART_1(mnemonic->x10) == 19) && (OPCODE_PART_3(mnemonic->x10) == 16) && (OPCODE_PART_2(mnemonic->x10) != 20)) + ) { + if (tk == '+') + flag1 = 1; + else if (tk == '-') + flag2 = 1; + tk = lex(); + } else { + CError_Error(CErrorStr120); + } + } + + stmt->expr = (ENode *) InlineAsm_ScanAssemblyOperands(mnemonic); + + ia = (InlineAsm *) stmt->expr; + if (record_flag) + ia->flags2 |= IAFlagsB_1; + if (flag3) + ia->flags2 |= IAFlagsB_2; + if (flag4) + ia->flags2 |= IAFlagsB_4; + if (flag5) + ia->flags2 |= IAFlagsB_8; + if (flag1) + ia->flags2 |= IAFlagsB_10; + if (flag2) + ia->flags2 |= IAFlagsB_20; + if (volatileasm) + ia->flags2 |= IAFlagsB_40; + + ++assembledinstructions; +} + +static PCode *InlineAsm_TranslateIRtoPCodePPC(InlineAsm *ia, int argcount, UInt8 assemblertype) { + OpcodeInfo *info; + PCode *pc; + int index; + int extra_args; + int reg; + int newargcount; + SInt32 buffersize; + IAOperand *src; + PCodeArg *dest; + + info = &opcodeinfo[ia->opcode]; + index = 0; + extra_args = 0; + reg = 0; + + if ((PCODE_FLAG_SET_F(info) & fPCodeFlag8000000) && !(PCODE_FLAG_SET_F(info) & fPCodeFlag20000000)) + extra_args++; + + if (!(PCODE_FLAG_SET_F(info) & fPCodeFlag10000000) && (PCODE_FLAG_SET_F(info) & fPCodeFlag4000000)) + extra_args++; + + if (argcount < ia->argcount) { + if ((argcount + extra_args) >= ia->argcount) { + extra_args -= (ia->argcount - argcount); + argcount = ia->argcount; + } else { +#line 3317 + CError_FATAL(); + } + } + + if (ia->opcode == PC_B && ia->args[0].type == IAOpnd_Imm) + ia->flags2 |= IAFlagsB_40; + + if (ia->opcode == PC_TWI || ia->opcode == PC_TW || ia->opcode == PC_TRAP || ia->opcode == PC_SC) + ia->flags |= IAFlag2; + + if (ia->flags & IAFlag2) { + newargcount = argcount + branch_count_volatiles(); + if (copts.exceptions && current_statement && assembler_type == 0) + newargcount += countexceptionactionregisters(current_statement->dobjstack); + + buffersize = sizeof(PCode) + sizeof(PCodeArg) * (newargcount + extra_args); + pc = lalloc(buffersize); + memset(pc, 0, buffersize); + pc->argCount = newargcount; + } else if (ia->opcode == PC_STMW || ia->opcode == PC_LMW) { + reg = ia->args[0].u.reg.object ? OBJECT_REG(ia->args[0].u.reg.object) : ia->args[0].u.reg.num; + newargcount = argcount + (32 - reg); + + buffersize = sizeof(PCode) + sizeof(PCodeArg) * newargcount; + pc = lalloc(buffersize); + memset(pc, 0, buffersize); + pc->argCount = newargcount; + } else { + buffersize = sizeof(PCode) + sizeof(PCodeArg) * (argcount + extra_args); + pc = lalloc(buffersize); + memset(pc, 0, buffersize); + pc->argCount = (ia->argcount > argcount) ? ia->argcount : argcount; + } + + pc->op = ia->opcode; + pc->flags = info->flags; + pc->sourceoffset = current_statement ? current_statement->sourceoffset : -1; + + dest = pc->args; + src = ia->args; + argcount += extra_args; + while (index < argcount) { + if (index >= ia->argcount) { + dest->kind = PCOp_PLACEHOLDEROPERAND; + } else { + switch (src->type) { + case IAOpnd_0: + dest->kind = PCOp_PLACEHOLDEROPERAND; + break; + + case IAOpnd_Imm: + dest->kind = PCOp_IMMEDIATE; + dest->data.imm.value = src->u.imm.value; + if (pc->flags & (fPCodeFlag2 | fPCodeFlag4)) + pc->flags |= fPCodeFlag20; + dest->data.imm.obj = NULL; + break; + + case IAOpnd_Reg: { + int r20; + r20 = 0; + if (src->u.reg.object) { + if (Registers_GetVarInfo(src->u.reg.object)->flags & VarInfoFlag2) { + if (src->u.reg.num == 1) + r20 = OBJECT_REG_HI(src->u.reg.object); + else + r20 = OBJECT_REG(src->u.reg.object); + } else { + if (Registers_GetVarInfo(src->u.reg.object)->flags & VarInfoFlag40) + PPCError_Error(172, src->u.reg.object->name->name); + else + PPCError_Error(167, src->u.reg.object->name->name); + } + } else if (src->u.reg.num == INVALID_PIC_REG) { + r20 = pic_base_reg; + } else { + r20 = src->u.reg.num; + } + + dest->kind = PCOp_REGISTER; + dest->arg = src->u.reg.rclass; + dest->data.reg.reg = r20; + dest->data.reg.effect = src->u.reg.effect; + if (pc->op == PC_RLWIMI && (dest->data.reg.effect & EffectWrite) && dest->arg == RegClass_GPR && !(dest->data.reg.effect & EffectRead)) { +#line 3442 + CError_FATAL(); + } + + if (dest->arg == RegClass_SPR) { + int i; + dest->kind = PCOp_SYSREG; + for (i = 0; i < 4; i++) { + if (dest->data.reg.reg == spr_to_sysreg[i]) { + dest->kind = PCOp_REGISTER; + dest->arg = RegClass_SPR; + dest->data.reg.reg = i; + break; + } + } + pcsetsideeffects(pc); + } else if (dest->arg == RegClass_6 || dest->arg == RegClass_DCR) { + short save = dest->data.reg.reg; + dest->kind = PCOp_IMMEDIATE; + dest->data.imm.value = save; + dest->data.imm.obj = NULL; + break; + } + + if ((src->u.reg.effect & EffectWrite) && dest->data.reg.reg < n_real_registers[dest->arg]) { + if (src->u.reg.object) { + if (Registers_GetVarInfo(src->u.reg.object)->flags & VarInfoFlag4) { + int reg, regHi; +#line 3474 + CError_ASSERT(dest->arg == RegClass_GPR); + + regHi = OBJECT_REG_HI(src->u.reg.object); + reg = OBJECT_REG(src->u.reg.object); + retain_GPR_pair(src->u.reg.object, reg, regHi); + } else { + retain_register(src->u.reg.object, dest->arg, dest->data.reg.reg); + } + } else { + retain_register(NULL, dest->arg, dest->data.reg.reg); + } + } + + break; + } + + case IAOpnd_Lab: + if (!src->u.lab.label->pclabel) + src->u.lab.label->pclabel = makepclabel(); + dest->kind = PCOp_LABEL; + dest->data.label.label = src->u.lab.label->pclabel; + break; + + case IAOpnd_3: + case IAOpnd_4: + dest->kind = PCOp_MEMORY; + dest->arg = src->u.obj.unk; + dest->data.mem.obj = src->u.obj.obj; + dest->data.mem.offset = src->u.obj.offset; + if (pc->flags & (fPCodeFlag2 | fPCodeFlag4 | fPCodeFlag20000 | fPCodeFlag40000)) { + pc->_18 = make_alias(dest->data.mem.obj, dest->data.mem.offset, nbytes_loaded_or_stored_by(pc)); + if (is_volatile_object(dest->data.mem.obj)) + pc->flags |= fIsVolatile; + if (OBJ_GET_TARGET_CONST(dest->data.mem.obj)) + pc->flags |= fIsConst; + } + break; + + case IAOpnd_LabDiff: + if (src->u.labdiff.label1->pclabel == NULL) + src->u.labdiff.label1->pclabel = makepclabel(); + if (src->u.labdiff.label2->pclabel == NULL) + src->u.labdiff.label2->pclabel = makepclabel(); + if (pc->flags & (fPCodeFlag2 | fPCodeFlag4)) + pc->flags |= fPCodeFlag20; + dest->kind = PCOp_LABELDIFF; + dest->data.labeldiff.labelA = src->u.labdiff.label1->pclabel; + dest->data.labeldiff.labelB = src->u.labdiff.label2->pclabel; + dest->arg = src->negated; + dest->data.labeldiff.offset = src->u.labdiff.offset; + break; + + default: +#line 3528 + CError_FATAL(); + } + } + + index++; + dest++; + src++; + } + + if (ia->opcode == PC_STMW || ia->opcode == PC_LMW) { + int i; + for (i = reg; i < 32; i++, dest++) { + dest->kind = PCOp_REGISTER; + dest->arg = RegClass_GPR; + dest->data.reg.reg = i; + dest->data.reg.effect = (short) ((ia->opcode == PC_LMW) ? EffectWrite : EffectRead); + } + } + + if (ia->flags & IAFlag2) { + UInt32 masks[5] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}; + branch_record_volatiles(dest, masks); + if (copts.exceptions && current_statement && assembler_type == 0) + noteexceptionactionregisters(current_statement->dobjstack, dest); + } + + return pc; +} + +void InlineAsm_TranslateIRtoPCode(Statement *stmt) { + InlineAsm *ia; + PCode *pc; + + ia = (InlineAsm *) stmt->expr; + pc = InlineAsm_TranslateIRtoPCodePPC(ia, opcodeinfo[ia->opcode].x8, assembler_type); + appendpcode(pclastblock, pc); + + if ((ia->flags2 & IAFlagsB_40) || !copts.optimizewithasm) + setpcodeflags(fSideEffects); + + if (ia->flags2 & IAFlagsB_1) { + if (PCODE_FLAG_SET_F(pc) & fPCodeFlag8000000) + pcsetrecordbit(pclastblock->lastPCode); + else + CError_Error(CErrorStr261); + } + + if (ia->flags2 & IAFlagsB_2) { + if (PCODE_FLAG_SET_F(pc) & fPCodeFlag4000000) + setpcodeflags(fOverflow); // idk? + else + CError_Error(CErrorStr261); + } + + if (ia->flags2 & IAFlagsB_4) { + if (PCODE_FLAG_SET_T(pc) & fPCodeFlag20000000) { + int i; + for (i = 0; i < pc->argCount; i++) { + if (pc->args[i].kind == PCOp_LABEL || pc->args[i].kind == PCOp_MEMORY) { + PPCError_Error(177); + break; + } + } + setpcodeflags(fAbsolute); // idk? + } else { + CError_Error(CErrorStr261); + } + } + + if (ia->flags2 & IAFlagsB_8) { + if (PCODE_FLAG_SET_T(pc) & fPCodeFlag2000000) { + pcsetlinkbit(pclastblock->lastPCode); + if (!(ia->flags & IAFlag2)) { + pclastblock->lastPCode->flags &= ~fPCodeFlag8; + pclastblock->lastPCode->flags |= fPCodeFlag1; + } + makes_call = 1; + } else { + CError_Error(CErrorStr261); + } + } + + if (ia->flags2 & IAFlagsB_10) + setpcodeflags(fPCodeFlag8000000); + if (ia->flags2 & IAFlagsB_20) + setpcodeflags(fPCodeFlag4000000); + + if (OPCODE_PART_1(opcodeinfo[pc->op].insn) == 16) { + PCodeLabel *dest = NULL; + PCodeLabel *src = makepclabel(); + switch (pc->op) { + case PC_BC: + if (pc->args[3].kind == PCOp_LABEL) + dest = pc->args[3].data.label.label; + break; + case PC_BT: + case PC_BF: + case PC_BDNZT: + case PC_BDNZF: + case PC_BDZT: + case PC_BDZF: + if (pc->args[2].kind == PCOp_LABEL) + dest = pc->args[2].data.label.label; + break; + case PC_BDNZ: + case PC_BDZ: + if (pc->args[0].kind == PCOp_LABEL) + dest = pc->args[0].data.label.label; + break; + default: +#line 3715 + CError_FATAL(); + } + + if (dest) { + pcbranch(pclastblock, dest); + pcbranch(pclastblock, src); + makepcblock(); + pclabel(pclastblock, src); + } + return; + } + + if (OPCODE_PART_1(opcodeinfo[pc->op].insn) == 18) { + PCodeLabel *label; + if (ia->flags2 & IAFlagsB_8) { + label = makepclabel(); + pcbranch(pclastblock, label); + } + if (pc->args[0].kind == PCOp_LABEL) + pcbranch(pclastblock, pc->args[0].data.label.label); + makepcblock(); + if (ia->flags2 & IAFlagsB_8) { + pclabel(pclastblock, label); + } + return; + } + + if (OPCODE_PART_1(opcodeinfo[pc->op].insn) == 19) { + switch (pc->op) { + case PC_BLR: + case PC_RFI: + if (asm_alloc_flags[3]) + asm_alloc_flags[9] = 1; + else + asm_alloc_flags[8] = 1; + + if (asm_alloc_flags[4]) + asm_alloc_flags[5] = 1; + + if (pc->op == PC_BLR) + asm_alloc_flags[6] = 1; + else + asm_alloc_flags[7] = 1; + break; + } + } +} + +const char *InlineAsm_GetMnemonic(InlineAsm *ia) { + return opcodeinfo[ia->opcode].name; +} + +static void savepicbase(short reg, HashNameNode *name) { + IALookupResult result; + + if (!InlineAsm_LookupSymbol(name, &result)) + result.label = InlineAsm_DeclareLabel(name); + + pic_base_label = result.label; + pic_base_reg = reg; + uses_globals = 1; +} + +static SInt32 InlineAsm_OpcodeSize(InlineAsm *ia) { + if (opcodeinfo[ia->opcode].flags & (fPCodeFlag2 | fPCodeFlag4)) { + switch (ia->opcode) { + case PC_LBZ: + case PC_LBZU: + case PC_LBZX: + case PC_LBZUX: + case PC_STB: + case PC_STBU: + case PC_STBX: + case PC_STBUX: + return 1; + case PC_LHZ: + case PC_LHZU: + case PC_LHZX: + case PC_LHZUX: + case PC_LHA: + case PC_LHAU: + case PC_LHAX: + case PC_LHAUX: + case PC_LHBRX: + case PC_STH: + case PC_STHU: + case PC_STHX: + case PC_STHUX: + case PC_STHBRX: + return 2; + case PC_LWZ: + case PC_LWZU: + case PC_LWZX: + case PC_LWZUX: + case PC_LWBRX: + case PC_STW: + case PC_STWU: + case PC_STWX: + case PC_STWUX: + case PC_STWBRX: + case PC_LFS: + case PC_LFSU: + case PC_LFSX: + case PC_LFSUX: + case PC_STFS: + case PC_STFSU: + case PC_STFSX: + case PC_STFSUX: + case PC_LWARX: + case PC_STFIWX: + case PC_STWCX: + case PC_ECIWX: + case PC_ECOWX: + case PC_MFROM: + case PC_LSCBX: + return 4; + case PC_LMW: + case PC_STMW: + if (ia->args[0].type == IAOpnd_Reg && ia->args[0].u.reg.object == NULL) + return (32 - ia->args[0].u.reg.num) * 4; + else + return 128; + case PC_LFD: + case PC_LFDU: + case PC_LFDX: + case PC_LFDUX: + case PC_STFD: + case PC_STFDU: + case PC_STFDX: + case PC_STFDUX: + return 8; + case PC_LSWI: + case PC_STSWI: + return ia->args[2].u.imm.value; + case PC_LSWX: + case PC_STSWX: + return 128; + case PC_LVEBX: + case PC_STVEBX: + return 1; + case PC_LVEHX: + case PC_STVEHX: + return 2; + case PC_LVEWX: + case PC_STVEWX: + return 4; + case PC_LVSL: + case PC_LVSR: + case PC_LVX: + case PC_LVXL: + case PC_STVX: + case PC_STVXL: + return 16; + default: +#line 3924 + CError_FATAL(); + } + } else { + if (opcodeinfo[ia->opcode].flags & fPCodeFlag80000000) + return 4; + if (opcodeinfo[ia->opcode].flags & fPCodeFlag40000000) + return 8; + if (opcodeinfo[ia->opcode].flags & (fPCodeFlag80000000 | fPCodeFlag40000000)) + return 16; + + if (opcodeinfo[ia->opcode].flags & fSideEffects) { + switch (ia->opcode) { + case PC_TLBIE: + case PC_TLBLD: + case PC_TLBLI: + return 4; + default: +#line 3941 + CError_FATAL(); + } + } + } + +#line 3944 + CError_FATAL(); + return 0; +} + +void CodeGen_GetAsmEffects(Statement *stmt, IAEffects *effects) { + InlineAsm *ia; + OpcodeInfo *info; + int i; + IAOperand *op; + VarInfo *vi; + + ia = (InlineAsm *) stmt->expr; + info = &opcodeinfo[ia->opcode]; + + effects->numoperands = 0; + effects->numlabels = 0; + effects->x1 = 0; + effects->x2 = 0; + effects->x3 = 0; + effects->x4 = 0; + effects->x0 = 0; + effects->x5 = 0; + + if (info->flags & fPCodeFlag20) { + if (info->flags & fPCodeFlag2) + effects->x1 = 1; + if (info->flags & fPCodeFlag4) + effects->x2 = 1; + } + + if (PCODE_FLAG_SET_T(info) & fPCodeFlag2000000) { + if (ia->flags2 & IAFlagsB_8) + effects->x4 = 1; + else if ((info->flags & fPCodeFlag8) || (info->flags & fPCodeFlag4)) + effects->x3 = 1; + + if (ia->opcode == PC_B) { + if (ia->args[0].type == IAOpnd_Imm) + effects->x0 = 1; + effects->x5 = 1; + } + } + + if (info->flags & fSideEffects) + effects->x0 = 1; + + if (ia->opcode == PC_BC && (ia->flags2 & IAFlagsB_8)) + effects->x4 = 1; + + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + switch (op->type) { + case IAOpnd_0: + case IAOpnd_Imm: + break; + case IAOpnd_Reg: + if (op->u.reg.object) { + if ((vi = Registers_GetVarInfo(op->u.reg.object))) + vi->flags |= VarInfoFlag40; + if (op->u.reg.effect & EffectRead) { + if ( + TYPE_FITS_IN_REGISTER(op->u.reg.object->type) || + IS_TYPE_FLOAT(op->u.reg.object->type) || + IS_TYPE_VECTOR(op->u.reg.object->type) + ) { + effects->operands[effects->numoperands].type = IAEffect_0; + effects->operands[effects->numoperands].object = op->u.reg.object; + effects->operands[effects->numoperands].offset = 0; + effects->operands[effects->numoperands].size = op->u.reg.object->type->size; + effects->numoperands++; + } else { +#line 4051 + CError_FATAL(); + } + } + } + break; + case IAOpnd_3: + case IAOpnd_4: + if (op->u.obj.obj) { + if (info->flags & fPCodeFlag2) { + effects->operands[effects->numoperands].type = IAEffect_0; + effects->operands[effects->numoperands].object = op->u.obj.obj; + effects->operands[effects->numoperands].offset = op->u.obj.offset; + effects->operands[effects->numoperands].size = InlineAsm_OpcodeSize(ia); + effects->numoperands++; + } else if (!(info->flags & (fPCodeFlag1 | fPCodeFlag8))) { + effects->operands[effects->numoperands].type = IAEffect_3; + effects->operands[effects->numoperands].object = op->u.obj.obj; + effects->operands[effects->numoperands].offset = op->u.obj.offset; + effects->operands[effects->numoperands].size = InlineAsm_OpcodeSize(ia); + effects->numoperands++; + } + } + break; + case IAOpnd_Lab: + effects->labels[effects->numlabels] = op->u.lab.label; + effects->numlabels++; + break; + case IAOpnd_LabDiff: + effects->labels[effects->numlabels] = op->u.labdiff.label1; + effects->numlabels++; + effects->labels[effects->numlabels] = op->u.labdiff.label2; + effects->numlabels++; + effects->x3 = 1; + break; + default: +#line 4087 + CError_FATAL(); + } + +#line 4090 + CError_ASSERT(effects->numoperands <= 16); +#line 4093 + CError_ASSERT(effects->numlabels <= 16); + } + + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + switch (op->type) { + case IAOpnd_Reg: + if (op->u.reg.object) { + if ((vi = Registers_GetVarInfo(op->u.reg.object))) + vi->flags |= VarInfoFlag40; + if (op->u.reg.effect & EffectWrite) { + if ( + TYPE_FITS_IN_REGISTER(op->u.reg.object->type) || + IS_TYPE_FLOAT(op->u.reg.object->type) || + IS_TYPE_VECTOR(op->u.reg.object->type) + ) { + effects->operands[effects->numoperands].type = IAEffect_1; + effects->operands[effects->numoperands].object = op->u.reg.object; + effects->operands[effects->numoperands].offset = 0; + effects->operands[effects->numoperands].size = op->u.reg.object->type->size; + effects->numoperands++; + } else { +#line 4132 + CError_FATAL(); + } + } + } + break; + case IAOpnd_3: + case IAOpnd_4: + if (op->u.obj.obj) { + if (info->flags & fPCodeFlag4) { + effects->operands[effects->numoperands].type = IAEffect_1; + effects->operands[effects->numoperands].object = op->u.obj.obj; + effects->operands[effects->numoperands].offset = op->u.obj.offset; + effects->operands[effects->numoperands].size = InlineAsm_OpcodeSize(ia); + effects->numoperands++; + } + } + break; + } + +#line 4151 + CError_ASSERT(effects->numoperands <= 16); + } + + if ((info->flags & (fPCodeFlag1 | fPCodeFlag8)) && (SInt32)effects->numlabels == 0) + effects->x3 = 1; +} + +void CodeGen_PropagateIntoAsm(Statement *stmt, Object *obj, ENode *expr) { + InlineAsm *ia; + Object *newobj; + + ia = (InlineAsm *) stmt->expr; + if (ENODE_IS(expr, EOBJREF)) { + newobj = expr->data.objref; + if (obj->otype == newobj->otype && obj->datatype == newobj->datatype) { + int i; + for (i = 0; i < ia->argcount; i++) { + switch (ia->args[i].type) { + case IAOpnd_Reg: + if (ia->args[i].u.reg.object == obj && + (ia->args[i].u.reg.effect & (EffectRead | EffectWrite)) == EffectRead) { + if (TYPE_FITS_IN_REGISTER(newobj->type) && + ia->args[i].u.reg.rclass == RegClass_GPR) { + ia->args[i].u.reg.object = newobj; + } else if (IS_TYPE_FLOAT(newobj->type) && + ia->args[i].u.reg.rclass == RegClass_FPR) { + ia->args[i].u.reg.object = newobj; + } else if (IS_TYPE_VECTOR(newobj->type) && + ia->args[i].u.reg.rclass == RegClass_VR) { + ia->args[i].u.reg.object = newobj; + } + } + break; + case IAOpnd_3: + case IAOpnd_4: + if (!(opcodeinfo[ia->opcode].flags & (fPCodeFlag4 | fPCodeFlag40000)) && + ia->args[i].u.obj.obj == obj) + ia->args[i].u.obj.obj = newobj; + break; + } + } + } + } +} + +Statement *CodeGen_CopyAsmStat(Statement *stmt) { + Statement *copy; + SInt32 size; + InlineAsm *ia; + InlineAsm *iacopy; + + copy = galloc(sizeof(Statement)); + *copy = *stmt; + + ia = (InlineAsm *) stmt->expr; + size = sizeof(InlineAsm) + sizeof(IAOperand) * ia->argcount; + iacopy = galloc(size); + memcpy(iacopy, ia, size); + copy->expr = (ENode *) iacopy; + + return copy; +} + diff --git a/compiler_and_linker/unsorted/InlineAsmRegisters.c b/compiler_and_linker/unsorted/InlineAsmRegisters.c new file mode 100644 index 0000000..31f94c4 --- /dev/null +++ b/compiler_and_linker/unsorted/InlineAsmRegisters.c @@ -0,0 +1,50 @@ +#include "compiler/InlineAsmRegisters.h" +#include "compiler/CompilerTools.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct HashedRegister { + struct HashedRegister *next; + IARegister reg; +} HashedRegister; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static HashedRegister *hashedregisters[64]; + +void InlineAsm_InitializeRegisters() { + SInt32 i; + + for (i = 0; i < 64; i++) + hashedregisters[i] = NULL; +} + +void InlineAsm_InsertRegister(char *name, char rclass, short num, Object *object) { + HashedRegister **ptr; + HashedRegister *hr; + + ptr = hashedregisters + (CHash(name) & 63); + hr = lalloc(sizeof(HashedRegister)); + hr->reg.name = name; + hr->reg.rclass = rclass; + hr->reg.num = num; + hr->reg.object = object; + + hr->next = *ptr; + *ptr = hr; +} + +IARegister *InlineAsm_LookupRegister(char *name) { + HashedRegister *scan; + IARegister *reg; + + for (scan = hashedregisters[CHash(name) & 63]; scan; scan = scan->next) { + reg = &scan->reg; + if (!strcmp(scan->reg.name, name)) + return reg; + } + + return NULL; +} diff --git a/compiler_and_linker/unsorted/InlineAsmRegistersPPC.c b/compiler_and_linker/unsorted/InlineAsmRegistersPPC.c new file mode 100644 index 0000000..a60bc15 --- /dev/null +++ b/compiler_and_linker/unsorted/InlineAsmRegistersPPC.c @@ -0,0 +1,854 @@ +#include "compiler/InlineAsmRegistersPPC.h" +#include "compiler/InlineAsm.h" +#include "compiler/InlineAsmRegisters.h" +#include "compiler/CompilerTools.h" +#include "compiler/RegisterInfo.h" +#include "compiler/objects.h" +#include "compiler/types.h" +#include "compiler/InlineAsmPPC.h" +#include "compiler/CParser.h" +#include "compiler/PPCError.h" +#include "compiler/CFunc.h" + +#pragma pool_strings on + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct RegInfo { + struct RegInfo *next; + UInt32 b; + IARegister reg; +} RegInfo; + +typedef struct AsmRegister { + char *name; + char rclass; + SInt32 num; +} AsmRegister; + +typedef struct AsmSpr { + char *name; + SInt32 num; + UInt32 mask; +} AsmSpr; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static RegInfo *hashedsprs[64]; +static RegInfo *hasheddcrs[64]; + +static AsmRegister asm_registers[] = { + "r0", RegClass_GPR, 0, + "r1", RegClass_GPR, 1, + "r2", RegClass_GPR, 2, + "r3", RegClass_GPR, 3, + "r4", RegClass_GPR, 4, + "r5", RegClass_GPR, 5, + "r6", RegClass_GPR, 6, + "r7", RegClass_GPR, 7, + "r8", RegClass_GPR, 8, + "r9", RegClass_GPR, 9, + "r10", RegClass_GPR, 10, + "r11", RegClass_GPR, 11, + "r12", RegClass_GPR, 12, + "r13", RegClass_GPR, 13, + "r14", RegClass_GPR, 14, + "r15", RegClass_GPR, 15, + "r16", RegClass_GPR, 16, + "r17", RegClass_GPR, 17, + "r18", RegClass_GPR, 18, + "r19", RegClass_GPR, 19, + "r20", RegClass_GPR, 20, + "r21", RegClass_GPR, 21, + "r22", RegClass_GPR, 22, + "r23", RegClass_GPR, 23, + "r24", RegClass_GPR, 24, + "r25", RegClass_GPR, 25, + "r26", RegClass_GPR, 26, + "r27", RegClass_GPR, 27, + "r28", RegClass_GPR, 28, + "r29", RegClass_GPR, 29, + "r30", RegClass_GPR, 30, + "r31", RegClass_GPR, 31, + "gpr0", RegClass_GPR, 0, + "gpr1", RegClass_GPR, 1, + "gpr2", RegClass_GPR, 2, + "gpr3", RegClass_GPR, 3, + "gpr4", RegClass_GPR, 4, + "gpr5", RegClass_GPR, 5, + "gpr6", RegClass_GPR, 6, + "gpr7", RegClass_GPR, 7, + "gpr8", RegClass_GPR, 8, + "gpr9", RegClass_GPR, 9, + "gpr10", RegClass_GPR, 10, + "gpr11", RegClass_GPR, 11, + "gpr12", RegClass_GPR, 12, + "gpr13", RegClass_GPR, 13, + "gpr14", RegClass_GPR, 14, + "gpr15", RegClass_GPR, 15, + "gpr16", RegClass_GPR, 16, + "gpr17", RegClass_GPR, 17, + "gpr18", RegClass_GPR, 18, + "gpr19", RegClass_GPR, 19, + "gpr20", RegClass_GPR, 20, + "gpr21", RegClass_GPR, 21, + "gpr22", RegClass_GPR, 22, + "gpr23", RegClass_GPR, 23, + "gpr24", RegClass_GPR, 24, + "gpr25", RegClass_GPR, 25, + "gpr26", RegClass_GPR, 26, + "gpr27", RegClass_GPR, 27, + "gpr28", RegClass_GPR, 28, + "gpr29", RegClass_GPR, 29, + "gpr30", RegClass_GPR, 30, + "gpr31", RegClass_GPR, 31, + "rtoc", RegClass_GPR, 2, + "RTOC", RegClass_GPR, 2, + "sp", RegClass_GPR, 1, + "SP", RegClass_GPR, 1, + "rsp", RegClass_GPR, 1, + "RSP", RegClass_GPR, 1, + "RPIC", RegClass_GPR, -2, + "rpic", RegClass_GPR, -2, + "f0", RegClass_FPR, 0, + "f1", RegClass_FPR, 1, + "f2", RegClass_FPR, 2, + "f3", RegClass_FPR, 3, + "f4", RegClass_FPR, 4, + "f5", RegClass_FPR, 5, + "f6", RegClass_FPR, 6, + "f7", RegClass_FPR, 7, + "f8", RegClass_FPR, 8, + "f9", RegClass_FPR, 9, + "f10", RegClass_FPR, 10, + "f11", RegClass_FPR, 11, + "f12", RegClass_FPR, 12, + "f13", RegClass_FPR, 13, + "f14", RegClass_FPR, 14, + "f15", RegClass_FPR, 15, + "f16", RegClass_FPR, 16, + "f17", RegClass_FPR, 17, + "f18", RegClass_FPR, 18, + "f19", RegClass_FPR, 19, + "f20", RegClass_FPR, 20, + "f21", RegClass_FPR, 21, + "f22", RegClass_FPR, 22, + "f23", RegClass_FPR, 23, + "f24", RegClass_FPR, 24, + "f25", RegClass_FPR, 25, + "f26", RegClass_FPR, 26, + "f27", RegClass_FPR, 27, + "f28", RegClass_FPR, 28, + "f29", RegClass_FPR, 29, + "f30", RegClass_FPR, 30, + "f31", RegClass_FPR, 31, + "fp0", RegClass_FPR, 0, + "fp1", RegClass_FPR, 1, + "fp2", RegClass_FPR, 2, + "fp3", RegClass_FPR, 3, + "fp4", RegClass_FPR, 4, + "fp5", RegClass_FPR, 5, + "fp6", RegClass_FPR, 6, + "fp7", RegClass_FPR, 7, + "fp8", RegClass_FPR, 8, + "fp9", RegClass_FPR, 9, + "fp10", RegClass_FPR, 10, + "fp11", RegClass_FPR, 11, + "fp12", RegClass_FPR, 12, + "fp13", RegClass_FPR, 13, + "fp14", RegClass_FPR, 14, + "fp15", RegClass_FPR, 15, + "fp16", RegClass_FPR, 16, + "fp17", RegClass_FPR, 17, + "fp18", RegClass_FPR, 18, + "fp19", RegClass_FPR, 19, + "fp20", RegClass_FPR, 20, + "fp21", RegClass_FPR, 21, + "fp22", RegClass_FPR, 22, + "fp23", RegClass_FPR, 23, + "fp24", RegClass_FPR, 24, + "fp25", RegClass_FPR, 25, + "fp26", RegClass_FPR, 26, + "fp27", RegClass_FPR, 27, + "fp28", RegClass_FPR, 28, + "fp29", RegClass_FPR, 29, + "fp30", RegClass_FPR, 30, + "fp31", RegClass_FPR, 31, + "v0", RegClass_VR, 0, + "v1", RegClass_VR, 1, + "v2", RegClass_VR, 2, + "v3", RegClass_VR, 3, + "v4", RegClass_VR, 4, + "v5", RegClass_VR, 5, + "v6", RegClass_VR, 6, + "v7", RegClass_VR, 7, + "v8", RegClass_VR, 8, + "v9", RegClass_VR, 9, + "v10", RegClass_VR, 10, + "v11", RegClass_VR, 11, + "v12", RegClass_VR, 12, + "v13", RegClass_VR, 13, + "v14", RegClass_VR, 14, + "v15", RegClass_VR, 15, + "v16", RegClass_VR, 16, + "v17", RegClass_VR, 17, + "v18", RegClass_VR, 18, + "v19", RegClass_VR, 19, + "v20", RegClass_VR, 20, + "v21", RegClass_VR, 21, + "v22", RegClass_VR, 22, + "v23", RegClass_VR, 23, + "v24", RegClass_VR, 24, + "v25", RegClass_VR, 25, + "v26", RegClass_VR, 26, + "v27", RegClass_VR, 27, + "v28", RegClass_VR, 28, + "v29", RegClass_VR, 29, + "v30", RegClass_VR, 30, + "v31", RegClass_VR, 31, + "vr0", RegClass_VR, 0, + "vr1", RegClass_VR, 1, + "vr2", RegClass_VR, 2, + "vr3", RegClass_VR, 3, + "vr4", RegClass_VR, 4, + "vr5", RegClass_VR, 5, + "vr6", RegClass_VR, 6, + "vr7", RegClass_VR, 7, + "vr8", RegClass_VR, 8, + "vr9", RegClass_VR, 9, + "vr10", RegClass_VR, 10, + "vr11", RegClass_VR, 11, + "vr12", RegClass_VR, 12, + "vr13", RegClass_VR, 13, + "vr14", RegClass_VR, 14, + "vr15", RegClass_VR, 15, + "vr16", RegClass_VR, 16, + "vr17", RegClass_VR, 17, + "vr18", RegClass_VR, 18, + "vr19", RegClass_VR, 19, + "vr20", RegClass_VR, 20, + "vr21", RegClass_VR, 21, + "vr22", RegClass_VR, 22, + "vr23", RegClass_VR, 23, + "vr24", RegClass_VR, 24, + "vr25", RegClass_VR, 25, + "vr26", RegClass_VR, 26, + "vr27", RegClass_VR, 27, + "vr28", RegClass_VR, 28, + "vr29", RegClass_VR, 29, + "vr30", RegClass_VR, 30, + "vr31", RegClass_VR, 31, + "cr0", RegClass_CRFIELD, 0, + "cr1", RegClass_CRFIELD, 1, + "cr2", RegClass_CRFIELD, 2, + "cr3", RegClass_CRFIELD, 3, + "cr4", RegClass_CRFIELD, 4, + "cr5", RegClass_CRFIELD, 5, + "cr6", RegClass_CRFIELD, 6, + "cr7", RegClass_CRFIELD, 7, + "crf0", RegClass_CRFIELD, 0, + "crf1", RegClass_CRFIELD, 1, + "crf2", RegClass_CRFIELD, 2, + "crf3", RegClass_CRFIELD, 3, + "crf4", RegClass_CRFIELD, 4, + "crf5", RegClass_CRFIELD, 5, + "crf6", RegClass_CRFIELD, 6, + "crf7", RegClass_CRFIELD, 7, + "lt", RegClass_6, 0, + "gt", RegClass_6, 1, + "eq", RegClass_6, 2, + "so", RegClass_6, 3, + "un", RegClass_6, 3, + "LT", RegClass_6, 0, + "GT", RegClass_6, 1, + "EQ", RegClass_6, 2, + "SO", RegClass_6, 3, + "UN", RegClass_6, 3, + NULL, 0, 0 +}; + +static AsmSpr asm_sprs[] = { + "xer", 1, 0xFFFFF, + "lr", 8, 0xFFFFF, + "ctr", 9, 0xFFFFF, + "mq", 0, 1, + "rtcu", 4, 1, + "rtcl", 5, 1, + "dsisr", 0x12, 0xFF83F, + "dar", 0x13, 0xFF83F, + "dec", 0x16, 0xFF83F, + "sdr1", 0x19, 0xFE00F, + "srr0", 0x1A, 0xFFFFF, + "srr1", 0x1B, 0xFFFFF, + "eie", 0x50, 0x1830, + "eid", 0x51, 0x1830, + "nri", 0x52, 0x1830, + "cmpa", 0x90, 0x1830, + "cmpb", 0x91, 0x1830, + "cmpc", 0x92, 0x1830, + "cmpd", 0x93, 0x1830, + "icr", 0x94, 0x30, + "ecr", 0x94, 0x1800, + "der", 0x95, 0x1830, + "counta", 0x96, 0x1830, + "countb", 0x97, 0x1830, + "cmpe", 0x98, 0x1830, + "cmpf", 0x99, 0x1830, + "cmpg", 0x9A, 0x1830, + "cmph", 0x9B, 0x1830, + "lctrl1", 0x9C, 0x1830, + "lctrl2", 0x9D, 0x1830, + "ictrl", 0x9E, 0x1830, + "bar", 0x9F, 0x1830, + "vrsave", 0x100, 0x40000000, + "sprg0", 0x110, 0xFFFFF, + "sprg1", 0x111, 0xFFFFF, + "sprg2", 0x112, 0xFFFFF, + "sprg3", 0x113, 0xFFFFF, + "ear", 0x11A, 0xFE7CF, + "tbl", 0x11C, 0xFF83F, + "tbu", 0x11D, 0xFF83F, + "tbl_write", 0x11C, 0xFF83F, + "tbu_write", 0x11D, 0xFF83F, + "pvr", 0x11F, 0xFFFFF, + "ibat0u", 0x210, 0xFE7CF, + "mi_gra", 0x210, 0x1000, + "ibat0l", 0x211, 0xFE7CF, + "ibat1u", 0x212, 0xFE7CF, + "ibat1l", 0x213, 0xFE7CF, + "ibat2u", 0x214, 0xFE7CF, + "ibat2l", 0x215, 0xFE7CF, + "ibat3u", 0x216, 0xFE7CF, + "ibat3l", 0x217, 0xFE7CF, + "dbat0u", 0x218, 0xFE7CE, + "l2u_gra", 0x218, 0x1000, + "dbat0l", 0x219, 0xFE7CE, + "dbat1u", 0x21A, 0xFE7CE, + "dbat1l", 0x21B, 0xFE7CE, + "dbat2u", 0x21C, 0xFE7CE, + "dbat2l", 0x21D, 0xFE7CE, + "dbat3u", 0x21E, 0xFE7CE, + "dbat3l", 0x21F, 0xFE7CE, + "ic_cst", 0x230, 0x30, + "iccst", 0x230, 0x800, + "bbcmcr", 0x230, 0x1000, + "ic_adr", 0x231, 0x30, + "icadr", 0x231, 0x800, + "ic_dat", 0x232, 0x30, + "icdat", 0x232, 0x800, + "dc_cst", 0x238, 0x30, + "l2u_mcr", 0x238, 0x1000, + "dc_adr", 0x239, 0x30, + "dc_dat", 0x23A, 0x30, + "dpdr", 0x276, 0x1830, + "dpir", 0x277, 0x30, + "immr", 0x27E, 0x30, + "mi_ctr", 0x310, 0x30, + "mi_rba0", 0x310, 0x1000, + "mi_rba1", 0x311, 0x1000, + "mi_rba2", 0x312, 0x1000, + "mi_ap", 0x312, 0x30, + "mi_epn", 0x313, 0x30, + "mi_rba3", 0x313, 0x1000, + "mi_twc", 0x315, 0x30, + "mi_l1dl2p", 0x315, 0x30, + "mi_rpn", 0x316, 0x30, + "md_ctr", 0x318, 0x30, + "l2u_rba0", 0x318, 0x1000, + "l2u_rba1", 0x319, 0x1000, + "m_casid", 0x319, 0x30, + "md_ap", 0x31A, 0x30, + "l2u_rba2", 0x31A, 0x1000, + "l2u_rba3", 0x31B, 0x1000, + "md_epn", 0x31B, 0x30, + "m_twb", 0x31C, 0x30, + "md_l1p", 0x31C, 0x30, + "md_twc", 0x31D, 0x30, + "md_l1dl2p", 0x31D, 0x30, + "md_rpn", 0x31E, 0x30, + "m_tw", 0x31F, 0x30, + "m_save", 0x31F, 0x30, + "mi_dbcam", 0x330, 0x10, + "mi_cam", 0x330, 0x20, + "mi_ra0", 0x330, 0x1000, + "mi_ra1", 0x331, 0x1000, + "mi_dbram0", 0x331, 0x10, + "mi_ram0", 0x331, 0x20, + "mi_dbram1", 0x332, 0x10, + "mi_ram1", 0x332, 0x20, + "mi_ra2", 0x332, 0x1000, + "mi_ra3", 0x333, 0x1000, + "md_dbcam", 0x338, 0x10, + "md_cam", 0x338, 0x20, + "l2u_ra0", 0x338, 0x1000, + "l2u_ra1", 0x339, 0x1000, + "md_dbram0", 0x339, 0x10, + "md_ram0", 0x339, 0x20, + "md_dbram1", 0x33A, 0x10, + "md_ram1", 0x33A, 0x20, + "l2u_ra2", 0x33A, 0x1000, + "l2u_ra3", 0x33B, 0x1000, + "ummcr2", 0x3A0, 0x4000, + "ubamr", 0x3A7, 0x4000, + "ummcr0", 0x3A8, 0xE000, + "upmc1", 0x3A9, 0xE000, + "upmc2", 0x3AA, 0xE000, + "usia", 0x3AB, 0x2000, + "usiar", 0x3AB, 0x4000, + "ummcr1", 0x3AC, 0xE000, + "upmc3", 0x3AD, 0xE000, + "upmc4", 0x3AE, 0xE000, + "zpr", 0x3B0, 0x200, + "mmcr2", 0x3B0, 0x4000, + "pid", 0x3B1, 0x200, + "bamr", 0x3B7, 0x4000, + "mmcr0", 0x3B8, 0xE008, + "pmc1", 0x3B9, 0xE008, + "sgr", 0x3B9, 0x240, + "pmc2", 0x3BA, 0xE008, + "dcwr", 0x3BA, 0x240, + "sia", 0x3BB, 0xE008, + "siar", 0x3BB, 0x4000, + "sler", 0x3BB, 0x40, + "mmcr1", 0x3BC, 0xE000, + "pmc3", 0x3BD, 0xE000, + "pmc4", 0x3BE, 0xE000, + "sda", 0x3BF, 8, + "tbhu", 0x3CC, 0x240, + "tblu", 0x3CD, 0x240, + "dmiss", 0x3D0, 0x10006, + "dcmp", 0x3D1, 0x10006, + "hash1", 0x3D2, 0x10006, + "hash2", 0x3D3, 0x10006, + "icdbdr", 0x3D3, 0x7C0, + "imiss", 0x3D4, 0x10006, + "esr", 0x3D4, 0x7C0, + "icmp", 0x3D5, 0x10006, + "dear", 0x3D5, 0x7C0, + "rpa", 0x3D6, 0x10006, + "evpr", 0x3D6, 0x7C0, + "cdbcr", 0x3D7, 0x7C0, + "tsr", 0x3D8, 0x7C0, + "tcr", 0x3D8, 2, + "tcr", 0x3DA, 0x7C0, + "ibr", 0x3DA, 2, + "pit", 0x3DB, 0x7C0, + "esasrr", 0x3DB, 2, + "tbhi", 0x3DC, 0x7C0, + "tblo", 0x3DD, 0x7C0, + "srr2", 0x3DE, 0x7C0, + "sebr", 0x3DE, 2, + "srr3", 0x3DF, 0x7C0, + "ser", 0x3DF, 2, + "mid0", 0x3F0, 0x1E00F, + "dbsr", 0x3F0, 0x80, + "hid1", 0x3F1, 0x1E007, + "hid2", 0x3F2, 1, + "iabr", 0x3F2, 0x1E00F, + "dbcr", 0x3F2, 0x7C0, + "hid2", 0x3F3, 0x10000, + "iac1", 0x3F4, 0x80, + "iac", 0x3F4, 0x40, + "dabr", 0x3F5, 0xE009, + "iac2", 0x3F5, 0x80, + "hid5", 0x3F5, 1, + "dac1", 0x3F6, 0x80, + "dac", 0x3F6, 0x40, + "msscr0", 0x3F6, 0x4000, + "dac2", 0x3F7, 0x80, + "l2cr", 0x3F9, 0xE000, + "dccr", 0x3FA, 0x7C0, + "iccr", 0x3FB, 0x7C0, + "ictc", 0x3FB, 0xE000, + "pbl1", 0x3FC, 0x80, + "thrm1", 0x3FC, 0xE000, + "pbu1", 0x3FD, 0x80, + "thrm2", 0x3FD, 0xE000, + "fpecr", 0x3FE, 0x1800, + "pbl2", 0x3FE, 0x80, + "thrm3", 0x3FE, 0xE000, + "pir", 0x3FF, 0x4008, + "hid15", 0x3FF, 1, + "pbu2", 0x3FF, 0x80, + NULL, 0, 0 +}; + +UInt32 spr_cpus[1024] = { + 1, 0xFFFFF, 0, 0, 1, 1, 0, 0, + 0xFFFFF, 0xFFFFF, 0, 0, 0, 0, 0, 0, + 0, 0, 0xFF83F, 0xFF83F, 0, 0, 0xFF83F, 0, + 0, 0xFE00F, 0xFFFFF, 0xFFFFF, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x1830, 0x1830, 0x1830, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x1830, 0x1830, 0x1830, 0x1830, 0x1830, 0x1830, 0x1830, 0x1830, + 0x1830, 0x1830, 0x1830, 0x1830, 0x1830, 0x1830, 0x1830, 0x1830, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x40000000, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0xFFFFF, 0xFFFFF, 0xFFFFF, 0xFFFFF, 0, 0, 0, 0, + 0, 0, 0xFE7CF, 0, 0xFF83F, 0xFF83F, 0, 0xFFFFF, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0xFF7CF, 0xFE7CF, 0xFE7CF, 0xFE7CF, 0xFE7CF, 0xFE7CF, 0xFE7CF, 0xFE7CF, + 0xFF7CE, 0xFE7CE, 0xFE7CE, 0xFE7CE, 0xFE7CE, 0xFE7CE, 0xFE7CE, 0xFE7CE, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x1830, 0x1830, 0x1830, 0, 0, 0, 0, 0, + 0x1030, 0x30, 0x30, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0x1830, 0x30, + 0, 0, 0, 0, 0, 0, 0x30, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x1030, 0x1000, 0x1030, 0x1030, 0, 0x30, 0x30, 0, + 0x1030, 0x1030, 0x1030, 0x1030, 0x30, 0x30, 0x30, 0x30, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x1030, 0x1030, 0x1030, 0x1000, 0, 0, 0, 0, + 0x1030, 0x1030, 0x1030, 0x1000, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x20000000, 0x20000000, 0x20000000, 0x20000000, 0x20000000, 0x20000000, 0x20000000, 0x20000000, + 0x20000000, 0x20000000, 0x20000000, 0x20000000, 0, 0, 0, 0, + 0x4000, 0, 0, 0, 0, 0, 0, 0x4000, + 0xE000, 0xE000, 0xE000, 0xE000, 0xE000, 0xE000, 0xE000, 0, + 0x4200, 0x200, 0, 0, 0, 0, 0, 0x4000, + 0xE008, 0xE248, 0xE248, 0xE048, 0xE000, 0xE000, 0xE000, 8, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0x240, 0x240, 0, 0, + 0x10006, 0x10006, 0x10006, 0x107C6, 0x107C6, 0x107C6, 0x107C6, 0x7C0, + 0x7C2, 0, 0x7C2, 0x7C2, 0x7C0, 0x7C0, 0x7C2, 0x7C2, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x1E08F, 0x1E007, 0x1E7CF, 0x10000, 0xC0, 0xE089, 0x40C0, 0x80, + 0, 0xE000, 0x7C0, 0xE7C0, 0xE080, 0xE080, 0xF880, 0xE089 +}; + +static void InlineAsm_InsertSPR(char *name, short num, UInt32 b) { + RegInfo **ptr; + RegInfo *info; + + ptr = hashedsprs + (CHash(name) & 63); + info = lalloc(sizeof(RegInfo)); + info->b = b; + info->reg.name = name; + info->reg.rclass = RegClass_SPR; + info->reg.num = num; + info->reg.object = NULL; + + info->next = *ptr; + *ptr = info; +} + +static void InlineAsm_InsertRegisterDCR(char *name, UInt32 b, short num) { + RegInfo **ptr; + RegInfo *info; + + ptr = hasheddcrs + (CHash(name) & 63); + info = lalloc(sizeof(RegInfo)); + info->b = b; + info->reg.name = name; + info->reg.rclass = RegClass_DCR; + info->reg.num = num; + info->reg.object = NULL; + + info->next = *ptr; + *ptr = info; +} + +IARegister *InlineAsm_LookupRegisterPPCName(HashNameNode *name) { + IALookupResult result; + IARegister *reg; + Type *type; + + if (InlineAsm_LookupSymbol(name, &result) && result.object && is_register_object(result.object)) { + type = result.object->type; + if ((reg = InlineAsm_LookupRegisterPPC(name->name)) && reg->object == result.object) + return reg; + + if (IS_TYPE_FLOAT(type)) { + InlineAsm_InsertRegister(name->name, RegClass_FPR, 0, result.object); + } else if (IS_TYPE_VECTOR(type)) { + InlineAsm_InsertRegister(name->name, RegClass_VR, 0, result.object); + } else { + InlineAsm_InsertRegister(name->name, RegClass_GPR, 0, result.object); + } + } + + return InlineAsm_LookupRegisterPPC(name->name); +} + +IARegister *InlineAsm_LookupRegisterPPC(char *name) { + RegInfo *scan; + IARegister *reg; + IARegister *check; + char buf[40]; + + if ((check = InlineAsm_LookupRegister(name))) + return check; + + reg = NULL; + if (strlen(name) < 40) + CToLowercase(name, buf); + else + return NULL; + + for (scan = hashedsprs[CHash(buf) & 63]; scan; scan = scan->next) { + check = &scan->reg; + if (!strcmp(scan->reg.name, buf)) { + if (cpu == CPUMask_Generic) { + if ((cpu & CPUFLAG_LOW_MASK) == ((cpu & CPUFLAG_LOW_MASK) & scan->b)) + return check; + } else { + if (scan->b & cpu) + return check; + } + reg = check; + } + } + + if (reg) { + if (copts.warn_possunwant) + PPCError_Warning(117, name); + return reg; + } + + if (!strncmp("spr", buf, 3)) { + static IARegister thespr; + UInt32 result; + Boolean overflow; + ScanDec(buf + 3, &result, &overflow); + if (overflow || result > 1024) { + PPCError_Error(117, name); + return NULL; + } + + thespr.name = NULL; + thespr.rclass = RegClass_SPR; + thespr.num = result; + thespr.object = NULL; + + if (copts.warn_possunwant) { + if (cpu == CPUMask_Generic) { + if ((cpu & CPUFLAG_LOW_MASK) != ((cpu & CPUFLAG_LOW_MASK) & spr_cpus[result])) + PPCError_Warning(117, name); + } else { + if (!(cpu & spr_cpus[result])) + PPCError_Warning(117, name); + } + } + + return &thespr; + } + + return NULL; +} + +IARegister *InlineAsm_LookupDCRRegister(char *name) { + RegInfo *scan; + IARegister *check; + IARegister *reg; + char buf[40]; + + if (strlen(name) < 40) + CToLowercase(name, buf); + else + return NULL; + + reg = NULL; + for (scan = hasheddcrs[CHash(buf) & 63]; scan; scan = scan->next) { + check = &scan->reg; + if (!strcmp(scan->reg.name, buf)) { + if (cpu == CPUMask_Generic) { + if ((cpu & CPUFLAG_LOW_MASK) == ((cpu & CPUFLAG_LOW_MASK) & scan->b)) + return check; + } else { + if (scan->b & cpu) + return check; + } + reg = check; + } + } + + if (reg) { + if (copts.warn_possunwant) + PPCError_Warning(117, name); + return reg; + } + + if (!strncmp("dcr", buf, 3)) { + static IARegister thespr; + UInt32 result; + Boolean overflow; + ScanDec(buf + 3, &result, &overflow); + if (overflow || result > 1024) { + PPCError_Error(117, name); + return NULL; + } + + thespr.name = NULL; + thespr.rclass = RegClass_DCR; + thespr.num = result; + thespr.object = NULL; + return &thespr; + } + + return NULL; +} + +void InlineAsm_InitializeRegistersPPC(void) { + AsmRegister *asmreg; + AsmSpr *asmspr; + HashNameNode *name; + Object *obj; + ObjectList *list; + char buf[16]; + SInt32 i; + + setup_diagnostic_reg_strings(); + + for (i = 0; i < 64; i++) + hashedsprs[i] = NULL; + for (i = 0; i < 64; i++) + hasheddcrs[i] = NULL; + + for (asmreg = asm_registers; asmreg->name; asmreg++) { + name = GetHashNameNodeExport(asmreg->name); + for (list = arguments; list; list = list->next) { + obj = list->object; + if (obj && obj->name == name) { + switch (asmreg->rclass) { + case RegClass_SPR: + case RegClass_CRFIELD: + case RegClass_VR: + case RegClass_FPR: + case RegClass_GPR: + sprintf(buf, register_class_format[asmreg->rclass], asmreg->num); + break; + case RegClass_6: + sprintf(buf, "crbit_%ld", asmreg->num); + break; + case RegClass_DCR: + sprintf(buf, "DCR%ld", asmreg->num); + break; + default: + sprintf(buf, "{?}%ld", asmreg->num); + break; + } + PPCError_Warning(100, obj->name->name, buf); + } + } + for (list = locals; list; list = list->next) { + obj = list->object; + if (obj && obj->name == name) { + switch (asmreg->rclass) { + case RegClass_SPR: + case RegClass_CRFIELD: + case RegClass_VR: + case RegClass_FPR: + case RegClass_GPR: + sprintf(buf, register_class_format[asmreg->rclass], asmreg->num); + break; + case RegClass_6: + sprintf(buf, "crbit_%ld", asmreg->num); + break; + case RegClass_DCR: + sprintf(buf, "DCR%ld", asmreg->num); + break; + default: + sprintf(buf, "{?}%ld", asmreg->num); + break; + } + PPCError_Warning(100, obj->name->name, buf); + } + } + + InlineAsm_InsertRegister(asmreg->name, asmreg->rclass, asmreg->num, NULL); + } + + for (asmspr = asm_sprs; asmspr->name; asmspr++) { + InlineAsm_InsertSPR(asmspr->name, asmspr->num, asmspr->mask); + } +} diff --git a/compiler_and_linker/unsorted/InstrSelection.c b/compiler_and_linker/unsorted/InstrSelection.c new file mode 100644 index 0000000..ac60baf --- /dev/null +++ b/compiler_and_linker/unsorted/InstrSelection.c @@ -0,0 +1,4858 @@ +#include "compiler/InstrSelection.h" +#include "compiler/CError.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/CodeGen.h" +#include "compiler/Operands.h" +#include "compiler/PCode.h" +#include "compiler/PCodeInfo.h" +#include "compiler/PCodeUtilities.h" +#include "compiler/RegisterInfo.h" +#include "compiler/TOC.h" +#include "compiler/CompilerTools.h" +#include "compiler/enode.h" +#include "compiler/objects.h" +#include "compiler/types.h" + +// TODO: move me +extern void move_block(Operand *, Operand *, SInt32, SInt32); + +PrecomputedOperand *precomputedoperands; +void (*cgdispatch[MAXEXPR + 1])(ENode *, short, short, Operand *); + +// forward decls +static int ispowerof2(SInt32 val); +static void binary_immediate(Opcode opcode, ENode *left, SInt32 value, short outputReg, Operand *output); +static void shift_left_immediate(ENode *expr, short shift, short negate, short outputReg, Operand *output); +static void shift_right_immediate(ENode *expr, Type *type, short shift, short outputReg, Operand *output); +static void or_xor_immediate(Opcode opcode, ENode *expr, SInt32 value, short outputReg, Operand *output); +static void signed_divide_by_power_of_2(ENode *expr, int shift, int negate, short outputReg, Operand *output); +static void signed_mod_by_power_of_2(ENode *expr, int shift, int negate, short outputReg, Operand *output); +static void fp_binary_operator(Opcode opcode, ENode *left, ENode *right, short outputReg, Operand *output); +static void logical_expression_nobranch(ENode *cond, Boolean invert, Operand *output); +static void shift_and_mask(ENode *expr, short a, short b, short c, short outputReg, Operand *output); +static ENodeType invert_relop(ENodeType nt); + +#define IS_INT_CONST(node) ( ENODE_IS((node), EINTCONST) && IS_TYPE_INT((node)->rtype) && (node)->rtype->size <= 4 ) +#define IS_INT_CONST_ZERO(node) ( IS_INT_CONST(node) && (node)->data.intval.lo == 0 ) + +void init_cgdispatch(void) { + ENodeType t; + + for (t = 0; t <= MAXEXPR; t++) + cgdispatch[t] = gen_UNEXPECTED; + + cgdispatch[EPOSTINC] = gen_POSTINCDEC; + cgdispatch[EPOSTDEC] = gen_POSTINCDEC; + cgdispatch[EINDIRECT] = gen_INDIRECT; + cgdispatch[EMONMIN] = gen_MONMIN; + cgdispatch[EBINNOT] = gen_BINNOT; + cgdispatch[ELOGNOT] = gen_LOGICAL; + cgdispatch[EFORCELOAD] = gen_FORCELOAD; + cgdispatch[EMUL] = gen_MUL; + cgdispatch[EDIV] = gen_DIV; + cgdispatch[EMODULO] = gen_MODULO; + cgdispatch[EADD] = gen_ADD; + cgdispatch[ESUB] = gen_SUB; + cgdispatch[ESHL] = gen_SHL; + cgdispatch[ESHR] = gen_SHR; + cgdispatch[ELESS] = gen_COMPARE; + cgdispatch[EGREATER] = gen_COMPARE; + cgdispatch[ELESSEQU] = gen_COMPARE; + cgdispatch[EGREATEREQU] = gen_COMPARE; + cgdispatch[EEQU] = gen_COMPARE; + cgdispatch[ENOTEQU] = gen_COMPARE; + cgdispatch[EAND] = gen_AND; + cgdispatch[EXOR] = gen_XOR; + cgdispatch[EOR] = gen_OR; + cgdispatch[ELAND] = gen_LOGICAL; + cgdispatch[ELOR] = gen_LOGICAL; + cgdispatch[EASS] = gen_ASS; + cgdispatch[ECOMMA] = gen_COMMA; + cgdispatch[ETYPCON] = gen_TYPCON; + cgdispatch[EBITFIELD] = gen_BITFIELD; + cgdispatch[EINTCONST] = gen_INTCONST; + cgdispatch[EFLOATCONST] = gen_FLOATCONST; + cgdispatch[ESTRINGCONST] = gen_STRINGCONST; + cgdispatch[ECOND] = gen_COND; + cgdispatch[EFUNCCALL] = gen_FUNCCALL; + cgdispatch[EFUNCCALLP] = gen_FUNCCALL; + cgdispatch[EOBJREF] = gen_OBJREF; + cgdispatch[ENULLCHECK] = gen_NULLCHECK; + cgdispatch[EPRECOMP] = gen_PRECOMP; + cgdispatch[EDEFINE] = gen_DEFINE; + cgdispatch[EREUSE] = gen_REUSE; + cgdispatch[EVECTOR128CONST] = gen_VECTOR128CONST; + cgdispatch[ECONDASS] = gen_CONDASS; +} + +void gen_DEFINE(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + Operand *op; + + if (!expr->data.diadic.right) { + op = lalloc(sizeof(Operand)); + memclrw(op, sizeof(Operand)); + expr->data.diadic.right = (ENode *) op; + GEN_NODE(expr->data.diadic.left, op); + } + + op = (Operand *) expr->data.diadic.right; + *output = *op; +} + +void gen_REUSE(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *inner = expr->data.monadic; +#line 250 + CError_ASSERT(ENODE_IS(inner, EDEFINE)); + gen_DEFINE(inner, outputReg, outputRegHi, output); +} + +void gen_POSTINCDEC(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + TypeBitfield *tbitfield; + ENode *inner; + Type *type; + Operand a; + Operand b; + Operand c; + Float fval; + int objReg; + int constReg; + int finalReg; + SInt32 incval; + + inner = expr->data.monadic->data.monadic; + type = expr->rtype; + tbitfield = NULL; + + memclrw(&a, sizeof(Operand)); + memclrw(&b, sizeof(Operand)); + memclrw(&c, sizeof(Operand)); + + if (TYPE_IS_8BYTES(type)) { + I8_gen_POSTINCDEC(expr, outputReg, outputRegHi, output); + return; + } + + if (IS_TYPE_FLOAT(type)) { + if (ENODE_IS(inner, EOBJREF) && (objReg = OBJECT_REG(inner->data.objref))) { + output->optype = OpndType_FPR; + output->reg = (outputReg && outputReg != objReg) ? outputReg : ALLOC_FPR(); + emitpcode(PC_FMR, output->reg, objReg); + fval = one_point_zero; + load_floating_constant(constReg = ALLOC_FPR(), type, &fval.value); + + if (ENODE_IS(expr, EPOSTINC)) { + emitpcode((type->size == 4) ? PC_FADDS : PC_FADD, objReg, objReg, constReg); + } else { + emitpcode((type->size == 4) ? PC_FSUBS : PC_FSUB, objReg, objReg, constReg); + } + } else { + GEN_NODE(inner, &a); + indirect(&a, inner); + b = a; + ENSURE_FPR(&b, type, 0); + + output->optype = OpndType_FPR; + output->reg = ALLOC_FPR(); + emitpcode(PC_FMR, output->reg, b.reg); + + fval = one_point_zero; + load_floating_constant(constReg = ALLOC_FPR(), type, &fval.value); + + finalReg = ALLOC_FPR(); + if (ENODE_IS(expr, EPOSTINC)) + emitpcode((type->size == 4) ? PC_FADDS : PC_FADD, finalReg, b.reg, constReg); + else + emitpcode((type->size == 4) ? PC_FSUBS : PC_FSUB, finalReg, b.reg, constReg); + + store_fp(finalReg, &a, type); + } + } else { + if (IS_TYPE_POINTER(type)) { + if (ENODE_IS(expr, EPOSTINC)) + incval = TPTR_TARGET(type)->size; + else + incval = -TPTR_TARGET(type)->size; + } else { + if (ENODE_IS(expr, EPOSTINC)) + incval = 1; + else + incval = -1; + } + + if (ENODE_IS(inner, EOBJREF) && (objReg = OBJECT_REG(inner->data.objref))) { + output->optype = OpndType_GPR; + output->reg = (outputReg && outputReg != objReg) ? outputReg : ALLOC_GPR(); + emitpcode(PC_MR, output->reg, objReg); + add_register_immediate(objReg, objReg, incval); + } else { + if (ENODE_IS(inner, EBITFIELD)) { + tbitfield = TYPE_BITFIELD(TPTR_TARGET(inner)); + inner = inner->data.monadic; + } + GEN_NODE(inner, &a); + indirect(&a, inner); + b = a; + ENSURE_GPR(&b, type, 0); + + if (tbitfield) { + c = b; + extract_bitfield(&c, tbitfield, 0, &b); + } + output->optype = OpndType_GPR; + + output->reg = ALLOC_GPR(); + emitpcode(PC_MR, output->reg, b.reg); + + finalReg = ALLOC_GPR(); + add_register_immediate(finalReg, b.reg, incval); + + if (tbitfield) { + insert_bitfield(finalReg, &c, tbitfield); + finalReg = c.reg; + } + + store(finalReg, &a, type); + } + } +} + +void gen_INDIRECT(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + Type *type; + ENode *inner; + VarInfo *vi; + SInt32 postincvalue; + Operand op; + + type = expr->rtype; + inner = expr->data.monadic; + + if (TYPE_IS_8BYTES(type)) { + I8_gen_INDIRECT(expr, outputReg, outputRegHi, output); + return; + } + + memclrw(&op, sizeof(Operand)); + if (ENODE_IS(inner, EOBJREF) && OBJECT_REG(inner->data.objref)) { + vi = Registers_GetVarInfo(inner->data.objref); + switch (vi->rclass) { + case RegClass_GPR: + output->optype = OpndType_GPR; + break; + case RegClass_FPR: + output->optype = OpndType_FPR; + break; + case RegClass_VR: + output->optype = OpndType_VR; + break; + case RegClass_CRFIELD: + output->optype = OpndType_CRField; + break; + default: +#line 456 + CError_FATAL(); + } + output->reg = vi->reg; + output->object = NULL; + return; + } + + if (ENODE_IS(inner, EBITFIELD)) { + GEN_NODE(inner->data.monadic, &op); + indirect(&op, expr); + ENSURE_GPR(&op, type, 0); + extract_bitfield(&op, TYPE_BITFIELD(inner->rtype), outputReg, output); + return; + } + + if (ispostincrementopportunity(inner, &op, &postincvalue) && (TYPE_FITS_IN_REGISTER(type) || IS_TYPE_FLOAT(type) || IS_TYPE_VECTOR(type))) { + indirect(&op, expr); + *output = op; + if (TYPE_FITS_IN_REGISTER(type)) { + ENSURE_GPR(output, type, outputReg); + } else if (IS_TYPE_FLOAT(type)) { + ENSURE_FPR(output, type, outputReg); + } else { + ENSURE_VR(output, type, outputReg); + } + + add_register_immediate(op.reg, op.reg, postincvalue); + return; + } + + GEN_NODE(inner, output); + indirect(output, expr); +} + +void gen_MONMIN(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *inner; + Type *type; + ENode *scan; + + inner = expr->data.monadic; + type = expr->rtype; + + if (TYPE_IS_8BYTES(type)) { + I8_gen_MONMIN(expr, outputReg, outputRegHi, output); + return; + } + + if (IS_TYPE_FLOAT(type)) { + if (ENODE_IS(inner, EADD) && ENODE_IS(inner->data.diadic.left, EMUL) && copts.fp_contract) { + fp_multiply_add( + (type->size == 4) ? PC_FNMADDS : PC_FNMADD, + inner->data.diadic.left->data.diadic.left, + inner->data.diadic.left->data.diadic.right, + inner->data.diadic.right, + outputReg, + output); + } else if (ENODE_IS(inner, EADD) && ENODE_IS(inner->data.diadic.right, EMUL) && copts.fp_contract) { + fp_multiply_add( + (type->size == 4) ? PC_FNMADDS : PC_FNMADD, + inner->data.diadic.right->data.diadic.left, + inner->data.diadic.right->data.diadic.right, + inner->data.diadic.left, + outputReg, + output); + } else if (ENODE_IS(inner, ESUB) && ENODE_IS(inner->data.diadic.left, EMUL) && copts.fp_contract) { + fp_multiply_add( + (type->size == 4) ? PC_FNMSUBS : PC_FNMSUB, + inner->data.diadic.left->data.diadic.left, + inner->data.diadic.left->data.diadic.right, + inner->data.diadic.right, + outputReg, + output); + } else { + fp_unary_operator(PC_FNEG, inner, outputReg, output); + } + return; + } + + scan = inner; + while (ENODE_IS(scan, ETYPCON) && IS_TYPE_INT_OR_ENUM(type) && !is_unsigned(type)) + scan = scan->data.monadic; + + switch (scan->type) { + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + if (TYPE_FITS_IN_REGISTER(scan->data.diadic.left->rtype) && TYPE_FITS_IN_REGISTER(scan->data.diadic.right->rtype)) { + gen_negated_condition_gpr(scan, output, outputReg); + return; + } + } + unary_operator(PC_NEG, inner, outputReg, output); +} + +void gen_BINNOT(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *inner; + Type *type; + + inner = expr->data.monadic; + type = expr->rtype; + + if (TYPE_IS_8BYTES(type)) { + I8_gen_BINNOT(expr, outputReg, outputRegHi, output); + return; + } + + if (ENODE_IS(inner, EAND)) + binary_operator(PC_NAND, inner->data.diadic.left, inner->data.diadic.right, outputReg, output); + else if (ENODE_IS(inner, EOR)) + binary_operator(PC_NOR, inner->data.diadic.left, inner->data.diadic.right, outputReg, output); + else if (ENODE_IS(inner, EXOR)) + binary_operator(PC_EQV, inner->data.diadic.left, inner->data.diadic.right, outputReg, output); + else + unary_operator(PC_NOT, inner, outputReg, output); +} + +void gen_FORCELOAD(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *inner; + + inner = expr->data.monadic; + GEN_NODE(inner, output); + + if (IS_TYPE_FLOAT(inner->rtype)) { + ENSURE_FPR(output, inner->rtype, outputReg); + } else if (IS_TYPE_VECTOR(inner->rtype)) { + ENSURE_VR(output, inner->rtype, outputReg); + } else if (TYPE_FITS_IN_REGISTER(inner->rtype)) { + if (TYPE_IS_8BYTES(inner->rtype)) + coerce_to_register_pair(output, inner->rtype, outputReg, outputRegHi); + else + ENSURE_GPR(output, inner->rtype, outputReg); + } else if (!IS_TYPE_VOID(inner->rtype)) { +#line 681 + CError_FATAL(); + } +} + +void gen_MUL(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *left; + ENode *right; + Type *type; + int tmp; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + type = expr->rtype; + + if (TYPE_IS_8BYTES(type)) { + I8_gen_MUL(expr, outputReg, outputRegHi, output); + return; + } + + if (IS_TYPE_FLOAT(type)) { + fp_binary_operator((type->size == 4) ? PC_FMULS : PC_FMUL, left, right, outputReg, output); + return; + } + + if (ENODE_IS(right, EINTCONST) && (tmp = ispowerof2(right->data.intval.lo))) { + shift_left_immediate(left, tmp, 0, outputReg, output); + } else if (ENODE_IS(right, EINTCONST) && (tmp = ispowerof2(-right->data.intval.lo))) { + shift_left_immediate(left, tmp, 1, outputReg, output); + } else if (ENODE_IS(left, EINTCONST) && (tmp = ispowerof2(left->data.intval.lo))) { + shift_left_immediate(right, tmp, 0, outputReg, output); + } else if (ENODE_IS(left, EINTCONST) && (tmp = ispowerof2(-left->data.intval.lo))) { + shift_left_immediate(right, tmp, 1, outputReg, output); + } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT(right->data.intval.lo)) { + binary_immediate(PC_MULLI, left, right->data.intval.lo, outputReg, output); + } else if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT(left->data.intval.lo)) { + binary_immediate(PC_MULLI, right, left->data.intval.lo, outputReg, output); + } else { + binary_operator(PC_MULLW, left, right, outputReg, output); + } +} + +struct ms { + SInt32 m; + int s; +}; +static void create_signed_magic(SInt32 val, struct ms *output) { + // PowerPC CWG page 57-58 + int p; + UInt32 ad, anc, delta, q1, r1, q2, r2, t; + + ad = abs(val); + t = 0x80000000U + ((UInt32) val >> 31); + anc = t - 1 - t % ad; + p = 31; + q1 = 0x80000000U / anc; + r1 = 0x80000000U - q1 * anc; + q2 = 0x80000000U / ad; + r2 = 0x80000000U - q2 * ad; + + do { + p = p + 1; + q1 = 2 * q1; + r1 = 2 * r1; + if (r1 >= anc) { + q1 = q1 + 1; + r1 = r1 - anc; + } + q2 = 2 * q2; + r2 = 2 * r2; + if (r2 >= ad) { + q2 = q2 + 1; + r2 = r2 - ad; + } + delta = ad - r2; + } while (q1 < delta || (q1 == delta && r1 == 0)); + + // after loop + output->m = q2 + 1; + if (val < 0) + output->m = -output->m; + output->s = p - 32; +} + +struct mu { + UInt32 m; + int a; + int s; +}; +static void create_unsigned_magic(UInt32 val, struct mu *output) { + // PowerPC CWG page 58-59 + int p; + UInt32 nc, delta, q1, r1, q2, r2; + + output->a = 0; + nc = - 1 - (-val) % val; + p = 31; + q1 = 0x80000000U / nc; + r1 = 0x80000000U - q1 * nc; + q2 = 0x7FFFFFFFU / val; + r2 = 0x7FFFFFFFU - q2 * val; + do { + p = p + 1; + if (r1 >= nc - r1) { + q1 = 2 * q1 + 1; + r1 = 2 * r1 - nc; + } else { + q1 = 2 * q1; + r1 = 2 * r1; + } + if (r2 + 1 >= val - r2) { + if (q2 >= 0x7FFFFFFFU) + output->a = 1; + q2 = 2 * q2 + 1; + r2 = 2 * r2 + 1 - val; + } else { + if (q2 >= 0x80000000U) + output->a = 1; + q2 = 2 * q2; + r2 = 2 * r2 + 1; + } + delta = val - 1 - r2; + } while (p < 64 && (q1 < delta || (q1 == delta && r1 == 0))); + + output->m = q2 + 1; + output->s = p - 32; +} + +void gen_DIV(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *left; + ENode *right; + Type *type; + int tmp; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + type = expr->rtype; + + if (TYPE_IS_8BYTES(type)) { + I8_gen_DIV_MOD(expr, outputReg, outputRegHi, output); + return; + } + + if (IS_TYPE_FLOAT(type)) { + fp_binary_operator((type->size == 4) ? PC_FDIVS : PC_FDIV, left, right, outputReg, output); + return; + } + + if (is_unsigned(type)) { + if (ENODE_IS(right, EINTCONST) && (tmp = ispowerof2(right->data.intval.lo))) { + shift_right_immediate(left, type, tmp, outputReg, output); + } else if (!copts.optimize_for_size && ENODE_IS(right, EINTCONST) && right->data.intval.lo != 1) { + SInt32 value; + int tmpreg1; + int tmpreg2; + int tmpreg3; + int tmpreg4; + int tmpreg5; + int tmpreg6; + int finalReg; + struct mu u_magicoutput; + Operand op1; + value = right->data.intval.lo; + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + + memclrw(&op1, sizeof(Operand)); + GEN_NODE(left, &op1); + ENSURE_GPR(&op1, left->rtype, 0); + + tmpreg3 = op1.reg; + create_unsigned_magic(value, &u_magicoutput); + load_immediate(tmpreg2, u_magicoutput.m); + emitpcode(PC_MULHWU, tmpreg1, tmpreg2, tmpreg3); + if (u_magicoutput.a == 0) { + if (u_magicoutput.s) + emitpcode(PC_RLWINM, finalReg, tmpreg1, (32 - u_magicoutput.s) & 31, u_magicoutput.s, 31); + else + emitpcode(PC_MR, finalReg, tmpreg1); + } else if (u_magicoutput.a == 1) { + tmpreg4 = ALLOC_GPR(); + if (copts.optimizationlevel > 1) { + tmpreg5 = ALLOC_GPR(); + tmpreg6 = ALLOC_GPR(); + } else { + tmpreg5 = tmpreg4; + tmpreg6 = tmpreg4; + } + + emitpcode(PC_SUBF, tmpreg4, tmpreg1, tmpreg3); + emitpcode(PC_RLWINM, tmpreg5, tmpreg4, 31, 1, 31); + emitpcode(PC_ADD, tmpreg6, tmpreg5, tmpreg1); + emitpcode(PC_RLWINM, finalReg, tmpreg6, (32 - (u_magicoutput.s - 1)) & 31, u_magicoutput.s - 1, 31); + } + + output->optype = OpndType_GPR; + output->reg = finalReg; + } else { + binary_operator(PC_DIVWU, left, right, outputReg, output); + } + } else { + SInt32 value; + if (ENODE_IS(right, EINTCONST) && (tmp = ispowerof2(right->data.intval.lo))) { + signed_divide_by_power_of_2(left, tmp, 0, outputReg, output); + } else if (ENODE_IS(right, EINTCONST) && (tmp = ispowerof2(-right->data.intval.lo))) { + signed_divide_by_power_of_2(left, tmp, 1, outputReg, output); + } else if (!copts.optimize_for_size && ENODE_IS(right, EINTCONST) && (value = right->data.intval.lo) != 1u && value != -1) { + int tmpreg2; + int tmpreg3; + int tmpreg1; + int tmpreg4; + int finalReg; + struct ms s_magicoutput; + Operand op2; + value = right->data.intval.lo; + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); + tmpreg3 = ALLOC_GPR(); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + + memclrw(&op2, sizeof(Operand)); + GEN_NODE(left, &op2); + ENSURE_GPR(&op2, left->rtype, 0); + + tmpreg4 = op2.reg; + create_signed_magic(value, &s_magicoutput); + load_immediate(tmpreg2, s_magicoutput.m); + emitpcode(PC_MULHW, tmpreg1, tmpreg2, tmpreg4); + if (value > 0 && s_magicoutput.m < 0) { + int t = ALLOC_GPR(); + emitpcode(PC_ADD, t, tmpreg1, tmpreg4); + tmpreg1 = t; + } else if (value < 0 && s_magicoutput.m > 0) { + int t = ALLOC_GPR(); + emitpcode(PC_SUBF, t, tmpreg4, tmpreg1); + tmpreg1 = t; + } + + if (s_magicoutput.s) { + int t = ALLOC_GPR(); + emitpcode(PC_SRAWI, t, tmpreg1, s_magicoutput.s); + tmpreg1 = t; + } + + emitpcode(PC_RLWINM, tmpreg3, tmpreg1, 1, 31, 31); + emitpcode(PC_ADD, finalReg, tmpreg1, tmpreg3); + + output->optype = OpndType_GPR; + output->reg = finalReg; + } else { + binary_operator(PC_DIVW, left, right, outputReg, output); + } + } +} + +void gen_MODULO(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *left; + ENode *right; + int tmp; + struct mu u_magicoutput; + struct ms s_magicoutput; + Operand op1; + Operand op2; + SInt32 value; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + memclrw(&op1, sizeof(Operand)); + memclrw(&op2, sizeof(Operand)); + + if (TYPE_IS_8BYTES(expr->rtype)) { + I8_gen_DIV_MOD(expr, outputReg, outputRegHi, output); + return; + } + + if (ENODE_IS(right, EINTCONST) && (tmp = ispowerof2(right->data.intval.lo))) { + if (is_unsigned(expr->rtype)) + shift_and_mask(left, 0, 32 - tmp, 31, outputReg, output); + else + signed_mod_by_power_of_2(left, tmp, 0, outputReg, output); + } else if (!copts.optimize_for_size && ENODE_IS(right, EINTCONST) && (value = right->data.intval.lo) != 1u && value != -1) { + GEN_NODE(left, &op1); + ENSURE_GPR(&op1, left->rtype, 0); + + if (is_unsigned(expr->rtype)) { + int tmpreg1; + int tmpreg2; + int tmpreg3; + int tmpreg4; + int tmpreg5; + int tmpreg6; + int tmpreg7; + int tmpreg8; + int finalReg; + + tmpreg1 = op1.reg; + tmpreg2 = ALLOC_GPR(); + tmpreg3 = ALLOC_GPR(); + tmpreg4 = ALLOC_GPR(); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + + create_unsigned_magic(right->data.intval.lo, &u_magicoutput); + load_immediate(tmpreg3, u_magicoutput.m); + emitpcode(PC_MULHWU, tmpreg2, tmpreg3, tmpreg1); + + if (u_magicoutput.a == 0 && u_magicoutput.s != 0) + emitpcode(PC_RLWINM, tmpreg2, tmpreg2, (32 - u_magicoutput.s) & 31, u_magicoutput.s, 31); + + if (u_magicoutput.a == 1) { + tmpreg5 = ALLOC_GPR(); + if (copts.optimizationlevel > 1) { + tmpreg6 = ALLOC_GPR(); + tmpreg7 = ALLOC_GPR(); + tmpreg8 = ALLOC_GPR(); + } else { + tmpreg6 = tmpreg5; + tmpreg7 = tmpreg5; + tmpreg8 = tmpreg5; + } + emitpcode(PC_SUBF, tmpreg5, tmpreg2, tmpreg1); + emitpcode(PC_RLWINM, tmpreg6, tmpreg5, 31, 1, 31); + emitpcode(PC_ADD, tmpreg7, tmpreg6, tmpreg2); + emitpcode(PC_RLWINM, tmpreg8, tmpreg7, (32 - (u_magicoutput.s - 1)) & 31, u_magicoutput.s - 1, 31); + tmpreg2 = tmpreg8; + } + + if (value > 0 && value < 0x7FFF) { + emitpcode(PC_MULLI, tmpreg4, tmpreg2, value); + } else { + GEN_NODE(right, &op2); + ENSURE_GPR(&op2, right->rtype, 0); + emitpcode(PC_MULLW, tmpreg4, tmpreg2, op2.reg); + } + + emitpcode(PC_SUBF, finalReg, tmpreg4, tmpreg1); + output->optype = OpndType_GPR; + output->reg = finalReg; + } else { + int tmpreg1; + int tmpreg2; + int tmpreg3; + int tmpreg4; + int tmpreg5; + int tmpreg6; + int finalReg; + + tmpreg1 = op1.reg; + tmpreg2 = ALLOC_GPR(); + tmpreg3 = ALLOC_GPR(); + tmpreg4 = ALLOC_GPR(); + tmpreg5 = ALLOC_GPR(); + tmpreg6 = ALLOC_GPR(); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + + create_signed_magic(right->data.intval.lo, &s_magicoutput); + load_immediate(tmpreg3, s_magicoutput.m); + emitpcode(PC_MULHW, tmpreg2, tmpreg3, tmpreg1); + + if (value > 0 && s_magicoutput.m < 0) { + int tmp = ALLOC_GPR(); + emitpcode(PC_ADD, tmp, tmpreg2, tmpreg1); + tmpreg2 = tmp; + } else if (value < 0 && s_magicoutput.m > 0) { + int tmp = ALLOC_GPR(); + emitpcode(PC_SUBF, tmp, tmpreg1, tmpreg2); + tmpreg2 = tmp; + } + + if (s_magicoutput.s != 0) { + int tmp = ALLOC_GPR(); + emitpcode(PC_SRAWI, tmp, tmpreg2, s_magicoutput.s); + tmpreg2 = tmp; + } + + emitpcode(PC_RLWINM, tmpreg4, tmpreg2, 1, 31, 31); + emitpcode(PC_ADD, tmpreg5, tmpreg2, tmpreg4); + + if (value < 0x7FFF && value > -0x4000) { + emitpcode(PC_MULLI, tmpreg6, tmpreg5, value); + } else { + GEN_NODE(right, &op2); + ENSURE_GPR(&op2, right->rtype, 0); + + emitpcode(PC_MULLW, tmpreg6, tmpreg5, op2.reg); + } + + emitpcode(PC_SUBF, finalReg, tmpreg6, tmpreg1); + output->optype = OpndType_GPR; + output->reg = finalReg; + } + } else { + int tmpreg1; + int tmpreg2; + int finalReg; + + if (right->hascall) { + GEN_NODE(right, &op2); + ENSURE_GPR(&op2, right->rtype, 0); + GEN_NODE(left, &op1); + ENSURE_GPR(&op1, left->rtype, 0); + } else { + GEN_NODE(left, &op1); + ENSURE_GPR(&op1, left->rtype, 0); + GEN_NODE(right, &op2); + ENSURE_GPR(&op2, right->rtype, 0); + } + + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); + finalReg = outputReg ? outputReg : ALLOC_GPR(); + + emitpcode(is_unsigned(expr->rtype) ? PC_DIVWU : PC_DIVW, tmpreg1, op1.reg, op2.reg); + emitpcode(PC_MULLW, tmpreg2, tmpreg1, op2.reg); + emitpcode(PC_SUBF, finalReg, tmpreg2, op1.reg); + + output->optype = OpndType_GPR; + output->reg = finalReg; + } +} + +void gen_ADD(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *left; + ENode *right; + Type *type; + Operand opleft; + Operand opright; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + type = expr->rtype; + + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + + if (TYPE_IS_8BYTES(type)) { + I8_gen_ADD(expr, outputReg, outputRegHi, output); + return; + } + + if (IS_TYPE_FLOAT(type)) { + if (ENODE_IS(left, EMUL) && copts.fp_contract) { + fp_multiply_add( + (type->size == 4) ? PC_FMADDS : PC_FMADD, + left->data.diadic.left, + left->data.diadic.right, + right, + outputReg, output); + } else if (ENODE_IS(right, EMUL) && copts.fp_contract) { + fp_multiply_add( + (type->size == 4) ? PC_FMADDS : PC_FMADD, + right->data.diadic.left, + right->data.diadic.right, + left, + outputReg, output); + } else { + fp_binary_operator( + (type->size == 4) ? PC_FADDS : PC_FADD, + left, right, + outputReg, output); + } + return; + } + + if (right->hascall) { + GEN_NODE(right, &opright); + if (opright.optype >= OpndType_IndirectGPR_ImmOffset) + ENSURE_GPR(&opright, right->rtype, 0); + + GEN_NODE(left, &opleft); + if (opleft.optype >= OpndType_IndirectGPR_ImmOffset) + ENSURE_GPR(&opleft, left->rtype, 0); + } else { + GEN_NODE(left, &opleft); + if (opleft.optype >= OpndType_IndirectGPR_ImmOffset) + ENSURE_GPR(&opleft, left->rtype, 0); + + GEN_NODE(right, &opright); + if (opright.optype >= OpndType_IndirectGPR_ImmOffset) + ENSURE_GPR(&opright, right->rtype, 0); + } + + if (IS_TYPE_POINTER(expr->rtype)) { + if (TYPE_IS_8BYTES(expr->data.diadic.left->rtype)) { + opleft.optype = OpndType_GPR; + opleft.regHi = 0; + } + if (TYPE_IS_8BYTES(expr->data.diadic.right->rtype)) { + opright.optype = OpndType_GPR; + opright.regHi = 0; + } + } + + combine(&opleft, &opright, outputReg, output); +} + +void gen_SUB(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *left; + ENode *right; + Type *type; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + type = expr->rtype; + + if (TYPE_IS_8BYTES(type)) { + I8_gen_SUB(expr, outputReg, outputRegHi, output); + return; + } + + if (IS_TYPE_FLOAT(type)) { + if (ENODE_IS(left, EMUL) && copts.fp_contract) { + fp_multiply_add( + (type->size == 4) ? PC_FMSUBS : PC_FMSUB, + left->data.diadic.left, + left->data.diadic.right, + right, + outputReg, output); + } else if (ENODE_IS(right, EMUL) && copts.fp_contract) { + fp_multiply_add( + (type->size == 4) ? PC_FNMSUBS : PC_FNMSUB, + right->data.diadic.left, + right->data.diadic.right, + left, + outputReg, output); + } else { + fp_binary_operator( + (type->size == 4) ? PC_FSUBS : PC_FSUB, + left, right, + outputReg, output); + } + return; + } + + if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT(left->data.intval.lo)) + binary_immediate(PC_SUBFIC, right, left->data.intval.lo, outputReg, output); + else + binary_operator(PC_SUBF, right, left, outputReg, output); +} + +void gen_SHL(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + Type *type; + ENode *left; + ENode *right; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + type = expr->rtype; + + if (TYPE_IS_8BYTES(type)) { + I8_gen_SHL_SHR(expr, outputReg, outputRegHi, output); + return; + } + + if (ENODE_IS(right, EINTCONST)) + shift_left_immediate(left, right->data.intval.lo, 0, outputReg, output); + else + binary_operator(PC_SLW, left, right, outputReg, output); +} + +void gen_SHR(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + Type *type; + ENode *left; + ENode *right; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + type = expr->rtype; + + if (TYPE_IS_8BYTES(type)) { + I8_gen_SHL_SHR(expr, outputReg, outputRegHi, output); + return; + } + + if (ENODE_IS(right, EINTCONST)) + shift_right_immediate(left, type, right->data.intval.lo, outputReg, output); + else + binary_operator(is_unsigned(type) ? PC_SRW : PC_SRAW, left, right, outputReg, output); +} + +void gen_AND(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + Type *type; + ENode *left; + ENode *right; + short first; + short last; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + type = expr->rtype; + + if (TYPE_IS_8BYTES(type)) { + I8_gen_AND(expr, outputReg, outputRegHi, output); + return; + } + + if (ENODE_IS(right, EINTCONST) && ismaskconstant(right->data.intval.lo, &first, &last)) { + if (ENODE_IS(left, ESHL) && ENODE_IS(left->data.diadic.right, EINTCONST) && (int)(left->data.diadic.right->data.intval.lo + last) < 32) { + shift_and_mask( + left->data.diadic.left, + left->data.diadic.right->data.intval.lo, + first, last, + outputReg, output); + } else if (ENODE_IS(left, ESHR) && ENODE_IS(left->data.diadic.right, EINTCONST) && (int)left->data.diadic.right->data.intval.lo <= first && last >= first) { + if (left->data.diadic.right->data.intval.lo == 0) + shift_and_mask(left->data.diadic.left, 0, first, last, outputReg, output); + else + shift_and_mask(left->data.diadic.left, 32 - left->data.diadic.right->data.intval.lo, first, last, outputReg, output); + } else { + shift_and_mask(left, 0, first, last, outputReg, output); + } + return; + } + + if (ENODE_IS(right, EINTCONST) && FITS_IN_USHORT(right->data.intval.lo)) { + binary_immediate(PC_ANDI, left, right->data.intval.lo, outputReg, output); + return; + } + if (ENODE_IS(right, EINTCONST) && FITS_IN_HI_SHORT(right->data.intval.lo)) { + binary_immediate(PC_ANDIS, left, right->data.intval.lo >> 16, outputReg, output); + return; + } + + if (ENODE_IS(left, EINTCONST) && ismaskconstant(left->data.intval.lo, &first, &last)) { + if (ENODE_IS(right, ESHL) && ENODE_IS(right->data.diadic.right, EINTCONST) && (int)(right->data.diadic.right->data.intval.lo + last) < 32) { + shift_and_mask( + right->data.diadic.left, + right->data.diadic.right->data.intval.lo, + first, last, + outputReg, output); + } else if (ENODE_IS(right, ESHR) && ENODE_IS(right->data.diadic.right, EINTCONST) && (int)right->data.diadic.right->data.intval.lo <= first) { + if (right->data.diadic.right->data.intval.lo == 0) + shift_and_mask(right->data.diadic.left, 0, first, last, outputReg, output); + else + shift_and_mask(right->data.diadic.left, 32 - right->data.diadic.right->data.intval.lo, first, last, outputReg, output); + } else { + shift_and_mask(right, 0, first, last, outputReg, output); + } + return; + } + + if (ENODE_IS(left, EINTCONST) && FITS_IN_USHORT(left->data.intval.lo)) { + binary_immediate(PC_ANDI, right, left->data.intval.lo, outputReg, output); + return; + } + if (ENODE_IS(left, EINTCONST) && FITS_IN_HI_SHORT(left->data.intval.lo)) { + binary_immediate(PC_ANDIS, right, left->data.intval.lo >> 16, outputReg, output); + return; + } + + if (ENODE_IS(right, EBINNOT)) + binary_operator(PC_ANDC, left, right->data.monadic, outputReg, output); + else if (ENODE_IS(left, EBINNOT)) + binary_operator(PC_ANDC, right, left->data.monadic, outputReg, output); + else + binary_operator(PC_AND, left, right, outputReg, output); +} + +void gen_XOR(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + Type *type; + ENode *left; + ENode *right; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + type = expr->rtype; + + if (TYPE_IS_8BYTES(type)) { + I8_gen_XOR(expr, outputReg, outputRegHi, output); + return; + } + + if (ENODE_IS(left, EINTCONST)) + or_xor_immediate(PC_XORI, right, left->data.intval.lo, outputReg, output); + else if (ENODE_IS(right, EINTCONST)) + or_xor_immediate(PC_XORI, left, right->data.intval.lo, outputReg, output); + else if (ENODE_IS(right, EBINNOT)) + binary_operator(PC_EQV, left, right->data.monadic, outputReg, output); + else if (ENODE_IS(left, EBINNOT)) + binary_operator(PC_EQV, left->data.monadic, right, outputReg, output); + else + binary_operator(PC_XOR, left, right, outputReg, output); +} + +void gen_OR(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + Type *type; + ENode *left; + ENode *right; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + type = expr->rtype; + + if (TYPE_IS_8BYTES(type)) { + I8_gen_OR(expr, outputReg, outputRegHi, output); + return; + } + + if (ENODE_IS(left, EINTCONST)) + or_xor_immediate(PC_ORI, right, left->data.intval.lo, outputReg, output); + else if (ENODE_IS(right, EINTCONST)) + or_xor_immediate(PC_ORI, left, right->data.intval.lo, outputReg, output); + else if (ENODE_IS(right, EBINNOT)) + binary_operator(PC_ORC, left, right->data.monadic, outputReg, output); + else if (ENODE_IS(left, EBINNOT)) + binary_operator(PC_ORC, right, left->data.monadic, outputReg, output); + else + binary_operator(PC_OR, left, right, outputReg, output); +} + +void gen_ASS(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + Type *type; + ENode *left; + ENode *right; + Operand opleft; + Operand opright; + Operand op2; + VarInfo *vi; + SInt32 incval; + short align; + short align2; + + type = expr->rtype; + if (ENODE_IS(expr, ECONDASS)) { + left = expr->data.cond.expr1; + if (ENODE_IS(left, EINDIRECT)) { + left = left->data.monadic; + } else { +#line 1759 + CError_FATAL(); + } + right = expr->data.cond.expr2; + } else { + left = expr->data.diadic.left; + right = expr->data.diadic.right; + } + + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + memclrw(&op2, sizeof(Operand)); + + if (TYPE_IS_8BYTES(type)) { + I8_gen_ASS(expr, outputReg, outputRegHi, output); + return; + } + + if (ENODE_IS(left, EOBJREF) && OBJECT_REG(left->data.objref)) { + vi = Registers_GetVarInfo(left->data.objref); + GEN_NODE_TO_REG(right, vi->reg, 0, &opright); + switch (vi->rclass) { + case RegClass_GPR: + ENSURE_GPR(&opright, type, vi->reg); + output->optype = OpndType_GPR; + break; + case RegClass_FPR: + ENSURE_FPR(&opright, type, vi->reg); + output->optype = OpndType_FPR; + break; + case RegClass_VR: + ENSURE_VR(&opright, type, vi->reg); + output->optype = OpndType_VR; + break; + default: +#line 1810 + CError_FATAL(); + } + if (opright.reg != vi->reg) { + PCodeArg a, b; + a.kind = PCOp_REGISTER; + a.arg = vi->rclass; + a.data.reg.reg = vi->reg; + a.data.reg.effect = EffectWrite; + b.kind = PCOp_REGISTER; + b.arg = vi->rclass; + b.data.reg.reg = opright.reg; + b.data.reg.effect = EffectRead; + appendpcode(pclastblock, makecopyinstruction(&b, &a)); + } + output->reg = vi->reg; + return; + } + + if (IS_TYPE_FLOAT(type)) { + GEN_NODE_TO_FPR(right, &opright, right->rtype, 0); + if (ispostincrementopportunity(left, &opleft, &incval)) { + indirect(&opleft, expr); + store_fp(opright.reg, &opleft, type); + add_register_immediate(opleft.reg, opleft.reg, incval); + } else { + GEN_NODE(left, &opleft); + indirect(&opleft, expr); + store_fp(opright.reg, &opleft, type); + } + output->optype = OpndType_FPR; + output->reg = opright.reg; + return; + } + + if (IS_TYPE_VECTOR(type)) { + GEN_NODE(right, &opright); + if (opright.optype == OpndType_Absolute) + ENSURE_VR(&opright, type, 0); + else + ENSURE_VR(&opright, right->rtype, 0); + + if (ispostincrementopportunity(left, &opleft, &incval)) { + indirect(&opleft, expr); + store_v(opright.reg, &opleft, type); + add_register_immediate(opleft.reg, opleft.reg, incval); + } else { + GEN_NODE(left, &opleft); + indirect(&opleft, expr); + store_v(opright.reg, &opleft, type); + } + output->optype = OpndType_VR; + output->reg = opright.reg; + return; + } + + if (TYPE_FITS_IN_REGISTER(type)) { + GEN_NODE_TO_GPR(right, &opright, right->rtype, 0); + + if (ENODE_IS(left, EBITFIELD)) { + GEN_NODE(left->data.monadic, &opleft); + indirect(&opleft, expr); + + op2 = opleft; + ENSURE_GPR(&op2, type, 0); + insert_bitfield(opright.reg, &op2, TYPE_BITFIELD(left->rtype)); + store(op2.reg, &opleft, type); + + if (!expr->ignored) + extract_bitfield(&op2, TYPE_BITFIELD(left->rtype), opright.reg, &opleft); + } else if (ispostincrementopportunity(left, &opleft, &incval)) { + indirect(&opleft, expr); + store(opright.reg, &opleft, type); + add_register_immediate(opleft.reg, opleft.reg, incval); + } else { + GEN_NODE(left, &opleft); + indirect(&opleft, expr); + store(opright.reg, &opleft, type); + } + + output->optype = OpndType_GPR; + output->reg = opright.reg; + return; + } + + GEN_NODE(right, &opright); + GEN_NODE(left, output); + + indirect(output, expr); + if (output->object) { + if (output->object->datatype == DLOCAL && (output->object->u.var.info->flags & VarInfoFlag1)) + align = CMach_ArgumentAlignment(type); + else + align = CMach_AllocationAlignment(type, output->object->qual); + } else { + align = CMach_AllocationAlignment(type, 0); + } + if (opright.object) { + if (opright.object->datatype == DLOCAL && (opright.object->u.var.info->flags & VarInfoFlag1)) + align2 = CMach_ArgumentAlignment(type); + else + align2 = CMach_AllocationAlignment(type, opright.object->qual); + } else { + align2 = CMach_AllocationAlignment(type, 0); + } + + if (align2 < align) + align = align2; + + move_block(output, &opright, type->size, align); +} + +ENode *evaluate_and_skip_comma(ENode *expr) { + Operand op; + ENode *inner; + + memclrw(&op, sizeof(Operand)); + while (ENODE_IS(expr, ECOMMA)) { + inner = expr->data.diadic.left; + GEN_NODE(inner, &op); + if (ENODE_IS(inner, EINDIRECT) && (op.flags & OpndFlags_Volatile)) { + if (TYPE_FITS_IN_REGISTER_2(inner->rtype)) { + ENSURE_GPR(&op, inner->rtype, 0); + } else if (IS_TYPE_FLOAT(inner->rtype)) { + ENSURE_FPR(&op, inner->rtype, 0); + } + } + expr = expr->data.diadic.right; + } + return expr; +} + +void gen_COMMA(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *left; + ENode *right; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + GEN_NODE(left, output); + + if (ENODE_IS(left, EINDIRECT) && (output->flags & OpndFlags_Volatile)) { + if (TYPE_FITS_IN_REGISTER_2(left->rtype)) { + ENSURE_GPR(output, left->rtype, 0); + } else if (IS_TYPE_FLOAT(left->rtype)) { + ENSURE_FPR(output, left->rtype, 0); + } + } + + GEN_NODE_TO_REG(right, outputReg, 0, output); +} + +void gen_TYPCON(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *inner; + Type *srctype; + Type *dsttype; + + inner = expr->data.monadic; + srctype = inner->rtype; + dsttype = expr->rtype; + + if (TYPE_IS_8BYTES(srctype) || TYPE_IS_8BYTES(dsttype)) { + I8_gen_TYPCON(expr, outputReg, outputRegHi, output); + return; + } + + if (IS_TYPE_VOID(dsttype)) { + GEN_NODE(inner, output); + if (ENODE_IS(inner, EINDIRECT) && (output->flags & OpndFlags_Volatile)) { + if (TYPE_FITS_IN_REGISTER_2(srctype)) { + ENSURE_GPR(output, srctype, 0); + } else if (IS_TYPE_FLOAT(srctype)) { + ENSURE_FPR(output, srctype, 0); + } + } + } else if (IS_TYPE_INT_OR_ENUM(srctype)) { + if (IS_TYPE_FLOAT(dsttype)) { + GEN_NODE(inner, output); + if (srctype->size < 4) + extend32(output, srctype, 0); + ENSURE_GPR(output, srctype, 0); + + if (is_unsigned(srctype)) + convert_unsigned_to_floating(output, dsttype->size == 4, outputReg); + else + convert_integer_to_floating(output, dsttype->size == 4, outputReg); + } else if (IS_TYPE_VECTOR(dsttype)) { + GEN_NODE_TO_REG(inner, outputReg, 0, output); + ENSURE_VR(output, dsttype, outputReg); + } else if ( + srctype->size < dsttype->size && + !ENODE_IS_INDIRECT_TO(inner, EBITFIELD) && + !ENODE_IS_ASSIGN_TO(inner, EBITFIELD) && + !(ENODE_IS_RANGE(inner, EPOSTINC, EPREDEC) && ENODE_IS(inner->data.monadic->data.monadic, EBITFIELD)) + ) { + GEN_NODE(inner, output); + extend32(output, srctype, outputReg); + } else if (dsttype->size < srctype->size || dsttype->size < 4) { + GEN_NODE(inner, output); + ENSURE_GPR(output, srctype, 0); + extend32(output, dsttype, outputReg); + } else { + GEN_NODE_TO_REG(inner, outputReg, 0, output); + } + } else if (IS_TYPE_POINTER(srctype)) { + GEN_NODE_TO_REG(inner, outputReg, 0, output); + if (dsttype->size < srctype->size) + ENSURE_GPR(output, srctype, outputReg); + } else if (IS_TYPE_FLOAT(srctype)) { + if (IS_TYPE_FLOAT(dsttype)) { + GEN_NODE_TO_REG(inner, outputReg, 0, output); + ENSURE_FPR(output, srctype, outputReg); + + if (dsttype->size == 4 && srctype->size != 4) { + int tmp = outputReg ? outputReg : ALLOC_FPR(); + emitpcode(PC_FRSP, tmp, output->reg); + output->optype = OpndType_FPR; + output->reg = tmp; + } + } else if (is_unsigned(dsttype) && dsttype->size == 4) { + GEN_NODE_TO_REG(inner, 1, 0, output); + ENSURE_FPR(output, srctype, 1); + convert_floating_to_unsigned(output, outputReg); + } else { + GEN_NODE_TO_REG(inner, 0, 0, output); + ENSURE_FPR(output, srctype, 0); + convert_floating_to_integer(output, outputReg); + } + } else if (IS_TYPE_VECTOR(srctype) && IS_TYPE_VECTOR(dsttype)) { + GEN_NODE_TO_REG(inner, outputReg, 0, output); + ENSURE_VR(output, srctype, outputReg); + } else if (srctype->size == dsttype->size) { + GEN_NODE_TO_REG(inner, outputReg, 0, output); + } else { +#line 2224 + CError_FATAL(); + } +} + +void gen_BITFIELD(ENode *expr, short outputReg, short outputRegHi, Operand *output) { +#line 2238 + CError_FATAL(); +} + +void gen_INTCONST(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + if (TYPE_IS_8BYTES(expr->rtype)) { + I8_gen_INTCONST(expr, outputReg, outputRegHi, output); + return; + } + + output->optype = OpndType_Absolute; + output->immediate = CInt64_GetULong(&expr->data.intval); +} + +void gen_FLOATCONST(ENode *expr, short outputReg, short outputRegHi, Operand *output) { +#line 2294 + CError_FATAL(); +} + +void gen_STRINGCONST(ENode *expr, short outputReg, short outputRegHi, Operand *output) { +#line 2308 + CError_FATAL(); +} + +static Boolean COND_is_ABS_MatchNodes(ENode *cond, ENode *expr1, ENode *expr2) { + if (cond->type != expr1->type || cond->type != expr2->type) + return 0; + + if (!(TYPE_FITS_IN_REGISTER(cond->rtype) && TYPE_FITS_IN_REGISTER(expr1->rtype) && TYPE_FITS_IN_REGISTER(expr2->rtype))) + return 0; + + if (cond->rtype->size != expr1->rtype->size || cond->rtype->size != expr2->rtype->size) + return 0; + + switch (cond->type) { + case EOBJREF: + if (cond->data.objref != expr1->data.objref || cond->data.objref != expr2->data.objref) + return 0; + return 1; + case EINDIRECT: + case ETYPCON: + return COND_is_ABS_MatchNodes(cond->data.monadic, expr1->data.monadic, expr2->data.monadic); + default: + return 0; + } +} + +static ENode *COND_is_ABS(ENode *cond, ENode *expr1, ENode *expr2) { + ENode *tmp; + + int parity = 0; + while (ENODE_IS(cond, ELOGNOT)) { + parity = (parity + 1) & 1; + cond = cond->data.monadic; + } + + if (parity) { + tmp = expr1; + expr1 = expr2; + expr2 = tmp; + } + + switch (cond->type) { + case ELESS: + case ELESSEQU: + tmp = expr1; + expr1 = expr2; + expr2 = tmp; + break; + case EGREATER: + case EGREATEREQU: + break; + default: + return NULL; + } + + if (IS_INT_CONST_ZERO(cond->data.diadic.right)) { + cond = cond->data.diadic.left; + } else if (IS_INT_CONST_ZERO(cond->data.diadic.left)) { + cond = cond->data.diadic.left; + tmp = expr1; + expr1 = expr2; + expr2 = tmp; + } else { + return NULL; + } + + if (ENODE_IS(expr1, EADD) && ENODE_IS(expr2, ESUB)) { + if (COND_is_ABS_MatchNodes(cond, expr1->data.diadic.right, expr2->data.diadic.right)) + return expr1; + else + return NULL; + } + + if (!ENODE_IS(expr2, EMONMIN)) + return NULL; + + expr2 = expr2->data.monadic; + if (COND_is_ABS_MatchNodes(cond, expr1, expr2)) + return expr1; + + return NULL; +} + +static int COND_has_const(ENode *expr1, ENode *expr2) { + SInt32 diff; + int result = 0; + + if (IS_INT_CONST(expr1)) + result += 1; + if (IS_INT_CONST(expr2)) + result += 2; + + if (result & 1) { + if (IS_INT_CONST_ZERO(expr1)) + return 5; + } + if (result & 2) { + if (IS_INT_CONST_ZERO(expr2)) + return 6; + } + + if (result == 3) { + diff = expr1->data.intval.lo - expr2->data.intval.lo; + if (diff == 1 || diff == -1) + return 4; + } + + return result; +} + +static Boolean COND_is_COMPARE(ENode *cond, ENode *expr1, ENode *expr2, short outputReg, Operand *output) { + SInt32 left; + SInt32 right; + int parity; + int negate; + ENodeType nt; + + while (ENODE_IS(expr1, ETYPCON) && TYPE_FITS_IN_REGISTER(expr1->rtype)) + expr1 = expr1->data.monadic; + while (ENODE_IS(expr2, ETYPCON) && TYPE_FITS_IN_REGISTER(expr2->rtype)) + expr2 = expr2->data.monadic; + + if (!(ENODE_IS(expr1, EINTCONST) && TYPE_FITS_IN_REGISTER(expr1->rtype) && CInt64_IsInRange(expr1->data.intval, 4))) + return 0; + if (!(ENODE_IS(expr2, EINTCONST) && TYPE_FITS_IN_REGISTER(expr2->rtype) && CInt64_IsInRange(expr2->data.intval, 4))) + return 0; + + left = CInt64_GetULong(&expr1->data.intval); + right = CInt64_GetULong(&expr2->data.intval); + parity = 0; + negate = 0; + switch (left) { + case 1: + if (right != 0) + return 0; + break; + case 0: + parity = 1; + if (right == -1) + negate = 1; + else if (right != 1) + return 0; + break; + case -1: + if (right != 0) + return 0; + negate = 1; + break; + default: + return 0; + } + + while (ENODE_IS(cond, ELOGNOT)) { + parity = (parity + 1) & 1; + cond = cond->data.monadic; + } + + if (parity) { + nt = invert_relop(cond->type); + if (nt == cond->type) + return 0; + cond->type = nt; + } + + if (negate) + gen_negated_condition_gpr(cond, output, outputReg); + else + gen_condition_gpr(cond, output, outputReg); + + return 1; +} + +void gen_COND(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *cond; + ENode *expr1; + ENode *expr2; + Type *type; + PCodeLabel *label1; + PCodeLabel *label2; + PCodeLabel *label3; + Operand op1; + Operand op2; + int has_const; + int reg1; + int reg2; + int reg3; + short align; + short max_align; + + expr1 = expr->data.cond.expr1; + expr2 = expr->data.cond.expr2; + type = expr->rtype; + + label1 = makepclabel(); + label2 = makepclabel(); + label3 = makepclabel(); + + memclrw(&op1, sizeof(Operand)); + memclrw(&op2, sizeof(Operand)); + + cond = evaluate_and_skip_comma(expr->data.cond.cond); + + if (TOC_use_fsel(expr)) { + ENode *left; + ENode *right; + ENode *tmp; + ENodeType nt; + Boolean flag; + Operand op; + int fneg_reg; + int fsel_reg; + int final_reg; + + left = cond->data.diadic.left; + right = cond->data.diadic.right; + nt = cond->type; + flag = 0; + memclrw(&op, sizeof(Operand)); + + switch (nt) { + case EGREATEREQU: + case EEQU: + break; + case EGREATER: + tmp = left; + left = right; + right = tmp; + case ELESS: + case ENOTEQU: + tmp = expr1; + expr1 = expr2; + expr2 = tmp; + break; + case ELESSEQU: + tmp = left; + left = right; + right = tmp; + break; + default: +#line 2780 + CError_FATAL(); + } + + if (ENODE_IS(left, EFLOATCONST) && CMach_FloatIsZero(left->data.floatval)) { + GEN_NODE(right, &op); + ENSURE_FPR(&op, right->rtype, 0); + flag = 1; + } else if (ENODE_IS(right, EFLOATCONST) && CMach_FloatIsZero(right->data.floatval)) { + GEN_NODE(left, &op); + ENSURE_FPR(&op, left->rtype, 0); + } else { + fp_binary_operator((type->size == 4) ? PC_FSUBS : PC_FSUB, left, right, 0, &op); + } + + switch (cond->type) { + case EEQU: + case ENOTEQU: + if (flag) { + GEN_NODE_TO_FPR(expr1, &op1, expr1->rtype, 0); + GEN_NODE_TO_FPR(expr2, &op2, expr2->rtype, 0); + + fneg_reg = ALLOC_FPR(); + emitpcode(PC_FNEG, fneg_reg, op.reg); + fsel_reg = ALLOC_FPR(); + emitpcode(PC_FSEL, fsel_reg, op.reg, op1.reg, op2.reg); + final_reg = outputReg ? outputReg : ALLOC_FPR(); + emitpcode(PC_FSEL, final_reg, fneg_reg, fsel_reg, op2.reg); + } else { + GEN_NODE_TO_FPR(expr1, &op1, expr1->rtype, 0); + GEN_NODE_TO_FPR(expr2, &op2, expr2->rtype, 0); + + fneg_reg = ALLOC_FPR(); + emitpcode(PC_FNEG, fneg_reg, op.reg); + fsel_reg = ALLOC_FPR(); + emitpcode(PC_FSEL, fsel_reg, op.reg, op1.reg, op2.reg); + final_reg = outputReg ? outputReg : ALLOC_FPR(); + emitpcode(PC_FSEL, final_reg, fneg_reg, fsel_reg, op2.reg); + } + break; + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + GEN_NODE_TO_FPR(expr1, &op1, expr1->rtype, 0); + GEN_NODE_TO_FPR(expr2, &op2, expr2->rtype, 0); + + fneg_reg = op.reg; + if (flag) { + fneg_reg = ALLOC_FPR(); + emitpcode(PC_FNEG, fneg_reg, op.reg); + } + + final_reg = outputReg ? outputReg : ALLOC_FPR(); + emitpcode(PC_FSEL, final_reg, fneg_reg, op1.reg, op2.reg); + break; + default: +#line 2862 + CError_FATAL(); + } + + output->optype = OpndType_FPR; + output->reg = final_reg; + return; + } + + if (TOC_use_isel(expr, 1)) { + Operand isel_op1; + Operand isel_op2; + ENode *x; + ENode *y; + ENode *abs_expr; + + memclrw(&isel_op1, sizeof(Operand)); + memclrw(&isel_op2, sizeof(Operand)); + + if (COND_is_COMPARE(cond, expr1, expr2, outputReg, output)) + return; + + if ((abs_expr = COND_is_ABS(cond, expr1, expr2))) { + if (ENODE_IS(expr1, EADD) && ENODE_IS(expr2, ESUB)) { + x = expr1->data.diadic.left; + y = expr2->data.diadic.right; + if (y->hascall) { + GEN_NODE(y, &op2); + ENSURE_GPR(&op2, y->rtype, 0); + + GEN_NODE(x, &op1); + if (op1.optype >= OpndType_IndirectGPR_ImmOffset) + ENSURE_GPR(&op1, x->rtype, 0); + } else { + GEN_NODE(x, &op1); + if (op1.optype >= OpndType_IndirectGPR_ImmOffset) + ENSURE_GPR(&op1, x->rtype, 0); + + GEN_NODE(y, &op2); + ENSURE_GPR(&op2, y->rtype, 0); + } + + reg1 = ALLOC_GPR(); + emitpcode(PC_SRAWI, reg1, op2.reg, 31); + reg2 = ALLOC_GPR(); + emitpcode(PC_XOR, reg2, reg1, op2.reg); + reg3 = ALLOC_GPR(); + emitpcode(PC_SUBF, reg3, reg1, reg2); + op2.optype = OpndType_GPR; + op2.reg = reg3; + combine(&op1, &op2, outputReg, output); + } else { + GEN_NODE(abs_expr, output); + ENSURE_GPR(output, abs_expr->rtype, 0); + + reg1 = ALLOC_GPR(); + emitpcode(PC_SRAWI, reg1, output->reg, 31); + reg2 = ALLOC_GPR(); + emitpcode(PC_XOR, reg2, reg1, output->reg); + reg3 = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBF, reg3, reg1, reg2); + op2.optype = OpndType_GPR; + op2.reg = reg3; + } + return; + } + + if ((has_const = COND_has_const(expr1, expr2))) { + switch (COND_has_const(expr1, expr2)) { + case 0: + case 2: + break; + case 3: + case 4: + if (has_const == 4) { + if (expr1->data.intval.lo < expr2->data.intval.lo) + gen_negated_condition_gpr(cond, &isel_op1, 0); + else + gen_condition_gpr(cond, &isel_op1, 0); + + GEN_NODE(expr1, &op1); + GEN_NODE(expr2, &op2); + reg1 = ALLOC_GPR(); + ENSURE_GPR(&op2, expr2->rtype, reg1); + emitpcode(PC_ADD, reg1, isel_op1.reg, op2.reg); + if (outputReg) { + emitpcode(PC_MR, reg2 = outputReg, reg1); + reg1 = reg2; + } + output->optype = OpndType_GPR; + output->reg = reg1; + return; + } + break; + case 5: + case 6: + gen_negated_condition_gpr(cond, &isel_op1, 0); + ENSURE_GPR(&isel_op1, TYPE(&stunsignedint), 0); + GEN_NODE(expr1, &op1); + GEN_NODE(expr2, &op2); + + reg1 = outputReg ? outputReg : ALLOC_GPR(); + if (op1.optype == OpndType_Absolute && op1.immediate == 0) { + ENSURE_GPR(&op2, expr2->rtype, 0); + emitpcode(PC_ANDC, reg1, op2.reg, isel_op1.reg); + } else if (op2.optype == OpndType_Absolute && op2.immediate == 0) { + ENSURE_GPR(&op1, expr1->rtype, 0); + emitpcode(PC_AND, reg1, op1.reg, isel_op1.reg); + } else { +#line 3119 + CError_FATAL(); + } + + output->optype = OpndType_GPR; + output->reg = reg1; + return; + case 1: + reg2 = ALLOC_GPR(); + reg1 = reg2; + logical_expression_nobranch(cond, 0, &isel_op2); + + GEN_NODE_TO_REG(expr1, reg1, 0, &op1); + ENSURE_GPR(&op1, expr1->rtype, reg1); + if (op1.reg != reg1) + emitpcode(PC_MR, reg1, op1.reg); + + branch_conditional(isel_op2.reg, isel_op2.regOffset, 1, label2); + branch_label(label1); + + GEN_NODE_TO_REG(expr2, reg1, 0, &op2); + ENSURE_GPR(&op2, expr2->rtype, reg1); + if (op2.reg != reg1) + emitpcode(PC_MR, reg1, op2.reg); + + branch_label(label2); + + if (outputReg) { + emitpcode(PC_MR, reg2 = outputReg, reg1); + reg1 = reg2; + } + + output->optype = OpndType_GPR; + output->reg = reg1; + return; + + default: +#line 3168 + CError_FATAL(); + } + } + + reg1 = ALLOC_GPR(); + logical_expression_nobranch(cond, 0, &isel_op2); + + GEN_NODE_TO_REG(expr2, reg1, 0, &op2); + ENSURE_GPR(&op2, expr2->rtype, reg1); + if (op2.reg != reg1) + emitpcode(PC_MR, reg1, op2.reg); + + branch_conditional(isel_op2.reg, isel_op2.regOffset, 0, label2); + branch_label(label1); + + GEN_NODE_TO_REG(expr1, reg1, 0, &op1); + ENSURE_GPR(&op1, expr1->rtype, reg1); + if (op1.reg != reg1) + emitpcode(PC_MR, reg1, op1.reg); + + branch_label(label2); + + if (outputReg) { + emitpcode(PC_MR, reg2 = outputReg, reg1); + reg1 = reg2; + } + + output->optype = OpndType_GPR; + output->reg = reg1; + return; + } + + logical_expression(cond, label1, label2, label1); + branch_label(label1); + + if (IS_TYPE_VOID(type) || expr->ignored) { + GEN_NODE(expr1, &op1); + branch_always(label3); + branch_label(label2); + GEN_NODE(expr2, &op2); + } else if (IS_TYPE_FLOAT(type)) { + if (expr1->hascall || expr2->hascall) + reg1 = ALLOC_FPR(); + else + reg1 = outputReg ? outputReg : ALLOC_FPR(); + + GEN_NODE_TO_REG(expr1, reg1, 0, &op1); + ENSURE_FPR(&op1, expr1->rtype, reg1); + if (op1.reg != reg1) + emitpcode(PC_FMR, reg1, op1.reg); + + branch_always(label3); + branch_label(label2); + + GEN_NODE_TO_REG(expr2, reg1, 0, &op2); + ENSURE_FPR(&op2, expr2->rtype, reg1); + if (op2.reg != reg1) + emitpcode(PC_FMR, reg1, op2.reg); + + output->optype = OpndType_FPR; + output->reg = reg1; + } else if (TYPE_IS_8BYTES(type)) { + if (expr1->hascall || expr2->hascall) { + reg1 = ALLOC_GPR(); + reg3 = ALLOC_GPR(); + reg2 = reg3; + } else { + reg1 = outputReg ? outputReg : ALLOC_GPR(); + reg3 = outputRegHi ? outputRegHi : ALLOC_GPR(); + reg2 = reg3; + } + + GEN_NODE_TO_REG(expr1, reg1, reg2, &op1); + coerce_to_register_pair(&op1, expr1->rtype, reg1, reg2); + + branch_always(label3); + branch_label(label2); + + GEN_NODE_TO_REG(expr2, reg1, reg2, &op2); + coerce_to_register_pair(&op2, expr2->rtype, reg1, reg2); + + output->optype = OpndType_GPRPair; + output->reg = reg1; + output->regHi = reg2; + } else if (TYPE_FITS_IN_REGISTER(type)) { + if (expr1->hascall || expr2->hascall) + reg1 = ALLOC_GPR(); + else + reg1 = outputReg ? outputReg : ALLOC_GPR(); + + GEN_NODE_TO_REG(expr1, reg1, 0, &op1); + ENSURE_GPR(&op1, expr1->rtype, reg1); + if (op1.reg != reg1) + emitpcode(PC_MR, reg1, op1.reg); + + branch_always(label3); + branch_label(label2); + + GEN_NODE_TO_REG(expr2, reg1, 0, &op2); + ENSURE_GPR(&op2, expr2->rtype, reg1); + if (op2.reg != reg1) + emitpcode(PC_MR, reg1, op2.reg); + + output->optype = OpndType_GPR; + output->reg = reg1; + } else if (IS_TYPE_VECTOR(type)) { + if (expr1->hascall || expr2->hascall) + reg1 = ALLOC_VR(); + else + reg1 = outputReg ? outputReg : ALLOC_VR(); + + GEN_NODE_TO_REG(expr1, reg1, 0, &op1); + ENSURE_VR(&op1, expr1->rtype, reg1); + if (op1.reg != reg1) + emitpcode(PC_VMR, reg1, op1.reg); + + branch_always(label3); + branch_label(label2); + + GEN_NODE_TO_REG(expr2, reg1, 0, &op2); + ENSURE_VR(&op2, expr2->rtype, reg1); + if (op2.reg != reg1) + emitpcode(PC_VMR, reg1, op2.reg); + + output->optype = OpndType_VR; + output->reg = reg1; + } else { + symbol_operand(output, maketemporary(type)); + indirect(output, NULL); + coerce_to_addressable(output); + + GEN_NODE(expr1, &op1); + + if (op1.object) { + if (op1.object->datatype == DLOCAL && (op1.object->u.var.info->flags & VarInfoFlag1)) + align = CMach_ArgumentAlignment(type); + else + align = CMach_AllocationAlignment(type, op1.object->qual); + } else { + align = CMach_AllocationAlignment(type, 0); + } + + max_align = CMach_AllocationAlignment(type, 0); + if (align > max_align) + align = max_align; + + move_block(output, &op1, type->size, align); + + branch_always(label3); + branch_label(label2); + + GEN_NODE(expr2, &op2); + + if (op2.object) { + if (op2.object->datatype == DLOCAL && (op2.object->u.var.info->flags & VarInfoFlag1)) + align = CMach_ArgumentAlignment(type); + else + align = CMach_AllocationAlignment(type, op2.object->qual); + } else { + align = CMach_AllocationAlignment(type, 0); + } + + if (align > max_align) + align = max_align; + + move_block(output, &op2, type->size, align); + } + + branch_label(label3); +} + +static Boolean CONDASS_is_ABS(ENode *cond, ENode *expr1, ENode *expr2) { + ENode *inner; + + int parity = 0; + while (ENODE_IS(cond, ELOGNOT)) { + parity = (parity + 1) & 1; + cond = cond->data.monadic; + } + + if (IS_INT_CONST_ZERO(cond->data.diadic.right)) { + inner = cond->data.diadic.left; + } else if (IS_INT_CONST_ZERO(cond->data.diadic.left)) { + inner = cond->data.diadic.left; + parity = (parity + 1) & 1; + } else { + return 0; + } + + switch (cond->type) { + case EGREATER: + case EGREATEREQU: + if (!parity) + return 0; + break; + case ELESS: + case ELESSEQU: + if (parity) + return 0; + break; + default: + return 0; + } + + if (!ENODE_IS(expr2, EMONMIN)) + return 0; + + expr2 = expr2->data.monadic; + if (ENODE_IS(inner, EASS)) { + inner = inner->data.diadic.left; + if (!ENODE_IS(expr2, EINDIRECT)) + return 0; + expr2 = expr2->data.monadic; + if (!ENODE_IS(expr1, EINDIRECT)) + return 0; + expr1 = expr1->data.monadic; + } + + return COND_is_ABS_MatchNodes(inner, expr1, expr2); +} + +static int CONDASS_is_OPASS_One(ENode *a, ENode *b, SInt32 *value, ENodeType *nodetype) { + Type *type; + + type = a->rtype; + if (!ENODE_IS(a, EINDIRECT)) + return 0; + a = a->data.monadic; + if (!ENODE_IS(a, EOBJREF)) + return 0; + + if (ENODE_IS(b, ETYPCON) && b->rtype == type) + b = b->data.monadic; + + if (b->type != EOR && b->type != EADD && b->type != ESUB) + return 0; + + *nodetype = b->type; + if (!IS_INT_CONST(b->data.diadic.right)) + return 0; + *value = b->data.diadic.right->data.intval.lo; + + if (*value != 1 && *value != -1) + return 0; + + b = b->data.diadic.left; + if (ENODE_IS(b, ETYPCON) && TYPE_FITS_IN_REGISTER(b->rtype)) + b = b->data.monadic; + + if (!ENODE_IS(b, EINDIRECT)) + return 0; + b = b->data.monadic; + if (!ENODE_IS(b, EOBJREF)) + return 0; + + if (a->data.objref == b->data.objref) + return 1; + return 0; +} + +void gen_CONDASS(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *cond; + ENode *expr1; + ENode *expr2; + Type *type; + PCodeLabel *label1; + PCodeLabel *label2; + Operand op1; + Operand op2; + Operand op3; + int reg1; + int reg2; + + expr1 = expr->data.cond.expr1; + expr2 = expr->data.cond.expr2; + type = expr->rtype; + + label1 = makepclabel(); + label2 = makepclabel(); + + memclrw(&op1, sizeof(Operand)); + memclrw(&op2, sizeof(Operand)); + memclrw(&op3, sizeof(Operand)); + + cond = evaluate_and_skip_comma(expr->data.cond.cond); + + if (TOC_use_fsel(expr)) { + ENode *left; + ENode *right; + ENode *tmp; + ENodeType nt; + Boolean flag; + Boolean flag2; + Operand op; + int tmpreg; + int fneg_reg; + int fsel_reg; + int final_reg; + + left = cond->data.diadic.left; + right = cond->data.diadic.right; + nt = cond->type; + flag = 0; + memclrw(&op, sizeof(Operand)); + +#line 3704 + CError_ASSERT(ENODE_IS(expr1, EINDIRECT)); + CError_ASSERT(ENODE_IS(expr1->data.monadic, EOBJREF)); + + tmpreg = OBJECT_REG(expr1->data.monadic->data.objref); + final_reg = outputReg ? tmpreg : ALLOC_FPR(); + + switch (nt) { + case EGREATER: + tmp = left; + left = right; + right = tmp; + case ELESS: + case ENOTEQU: + tmp = expr1; + expr1 = expr2; + expr2 = tmp; + flag2 = 1; + break; + case ELESSEQU: + tmp = left; + left = right; + right = tmp; + flag2 = 0; + break; + case EGREATEREQU: + case EEQU: + flag2 = 0; + break; + default: +#line 3744 + CError_FATAL(); + } + + if (ENODE_IS(left, EFLOATCONST) && CMach_FloatIsZero(left->data.floatval)) { + GEN_NODE(right, &op); + ENSURE_FPR(&op, right->rtype, 0); + flag = 1; + } else if (ENODE_IS(right, EFLOATCONST) && CMach_FloatIsZero(right->data.floatval)) { + GEN_NODE(left, &op); + ENSURE_FPR(&op, left->rtype, 0); + } else { + fp_binary_operator((type->size == 4) ? PC_FSUBS : PC_FSUB, left, right, 0, &op); + } + + switch (cond->type) { + case EEQU: + case ENOTEQU: + if (flag) { + GEN_NODE(expr1, &op1); + op3 = op1; + ENSURE_FPR(&op1, expr1->rtype, 0); + + GEN_NODE_TO_FPR(expr2, &op2, expr2->rtype, 0); + + fneg_reg = ALLOC_FPR(); + emitpcode(PC_FNEG, fneg_reg, op.reg); + fsel_reg = ALLOC_FPR(); + emitpcode(PC_FSEL, fsel_reg, op.reg, op2.reg, op1.reg); + emitpcode(PC_FSEL, final_reg, fneg_reg, op2.reg, fsel_reg); + } else { + GEN_NODE(expr1, &op1); + op3 = op1; + ENSURE_FPR(&op1, expr1->rtype, 0); + + GEN_NODE_TO_FPR(expr2, &op2, expr2->rtype, 0); + + fneg_reg = ALLOC_FPR(); + emitpcode(PC_FNEG, fneg_reg, op.reg); + fsel_reg = ALLOC_FPR(); + emitpcode(PC_FSEL, fsel_reg, op.reg, op2.reg, op1.reg); + emitpcode(PC_FSEL, final_reg, fneg_reg, op2.reg, fsel_reg); + } + break; + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + GEN_NODE(expr1, &op1); + GEN_NODE(expr2, &op2); + op3 = flag2 ? op2 : op1; + + ENSURE_FPR(&op1, expr1->rtype, 0); + ENSURE_FPR(&op2, expr2->rtype, 0); + + fneg_reg = op.reg; + if (flag) { + fneg_reg = ALLOC_FPR(); + emitpcode(PC_FNEG, fneg_reg, op.reg); + } + + emitpcode(PC_FSEL, final_reg, fneg_reg, op2.reg, op1.reg); + break; + default: +#line 2862 + CError_FATAL(); + } + + if (op3.optype != OpndType_FPR) + store_fp(final_reg, &op3, type); + + output->optype = OpndType_FPR; + output->reg = final_reg; + return; + } + + if (TOC_use_isel(expr, 1)) { + Operand isel_op; + ENode *x; + ENode *y; + ENode *abs_expr; + + memclrw(&isel_op, sizeof(Operand)); +#line 3966 + CError_ASSERT(ENODE_IS(expr1, EINDIRECT)); +#line 3968 + CError_ASSERT(ENODE_IS(expr1->data.monadic, EOBJREF)); + + if (CONDASS_is_ABS(cond, expr1, expr2)) { + if (ENODE_IS(cond->data.diadic.left, EASS)) + GEN_NODE(cond->data.diadic.left, &isel_op); + else if (ENODE_IS(cond->data.diadic.right, EASS)) + GEN_NODE(cond->data.diadic.right, &isel_op); + + outputReg = OBJECT_REG(expr1->data.monadic->data.objref); +#line 3979 + CError_ASSERT(outputReg); + + GEN_NODE(expr1, &op1); + op3 = op1; + +#line 3986 + CError_ASSERT(op3.optype == OpndType_GPR && op3.reg == outputReg); + + ENSURE_GPR(&op1, expr1->rtype, 0); + if (expr1->rtype->size < 4) + extend32(output, expr1->rtype, op3.reg); + + reg1 = ALLOC_GPR(); + reg2 = ALLOC_GPR(); + emitpcode(PC_SRAWI, reg1, op1.reg, 31); + emitpcode(PC_XOR, reg2, reg1, op1.reg); + emitpcode(PC_SUBF, outputReg, reg1, reg2); + output->optype = OpndType_GPR; + output->reg = op3.reg; + + if (expr1->rtype->size < 4) + extend32(output, expr1->rtype, op3.reg); + + return; + } + } + + logical_expression(cond, label1, label2, label1); + branch_label(label1); + gen_ASS(expr, outputReg, outputRegHi, output); + branch_label(label2); +} + +void gen_FUNCCALL(ENode *expr, short outputReg, short outputRegHi, Operand *output) { +} + +void gen_OBJREF(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + symbol_operand(output, expr->data.objref); +} + +void gen_UNEXPECTED(ENode *expr, short outputReg, short outputRegHi, Operand *output) { +#line 4160 + CError_FATAL(); +} + +static int small(ENode *expr) { + Type *type; + + type = expr->rtype; + if (!ENODE_IS(expr, ETYPCON)) + return 0; + + do { + expr = expr->data.monadic; + } while (ENODE_IS(expr, ETYPCON) && (type = expr->rtype)->size == 4); + + return IS_TYPE_INT_OR_ENUM(type) && ((type->size < 2) || (type->size == 2 && !is_unsigned(type))); +} + +void binary_operator(Opcode opcode, ENode *left, ENode *right, short outputReg, Operand *output) { + Operand opleft; + Operand opright; + int reg; + + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + + if (right->hascall) { + GEN_NODE_TO_GPR(right, &opright, right->rtype, 0); + GEN_NODE_TO_GPR(left, &opleft, left->rtype, 0); + } else { + GEN_NODE_TO_GPR(left, &opleft, left->rtype, 0); + GEN_NODE_TO_GPR(right, &opright, right->rtype, 0); + } + + reg = outputReg ? outputReg : ALLOC_GPR(); + + if (opcode == PC_MULLW && small(left)) + emitpcode(opcode, reg, opright.reg, opleft.reg); + else + emitpcode(opcode, reg, opleft.reg, opright.reg); + + output->optype = OpndType_GPR; + output->reg = reg; +} + +static void binary_immediate(Opcode opcode, ENode *left, SInt32 value, short outputReg, Operand *output) { + Operand opleft; + int reg; + + memclrw(&opleft, sizeof(Operand)); + GEN_NODE_TO_GPR(left, &opleft, left->rtype, 0); + + reg = outputReg ? outputReg : ALLOC_GPR(); + + if (opcode == PC_MULLI && value == 0) + emitpcode(PC_LI, reg, 0); + else if (opcode == PC_MULLI && value == 1) + emitpcode(PC_MR, reg, opleft.reg); + else + emitpcode(opcode, reg, opleft.reg, value); + + output->optype = OpndType_GPR; + output->reg = reg; +} + +void unary_operator(Opcode opcode, ENode *expr, short outputReg, Operand *output) { + Operand op; + int reg; + + memclrw(&op, sizeof(Operand)); + GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); + + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(opcode, reg, op.reg); + + output->optype = OpndType_GPR; + output->reg = reg; +} + +static void or_xor_immediate(Opcode opcode, ENode *expr, SInt32 value, short outputReg, Operand *output) { + Operand op; + int reg; + + memclrw(&op, sizeof(Operand)); + GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); + + reg = outputReg ? outputReg : ALLOC_GPR(); + + if (expr->rtype->size > 2 && value != (value & 0xFFFF)) { + if (value & 0xFFFF) { + emitpcode((opcode == PC_ORI) ? PC_ORIS : PC_XORIS, reg, op.reg, value >> 16); + emitpcode(opcode, reg, reg, value & 0xFFFF); + } else { + emitpcode((opcode == PC_ORI) ? PC_ORIS : PC_XORIS, reg, op.reg, value >> 16); + } + } else { + emitpcode(opcode, reg, op.reg, value & 0xFFFF); + } + + output->optype = OpndType_GPR; + output->reg = reg; +} + +static void shift_left_immediate(ENode *expr, short shift, short negate, short outputReg, Operand *output) { + Operand op; + int reg; + + memclrw(&op, sizeof(Operand)); + GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); + + if (negate) + reg = ALLOC_GPR(); + else + reg = outputReg ? outputReg : ALLOC_GPR(); + + emitpcode(PC_RLWINM, reg, op.reg, shift & 31, 0, 31 - (shift & 31)); + + if (negate) { + int tmp = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_NEG, tmp, reg); + reg = tmp; + } + + output->optype = OpndType_GPR; + output->reg = reg; +} + +static void shift_right_immediate(ENode *expr, Type *type, short shift, short outputReg, Operand *output) { + Operand op; + int reg; + + memclrw(&op, sizeof(Operand)); + GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); + + reg = outputReg ? outputReg : ALLOC_GPR(); + + if (is_unsigned(type)) + emitpcode(PC_RLWINM, reg, op.reg, (32 - (shift & 31)) & 31, (shift & 31) + (32 - (type->size * 8)), 31); + else + emitpcode(PC_SRAWI, reg, op.reg, shift & 31); + + output->optype = OpndType_GPR; + output->reg = reg; +} + +static void signed_divide_by_power_of_2(ENode *expr, int shift, int negate, short outputReg, Operand *output) { + Operand op; + int reg; + int tmpreg1; + int tmpreg2; + + memclrw(&op, sizeof(Operand)); + GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); + + if (!copts.optimize_for_size && shift == 1) { + tmpreg1 = ALLOC_GPR(); + emitpcode(PC_RLWINM, tmpreg1, op.reg, 1, 31, 31); + tmpreg2 = ALLOC_GPR(); + emitpcode(PC_ADD, tmpreg2, tmpreg1, op.reg); + reg = (outputReg && !negate) ? outputReg : ALLOC_GPR(); + emitpcode(PC_SRAWI, reg, tmpreg2, 1); + } else { + tmpreg1 = ALLOC_GPR(); + emitpcode(PC_SRAWI, tmpreg1, op.reg, shift); + reg = (outputReg && !negate) ? outputReg : ALLOC_GPR(); + emitpcode(PC_ADDZE, reg, tmpreg1); + } + + if (negate) { + int prevreg = reg; + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_NEG, reg, prevreg); + } + + output->optype = OpndType_GPR; + output->reg = reg; +} + +static void signed_mod_by_power_of_2(ENode *expr, int shift, int negate, short outputReg, Operand *output) { + Operand op; + int reg; + int tmpreg1; + int tmpreg2; + int tmpreg3; + int tmpreg4; + + memclrw(&op, sizeof(Operand)); + GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0); + + reg = outputReg ? outputReg : ALLOC_GPR(); + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); + tmpreg3 = ALLOC_GPR(); + + if (shift == 1) { + emitpcode(PC_RLWINM, tmpreg1, op.reg, 1, 31, 31); + emitpcode(PC_RLWINM, tmpreg2, op.reg, 0, 31, 31); + emitpcode(PC_XOR, tmpreg3, tmpreg2, tmpreg1); + emitpcode(PC_SUBF, reg, tmpreg1, tmpreg3); + } else { + tmpreg4 = ALLOC_GPR(); + emitpcode(PC_RLWINM, tmpreg1, op.reg, 32 - shift, 0, 31 - (32 - shift)); + emitpcode(PC_RLWINM, tmpreg2, op.reg, 1, 31, 31); + emitpcode(PC_SUBF, tmpreg3, tmpreg2, tmpreg1); + emitpcode(PC_RLWINM, tmpreg4, tmpreg3, shift, 0, 31); + emitpcode(PC_ADD, reg, tmpreg4, tmpreg2); + } + + output->optype = OpndType_GPR; + output->reg = reg; +} + +static void fp_binary_operator(Opcode opcode, ENode *left, ENode *right, short outputReg, Operand *output) { + Operand opleft; + Operand opright; + int reg; + + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + + if (right->hascall) { + GEN_NODE_TO_FPR(right, &opright, right->rtype, 0); + GEN_NODE_TO_FPR(left, &opleft, left->rtype, 0); + } else { + GEN_NODE_TO_FPR(left, &opleft, left->rtype, 0); + GEN_NODE_TO_FPR(right, &opright, right->rtype, 0); + } + + reg = outputReg ? outputReg : ALLOC_FPR(); + emitpcode(opcode, reg, opleft.reg, opright.reg); + + output->optype = OpndType_FPR; + output->reg = reg; +} + +void fp_unary_operator(Opcode opcode, ENode *expr, short outputReg, Operand *output) { + Operand op; + int reg; + + memclrw(&op, sizeof(Operand)); + GEN_NODE_TO_FPR(expr, &op, expr->rtype, 0); + + reg = outputReg ? outputReg : ALLOC_FPR(); + emitpcode(opcode, reg, op.reg); + + output->optype = OpndType_FPR; + output->reg = reg; +} + +void fp_multiply_add(Opcode opcode, ENode *a, ENode *b, ENode *c, short outputReg, Operand *output) { + Operand opA; + Operand opB; + Operand opC; + int reg; + + memclrw(&opA, sizeof(Operand)); + memclrw(&opB, sizeof(Operand)); + memclrw(&opC, sizeof(Operand)); + + if (c->hascall) { + GEN_NODE_TO_FPR(c, &opC, c->rtype, 0); + if (b->hascall) { + GEN_NODE_TO_FPR(b, &opB, b->rtype, 0); + GEN_NODE_TO_FPR(a, &opA, a->rtype, 0); + } else { + GEN_NODE_TO_FPR(a, &opA, a->rtype, 0); + GEN_NODE_TO_FPR(b, &opB, b->rtype, 0); + } + } else { + if (b->hascall) { + GEN_NODE_TO_FPR(b, &opB, b->rtype, 0); + GEN_NODE_TO_FPR(a, &opA, a->rtype, 0); + GEN_NODE_TO_FPR(c, &opC, c->rtype, 0); + } else { + GEN_NODE_TO_FPR(a, &opA, a->rtype, 0); + GEN_NODE_TO_FPR(b, &opB, b->rtype, 0); + GEN_NODE_TO_FPR(c, &opC, c->rtype, 0); + } + } + + reg = outputReg ? outputReg : ALLOC_FPR(); + emitpcode(opcode, reg, opA.reg, opB.reg, opC.reg); + + output->optype = OpndType_FPR; + output->reg = reg; +} + +void gen_COMPARE(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + expr = evaluate_and_skip_comma(expr); + if (TYPE_IS_8BYTES(expr->data.diadic.right->rtype) || TYPE_IS_8BYTES(expr->data.diadic.left->rtype)) + I8_gen_condition(expr, output, 1); + else + gen_condition_gpr(expr, output, outputReg); +} + +void gen_LOGICAL(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *inner; + ENodeType op; + + expr = evaluate_and_skip_comma(expr); + inner = evaluate_and_skip_comma(expr->data.monadic); + expr->data.monadic = inner; + + if (ENODE_IS(expr, ELOGNOT) && !ENODE_IS2(inner, ELAND, ELOR)) { + op = inner->type; + if (ENODE_IS(inner, ELOGNOT)) { + switch (inner->data.monadic->type) { + case ELOGNOT: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case ELAND: + case ELOR: + GEN_NODE(inner->data.monadic, output); + if (expr->data.monadic->rtype->size < 4) + extend32(output, expr->data.monadic->rtype, 0); + ENSURE_GPR(output, expr->data.monadic->rtype, 0); + return; + } + } + + if (ENODE_IS(inner, ENOTEQU) && !TYPE_IS_8BYTES(inner->data.diadic.left->rtype) && ENODE_IS(inner->data.diadic.right, EINTCONST) && inner->data.diadic.right->data.intval.lo == 0) { + int tmpreg1; + int tmpreg2; + GEN_NODE(inner->data.diadic.left, output); + if (inner->data.diadic.left->rtype->size < 4) + extend32(output, inner->data.diadic.left->rtype, 0); + ENSURE_GPR(output, inner->data.diadic.left->rtype, 0); + + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); +#line 4853 + CError_ASSERT(output->optype == OpndType_GPR); + + emitpcode(PC_CNTLZW, tmpreg2, output->reg); + emitpcode(PC_RLWINM, tmpreg1, tmpreg2, 27, 5, 31); + output->optype = OpndType_GPR; + output->reg = tmpreg1; + } else { + int tmpreg1; + int tmpreg2; + ENodeType inverted; + + inverted = invert_relop(op); + if (op != inverted && !IS_TYPE_FLOAT(inner->data.diadic.left->rtype)) { + inner->type = inverted; + gen_COMPARE(inner, 0, 0, output); + inner->type = inverted; + return; + } + + GEN_NODE(inner, output); + if (inner->rtype->size < 4) + extend32(output, inner->rtype, 0); + ENSURE_GPR(output, inner->rtype, 0); + + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); +#line 4883 + CError_ASSERT(output->optype == OpndType_GPR); + + emitpcode(PC_CNTLZW, tmpreg2, output->reg); + emitpcode(PC_RLWINM, tmpreg1, tmpreg2, 27, 5, 31); + output->optype = OpndType_GPR; + output->reg = tmpreg1; + } + } else { + PCodeLabel *label1; + PCodeLabel *label2; + int tmpreg; + + label1 = makepclabel(); + label2 = makepclabel(); + + tmpreg = ALLOC_GPR(); + emitpcode(PC_LI, tmpreg, 0); + logical_expression(expr, label1, label2, label1); + branch_label(label1); + emitpcode(PC_LI, tmpreg, 1); + branch_label(label2); + output->optype = OpndType_GPR; + output->reg = tmpreg; + } +} + +void gen_NULLCHECK(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *left; + ENode *right; + Operand opleft; + Operand opright; + PrecomputedOperand *precomp; + int flag; + int reg; + PCodeLabel *label; + + left = expr->data.nullcheck.nullcheckexpr; + right = expr->data.nullcheck.condexpr; + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + flag = !IS_TYPE_VOID(expr->rtype) && !expr->ignored; + + GEN_NODE(left, &opleft); + if (left->rtype->size < 4) + extend32(&opleft, left->rtype, 0); + ENSURE_GPR(&opleft, left->rtype, 0); + + precomp = lalloc(sizeof(PrecomputedOperand)); + precomp->precompid = expr->data.nullcheck.precompid; + precomp->operand = opleft; + precomp->next = precomputedoperands; + precomputedoperands = precomp; + + emitpcode(PC_CMPI, 0, opleft.reg, 0); + if (flag) { + emitpcode(PC_MR, reg = ALLOC_GPR(), opleft.reg); + } + + label = makepclabel(); + branch_conditional(0, EEQU, 1, label); + GEN_NODE(right, &opright); + precomputedoperands = precomputedoperands->next; + + if (flag) { + ENSURE_GPR(&opright, right->rtype, reg); + if (opright.reg != reg) + emitpcode(PC_MR, reg, opright.reg); + output->optype = OpndType_GPR; + output->reg = reg; + } + + branch_label(label); +} + +void gen_PRECOMP(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + PrecomputedOperand *precomp; + + for (precomp = precomputedoperands; precomp; precomp = precomp->next) { + if (precomp->precompid == expr->data.precompid) + break; + } + + *output = precomp->operand; +} + +void logical_expression(ENode *cond, PCodeLabel *if_true, PCodeLabel *if_false, PCodeLabel *end) { + PCodeLabel *label; + Operand op; + memclrw(&op, sizeof(Operand)); + + cond = evaluate_and_skip_comma(cond); + switch (cond->type) { + case ELAND: + label = makepclabel(); + logical_expression(cond->data.diadic.left, label, if_false, label); + branch_label(label); + logical_expression(cond->data.diadic.right, if_true, if_false, end); + break; + case ELOR: + label = makepclabel(); + logical_expression(cond->data.diadic.left, if_true, label, label); + branch_label(label); + logical_expression(cond->data.diadic.right, if_true, if_false, end); + break; + case ELOGNOT: + logical_expression(cond->data.monadic, if_false, if_true, end); + break; + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + if (TYPE_IS_8BYTES(cond->data.diadic.right->rtype) || TYPE_IS_8BYTES(cond->data.diadic.left->rtype)) + I8_gen_condition(cond, &op, 0); + else + gen_condition(cond, &op); + + if (end == if_true) + branch_conditional(op.reg, op.regOffset, 0, if_false); + else + branch_conditional(op.reg, op.regOffset, 1, if_true); + break; + default: +#line 5160 + CError_FATAL(); + } +} + +static void logical_expression_nobranch(ENode *cond, Boolean invert, Operand *output) { + cond = evaluate_and_skip_comma(cond); + switch (cond->type) { + case ELOGNOT: + logical_expression_nobranch(cond->data.monadic, 1, output); + break; + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + if (invert) { + ENodeType nt = invert_relop(cond->type); +#line 5190 + CError_ASSERT(nt != cond->type); + cond->type = nt; + } + + if (TYPE_IS_8BYTES(cond->data.diadic.right->rtype) || TYPE_IS_8BYTES(cond->data.diadic.left->rtype)) + I8_gen_condition(cond, output, 0); + else + gen_condition(cond, output); + + break; + default: +#line 5206 + CError_FATAL(); + } +} + +static ENodeType invert_relop(ENodeType nt) { + switch (nt) { + case ELESS: return EGREATEREQU; + case EGREATER: return ELESSEQU; + case ELESSEQU: return EGREATER; + case EGREATEREQU: return ELESS; + case EEQU: return ENOTEQU; + case ENOTEQU: return EEQU; + default: return nt; + } +} + +static int reverse_relop(int nt) { + switch (nt) { + case ELESS: return EGREATER; + case EGREATER: return ELESS; + case ELESSEQU: return EGREATEREQU; + case EGREATEREQU: return ELESSEQU; + default: return nt; + } +} + +void gen_condition(ENode *cond, Operand *output) { + ENode *left; + ENode *right; + + left = cond->data.diadic.left; + right = cond->data.diadic.right; + if (IS_TYPE_FLOAT(left->rtype)) { + compare_floating(cond->type, left, right, output); + return; + } + + if (ENODE_IS(right, EINTCONST)) { + if (is_unsigned(left->rtype)) { + UInt32 val = right->data.intval.lo; + if (FITS_IN_USHORT(val)) { + compare_immediate(cond->type, left, val, output); + return; + } else if (ENODE_IS2(cond, EEQU, ENOTEQU)) { + compare_immediate_long(cond->type, left, val, output); + return; + } + } else { + UInt32 val = right->data.intval.lo; + if (FITS_IN_SHORT(val)) { + compare_immediate(cond->type, left, val, output); + return; + } else if (ENODE_IS2(cond, EEQU, ENOTEQU)) { + compare_immediate_long(cond->type, left, val, output); + return; + } + } + } else if (ENODE_IS(left, EINTCONST)) { + if (is_unsigned(right->rtype)) { + UInt32 val = left->data.intval.lo; + if (FITS_IN_USHORT(val)) { + compare_immediate(reverse_relop(cond->type), right, val, output); + return; + } else if (ENODE_IS2(cond, EEQU, ENOTEQU)) { + compare_immediate_long(reverse_relop(cond->type), right, val, output); + return; + } + } else { + UInt32 val = left->data.intval.lo; + if (FITS_IN_SHORT(val)) { + compare_immediate(reverse_relop(cond->type), right, val, output); + return; + } else if (ENODE_IS2(cond, EEQU, ENOTEQU)) { + compare_immediate_long(reverse_relop(cond->type), right, val, output); + return; + } + } + } + + compare_integer(cond->type, left, right, output); +} + +void gen_condition_gpr(ENode *cond, Operand *output, short outputReg) { + ENode *left; + ENode *right; + Operand op1; + int tmpReg; + int reg; + int a; + int b; + + left = cond->data.diadic.left; + right = cond->data.diadic.right; + memclrw(&op1, sizeof(Operand)); + + if (!IS_TYPE_FLOAT(left->rtype)) { + Operand op2; + Operand op3; + Operand op4; + memclrw(&op2, sizeof(Operand)); + memclrw(&op3, sizeof(Operand)); + memclrw(&op4, sizeof(Operand)); + + if (right->hascall) { + GEN_NODE(right, &op3); + if (!IS_INT_CONST_ZERO(right)) { + if (right->rtype->size < 4) + extend32(&op3, right->rtype, 0); + ENSURE_GPR(&op3, right->rtype, 0); + } + + GEN_NODE(left, &op2); + if (left->rtype->size < 4) + extend32(&op2, left->rtype, 0); + ENSURE_GPR(&op2, left->rtype, 0); + } else { + GEN_NODE(left, &op2); + ENSURE_GPR(&op2, left->rtype, 0); + if (left->rtype->size < 4) + extend32(&op2, left->rtype, 0); + + GEN_NODE(right, &op3); + if (!IS_INT_CONST_ZERO(right)) { + if (right->rtype->size < 4) + extend32(&op3, right->rtype, 0); + ENSURE_GPR(&op3, right->rtype, 0); + } + } + + switch (cond->type) { + case EEQU: + if ( + copts.peephole && + IS_INT_CONST(right) && + pclastblock->pcodeCount > 0) { + PCode *pc = pclastblock->lastPCode; + if (pc->op == PC_RLWINM && pc->args[0].data.reg.reg == op2.reg) { + SInt32 r6 = pc->args[2].data.imm.value; + SInt32 r7 = pc->args[3].data.imm.value; + SInt32 r3 = right->data.intval.lo; + if (r7 == pc->args[4].data.imm.value) { + reg = outputReg ? outputReg : ALLOC_GPR(); + if (r3 != (r3 & 1)) { + emitpcode(PC_LI, reg, 0); + } else if (r3 == 0) { + int tmpreg = ALLOC_GPR(); + emitpcode( + PC_RLWINM, tmpreg, + pc->args[1].data.reg.reg, + (r6 + r7 + 1) & 31, 31, 31); + emitpcode(PC_XORI, reg, tmpreg, 1); + } else if (r3 == 1) { + emitpcode( + PC_RLWINM, reg, + pc->args[1].data.reg.reg, + (r6 + r7 + 1) & 31, 31, 31); + } else { +#line 5434 + CError_FATAL(); + } + output->optype = OpndType_GPR; + output->reg = reg; + return; + } + } + } + + if (IS_INT_CONST_ZERO(right)) { + //int tmpReg = ALLOC_GPR(); // affected + int tmpReg; + int t = used_virtual_registers[RegClass_GPR]; + used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_CNTLZW, t, op2.reg, 0); + tmpReg = t; + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, reg, tmpReg, 27, 5, 31); + output->optype = OpndType_GPR; + output->reg = reg; + return; + } else { + int tmpReg, tmpReg2; + tmpReg = ALLOC_GPR(); // affected + emitpcode(PC_SUBF, tmpReg, op2.reg, op3.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_CNTLZW, tmpReg2, tmpReg); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, reg, tmpReg2, 27, 5, 31); + output->optype = OpndType_GPR; + output->reg = reg; + return; + } + + case ENOTEQU: + if ( + copts.peephole && + IS_INT_CONST(right) && + pclastblock->pcodeCount > 0) { + PCode *pc = pclastblock->lastPCode; + if (pc->op == PC_RLWINM && pc->args[0].data.reg.reg == op2.reg) { + SInt32 r6 = pc->args[2].data.imm.value; + SInt32 r7 = pc->args[3].data.imm.value; + SInt32 r3 = right->data.intval.lo; + if (r7 == pc->args[4].data.imm.value) { + reg = outputReg ? outputReg : ALLOC_GPR(); + if (r3 != (r3 & 1)) { + emitpcode(PC_LI, reg, 1); + } else if (r3 == 0) { + emitpcode( + PC_RLWINM, reg, + pc->args[1].data.reg.reg, + (r6 + r7 + 1) & 31, 31, 31); + } else if (r3 == 1) { + int tmpreg = ALLOC_GPR(); // affected + emitpcode( + PC_RLWINM, tmpreg, + pc->args[1].data.reg.reg, + (r6 + r7 + 1) & 31, 31, 31); + emitpcode(PC_XORI, reg, tmpreg, 1); + } else { +#line 5503 + CError_FATAL(); + } + output->optype = OpndType_GPR; + output->reg = reg; + return; + } + } + } + + if (IS_INT_CONST_ZERO(right)) { + if (copts.optimize_for_size) { + int tmpReg; + tmpReg = ALLOC_GPR(); // affected + emitpcode(PC_ADDIC, tmpReg, op2.reg, -1); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBFE, reg, tmpReg, op2.reg); + } else { + int tmpReg, tmpReg2; + // tmpReg, tmpReg2 swap + tmpReg = ALLOC_GPR(); + emitpcode(PC_NEG, tmpReg, op2.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_OR, tmpReg2, tmpReg, op2.reg); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, reg, tmpReg2, 1, 31, 31); + } + output->optype = OpndType_GPR; + output->reg = reg; + return; + } else { + if (copts.optimize_for_size) { + int tmpReg, tmpReg2; + // tmpReg, tmpReg2 swap + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg, op2.reg, op3.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_ADDIC, tmpReg2, tmpReg, -1); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBFE, reg, tmpReg2, tmpReg); + } else { + int tmpReg, tmpReg2, tmpReg3; + // tmpReg, tmpReg2 swap + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg, op2.reg, op3.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg2, op3.reg, op2.reg); + tmpReg3 = ALLOC_GPR(); + emitpcode(PC_OR, tmpReg3, tmpReg, tmpReg2); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, reg, tmpReg3, 1, 31, 31); + } + output->optype = OpndType_GPR; + output->reg = reg; + return; + } + + case EGREATEREQU: + if (!is_unsigned(left->rtype) && IS_INT_CONST_ZERO(right)) { + int tmpReg; + tmpReg = ALLOC_GPR(); + emitpcode(PC_RLWINM, tmpReg, op2.reg, 1, 31, 31); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_XORI, reg, tmpReg, 1); + output->optype = OpndType_GPR; + output->reg = reg; + return; + } + op4 = op3; + op3 = op2; + op2 = op4; + case ELESSEQU: + if (is_unsigned(left->rtype)) { + if (copts.optimize_for_size) { + int tmpReg, tmpReg2; + tmpReg = ALLOC_GPR(); + emitpcode(PC_LI, tmpReg, -1); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_SUBFC, tmpReg2, op2.reg, op3.reg); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_SUBFZE, reg, tmpReg); + } else { + int tmpReg, tmpReg2, tmpReg3, tmpReg4; + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg, op2.reg, op3.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_ORC, tmpReg2, op3.reg, op2.reg); + tmpReg3 = ALLOC_GPR(); + emitpcode(PC_RLWINM, tmpReg3, tmpReg, 31, 1, 31); + tmpReg4 = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg4, tmpReg3, tmpReg2); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, reg, tmpReg4, 1, 31, 31); + } + output->optype = OpndType_GPR; + output->reg = reg; + return; + } + + if (IS_INT_CONST_ZERO(right)) { + int tmpReg, tmpReg2; + tmpReg = ALLOC_GPR(); + emitpcode(PC_LI, tmpReg, 1); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_CNTLZW, tmpReg2, op2.reg); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWNM, reg, tmpReg, tmpReg2, 31, 31); + output->optype = OpndType_GPR; + output->reg = reg; + return; + } else { + int tmpReg, tmpReg2, tmpReg3; + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_SRAWI, tmpReg2, op3.reg, 31); + tmpReg = ALLOC_GPR(); + emitpcode(PC_RLWINM, tmpReg, op2.reg, 1, 31, 31); + tmpReg3 = ALLOC_GPR(); + emitpcode(PC_SUBFC, tmpReg3, op2.reg, op3.reg); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_ADDE, reg, tmpReg2, tmpReg); + output->optype = OpndType_GPR; + output->reg = reg; + return; + } + + case EGREATER: + if (!is_unsigned(left->rtype) && IS_INT_CONST_ZERO(right)) { + int tmpReg, tmpReg2; + tmpReg = ALLOC_GPR(); + emitpcode(PC_NEG, tmpReg, op2.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_ANDC, tmpReg2, tmpReg, op2.reg); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, reg, tmpReg2, 1, 31, 31); + output->optype = OpndType_GPR; + output->reg = reg; + return; + } + + op4 = op3; + op3 = op2; + op2 = op4; + case ELESS: + if (is_unsigned(left->rtype)) { + if (left->rtype->size <= 2) { + int tmpReg; + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg, op3.reg, op2.reg); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, reg, tmpReg, 1, 31, 31); + output->optype = OpndType_GPR; + output->reg = reg; + } else { + if (copts.optimize_for_size) { + int tmpReg, tmpReg2; + tmpReg = ALLOC_GPR(); + emitpcode(PC_SUBFC, tmpReg, op3.reg, op2.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_SUBFE, tmpReg2, tmpReg, tmpReg); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_NEG, reg, tmpReg2); + } else { + int tmpReg, tmpReg2, tmpReg3; + tmpReg = ALLOC_GPR(); + emitpcode(PC_XOR, tmpReg, op3.reg, op2.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_CNTLZW, tmpReg2, tmpReg); + tmpReg3 = ALLOC_GPR(); + emitpcode(PC_SLW, tmpReg3, op3.reg, tmpReg2); + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, reg, tmpReg3, 1, 31, 31); + } + output->optype = OpndType_GPR; + output->reg = reg; + return; + } + return; + } else { + if (IS_INT_CONST_ZERO(right)) { + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, reg, op2.reg, 1, 31, 31); + output->optype = OpndType_GPR; + output->reg = reg; + return; + } else { + int tmpReg, tmpReg2, tmpReg3, tmpReg4; + tmpReg = ALLOC_GPR(); + emitpcode(PC_XOR, tmpReg, op3.reg, op2.reg); + tmpReg2 = ALLOC_GPR(); + emitpcode(PC_SRAWI, tmpReg2, tmpReg, 1); + tmpReg3 = ALLOC_GPR(); + emitpcode(PC_AND, tmpReg3, tmpReg, op3.reg); + tmpReg4 = ALLOC_GPR(); + emitpcode(PC_SUBF, tmpReg4, tmpReg3, tmpReg2); + + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, reg, tmpReg4, 1, 31, 31); + output->optype = OpndType_GPR; + output->reg = reg; + return; + } + } + + default: +#line 5777 + CError_FATAL(); + } + } + + gen_condition(cond, &op1); + emitpcode(PC_MFCR, tmpReg = used_virtual_registers[RegClass_GPR]++); + a = 0; + b = op1.reg * 4; + switch (op1.regOffset) { + case ENOTEQU: + a = 1; + case EEQU: + b += 2; + break; + case EGREATEREQU: + a = 1; + break; + case ELESSEQU: + a = 1; + case EGREATER: + b += 1; + break; + } + + reg = outputReg ? outputReg : ALLOC_GPR(); + if (a) { + emitpcode(PC_RLWINM, tmpReg, tmpReg, b + 1, 31, 31); + emitpcode(PC_XORI, reg, tmpReg, 1); + } else { + emitpcode(PC_RLWINM, reg, tmpReg, b + 1, 31, 31); + } + output->optype = OpndType_GPR; + output->reg = reg; +} + +void gen_negated_condition_gpr(ENode *cond, Operand *output, short outputReg) { +} + +void compare_floating(short nt, ENode *left, ENode *right, Operand *output) { + Operand opleft; + Operand opright; + + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + + if (right->hascall) { + GEN_NODE_TO_FPR(right, &opright, right->rtype, 0); + GEN_NODE_TO_FPR(left, &opleft, left->rtype, 0); + } else { + GEN_NODE_TO_FPR(left, &opleft, left->rtype, 0); + GEN_NODE_TO_FPR(right, &opright, right->rtype, 0); + } + + emitpcode((nt == EEQU || nt == ENOTEQU) ? PC_FCMPU : PC_FCMPO, 0, opleft.reg, opright.reg); + if (nt == ELESSEQU) { + emitpcode(PC_CROR, 0, 2, 0, 0, 0, 2); + nt = EEQU; + } else if (nt == EGREATEREQU) { + emitpcode(PC_CROR, 0, 2, 0, 1, 0, 2); + nt = EEQU; + } + + output->optype = OpndType_CRField; + output->reg = 0; + output->regOffset = nt; +} + +void compare_integer(short nt, ENode *left, ENode *right, Operand *output) { + Operand opleft; + Operand opright; + + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + + if (right->hascall) { + GEN_NODE(right, &opright); + if (right->rtype->size < 4) + extend32(&opright, right->rtype, 0); + ENSURE_GPR(&opright, right->rtype, 0); + + GEN_NODE(left, &opleft); + if (left->rtype->size < 4) + extend32(&opleft, left->rtype, 0); + ENSURE_GPR(&opleft, left->rtype, 0); + } else { + GEN_NODE(left, &opleft); + ENSURE_GPR(&opleft, left->rtype, 0); + if (left->rtype->size < 4) + extend32(&opleft, left->rtype, 0); + + GEN_NODE(right, &opright); + if (right->rtype->size < 4) + extend32(&opright, right->rtype, 0); + ENSURE_GPR(&opright, right->rtype, 0); + } + + emitpcode(is_unsigned(left->rtype) ? PC_CMPL : PC_CMP, 0, opleft.reg, opright.reg); + + output->optype = OpndType_CRField; + output->reg = 0; + output->regOffset = nt; +} + +void compare_immediate(short nt, ENode *left, SInt32 value, Operand *output) { +} + +void compare_immediate_long(short nt, ENode *left, SInt32 value, Operand *output) { +} + +static int ismask(SInt32 value, short *first, short *last) { + int start, end, bit; + start = end = -1; + for (bit = 31; bit >= 0; bit--) { + if (value & 1) { + if (start != -1) + return 0; + if (end == -1) + end = bit; + } else { + if (end != -1 && start == -1) + start = bit + 1; + } + value >>= 1; + } + + if (end == -1) + return 0; + if (start == -1) + start = 0; + *first = start; + *last = end; + return 1; +} + +int ismaskconstant(SInt32 value, short *first, short *last) { + short my_first; + short my_last; + if (ismask(value, first, last)) + return 1; + + if (value && ismask(~value, &my_first, &my_last)) { + *first = my_last + 1; + *last = my_first - 1; + return 1; + } else { + return 0; + } +} + +static void shift_and_mask(ENode *expr, short a, short b, short c, short outputReg, Operand *output) { + Operand op; + int reg; + + memclrw(&op, sizeof(Operand)); + GEN_NODE(expr, &op); + ENSURE_GPR(&op, expr->rtype, 0); + + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_RLWINM, reg, op.reg, a, b, c); + + output->optype = OpndType_GPR; + output->reg = reg; +} + +int ispostincrementopportunity(ENode *expr, Operand *op, SInt32 *value) { + Type *type; + int reg; + + type = expr->rtype; + if (!ENODE_IS2(expr, EPOSTINC, EPOSTDEC)) + return 0; + if (!ENODE_IS(expr->data.monadic, EINDIRECT)) + return 0; + if (!ENODE_IS(expr->data.monadic->data.monadic, EOBJREF)) + return 0; + + reg = OBJECT_REG(expr->data.monadic->data.monadic->data.objref); + if (!reg) + return 0; + + if (IS_TYPE_POINTER(type)) { + if (ENODE_IS(expr, EPOSTINC)) + *value = TPTR_TARGET(type)->size; + else + *value = -TPTR_TARGET(type)->size; + } else { + if (ENODE_IS(expr, EPOSTINC)) + *value = 1; + else + *value = -1; + } + + op->optype = OpndType_GPR; + op->reg = reg; + return 1; +} + +void add_register_immediate(short regA, short regB, SInt32 value) { + if (!FITS_IN_SHORT(value)) { + emitpcode(PC_ADDIS, regA, regB, 0, HIGH_PART(value)); + if (LOW_PART(value)) + emitpcode(PC_ADDI, regA, regA, 0, LOW_PART(value)); + } else { + emitpcode(PC_ADDI, regA, regB, 0, value); + } +} + +static int ispowerof2(SInt32 val) { + int bit = getbit(val); + return (bit > 0 && bit < 31) ? bit : 0; +} + +void I8_gen_ADD(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + int is_uns; + ENode *left; + ENode *right; + short reg; + short regHi; + short tmpreg1; + short tmpreg2; + SInt32 skipleft; + SInt32 skipright; + Operand opleft; + Operand opright; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + + if (right->hascall) { + GEN_NODE(right, &opright); + if (TYPE_IS_8BYTES(right->rtype)) + coerce_to_register_pair(&opright, right->rtype, 0, 0); + else + ENSURE_GPR(&opright, right->rtype, 0); + + GEN_NODE(left, &opleft); + if (TYPE_IS_8BYTES(left->rtype)) + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + else + ENSURE_GPR(&opleft, left->rtype, 0); + } else { + GEN_NODE(left, &opleft); + if (TYPE_IS_8BYTES(left->rtype)) + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + else + ENSURE_GPR(&opleft, left->rtype, 0); + + GEN_NODE(right, &opright); + if (TYPE_IS_8BYTES(right->rtype)) + coerce_to_register_pair(&opright, right->rtype, 0, 0); + else + ENSURE_GPR(&opright, right->rtype, 0); + } + + reg = ALLOC_GPR(); + regHi = ALLOC_GPR(); + is_uns = is_unsigned(expr->rtype) != 0; + skipleft = GetSizeSkip(left); + skipright = GetSizeSkip(right); + + if (skipleft < skipright) { + Operand tmpop; + SInt32 tmp; + + expr->data.diadic.left = right; + expr->data.diadic.right = left; + left = expr->data.diadic.left; + right = expr->data.diadic.right; + + tmpop = opright; + opright = opleft; + opleft = tmpop; + + tmp = skipleft; + skipleft = skipright; + skipright = tmp; + } + + switch (skipleft + skipright) { + case 1 + 1: + case 1 + 2: + case 2 + 2: + if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo)) { + emitpcode(PC_ADDIC, reg, opright.reg, LOW_PART(left->data.intval.lo)); + } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo)) { + emitpcode(PC_ADDIC, reg, opleft.reg, LOW_PART(right->data.intval.lo)); + } else { + emitpcode(PC_ADDC, reg, opleft.reg, opright.reg); + } + if (is_uns) + emitpcode(PC_LI, regHi, 0); + else + emitpcode(PC_SRAWI, regHi, reg, 31); + break; + case 1 + 4: + case 2 + 4: + case 4 + 4: + if (!is_uns) { + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); + emitpcode(PC_SRAWI, tmpreg2, opleft.reg, 31); + emitpcode(PC_SRAWI, tmpreg1, opright.reg, 31); + } + if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo)) { + emitpcode(PC_ADDIC, reg, opright.reg, LOW_PART(left->data.intval.lo)); + } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo)) { + emitpcode(PC_ADDIC, reg, opleft.reg, LOW_PART(right->data.intval.lo)); + } else { + emitpcode(PC_ADDC, reg, opleft.reg, opright.reg); + } + if (is_uns) { + tmpreg1 = ALLOC_GPR(); + emitpcode(PC_LI, tmpreg1, 0); + emitpcode(PC_ADDZE, regHi, tmpreg1); + } else { + emitpcode(PC_ADDE, regHi, tmpreg1, tmpreg2); + } + break; + case 1 + 8: + case 2 + 8: + case 4 + 8: +#line 6933 + CError_ASSERT(skipleft == 8); + if (!is_uns) { + tmpreg2 = ALLOC_GPR(); + emitpcode(PC_SRAWI, tmpreg2, opright.reg, 31); + } + if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo) && left->data.intval.hi == 0) { + emitpcode(PC_ADDIC, reg, opright.reg, LOW_PART(left->data.intval.lo)); + } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo) && right->data.intval.hi == 0) { + emitpcode(PC_ADDIC, reg, opleft.reg, LOW_PART(right->data.intval.lo)); + } else { + emitpcode(PC_ADDC, reg, opleft.reg, opright.reg); + } + if (is_uns) + emitpcode(PC_ADDZE, regHi, opleft.regHi); + else + emitpcode(PC_ADDE, regHi, opleft.regHi, tmpreg2); + break; + case 8 + 8: + emitpcode(PC_ADDC, reg, opleft.reg, opright.reg); + emitpcode(PC_ADDE, regHi, opleft.regHi, opright.regHi); + break; + default: +#line 6979 + CError_FATAL(); + } + + output->optype = OpndType_GPRPair; + output->reg = reg; + output->regHi = regHi; +} + +void I8_gen_INTCONST(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + short reg; + short regHi; + + reg = outputReg ? outputReg : ALLOC_GPR(); + regHi = outputRegHi ? outputRegHi : ALLOC_GPR(); + + load_immediate(reg, expr->data.intval.lo); + load_immediate(regHi, expr->data.intval.hi); + + output->optype = OpndType_GPRPair; + output->reg = reg; + output->regHi = regHi; +} + +void I8_gen_SUB(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + int is_uns; + ENode *left; + ENode *right; + short reg; + short regHi; + short tmpreg1; + short tmpreg2; + short tmpreg3; + SInt32 skipleft; + SInt32 skipright; + Operand opleft; + Operand opright; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + + if (right->hascall) { + GEN_NODE(right, &opright); + if (TYPE_IS_8BYTES(right->rtype)) + coerce_to_register_pair(&opright, right->rtype, 0, 0); + else + ENSURE_GPR(&opright, right->rtype, 0); + + GEN_NODE(left, &opleft); + if (TYPE_IS_8BYTES(left->rtype)) + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + else + ENSURE_GPR(&opleft, left->rtype, 0); + } else { + GEN_NODE(left, &opleft); + if (TYPE_IS_8BYTES(left->rtype)) + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + else + ENSURE_GPR(&opleft, left->rtype, 0); + + GEN_NODE(right, &opright); + if (TYPE_IS_8BYTES(right->rtype)) + coerce_to_register_pair(&opright, right->rtype, 0, 0); + else + ENSURE_GPR(&opright, right->rtype, 0); + } + + reg = ALLOC_GPR(); + regHi = ALLOC_GPR(); + is_uns = is_unsigned(expr->rtype) != 0; + skipleft = GetSizeSkip(left); + skipright = GetSizeSkip(right); + + switch (skipleft + skipright) { + case 1 + 1: + case 1 + 2: + case 2 + 2: + if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo)) { + emitpcode(PC_SUBFIC, reg, opright.reg, LOW_PART(left->data.intval.lo)); + } else { + emitpcode(PC_SUBFC, reg, opright.reg, opleft.reg); + } + if (is_uns) + emitpcode(PC_LI, regHi, 0); + else + emitpcode(PC_SRAWI, regHi, reg, 31); + break; + case 1 + 4: + case 2 + 4: + case 4 + 4: + if (!is_uns) { + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); + emitpcode(PC_SRAWI, tmpreg2, opleft.reg, 31); + emitpcode(PC_SRAWI, tmpreg1, opright.reg, 31); + } + if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo)) { + emitpcode(PC_SUBFIC, reg, opright.reg, LOW_PART(left->data.intval.lo)); + } else { + emitpcode(PC_SUBFC, reg, opright.reg, opleft.reg); + } + if (is_uns) { + tmpreg1 = ALLOC_GPR(); + emitpcode(PC_LI, tmpreg1, 0); + emitpcode(PC_SUBFZE, regHi, tmpreg1); + } else { + emitpcode(PC_SUBFE, regHi, tmpreg1, tmpreg2); + } + break; + case 1 + 8: + case 2 + 8: + case 4 + 8: + if (skipleft < skipright) { + emitpcode(PC_SUBFC, reg, opright.reg, opleft.reg); + emitpcode(PC_SUBFE, regHi, opright.regHi, opleft.regHi); + } else { + if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo) && left->data.intval.hi == 0) { + emitpcode(PC_SUBFIC, reg, opright.reg, LOW_PART(left->data.intval.lo)); + } else { + emitpcode(PC_SUBFC, reg, opright.reg, opleft.reg); + } + tmpreg1 = ALLOC_GPR(); + emitpcode(PC_LI, tmpreg1, 0); + emitpcode(PC_SUBFE, regHi, tmpreg1, opleft.regHi); + } + break; + case 8 + 8: + emitpcode(PC_SUBFC, reg, opright.reg, opleft.reg); + emitpcode(PC_SUBFE, regHi, opright.regHi, opleft.regHi); + break; + default: +#line 7211 + CError_FATAL(); + } + + output->optype = OpndType_GPRPair; + output->reg = reg; + output->regHi = regHi; +} + +void I8_gen_XOR(ENode *expr, short outputReg, short outputRegHi, Operand *output) { +} + +void I8_gen_OR(ENode *expr, short outputReg, short outputRegHi, Operand *output) { +} + +void I8_gen_AND(ENode *expr, short outputReg, short outputRegHi, Operand *output) { +} + +int I8_getbit(UInt64 val) { + switch (val) { + case 0: return -1; + case 1ULL << 0: return 0; + case 1ULL << 1: return 1; + case 1ULL << 2: return 2; + case 1ULL << 3: return 3; + case 1ULL << 4: return 4; + case 1ULL << 5: return 5; + case 1ULL << 6: return 6; + case 1ULL << 7: return 7; + case 1ULL << 8: return 8; + case 1ULL << 9: return 9; + case 1ULL << 10: return 10; + case 1ULL << 11: return 11; + case 1ULL << 12: return 12; + case 1ULL << 13: return 13; + case 1ULL << 14: return 14; + case 1ULL << 15: return 15; + case 1ULL << 16: return 16; + case 1ULL << 17: return 17; + case 1ULL << 18: return 18; + case 1ULL << 19: return 19; + case 1ULL << 20: return 20; + case 1ULL << 21: return 21; + case 1ULL << 22: return 22; + case 1ULL << 23: return 23; + case 1ULL << 24: return 24; + case 1ULL << 25: return 25; + case 1ULL << 26: return 26; + case 1ULL << 27: return 27; + case 1ULL << 28: return 28; + case 1ULL << 29: return 29; + case 1ULL << 30: return 30; + case 1ULL << 31: return 31; + case 1ULL << 32: return 32; + case 1ULL << 33: return 33; + case 1ULL << 34: return 34; + case 1ULL << 35: return 35; + case 1ULL << 36: return 36; + case 1ULL << 37: return 37; + case 1ULL << 38: return 38; + case 1ULL << 39: return 39; + case 1ULL << 40: return 40; + case 1ULL << 41: return 41; + case 1ULL << 42: return 42; + case 1ULL << 43: return 43; + case 1ULL << 44: return 44; + case 1ULL << 45: return 45; + case 1ULL << 46: return 46; + case 1ULL << 47: return 47; + case 1ULL << 48: return 48; + case 1ULL << 49: return 49; + case 1ULL << 50: return 50; + case 1ULL << 51: return 51; + case 1ULL << 52: return 52; + case 1ULL << 53: return 53; + case 1ULL << 54: return 54; + case 1ULL << 55: return 55; + case 1ULL << 56: return 56; + case 1ULL << 57: return 57; + case 1ULL << 58: return 58; + case 1ULL << 59: return 59; + case 1ULL << 60: return 60; + case 1ULL << 61: return 61; + case 1ULL << 62: return 62; + case 1ULL << 63: return 63; + default: return -2; + } +} + +int I8_log2n(UInt64 val) { + int bit = I8_getbit(val); + return (bit > 0 && bit < 63) ? bit : 0; +} + +void I8_ShiftLeftImmediate(Operand opnd, SInt32 value, int is_unsigned, SInt32 size, short reg, short regHi) { + if (opnd.reg == reg || opnd.regHi == regHi || opnd.reg == regHi || opnd.regHi == reg) { +#line 7703 + CError_FATAL(); + } + + if (value < 32) { + emitpcode(PC_RLWINM, reg, opnd.reg, value, 0, 31 - value); + if (size > 4) { + emitpcode(PC_RLWINM, regHi, opnd.regHi, value, 0, 31 - value); + emitpcode(PC_RLWIMI, regHi, opnd.reg, value, 32 - value, 31); + } else { + emitpcode(PC_RLWINM, regHi, opnd.reg, value, 32 - value, 31); + } + } else if (value <= 63) { + if (value == 32) + emitpcode(PC_MR, regHi, opnd.reg); + else + emitpcode(PC_RLWINM, regHi, opnd.reg, value - 32, 0, 63 - value); + emitpcode(PC_LI, reg, 0); + } else { +#line 7732 + CError_FATAL(); + } +} + +void I8_ShiftRightImmediate(Operand opnd, SInt32 value, int is_unsigned, short reg, short regHi, int unk) { + short tmpreg1; + short tmpreg2; + short tmpreg3; + short tmpreg4; + + if (opnd.reg == reg || opnd.regHi == regHi || opnd.reg == regHi || opnd.regHi == reg) { +#line 7756 + CError_FATAL(); + } + + if (value < 32) { + emitpcode(PC_RLWINM, reg, opnd.reg, 32 - value, 0, 31); + emitpcode(PC_RLWIMI, reg, opnd.regHi, 32 - value, 0, value - 1); + if (is_unsigned) { + emitpcode(PC_RLWINM, regHi, opnd.regHi, 32 - value, value, 31); + } else if (unk) { + tmpreg1 = ALLOC_GPR(); + emitpcode(PC_MR, tmpreg1, opnd.regHi); + emitpcode(PC_RLWIMI, tmpreg1, opnd.reg, 0, 31 - (value - 1), 31); + emitpcode(PC_SRAWI, regHi, tmpreg1, value); + } else { + emitpcode(PC_SRAWI, regHi, opnd.regHi, value); + } + } else if (value == 32) { + if (is_unsigned) { + emitpcode(PC_MR, reg, opnd.regHi); + emitpcode(PC_LI, regHi, 0); + } else if (unk) { + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); + tmpreg3 = ALLOC_GPR(); + emitpcode(PC_NEG, tmpreg1, opnd.reg); + emitpcode(PC_OR, tmpreg2, tmpreg1, opnd.reg); + emitpcode(PC_RLWINM, tmpreg3, tmpreg2, 1, 31, 31); + emitpcode(PC_RLWIMI, tmpreg3, opnd.regHi, 0, 0, 0); + emitpcode(PC_MR, reg, opnd.regHi); + emitpcode(PC_SRAWI, regHi, value, 31); + } else { + emitpcode(PC_MR, reg, opnd.regHi); + emitpcode(PC_SRAWI, regHi, opnd.regHi, 31); + } + } else if (value <= 63) { + if (is_unsigned) { + emitpcode(PC_RLWINM, reg, opnd.regHi, 64 - value, value - 32, 31); + emitpcode(PC_LI, regHi, 0); + } else if (unk) { + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); + tmpreg3 = ALLOC_GPR(); + tmpreg4 = ALLOC_GPR(); + emitpcode(PC_NEG, tmpreg1, opnd.reg); + emitpcode(PC_OR, tmpreg2, tmpreg1, opnd.reg); + emitpcode(PC_RLWINM, tmpreg3, tmpreg2, 1, 31, 31); + emitpcode(PC_OR, tmpreg4, opnd.regHi, tmpreg3); + emitpcode(PC_SRAWI, regHi, opnd.regHi, 31); + emitpcode(PC_SRAWI, reg, tmpreg4, value - 32); + } else { + emitpcode(PC_SRAWI, reg, opnd.regHi, value - 32); + emitpcode(PC_SRAWI, regHi, opnd.regHi, 31); + } + } else { +#line 7866 + CError_FATAL(); + } +} + +void I8_gen_MUL(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + int is_uns; + ENode *left; + ENode *right; + short reg; + short regHi; + short tmpreg1; + short tmpreg2; + short tmpreg3; + short tmpreg4; + SInt32 skipleft; + SInt32 skipright; + Operand opleft; + Operand opright; + SInt64 leftval; + SInt64 rightval; + int shift; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + skipleft = GetSizeSkip(left); + skipright = GetSizeSkip(right); + + if (ENODE_IS(right, EINTCONST) && ENODE_IS(left, EINTCONST)) { +#line 7900 + CError_FATAL(); + } + + if (ENODE_IS(left, EINTCONST)) + leftval = left->data.intval.lo + (((SInt64) ((skipleft < 8) ? 0 : left->data.intval.hi)) << 32); + if (ENODE_IS(right, EINTCONST)) + rightval = right->data.intval.lo + (((SInt64) ((skipright < 8) ? 0 : right->data.intval.hi)) << 32); + + if (right->hascall) { + GEN_NODE(right, &opright); + if (TYPE_IS_8BYTES(right->rtype)) + coerce_to_register_pair(&opright, right->rtype, 0, 0); + else + ENSURE_GPR(&opright, right->rtype, 0); + + if (!(ENODE_IS(left, EINTCONST) && I8_log2n(leftval) > 0)) { + GEN_NODE(left, &opleft); + if (TYPE_IS_8BYTES(left->rtype)) + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + else + ENSURE_GPR(&opleft, left->rtype, 0); + } + } else { + if (!(ENODE_IS(left, EINTCONST) && I8_log2n(leftval) > 0)) { + GEN_NODE(left, &opleft); + if (TYPE_IS_8BYTES(left->rtype)) + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + else + ENSURE_GPR(&opleft, left->rtype, 0); + } + + if (!(ENODE_IS(right, EINTCONST) && I8_log2n(rightval) > 0)) { + GEN_NODE(right, &opright); + if (TYPE_IS_8BYTES(right->rtype)) + coerce_to_register_pair(&opright, right->rtype, 0, 0); + else + ENSURE_GPR(&opright, right->rtype, 0); + } + } + + is_uns = is_unsigned(expr->rtype) != 0; + + if (skipleft < skipright) { + Operand tmpop; + SInt64 tmp64; + SInt32 tmp; + + expr->data.diadic.left = right; + expr->data.diadic.right = left; + left = expr->data.diadic.left; + right = expr->data.diadic.right; + + tmpop = opright; + opright = opleft; + opleft = tmpop; + + tmp64 = leftval; + leftval = rightval; + rightval = tmp64; + + tmp = skipleft; + skipleft = skipright; + skipright = tmp; + } + + reg = ALLOC_GPR(); + regHi = ALLOC_GPR(); + + if (ENODE_IS(left, EINTCONST) && (shift = I8_log2n(leftval)) > 0) { + I8_ShiftLeftImmediate(opright, shift, is_uns, skipright, reg, regHi); + } else if (ENODE_IS(right, EINTCONST) && (shift = I8_log2n(rightval)) > 0) { + I8_ShiftLeftImmediate(opleft, shift, is_uns, skipleft, reg, regHi); + } else { + switch (skipleft + skipright) { + case 1 + 1: + case 1 + 2: + case 2 + 2: + if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo)) { + emitpcode(PC_MULLI, reg, opright.reg, LOW_PART(left->data.intval.lo)); + } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo)) { + emitpcode(PC_MULLI, reg, opleft.reg, LOW_PART(right->data.intval.lo)); + } else { + emitpcode(PC_MULLW, reg, opleft.reg, opright.reg); + } + if (is_uns) + emitpcode(PC_LI, regHi, 0); + else + emitpcode(PC_SRAWI, regHi, reg, 31); + break; + case 1 + 4: + case 2 + 4: + case 4 + 4: + if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo)) { + emitpcode(PC_MULLI, reg, opright.reg, LOW_PART(left->data.intval.lo)); + } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo)) { + emitpcode(PC_MULLI, reg, opleft.reg, LOW_PART(right->data.intval.lo)); + } else { + emitpcode(PC_MULLW, reg, opleft.reg, opright.reg); + } + if (is_uns) + emitpcode(PC_MULHWU, regHi, opleft.reg, opright.reg); + else + emitpcode(PC_MULHW, regHi, opleft.reg, opright.reg); + break; + case 1 + 8: + case 2 + 8: + case 4 + 8: +#line 8097 + CError_ASSERT(skipleft == 8); + if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo) && left->data.intval.hi == 0) { + emitpcode(PC_MULLI, reg, opright.reg, LOW_PART(left->data.intval.lo)); + if (is_uns) + emitpcode(PC_MULHWU, regHi, opright.reg, opleft.reg); + else + emitpcode(PC_MULHW, regHi, opright.reg, opleft.reg); + } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo) && right->data.intval.hi == 0) { + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); + if (is_uns) { + emitpcode(PC_MULHWU, tmpreg2, opleft.reg, opright.reg); + emitpcode(PC_MULLI, tmpreg1, opleft.regHi, LOW_PART(right->data.intval.lo)); + emitpcode(PC_MULLI, reg, opleft.reg, LOW_PART(right->data.intval.lo)); + emitpcode(PC_ADD, regHi, tmpreg2, tmpreg1); + } else { + tmpreg3 = ALLOC_GPR(); + tmpreg4 = ALLOC_GPR(); + emitpcode(PC_SRAWI, tmpreg4, opright.reg, 31); + emitpcode(PC_MULHWU, tmpreg2, opleft.reg, opright.reg); + emitpcode(PC_MULLI, tmpreg1, opleft.regHi, LOW_PART(right->data.intval.lo)); + emitpcode(PC_MULLI, reg, opleft.reg, LOW_PART(right->data.intval.lo)); + emitpcode(PC_MULLW, tmpreg3, opleft.reg, tmpreg4); + emitpcode(PC_ADD, regHi, tmpreg2, tmpreg1); + emitpcode(PC_ADD, regHi, regHi, tmpreg3); + } + } else { + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); + if (is_uns) { + emitpcode(PC_MULHWU, tmpreg2, opleft.reg, opright.reg); + emitpcode(PC_MULLW, tmpreg1, opleft.regHi, opright.reg); + emitpcode(PC_MULLW, reg, opleft.reg, opright.reg); + emitpcode(PC_ADD, regHi, tmpreg2, tmpreg1); + } else { + tmpreg3 = ALLOC_GPR(); + tmpreg4 = ALLOC_GPR(); + emitpcode(PC_SRAWI, tmpreg4, opright.reg, 31); + emitpcode(PC_MULHWU, tmpreg2, opleft.reg, opright.reg); + emitpcode(PC_MULLW, tmpreg1, opleft.regHi, opright.reg); + emitpcode(PC_MULLW, reg, opleft.reg, opright.reg); + emitpcode(PC_MULLW, tmpreg3, opleft.reg, tmpreg4); + emitpcode(PC_ADD, regHi, tmpreg2, tmpreg1); + emitpcode(PC_ADD, regHi, regHi, tmpreg3); + } + } + break; + case 8 + 8: + if (ENODE_IS(left, EINTCONST) && FITS_IN_SHORT2(left->data.intval.lo) && left->data.intval.hi == 0) { + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); + emitpcode(PC_MULHWU, tmpreg1, opright.reg, opleft.reg); + emitpcode(PC_MULLW, tmpreg2, opright.reg, opleft.regHi); + emitpcode(PC_MULLI, reg, opright.reg, LOW_PART(left->data.intval.lo)); + emitpcode(PC_ADD, regHi, tmpreg1, tmpreg2); + } else if (ENODE_IS(right, EINTCONST) && FITS_IN_SHORT2(right->data.intval.lo) && right->data.intval.hi == 0) { + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); + emitpcode(PC_MULHWU, tmpreg2, opleft.reg, opright.reg); + emitpcode(PC_MULLW, tmpreg1, opleft.regHi, opright.reg); + emitpcode(PC_MULLI, reg, opleft.reg, LOW_PART(right->data.intval.lo)); + emitpcode(PC_ADD, regHi, tmpreg2, tmpreg1); + } else { + tmpreg1 = ALLOC_GPR(); + tmpreg2 = ALLOC_GPR(); + tmpreg3 = ALLOC_GPR(); + tmpreg4 = ALLOC_GPR(); + emitpcode(PC_MULHWU, tmpreg2, opleft.reg, opright.reg); + emitpcode(PC_MULLW, tmpreg1, opleft.regHi, opright.reg); + emitpcode(PC_ADD, tmpreg3, tmpreg2, tmpreg1); + emitpcode(PC_MULLW, tmpreg4, opleft.reg, opright.regHi); + emitpcode(PC_MULLW, reg, opleft.reg, opright.reg); + emitpcode(PC_ADD, regHi, tmpreg3, tmpreg4); + } + break; + default: +#line 8218 + CError_FATAL(); + } + } + + output->optype = OpndType_GPRPair; + output->reg = reg; + output->regHi = regHi; +} + +void I8_gen_BINNOT(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *inner; + Operand op; + int reg; + int regHi; + + inner = expr->data.monadic; + memclrw(&op, sizeof(Operand)); + GEN_NODE(inner, &op); + coerce_to_register_pair(&op, inner->rtype, 0, 0); + + reg = outputReg ? outputReg : ALLOC_GPR(); + regHi = outputRegHi ? outputRegHi : ALLOC_GPR(); + emitpcode(PC_NOR, reg, op.reg, op.reg); + emitpcode(PC_NOR, regHi, op.regHi, op.regHi); + + output->optype = OpndType_GPRPair; + output->reg = reg; + output->regHi = regHi; +} + +void I8_gen_MONMIN(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *inner; + Operand op; + int reg; + int regHi; + + inner = expr->data.monadic; + memclrw(&op, sizeof(Operand)); + GEN_NODE(inner, &op); + coerce_to_register_pair(&op, inner->rtype, 0, 0); + + reg = outputReg ? outputReg : ALLOC_GPR(); + regHi = outputRegHi ? outputRegHi : ALLOC_GPR(); + emitpcode(PC_SUBFIC, reg, op.reg, 0); + emitpcode(PC_SUBFZE, regHi, op.regHi); + + output->optype = OpndType_GPRPair; + output->reg = reg; + output->regHi = regHi; +} + +void I8_gen_ASS(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + Type *type; + ENode *left; + ENode *right; + Operand opleft; + Operand opright; + VarInfo *vi; + + type = expr->rtype; + if (ENODE_IS(expr, ECONDASS)) { + left = expr->data.cond.expr1; + if (ENODE_IS(left, EINDIRECT)) { + left = left->data.monadic; + } else { +#line 8328 + CError_FATAL(); + } + right = expr->data.cond.expr2; + } else { + left = expr->data.diadic.left; + right = expr->data.diadic.right; + } + + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + + if (ENODE_IS(left, EOBJREF) && OBJECT_REG(left->data.objref)) { + vi = Registers_GetVarInfo(left->data.objref); + GEN_NODE_TO_REG(right, vi->reg, vi->regHi, &opright); + if (vi->rclass != RegClass_GPR) { +#line 8348 + CError_FATAL(); + } else { + coerce_to_register_pair(&opright, type, vi->reg, vi->regHi); + *output = opright; + } + return; + } + + if (TYPE_FITS_IN_REGISTER(type)) { + GEN_NODE(right, &opright); + coerce_to_register_pair(&opright, right->rtype, 0, 0); + + if (ENODE_IS(left, EBITFIELD)) { +#line 8376 + CError_FATAL(); + } else { + GEN_NODE(left, &opleft); + indirect(&opleft, left); + store_pair(opright.reg, opright.regHi, &opleft, type); + } + + output->optype = OpndType_GPRPair; + output->reg = opright.reg; + output->regHi = opright.regHi; + } +} + +void I8_gen_POSTINCDEC(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *inner; + Type *type; + int flag; + int reg; + int regHi; + Operand op1; + Operand op2; + Operand op3; + + inner = expr->data.monadic->data.monadic; + type = expr->rtype; + flag = 0; + memclrw(&op1, sizeof(Operand)); + memclrw(&op2, sizeof(Operand)); + + if (ENODE_IS(inner, EOBJREF) && (reg = OBJECT_REG(inner->data.objref))) { + regHi = Registers_GetVarInfo(inner->data.objref)->regHi; + output->optype = OpndType_GPRPair; + output->reg = (outputReg && outputReg != reg && outputReg != regHi) ? outputReg : ALLOC_GPR(); + output->regHi = (outputRegHi && outputRegHi != regHi && outputRegHi != reg) ? outputRegHi : ALLOC_GPR(); + emitpcode(PC_MR, output->reg, reg); + emitpcode(PC_MR, output->regHi, regHi); + if (ENODE_IS(expr, EPOSTINC)) { + emitpcode(PC_ADDIC, reg, reg, 1); + emitpcode(PC_ADDME, regHi, regHi); + } else { + emitpcode(PC_ADDIC, reg, reg, -1); + emitpcode(PC_ADDZE, regHi, regHi); + } + return; + } + +#line 8446 + CError_ASSERT(!ENODE_IS(inner, EBITFIELD)); + + GEN_NODE(inner, &op1); + indirect(&op1, inner); + op2 = op1; + coerce_to_register_pair(&op2, type, 0, 0); + + output->optype = OpndType_GPRPair; + output->reg = ALLOC_GPR(); + output->regHi = ALLOC_GPR(); + + emitpcode(PC_MR, output->reg, op2.reg); + emitpcode(PC_MR, output->regHi, op2.regHi); + + reg = ALLOC_GPR(); + regHi = ALLOC_GPR(); + + if (ENODE_IS(expr, EPOSTINC)) { + emitpcode(PC_ADDIC, reg, op2.reg, 1); + emitpcode(PC_ADDZE, regHi, op2.regHi); + } else { + emitpcode(PC_ADDIC, reg, op2.reg, -1); + emitpcode(PC_ADDME, regHi, op2.regHi); + } + store_pair(reg, regHi, &op1, type); +} + +void I8_gen_INDIRECT(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + ENode *inner; + VarInfo *vi; + + inner = expr->data.monadic; + if (ENODE_IS(inner, EOBJREF) && OBJECT_REG(inner->data.objref)) { + vi = Registers_GetVarInfo(inner->data.objref); + switch (vi->rclass) { + case RegClass_GPR: + output->optype = OpndType_GPRPair; + break; + case RegClass_FPR: + output->optype = OpndType_FPR; + break; + default: +#line 8511 + CError_FATAL(); + } + + output->reg = vi->reg; + output->regHi = vi->regHi; + output->object = NULL; + return; + } + + if (ENODE_IS(inner, EBITFIELD)) { +#line 8529 + CError_FATAL(); + return; + } + + GEN_NODE(inner, output); + indirect(output, inner); +} + +void I8_gen_condition(ENode *cond, Operand *output, int write_to_gpr) { + ENode *left; + ENode *right; + Operand opleft; + Operand opright; + Operand tmpop; + int reg1; + int reg2; + int reg3; + int reg4; + int reg5; + + left = cond->data.diadic.left; + right = cond->data.diadic.right; + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + memclrw(&tmpop, sizeof(Operand)); + + if (right->hascall) { + GEN_NODE(right, &opright); + if (right->rtype->size < 4) + extend32(&opright, right->rtype, 0); + ENSURE_GPR(&opright, right->rtype, 0); + + if (right->rtype->size < 8) { + short tmp = ALLOC_GPR(); + if (is_unsigned(right->rtype)) + load_immediate(tmp, 0); + else + emitpcode(PC_SRAWI, tmp, opright.reg, 31); + opright.optype = OpndType_GPRPair; + opright.regHi = tmp; + } + + GEN_NODE(left, &opleft); + if (left->rtype->size < 4) + extend32(&opleft, left->rtype, 0); + ENSURE_GPR(&opleft, left->rtype, 0); + + if (left->rtype->size < 8) { + short tmp = ALLOC_GPR(); + // this looks like a bug??? surely this should check left->rtype + if (is_unsigned(right->rtype)) + load_immediate(tmp, 0); + else + emitpcode(PC_SRAWI, tmp, opleft.reg, 31); + opleft.optype = OpndType_GPRPair; + opleft.regHi = tmp; + } + } else { + GEN_NODE(left, &opleft); + ENSURE_GPR(&opleft, left->rtype, 0); + if (left->rtype->size < 4) + extend32(&opleft, left->rtype, 0); + + if (left->rtype->size < 8) { + short tmp = ALLOC_GPR(); + if (is_unsigned(right->rtype)) + load_immediate(tmp, 0); + else + emitpcode(PC_SRAWI, tmp, opleft.reg, 31); + opleft.optype = OpndType_GPRPair; + opleft.regHi = tmp; + } + + GEN_NODE(right, &opright); + if (right->rtype->size < 4) + extend32(&opright, right->rtype, 0); + ENSURE_GPR(&opright, right->rtype, 0); + + if (right->rtype->size < 8) { + short tmp = ALLOC_GPR(); + if (is_unsigned(right->rtype)) + load_immediate(tmp, 0); + else + emitpcode(PC_SRAWI, tmp, opright.reg, 31); + opright.optype = OpndType_GPRPair; + opright.regHi = tmp; + } + } + +#line 8704 + CError_ASSERT(opleft.optype == OpndType_GPRPair && opright.optype == OpndType_GPRPair); + + switch (cond->type) { + case EEQU: + case ENOTEQU: + reg1 = ALLOC_GPR(); + reg2 = ALLOC_GPR(); + emitpcode(PC_XOR, reg1, opleft.reg, opright.reg); + emitpcode(PC_XOR, reg2, opleft.regHi, opright.regHi); + emitpcode(PC_OR, reg2, reg1, reg2); + if (write_to_gpr) { + if (ENODE_IS(cond, EEQU)) { + emitpcode(PC_CNTLZW, reg2, reg2); + emitpcode(PC_RLWINM, reg2, reg2, 27, 5, 31); + } else { + emitpcode(PC_ADDIC, reg1, reg2, -1); + emitpcode(PC_SUBFE, reg2, reg1, reg2); + } + output->optype = OpndType_GPR; + output->reg = reg2; + output->regHi = 0; + } else { + emitpcode(PC_CMPI, 0, reg2, 0); + output->optype = OpndType_CRField; + output->reg = 0; + output->regOffset = cond->type; + } + break; + case EGREATER: + tmpop = opleft; + opleft = opright; + opright = tmpop; + case ELESS: + reg1 = ALLOC_GPR(); + reg2 = ALLOC_GPR(); + reg3 = ALLOC_GPR(); + if (left->rtype != TYPE(&stunsignedlonglong) && right->rtype != TYPE(&stunsignedlonglong)) { + emitpcode(PC_XORIS, reg1, opleft.regHi, 0x8000); + emitpcode(PC_XORIS, reg2, opright.regHi, 0x8000); + reg4 = reg1; + reg5 = reg2; + } else { + reg4 = opleft.regHi; + reg5 = opright.regHi; + } + emitpcode(PC_SUBFC, reg3, opright.reg, opleft.reg); + emitpcode(PC_SUBFE, reg2, reg5, reg4); + emitpcode(PC_SUBFE, reg2, reg1, reg1); + emitpcode(PC_NEG, reg2, reg2); + if (write_to_gpr) { + output->optype = OpndType_GPR; + output->reg = reg2; + output->regHi = 0; + } else { + emitpcode(PC_CMPI, 0, reg2, 0); + output->optype = OpndType_CRField; + output->reg = 0; + output->regOffset = ENOTEQU; + } + break; + case ELESSEQU: + tmpop = opleft; + opleft = opright; + opright = tmpop; + case EGREATEREQU: + reg1 = ALLOC_GPR(); + reg2 = ALLOC_GPR(); + reg3 = ALLOC_GPR(); + if (left->rtype != TYPE(&stunsignedlonglong) && right->rtype != TYPE(&stunsignedlonglong)) { + emitpcode(PC_XORIS, reg1, opleft.regHi, 0x8000); + emitpcode(PC_XORIS, reg2, opright.regHi, 0x8000); + reg4 = reg1; + reg5 = reg2; + } else { + reg4 = opleft.regHi; + reg5 = opright.regHi; + } + emitpcode(PC_SUBFC, reg3, opright.reg, opleft.reg); + emitpcode(PC_SUBFE, reg2, reg5, reg4); + emitpcode(PC_SUBFE, reg2, reg1, reg1); + emitpcode(PC_NEG, reg2, reg2); + if (write_to_gpr) { + emitpcode(PC_SUBFIC, reg2, reg2, 1); + output->optype = OpndType_GPR; + output->reg = reg2; + output->regHi = 0; + } else { + emitpcode(PC_CMPI, 0, reg2, 0); + output->optype = OpndType_CRField; + output->reg = 0; + output->regOffset = EEQU; + } + break; + default: +#line 8814 + CError_FATAL(); + } +} + +void I8_gen_SHL_SHR(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + static UInt32 used_regs[RegClassMax] = {0, 0, 0, 0, (1 << 3) | (1 << 4) | (1 << 5)}; + + ENode *left; + ENode *right; + Operand opleft; + Operand opright; + int is_uns; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + + GEN_NODE(left, &opleft); + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + + output->optype = OpndType_GPRPair; + output->reg = ALLOC_GPR(); + output->regHi = ALLOC_GPR(); + + is_uns = is_unsigned(expr->rtype) != 0; + + if (ENODE_IS(right, EINTCONST)) { + if (ENODE_IS(expr, ESHL)) { + I8_ShiftLeftImmediate(opleft, right->data.intval.lo, is_uns, expr->rtype->size, output->reg, output->regHi); + } else { + I8_ShiftRightImmediate(opleft, right->data.intval.lo, is_uns, output->reg, output->regHi, 0); + } + return; + } + + GEN_NODE(right, &opright); + ENSURE_GPR(&opright, right->rtype, 0); + if (opright.optype == OpndType_GPRPair) { + opright.regHi = 0; + opright.optype = OpndType_GPR; + } + +#line 8890 + CError_ASSERT(opleft.optype == OpndType_GPRPair && opright.optype == OpndType_GPR); + + if (opleft.regHi != high_reg) + emitpcode(PC_MR, high_reg, opleft.regHi); + if (opleft.reg != low_reg) + emitpcode(PC_MR, low_reg, opleft.reg); + if (opright.reg != 5) + emitpcode(PC_MR, 5, opright.reg); + + if (ENODE_IS(expr, ESHR)) { + if (is_unsigned(left->rtype)) + branch_subroutine(rt_shr2u, 0, used_regs); + else + branch_subroutine(rt_shr2i, 0, used_regs); + } else if (ENODE_IS(expr, ESHL)) { + branch_subroutine(rt_shl2i, 0, used_regs); + } else { +#line 8909 + CError_FATAL(); + } + + emitpcode(PC_MR, output->reg, low_reg); + emitpcode(PC_MR, output->regHi, high_reg); +} + +void I8_gen_DIV_MOD(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + static UInt32 used_regs[RegClassMax] = {0, 0, 0, 0, (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6)}; + + int is_uns; + ENode *left; + ENode *right; + Operand opleft; + Operand opright; + SInt64 constval; + int shift; + + left = expr->data.diadic.left; + right = expr->data.diadic.right; + memclrw(&opleft, sizeof(Operand)); + memclrw(&opright, sizeof(Operand)); + + GEN_NODE(left, &opleft); + coerce_to_register_pair(&opleft, left->rtype, 0, 0); + + output->optype = OpndType_GPRPair; + output->reg = ALLOC_GPR(); + output->regHi = ALLOC_GPR(); + + is_uns = is_unsigned(expr->rtype) != 0; + + if (ENODE_IS(right, EINTCONST)) + constval = (((SInt64) right->data.intval.hi) << 32) + right->data.intval.lo; + if (ENODE_IS(right, EINTCONST) && ((shift = I8_log2n(constval)) > 0)) { +#line 8976 + CError_ASSERT(opleft.optype == OpndType_GPRPair); + if (ENODE_IS(expr, EDIV)) { + I8_ShiftRightImmediate(opleft, shift, is_uns, output->reg, output->regHi, 1); + if (!is_uns) { + emitpcode(PC_ADDZE, output->reg, output->reg); + emitpcode(PC_ADDZE, output->regHi, output->regHi); + } + } else { + if (is_uns) { + if (shift < 32) { + emitpcode(PC_LI, output->regHi, 0); + emitpcode(PC_RLWINM, output->reg, opleft.reg, 0, 32 - shift, 31); + } else if (shift == 32) { + emitpcode(PC_LI, output->regHi, 0); + emitpcode(PC_MR, output->reg, opleft.reg); + } else if (shift <= 63) { + emitpcode(PC_RLWINM, output->regHi, opleft.regHi, 0, 32 - (shift - 32), 31); + emitpcode(PC_MR, output->reg, opleft.reg); + } else { +#line 9018 + CError_FATAL(); + } + } else { + short tmpreg1 = ALLOC_GPR(); + short tmpreg2 = ALLOC_GPR(); + I8_ShiftRightImmediate(opleft, shift, is_uns, output->reg, output->regHi, 1); + emitpcode(PC_ADDZE, output->reg, output->reg); + emitpcode(PC_ADDZE, output->regHi, output->regHi); + I8_ShiftLeftImmediate(*output, shift, is_uns, expr->rtype->size, tmpreg1, tmpreg2); + emitpcode(PC_SUBFC, output->reg, tmpreg1, opleft.reg); + emitpcode(PC_SUBFE, output->regHi, tmpreg2, opleft.regHi); + } + } + return; + } + + GEN_NODE(right, &opright); + coerce_to_register_pair(&opright, right->rtype, 0, 0); + +#line 9048 + CError_ASSERT(opleft.optype == OpndType_GPRPair && opright.optype == OpndType_GPRPair); + + if (opleft.regHi != high_reg) + emitpcode(PC_MR, high_reg, opleft.regHi); + if (opleft.reg != low_reg) + emitpcode(PC_MR, low_reg, opleft.reg); + if (opright.regHi != high_reg2) + emitpcode(PC_MR, high_reg2, opright.regHi); + if (opright.reg != low_reg2) + emitpcode(PC_MR, low_reg2, opright.reg); + + if (ENODE_IS(expr, EDIV)) { + if (is_unsigned(left->rtype) || is_unsigned(right->rtype)) + branch_subroutine(rt_div2u, 0, used_regs); + else + branch_subroutine(rt_div2i, 0, used_regs); + } else if (ENODE_IS(expr, EMODULO)) { + if (is_unsigned(left->rtype) || is_unsigned(right->rtype)) + branch_subroutine(rt_mod2u, 0, used_regs); + else + branch_subroutine(rt_mod2i, 0, used_regs); + } else { +#line 9074 + CError_FATAL(); + } + + emitpcode(PC_MR, output->reg, low_reg); + emitpcode(PC_MR, output->regHi, high_reg); +} + +void I8_gen_TYPCON(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + Type *dsttype; + ENode *inner; + Type *srctype; + short regHi; + short reg; + + static UInt32 used_regs[RegClassMax] = {0, 0, 0, 0, (1 << 3) | (1 << 4)}; + static UInt32 used_regs_f1[RegClassMax] = {0, 0, 0, (1 << 1), 0}; + + inner = expr->data.monadic; + srctype = inner->rtype; + dsttype = expr->rtype; + + if (IS_TYPE_VOID(dsttype)) { + GEN_NODE(inner, output); + if (ENODE_IS(inner, EINDIRECT) && (output->flags & OpndFlags_Volatile)) + coerce_to_register_pair(output, inner->rtype, 0, 0); + output->optype = OpndType_Absolute; + output->immediate = 0; + return; + } + + if (IS_TYPE_INT_OR_ENUM(srctype)) { + if (IS_TYPE_FLOAT(dsttype)) { + GEN_NODE(inner, output); + coerce_to_register_pair(output, srctype, 0, 0); + if (output->regHi != high_reg) + emitpcode(PC_MR, high_reg, output->regHi); + if (output->reg != low_reg) + emitpcode(PC_MR, low_reg, output->reg); + + if (is_unsigned(srctype)) { + branch_subroutine( + (dsttype->size == 4) ? rt_cvt_ull_flt : rt_cvt_ull_dbl, + 0, + used_regs); + } else { + branch_subroutine( + (dsttype->size == 4) ? rt_cvt_sll_flt : rt_cvt_sll_dbl, + 0, + used_regs); + } + + output->optype = OpndType_FPR; + output->reg = ALLOC_FPR(); + emitpcode(PC_FMR, output->reg, 1); + return; + } + + if (srctype->size < dsttype->size) { +#line 9171 + CError_ASSERT(TYPE_IS_8BYTES(dsttype)); + + GEN_NODE(inner, output); + if (srctype->size < 4 && + !ENODE_IS_INDIRECT_TO(inner, EBITFIELD) && + !((ENODE_IS_ASSIGN(inner) || ENODE_IS_RANGE(inner, EPOSTINC, EPREDEC)) && ENODE_IS(inner->data.monadic->data.monadic, EBITFIELD)) + ) { + extend32(output, srctype, outputReg); + } + extend64(output, srctype, outputReg, outputRegHi); + } else { + GEN_NODE_TO_REG(inner, outputReg, 0, output); + if (dsttype->size < srctype->size) { + coerce_to_register_pair(output, srctype, outputReg, outputRegHi); + output->optype = OpndType_GPR; + output->regHi = 0; + } + } + return; + } + + if (IS_TYPE_POINTER(srctype)) { + GEN_NODE_TO_REG(inner, outputReg, 0, output); +#line 9200 + CError_ASSERT(TYPE_IS_8BYTES(expr->rtype)); + GEN_NODE_TO_REG(inner, outputReg, 0, output); + + regHi = outputRegHi ? outputRegHi : ALLOC_GPR(); + if (regHi == output->reg) { + reg = outputReg ? outputReg : ALLOC_GPR(); + emitpcode(PC_MR, reg, output->reg); + output->reg = reg; + } + if (is_unsigned(inner->rtype)) + load_immediate(regHi, 0); + else + emitpcode(PC_SRAWI, regHi, output->reg, 31); + output->optype = OpndType_GPRPair; + output->regHi = regHi; + return; + } + + if (IS_TYPE_FLOAT(srctype)) { + if (IS_TYPE_FLOAT(dsttype)) { +#line 9222 + CError_FATAL(); + return; + } + + GEN_NODE(inner, output); + ENSURE_FPR(output, srctype, 0); + if (output->reg != 1) + emitpcode(PC_FMR, 1, output->reg); + + branch_subroutine(rt_cvt_dbl_usll, 0, used_regs_f1); + + output->optype = OpndType_GPRPair; + output->reg = ALLOC_GPR(); + output->regHi = ALLOC_GPR(); + emitpcode(PC_MR, output->reg, low_reg); + emitpcode(PC_MR, output->regHi, high_reg); + return; + } + + if (IS_TYPE_STRUCT(srctype)) { + GEN_NODE_TO_REG(inner, outputReg, 0, output); + + if (TYPE_IS_8BYTES(expr->rtype) && dsttype->size == srctype->size) { + coerce_to_register_pair(output, srctype, outputReg, outputRegHi); + } else { +#line 9256 + CError_FATAL(); + } + return; + } + +#line 9261 + CError_FATAL(); +} + +void gen_VECTOR128CONST(ENode *expr, short outputReg, short outputRegHi, Operand *output) { + int gpr; + int vr; + COVCResult result; + + vr = outputReg ? outputReg : ALLOC_VR(); + if (!canoptimizevectorconst(&expr->data.vector128val, expr->rtype, &result)) { +#line 9282 + CError_FATAL(); + } + + if (result.op1 != -1) { + emitpcode(result.op1, vr, result.arg); + output->optype = OpndType_VR; + output->reg = vr; + return; + } + + if (result.op2 != -1) { + gpr = ALLOC_GPR(); + emitpcode(PC_LI, gpr, result.arg); + emitpcode(result.op2, vr, 0, gpr); + output->optype = OpndType_VR; + output->reg = vr; + return; + } + +#line 9298 + CError_FATAL(); +} diff --git a/compiler_and_linker/unsorted/InterferenceGraph.c b/compiler_and_linker/unsorted/InterferenceGraph.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/InterferenceGraph.c diff --git a/compiler_and_linker/unsorted/Intrinsics.c b/compiler_and_linker/unsorted/Intrinsics.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/Intrinsics.c diff --git a/compiler_and_linker/unsorted/IrOptimizer.c b/compiler_and_linker/unsorted/IrOptimizer.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IrOptimizer.c diff --git a/compiler_and_linker/unsorted/IroBitVect.c b/compiler_and_linker/unsorted/IroBitVect.c new file mode 100644 index 0000000..ecaea04 --- /dev/null +++ b/compiler_and_linker/unsorted/IroBitVect.c @@ -0,0 +1,114 @@ +#include "compiler/IroBitVect.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 { +#line 73 + CError_FATAL(); + } +} + +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/unsorted/IroCSE.c b/compiler_and_linker/unsorted/IroCSE.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroCSE.c diff --git a/compiler_and_linker/unsorted/IroDump.c b/compiler_and_linker/unsorted/IroDump.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroDump.c diff --git a/compiler_and_linker/unsorted/IroEmptyLoop.c b/compiler_and_linker/unsorted/IroEmptyLoop.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroEmptyLoop.c diff --git a/compiler_and_linker/unsorted/IroEval.c b/compiler_and_linker/unsorted/IroEval.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroEval.c diff --git a/compiler_and_linker/unsorted/IroExprRegeneration.c b/compiler_and_linker/unsorted/IroExprRegeneration.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroExprRegeneration.c diff --git a/compiler_and_linker/unsorted/IroFlowgraph.c b/compiler_and_linker/unsorted/IroFlowgraph.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroFlowgraph.c diff --git a/compiler_and_linker/unsorted/IroJump.c b/compiler_and_linker/unsorted/IroJump.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroJump.c diff --git a/compiler_and_linker/unsorted/IroLinearForm.c b/compiler_and_linker/unsorted/IroLinearForm.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroLinearForm.c diff --git a/compiler_and_linker/unsorted/IroLoop.c b/compiler_and_linker/unsorted/IroLoop.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroLoop.c diff --git a/compiler_and_linker/unsorted/IroMalloc.c b/compiler_and_linker/unsorted/IroMalloc.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroMalloc.c diff --git a/compiler_and_linker/unsorted/IroPointerAnalysis.c b/compiler_and_linker/unsorted/IroPointerAnalysis.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroPointerAnalysis.c diff --git a/compiler_and_linker/unsorted/IroPropagate.c b/compiler_and_linker/unsorted/IroPropagate.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroPropagate.c diff --git a/compiler_and_linker/unsorted/IroRangePropagation.c b/compiler_and_linker/unsorted/IroRangePropagation.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroRangePropagation.c diff --git a/compiler_and_linker/unsorted/IroSubable.c b/compiler_and_linker/unsorted/IroSubable.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroSubable.c diff --git a/compiler_and_linker/unsorted/IroTransform.c b/compiler_and_linker/unsorted/IroTransform.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroTransform.c diff --git a/compiler_and_linker/unsorted/IroUnrollLoop.c b/compiler_and_linker/unsorted/IroUnrollLoop.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroUnrollLoop.c diff --git a/compiler_and_linker/unsorted/IroUtil.c b/compiler_and_linker/unsorted/IroUtil.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroUtil.c diff --git a/compiler_and_linker/unsorted/IroVars.c b/compiler_and_linker/unsorted/IroVars.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/IroVars.c diff --git a/compiler_and_linker/unsorted/LoadDeletion.c b/compiler_and_linker/unsorted/LoadDeletion.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/LoadDeletion.c diff --git a/compiler_and_linker/unsorted/LoopDetection.c b/compiler_and_linker/unsorted/LoopDetection.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/LoopDetection.c diff --git a/compiler_and_linker/unsorted/LoopOptimization.c b/compiler_and_linker/unsorted/LoopOptimization.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/LoopOptimization.c diff --git a/compiler_and_linker/unsorted/MachO.c b/compiler_and_linker/unsorted/MachO.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/MachO.c diff --git a/compiler_and_linker/unsorted/ObjGenMachO.c b/compiler_and_linker/unsorted/ObjGenMachO.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/ObjGenMachO.c diff --git a/compiler_and_linker/unsorted/Operands.c b/compiler_and_linker/unsorted/Operands.c index c0fee65..68883e0 100644 --- a/compiler_and_linker/unsorted/Operands.c +++ b/compiler_and_linker/unsorted/Operands.c @@ -75,12 +75,12 @@ void indirect(Operand *op, ENode *expr) { set_op_flags(op, expr); break; case OpndType_Absolute: - if (FITS_IN_SHORT(op->abs_address)) { + if (FITS_IN_SHORT(op->immediate)) { op->reg = 0; - op->immOffset = op->abs_address; + op->immOffset = op->immediate; } else { - emitpcode(PC_LIS, op->reg = used_virtual_registers[RegClass_GPR]++, 0, (short) HIGH_PART(op->abs_address)); - op->immOffset = LOW_PART(op->abs_address); + emitpcode(PC_LIS, op->reg = used_virtual_registers[RegClass_GPR]++, 0, (short) HIGH_PART(op->immediate)); + op->immOffset = LOW_PART(op->immediate); } op->object = NULL; op->optype = OpndType_IndirectGPR_ImmOffset; @@ -201,27 +201,27 @@ void combine(Operand *opA, Operand *opB, short output_reg, Operand *opOut) { opOut->reg = opB->reg; opOut->immOffset = opB->immOffset; opOut->object = opB->object; - if (FITS_IN_SHORT(opOut->immOffset + opA->abs_address)) { - opOut->immOffset += opA->abs_address; + if (FITS_IN_SHORT(opOut->immOffset + opA->immediate)) { + opOut->immOffset += opA->immediate; } else { opOut->reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; - if (!HIGH_PART(opA->abs_address)) { - emitpcode(PC_ADDI, opOut->reg, opB->reg, 0, LOW_PART(opA->abs_address)); + if (!HIGH_PART(opA->immediate)) { + emitpcode(PC_ADDI, opOut->reg, opB->reg, 0, LOW_PART(opA->immediate)); } else { - emitpcode(PC_ADDIS, opOut->reg, opB->reg, 0, (short) HIGH_PART(opA->abs_address)); - if (FITS_IN_SHORT(opOut->immOffset + LOW_PART(opA->abs_address))) { - opOut->immOffset += LOW_PART(opA->abs_address); + emitpcode(PC_ADDIS, opOut->reg, opB->reg, 0, (short) HIGH_PART(opA->immediate)); + if (FITS_IN_SHORT(opOut->immOffset + LOW_PART(opA->immediate))) { + opOut->immOffset += LOW_PART(opA->immediate); } else { - emitpcode(PC_ADDI, opOut->reg, opOut->reg, 0, LOW_PART(opA->abs_address)); + emitpcode(PC_ADDI, opOut->reg, opOut->reg, 0, LOW_PART(opA->immediate)); } } } break; - } else if (opB->object->datatype == DLOCAL && can_add_displ_to_local(opB->object, opB->immOffset + opA->abs_address)) { + } else if (opB->object->datatype == DLOCAL && can_add_displ_to_local(opB->object, opB->immOffset + opA->immediate)) { opOut->optype = OpndType_GPR_ImmOffset; opOut->object = opB->object; opOut->reg = opB->reg; - opOut->immOffset = LOW_PART(opB->immOffset + opA->abs_address); + opOut->immOffset = LOW_PART(opB->immOffset + opA->immediate); break; } else { opOut->reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; @@ -237,14 +237,14 @@ void combine(Operand *opA, Operand *opB, short output_reg, Operand *opOut) { opA = opB; opB = tmp_op; case COMBO_OP(OpndType_Absolute, OpndType_GPR): - opOut->optype = (opA->abs_address != 0) ? OpndType_GPR_ImmOffset : OpndType_GPR; - opOut->immOffset = LOW_PART(opA->abs_address); + opOut->optype = (opA->immediate != 0) ? OpndType_GPR_ImmOffset : OpndType_GPR; + opOut->immOffset = LOW_PART(opA->immediate); opOut->object = NULL; - if (FITS_IN_SHORT(opA->abs_address)) { + if (FITS_IN_SHORT(opA->immediate)) { opOut->reg = opB->reg; } else { opOut->reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; - emitpcode(PC_ADDIS, opOut->reg, opB->reg, 0, (short) HIGH_PART(opA->abs_address)); + emitpcode(PC_ADDIS, opOut->reg, opB->reg, 0, (short) HIGH_PART(opA->immediate)); } break; case COMBO_OP(OpndType_GPR_Indexed, OpndType_Absolute): @@ -255,17 +255,17 @@ void combine(Operand *opA, Operand *opB, short output_reg, Operand *opOut) { opOut->optype = OpndType_GPR_Indexed; opOut->reg = opB->reg; opOut->regOffset = (output_reg && (output_reg != opB->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++; - if (!HIGH_PART(opA->abs_address)) { - emitpcode(PC_ADDI, opOut->regOffset, opB->regOffset, 0, LOW_PART(opA->abs_address)); + if (!HIGH_PART(opA->immediate)) { + emitpcode(PC_ADDI, opOut->regOffset, opB->regOffset, 0, LOW_PART(opA->immediate)); } else { - emitpcode(PC_ADDIS, opOut->regOffset, opB->regOffset, 0, (short) HIGH_PART(opA->abs_address)); - if (opA->abs_address != 0) - emitpcode(PC_ADDI, opOut->regOffset, opOut->regOffset, 0, LOW_PART(opA->abs_address)); + emitpcode(PC_ADDIS, opOut->regOffset, opB->regOffset, 0, (short) HIGH_PART(opA->immediate)); + if (opA->immediate != 0) + emitpcode(PC_ADDI, opOut->regOffset, opOut->regOffset, 0, LOW_PART(opA->immediate)); } break; case COMBO_OP(OpndType_Absolute, OpndType_Absolute): opOut->optype = OpndType_Absolute; - opOut->abs_address = opA->abs_address + opB->abs_address; + opOut->immediate = opA->immediate + opB->immediate; break; default: #line 415 @@ -344,7 +344,6 @@ void coerce_to_addressable(Operand *op) { } } -void Coerce_to_register(Operand *op, Type *type, short output_reg) { SInt32 offset; short opcode; short reg; @@ -375,7 +374,7 @@ void Coerce_to_register(Operand *op, Type *type, short output_reg) { break; case OpndType_Absolute: reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; - offset = op->abs_address; + offset = op->immediate; if (FITS_IN_SHORT(offset)) { emitpcode(PC_LI, reg, offset); } else { @@ -534,7 +533,7 @@ void coerce_to_register_pair(Operand *op, Type *type, short output_reg, short ou break; case OpndType_Absolute: reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++; - offset = op->abs_address; + offset = op->immediate; if (FITS_IN_SHORT(offset)) { emitpcode(PC_LI, reg, offset); } else { @@ -648,19 +647,19 @@ void Coerce_to_v_register(Operand *op, TypeStruct *tstruct, short output_reg) { case STRUCT_TYPE_4: case STRUCT_TYPE_5: case STRUCT_TYPE_6: - emitpcode(PC_VSPLTISB, reg, op->abs_address); + emitpcode(PC_VSPLTISB, reg, op->immediate); break; case STRUCT_TYPE_7: case STRUCT_TYPE_8: case STRUCT_TYPE_9: case STRUCT_TYPE_E: - emitpcode(PC_VSPLTISH, reg, op->abs_address); + emitpcode(PC_VSPLTISH, reg, op->immediate); break; case STRUCT_TYPE_A: case STRUCT_TYPE_B: case STRUCT_TYPE_C: case STRUCT_TYPE_D: - emitpcode(PC_VSPLTISW, reg, op->abs_address); + emitpcode(PC_VSPLTISW, reg, op->immediate); break; default: #line 1049 @@ -754,7 +753,7 @@ void store_pair(short reg, short regHi, Operand *op, Type *type) { } } -void store_fp(short reg, Operand *op, TypeIntegral *tint) { +void store_fp(short reg, Operand *op, Type *tint) { coerce_to_addressable(op); switch (op->optype) { case OpndType_IndirectGPR_ImmOffset: @@ -771,7 +770,7 @@ void store_fp(short reg, Operand *op, TypeIntegral *tint) { } } -void store_v(short reg, Operand *op, TypeStruct *tstruct) { +void store_v(short reg, Operand *op, Type *tstruct) { coerce_to_addressable(op); switch (op->optype) { case OpndType_IndirectGPR_ImmOffset: @@ -880,7 +879,7 @@ void extend64(Operand *op, Type *type, short output_reg, short output_regHi) { op->regHi = regHi; } -void load_floating_constant(short reg, TypeIntegral *type, double *data) { +void load_floating_constant(short reg, Type *type, double *data) { // do me AFTER } diff --git a/compiler_and_linker/unsorted/PCode.c b/compiler_and_linker/unsorted/PCode.c index 0fde159..f53030b 100644 --- a/compiler_and_linker/unsorted/PCode.c +++ b/compiler_and_linker/unsorted/PCode.c @@ -1,18 +1,22 @@ -#include "compiler.h" #include "compiler/CompilerTools.h" +#include "compiler/CFunc.h" +#include "compiler/CodeGen.h" #include "compiler/PCode.h" #include "compiler/PCodeInfo.h" +// TODO: move me +extern void initialize_aliases(); + PCodeBlock *pcbasicblocks; PCodeBlock *pclastblock; -void *prologue; -void *epilogue; +PCodeBlock *prologue; +PCodeBlock *epilogue; PCodeBlock **depthfirstordering; int pcblockcount; int pcloopweight; static unsigned short pclabelcount; -void initpcode() { +void initpcode(void) { pclastblock = 0; pcbasicblocks = 0; pcblockcount = 0; @@ -21,7 +25,7 @@ void initpcode() { initialize_aliases(); } -PCode *makepcode(short op, ...) { +PCode *makepcode(Opcode op, ...) { PCode *pcode; va_list list; @@ -31,7 +35,7 @@ PCode *makepcode(short op, ...) { return pcode; } -void emitpcode(short op, ...) { +void emitpcode(Opcode op, ...) { PCode *pcode; va_list list; @@ -67,7 +71,7 @@ PCode *copypcode(PCode *pcode) { return newpc; } -PCodeLabel *makepclabel() { +PCodeLabel *makepclabel(void) { PCodeLabel *label; label = (PCodeLabel *) lalloc(sizeof(PCodeLabel)); @@ -76,7 +80,7 @@ PCodeLabel *makepclabel() { return label; } -PCodeBlock *makepcblock() { +PCodeBlock *makepcblock(void) { PCodeBlock *block; block = (PCodeBlock *) lalloc(sizeof(PCodeBlock)); @@ -123,7 +127,7 @@ void pcbranch(PCodeBlock *block, PCodeLabel *label) { block->successors = link; } -void pccomputepredecessors() { +void pccomputepredecessors(void) { PCodeBlock *block; PCLink *succ; PCLink *pred; @@ -147,7 +151,7 @@ void deleteblock(PCodeBlock *block) { block->flags |= fPCBlockFlag20; } -void deleteunreachableblocks() { +void deleteunreachableblocks(void) { PCodeBlock *block; computedepthfirstordering(); @@ -238,7 +242,7 @@ void clearpcodeflags(int flags) { pclastblock->lastPCode->flags &= ~flags; } -int pccomputeoffsets() { +int pccomputeoffsets(void) { int offset; PCodeBlock *block; @@ -258,7 +262,7 @@ typedef struct _DFO { static int depthfirstorder; -void computedepthfirstordering() { +void computedepthfirstordering(void) { PCodeBlock *block; PCLink *link; DFO *dfo; diff --git a/compiler_and_linker/unsorted/PCodeAssembly.c b/compiler_and_linker/unsorted/PCodeAssembly.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/PCodeAssembly.c diff --git a/compiler_and_linker/unsorted/PCodeInfo.c b/compiler_and_linker/unsorted/PCodeInfo.c index e48dac0..3646930 100644 --- a/compiler_and_linker/unsorted/PCodeInfo.c +++ b/compiler_and_linker/unsorted/PCodeInfo.c @@ -90,7 +90,7 @@ int pcode_check_imm_bits(SInt32 value, int bits, char typechar) { return 0; } -int pcode_const_from_format(const char *format, int *pResult) { +int pcode_const_from_format(const char *format, SInt32 *pResult) { char buf[32]; int len = 0; diff --git a/compiler_and_linker/unsorted/PCodeListing.c b/compiler_and_linker/unsorted/PCodeListing.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/PCodeListing.c diff --git a/compiler_and_linker/unsorted/PPCError.c b/compiler_and_linker/unsorted/PPCError.c new file mode 100644 index 0000000..2ba28bd --- /dev/null +++ b/compiler_and_linker/unsorted/PPCError.c @@ -0,0 +1,71 @@ +#include "compiler/PPCError.h" +#include "compiler/CError.h" +#include "compiler/CParser.h" +#include "compiler/InlineAsm.h" +#include "cos.h" + +static void PPCError_GetErrorString(char *str, short code) { + short scode; + + scode = (short) code; +#line 40 + CError_ASSERT(scode >= 100 && scode < 212); + + COS_GetString(str, 10001, scode - 99); +} + +static void PPCError_VAErrorMessage(int code, va_list list, Boolean flag1, Boolean flag2) { + char format[256]; + PPCError_GetErrorString(format, code); + CError_ErrorMessageVA(code + 10001, format, list, flag1, flag2); +} + +void PPCError_Error(int code, ...) { + va_list list; + + if (trychain) + longjmp(trychain->jmpbuf, 1); + + va_start(list, code); + PPCError_VAErrorMessage(code, list, 0, 0); + va_end(list); + + if (in_assembler) + AssemblerError(); +} + +void PPCError_Warning(int code, ...) { + va_list list; + + if (!trychain) { + va_start(list, code); + PPCError_VAErrorMessage(code, list, 0, 1); + va_end(list); + } +} + +void PPCError_Message(char *format, ...) { + va_list list; + + if (!trychain) { + va_start(list, format); + CError_ErrorMessageVA(10213, format, list, 0, 1); + va_end(list); + } +} + +void PPCError_ErrorTerm(short code, ...) { + va_list list; + + if (trychain) + longjmp(trychain->jmpbuf, 1); + + va_start(list, code); + PPCError_VAErrorMessage(code, list, 1, 0); + va_end(list); + + if (in_assembler) + AssemblerError(); + + longjmp(errorreturn, 1); +} diff --git a/compiler_and_linker/unsorted/Peephole.c b/compiler_and_linker/unsorted/Peephole.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/Peephole.c diff --git a/compiler_and_linker/unsorted/RegisterInfo.c b/compiler_and_linker/unsorted/RegisterInfo.c index c1e67d8..80e348d 100644 --- a/compiler_and_linker/unsorted/RegisterInfo.c +++ b/compiler_and_linker/unsorted/RegisterInfo.c @@ -1,7 +1,11 @@ -#include "compiler.h" +#include "compiler/RegisterInfo.h" +#include "compiler/CodeGen.h" #include "compiler/CError.h" -#include "compiler/objects.h" +#include "compiler/CParser.h" #include "compiler/PCode.h" +#include "compiler/CompilerTools.h" +#include "compiler/objects.h" +#include "compiler/types.h" short last_exception_register[RegClassMax]; short first_fe_temporary_register[RegClassMax]; @@ -12,8 +16,6 @@ char *special_register_names[RegClassMax][RegisterMax]; static short used_regs_before_coloring; static UInt8 save_state[RegisterMax]; -char *XXspecial_register_names[RegClassMax * RegisterMax]; - short spr_to_sysreg[4] = {1, 8, 9, 0x100}; void asm_used_register(char rclass, short reg) { @@ -104,7 +106,7 @@ static int first_nonvolatile_reg(char rclass) { return GetABIFirstNonVolatile(rclass); } -void setup_diagnostic_reg_strings() { +void setup_diagnostic_reg_strings(void) { register_class_name[RegClass_SPR] = "SPR"; register_class_format[RegClass_SPR] = "spr%ld"; register_class_name[RegClass_CRFIELD] = "CRFIELD"; @@ -117,7 +119,7 @@ void setup_diagnostic_reg_strings() { register_class_format[RegClass_GPR] = "r%ld"; } -void init_target_registers() { +void init_target_registers(void) { char rclass; int reg; int end; @@ -244,7 +246,7 @@ void assign_GPR_pair(Object *obj) { } } -void open_fe_temp_registers() { +void open_fe_temp_registers(void) { int r; r = used_virtual_registers[RegClass_GPR]; @@ -258,13 +260,13 @@ void open_fe_temp_registers() { //first_fe_temporary_register[RegClass_VR] = last_temporary_register[RegClass_VR] = used_virtual_registers[RegClass_VR]; } -void set_last_exception_registers() { +void set_last_exception_registers(void) { last_exception_register[RegClass_GPR] = used_virtual_registers[RegClass_GPR] - 1; last_exception_register[RegClass_FPR] = used_virtual_registers[RegClass_FPR] - 1; last_exception_register[RegClass_VR] = used_virtual_registers[RegClass_VR] - 1; } -static VarInfo *Registers_GetNewVarInfo() { +static VarInfo *Registers_GetNewVarInfo(void) { VarInfo *vi = galloc(sizeof(VarInfo)); memclrw(vi, sizeof(VarInfo)); return vi; @@ -302,7 +304,7 @@ VarInfo *Registers_GetVarInfo(Object *obj) { } } -int used_vrstate_VRs() { +int used_vrstate_VRs(void) { int count = 0; int i; for (i = 0; i < RegisterMax; i++) { @@ -318,9 +320,9 @@ UInt32 colored_vrs_as_vrsave(PCodeBlock *block) { int i; mask = 0; - if (copts.x1B == 2) + if (copts.altivec_vrsave == 2) return 0xFFFFFFFF; - if (copts.x1B == 0) + if (copts.altivec_vrsave == 0) return 0; while (block) { @@ -359,7 +361,7 @@ int is_nonvolatile_register(char rclass, int reg) { return 0; } -void init_endian() { +void init_endian(void) { if (copts.little_endian) { high_offset = 4; low_offset = 0; @@ -377,7 +379,7 @@ void init_endian() { } } -void update_asm_nonvolatile_registers() { +void update_asm_nonvolatile_registers(void) { char rclass; int r31; diff --git a/compiler_and_linker/unsorted/Registers.c b/compiler_and_linker/unsorted/Registers.c index 9bcbf05..b8951b7 100644 --- a/compiler_and_linker/unsorted/Registers.c +++ b/compiler_and_linker/unsorted/Registers.c @@ -1,6 +1,9 @@ -#include "compiler.h" -#include "compiler/objects.h" +#include "compiler/Registers.h" +#include "compiler/RegisterInfo.h" +#include "compiler/CParser.h" #include "compiler/PCode.h" +#include "compiler/CompilerTools.h" +#include "compiler/objects.h" // haven't checked this object file for .data stuff yet @@ -30,7 +33,7 @@ typedef struct ModifiedRegisters { } ModifiedRegisters; static ModifiedRegisters *mod_regs_table[128]; -void init_registers() { +void init_registers(void) { char rclass; int j; @@ -117,7 +120,7 @@ short obtain_nonvolatile_register(char rclass) { return best; } -void open_temp_registers() { +void open_temp_registers(void) { int rclass; for (rclass = 0; (char)rclass < RegClassMax; rclass++) { @@ -135,7 +138,7 @@ void open_temp_registers() { }*/ } -void check_temp_registers() { +void check_temp_registers(void) { char rclass; if (!optimizing) { @@ -148,7 +151,7 @@ void check_temp_registers() { } } -void close_temp_registers() { +void close_temp_registers(void) { char rclass; for (rclass = 0; rclass < RegClassMax; rclass++) { @@ -159,7 +162,7 @@ void close_temp_registers() { } } -int count_scratch_registers() { +int count_scratch_registers(void) { int rclass; int count; @@ -169,7 +172,7 @@ int count_scratch_registers() { return count; } -void init_modified_registers() { +void init_modified_registers(void) { int i = 0; for (i = 0; i < 128; i++) diff --git a/compiler_and_linker/unsorted/Scheduler.c b/compiler_and_linker/unsorted/Scheduler.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/Scheduler.c diff --git a/compiler_and_linker/unsorted/SpillCode.c b/compiler_and_linker/unsorted/SpillCode.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/SpillCode.c diff --git a/compiler_and_linker/unsorted/StackFrame.c b/compiler_and_linker/unsorted/StackFrame.c index 5789cb5..18cb6fd 100644 --- a/compiler_and_linker/unsorted/StackFrame.c +++ b/compiler_and_linker/unsorted/StackFrame.c @@ -64,7 +64,7 @@ static void save_nonvolatile_GPRs(int reg, SInt32 offset); static void restore_nonvolatile_GPRs(int reg, SInt32 offset); static void do_allocate_dynamic_stack_space(Boolean flag1, int reg1, int reg2, SInt32 size); -void init_stack_globals(void) { +void init_stack_globals(Object *funcobj) { char rclass; UInt8 oclass; @@ -115,7 +115,7 @@ void init_stack_globals(void) { } } -void init_frame_sizes(void) { +void init_frame_sizes(Boolean has_varargs) { ObjectList *scan; Object *obj; SInt32 r30; @@ -326,7 +326,7 @@ static void allocate_new_frame(int reg1, int reg2) { } } -void generate_prologue(PCodeBlock *block) { +void generate_prologue(PCodeBlock *block, Boolean has_varargs) { PCodeBlock *save_block; Boolean needs_lr; Statement *save_statement; diff --git a/compiler_and_linker/unsorted/StrengthReduction.c b/compiler_and_linker/unsorted/StrengthReduction.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/StrengthReduction.c diff --git a/compiler_and_linker/unsorted/StructMoves.c b/compiler_and_linker/unsorted/StructMoves.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/StructMoves.c diff --git a/compiler_and_linker/unsorted/Switch.c b/compiler_and_linker/unsorted/Switch.c new file mode 100644 index 0000000..af62eb3 --- /dev/null +++ b/compiler_and_linker/unsorted/Switch.c @@ -0,0 +1,78 @@ +#include "compiler/Switch.h" +#include "compiler/CError.h" +#include "compiler/CFunc.h" +#include "compiler/CInt64.h" +#include "compiler/objects.h" +#include "compiler/CParser.h" +#include "compiler/PCode.h" + +ObjectList *switchtables; +static void *caselabels; +static void *caseranges; +static SInt32 ncases; +static SInt32 nranges_minus1; +static CInt64 min; +static CInt64 max; +static CInt64 first; +static short selector_gpr; +static short selector_gprHi; +static Type *selector_type; +static PCodeLabel *defaultlabel; +static CInt64 range; + +static void compare_cases() { +} + +static void build_case_ranges(Type *type, SwitchCase *cases, CLabel *label) { +} + +static void treecompare() { +} + +static void I8_treecompare() { +} + +static void generate_tree(ENode *expr) { +} + +static void create_switch_table() { +} + +static void generate_table(ENode *expr, SwitchInfo *info) { +} + +void switchstatement(ENode *expr, SwitchInfo *info) { + Boolean use_table; + SwitchCase *swcase; + + use_table = copts.switch_tables; + + ncases = 0; + for (swcase = info->cases; swcase; swcase = swcase->next) { + if (!swcase->label->pclabel) + swcase->label->pclabel = makepclabel(); + ncases++; + } + +#line 656 + CError_ASSERT(ncases >= 0 && ncases <= 0x3333332); + + if (!info->defaultlabel->pclabel) + info->defaultlabel->pclabel = makepclabel(); + defaultlabel = info->defaultlabel->pclabel; + + build_case_ranges(expr->rtype, info->cases, info->defaultlabel); + + if (TYPE_IS_8BYTES(expr->rtype)) { + generate_tree(expr); + return; + } + + if (!use_table || nranges_minus1 < 8 || (nranges_minus1 * 2) < ((range.lo / 1) + 4)) + generate_tree(expr); + else + generate_table(expr, info); +} + +void dumpswitchtables(Object *funcobj) { +} diff --git a/compiler_and_linker/unsorted/TOC.c b/compiler_and_linker/unsorted/TOC.c index 65dc39b..0f3024f 100644 --- a/compiler_and_linker/unsorted/TOC.c +++ b/compiler_and_linker/unsorted/TOC.c @@ -1,15 +1,21 @@ #include "cos.h" #include "compiler/TOC.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/CParser.h" +#include "compiler/CodeGen.h" #include "compiler/Operands.h" #include "compiler/PCode.h" #include "compiler/PCodeInfo.h" #include "compiler/StackFrame.h" +#include "compiler/CompilerTools.h" #include "compiler/enode.h" #include "compiler/objects.h" #include "compiler/types.h" -#include "compiler.h" ObjectList *toclist; ObjectList *exceptionlist; diff --git a/compiler_and_linker/unsorted/Unmangle.c b/compiler_and_linker/unsorted/Unmangle.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/Unmangle.c diff --git a/compiler_and_linker/unsorted/UseDefChains.c b/compiler_and_linker/unsorted/UseDefChains.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/UseDefChains.c diff --git a/compiler_and_linker/unsorted/ValueNumbering.c b/compiler_and_linker/unsorted/ValueNumbering.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/ValueNumbering.c diff --git a/compiler_and_linker/unsorted/VectorArraysToRegs.c b/compiler_and_linker/unsorted/VectorArraysToRegs.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/compiler_and_linker/unsorted/VectorArraysToRegs.c |