summaryrefslogtreecommitdiff
path: root/compiler_and_linker/BackEnd
diff options
context:
space:
mode:
authorAsh Wolf <ninji@wuffs.org>2023-01-26 11:30:47 +0000
committerAsh Wolf <ninji@wuffs.org>2023-01-26 11:30:47 +0000
commit094b96ca1df4a035b5f93c351f773306c0241f3f (patch)
tree95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/BackEnd
parentfc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff)
downloadMWCC-main.tar.gz
MWCC-main.zip
move lots of source files around to match their actual placement in the original treemain
Diffstat (limited to 'compiler_and_linker/BackEnd')
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CMachine.c1488
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/CodeGen.c2437
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Exceptions.c857
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/FunctionCalls.c642
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/InstrSelection.c5348
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Intrinsics.c4894
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Operands.c1040
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeAssembly.c1613
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeListing.c536
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeUtilities.c345
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Peephole.c2753
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c1252
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c792
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Switch.c518
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/TOC.c2272
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/Alias.c747
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/CodeMotion.c906
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/ConstantPropagation.c643
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/LoopDetection.c885
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/LoopOptimization.c1553
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/StrengthReduction.c751
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/ValueNumbering.c661
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/VectorArraysToRegs.c548
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/InlineAssembler/FuncLevelAsmPPC.c393
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c230
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c680
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsmPPC.c2586
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/PCode/PCodeInfo.c1354
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/PPCError.c70
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/Coloring.c268
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/InterferenceGraph.c364
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/RegisterInfo.c381
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/SpillCode.c452
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation601.c552
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation603.c626
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation603e.c650
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation604.c670
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation7400.c744
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation750.c678
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation821.c615
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulationAltiVec.c752
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/Scheduler/Scheduler.c547
42 files changed, 46093 insertions, 0 deletions
diff --git a/compiler_and_linker/BackEnd/PowerPC/CMachine.c b/compiler_and_linker/BackEnd/PowerPC/CMachine.c
new file mode 100644
index 0000000..bfa7023
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CMachine.c
@@ -0,0 +1,1488 @@
+#include "compiler/CMachine.h"
+#include "compiler/CClass.h"
+#include "compiler/CError.h"
+#include "compiler/CInt64.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/ScanFloat.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+TypeIntegral stbool = {TYPEINT, 1, IT_BOOL};
+TypeIntegral stchar = {TYPEINT, 1, IT_CHAR};
+TypeIntegral stsignedchar = {TYPEINT, 1, IT_SCHAR};
+TypeIntegral stunsignedchar = {TYPEINT, 1, IT_UCHAR};
+TypeIntegral stwchar = {TYPEINT, 4, IT_WCHAR_T};
+TypeIntegral stsignedshort = {TYPEINT, 2, IT_SHORT};
+TypeIntegral stunsignedshort = {TYPEINT, 2, IT_USHORT};
+TypeIntegral stsignedint = {TYPEINT, 4, IT_INT};
+TypeIntegral stunsignedint = {TYPEINT, 4, IT_UINT};
+TypeIntegral stsignedlong = {TYPEINT, 4, IT_LONG};
+TypeIntegral stunsignedlong = {TYPEINT, 4, IT_ULONG};
+TypeIntegral stsignedlonglong = {TYPEINT, 8, IT_LONGLONG};
+TypeIntegral stunsignedlonglong = {TYPEINT, 8, IT_ULONGLONG};
+TypeIntegral stfloat = {TYPEFLOAT, 4, IT_FLOAT};
+TypeIntegral stshortdouble = {TYPEFLOAT, 8, IT_SHORTDOUBLE};
+TypeIntegral stdouble = {TYPEFLOAT, 8, IT_DOUBLE};
+TypeIntegral stlongdouble = {TYPEFLOAT, 8, IT_LONGDOUBLE};
+
+static StructMember stVUC_unsignedchar15 = {NULL, (Type *) &stunsignedchar, NULL, 15, 0};
+static StructMember stVUC_unsignedchar14 = {&stVUC_unsignedchar15, (Type *) &stunsignedchar, NULL, 14, 0};
+static StructMember stVUC_unsignedchar13 = {&stVUC_unsignedchar14, (Type *) &stunsignedchar, NULL, 13, 0};
+static StructMember stVUC_unsignedchar12 = {&stVUC_unsignedchar13, (Type *) &stunsignedchar, NULL, 12, 0};
+static StructMember stVUC_unsignedchar11 = {&stVUC_unsignedchar12, (Type *) &stunsignedchar, NULL, 11, 0};
+static StructMember stVUC_unsignedchar10 = {&stVUC_unsignedchar11, (Type *) &stunsignedchar, NULL, 10, 0};
+static StructMember stVUC_unsignedchar9 = {&stVUC_unsignedchar10, (Type *) &stunsignedchar, NULL, 9, 0};
+static StructMember stVUC_unsignedchar8 = {&stVUC_unsignedchar9, (Type *) &stunsignedchar, NULL, 8, 0};
+static StructMember stVUC_unsignedchar7 = {&stVUC_unsignedchar7, (Type *) &stunsignedchar, NULL, 7, 0};
+static StructMember stVUC_unsignedchar6 = {&stVUC_unsignedchar7, (Type *) &stunsignedchar, NULL, 6, 0};
+static StructMember stVUC_unsignedchar5 = {&stVUC_unsignedchar6, (Type *) &stunsignedchar, NULL, 5, 0};
+static StructMember stVUC_unsignedchar4 = {&stVUC_unsignedchar5, (Type *) &stunsignedchar, NULL, 4, 0};
+static StructMember stVUC_unsignedchar3 = {&stVUC_unsignedchar4, (Type *) &stunsignedchar, NULL, 3, 0};
+static StructMember stVUC_unsignedchar2 = {&stVUC_unsignedchar3, (Type *) &stunsignedchar, NULL, 2, 0};
+static StructMember stVUC_unsignedchar1 = {&stVUC_unsignedchar2, (Type *) &stunsignedchar, NULL, 1, 0};
+static StructMember stVUC_unsignedchar0 = {&stVUC_unsignedchar1, (Type *) &stunsignedchar, NULL, 0, 0};
+
+static StructMember stVSC_signedchar15 = {NULL, (Type *) &stsignedchar, NULL, 15, 0};
+static StructMember stVSC_signedchar14 = {&stVSC_signedchar15, (Type *) &stsignedchar, NULL, 14, 0};
+static StructMember stVSC_signedchar13 = {&stVSC_signedchar14, (Type *) &stsignedchar, NULL, 13, 0};
+static StructMember stVSC_signedchar12 = {&stVSC_signedchar13, (Type *) &stsignedchar, NULL, 12, 0};
+static StructMember stVSC_signedchar11 = {&stVSC_signedchar12, (Type *) &stsignedchar, NULL, 11, 0};
+static StructMember stVSC_signedchar10 = {&stVSC_signedchar11, (Type *) &stsignedchar, NULL, 10, 0};
+static StructMember stVSC_signedchar9 = {&stVSC_signedchar10, (Type *) &stsignedchar, NULL, 9, 0};
+static StructMember stVSC_signedchar8 = {&stVSC_signedchar9, (Type *) &stsignedchar, NULL, 8, 0};
+static StructMember stVSC_signedchar7 = {&stVSC_signedchar7, (Type *) &stsignedchar, NULL, 7, 0};
+static StructMember stVSC_signedchar6 = {&stVSC_signedchar7, (Type *) &stsignedchar, NULL, 6, 0};
+static StructMember stVSC_signedchar5 = {&stVSC_signedchar6, (Type *) &stsignedchar, NULL, 5, 0};
+static StructMember stVSC_signedchar4 = {&stVSC_signedchar5, (Type *) &stsignedchar, NULL, 4, 0};
+static StructMember stVSC_signedchar3 = {&stVSC_signedchar4, (Type *) &stsignedchar, NULL, 3, 0};
+static StructMember stVSC_signedchar2 = {&stVSC_signedchar3, (Type *) &stsignedchar, NULL, 2, 0};
+static StructMember stVSC_signedchar1 = {&stVSC_signedchar2, (Type *) &stsignedchar, NULL, 1, 0};
+static StructMember stVSC_signedchar0 = {&stVSC_signedchar1, (Type *) &stsignedchar, NULL, 0, 0};
+
+static StructMember stVUS_unsignedshort7 = {NULL, (Type *) &stunsignedshort, NULL, 14, 0};
+static StructMember stVUS_unsignedshort6 = {&stVUS_unsignedshort7, (Type *) &stunsignedshort, NULL, 12, 0};
+static StructMember stVUS_unsignedshort5 = {&stVUS_unsignedshort7, (Type *) &stunsignedshort, NULL, 10, 0};
+static StructMember stVUS_unsignedshort4 = {&stVUS_unsignedshort5, (Type *) &stunsignedshort, NULL, 8, 0};
+static StructMember stVUS_unsignedshort3 = {&stVUS_unsignedshort4, (Type *) &stunsignedshort, NULL, 6, 0};
+static StructMember stVUS_unsignedshort2 = {&stVUS_unsignedshort3, (Type *) &stunsignedshort, NULL, 4, 0};
+static StructMember stVUS_unsignedshort1 = {&stVUS_unsignedshort2, (Type *) &stunsignedshort, NULL, 2, 0};
+static StructMember stVUS_unsignedshort0 = {&stVUS_unsignedshort1, (Type *) &stunsignedshort, NULL, 0, 0};
+
+static StructMember stVSS_signedshort7 = {NULL, (Type *) &stsignedshort, NULL, 14, 0};
+static StructMember stVSS_signedshort6 = {&stVSS_signedshort7, (Type *) &stsignedshort, NULL, 12, 0};
+static StructMember stVSS_signedshort5 = {&stVSS_signedshort7, (Type *) &stsignedshort, NULL, 10, 0};
+static StructMember stVSS_signedshort4 = {&stVSS_signedshort5, (Type *) &stsignedshort, NULL, 8, 0};
+static StructMember stVSS_signedshort3 = {&stVSS_signedshort4, (Type *) &stsignedshort, NULL, 6, 0};
+static StructMember stVSS_signedshort2 = {&stVSS_signedshort3, (Type *) &stsignedshort, NULL, 4, 0};
+static StructMember stVSS_signedshort1 = {&stVSS_signedshort2, (Type *) &stsignedshort, NULL, 2, 0};
+static StructMember stVSS_signedshort0 = {&stVSS_signedshort1, (Type *) &stsignedshort, NULL, 0, 0};
+
+static StructMember stVUL_unsignedlong3 = {NULL, (Type *) &stunsignedlong, NULL, 12, 0};
+static StructMember stVUL_unsignedlong2 = {&stVUL_unsignedlong3, (Type *) &stunsignedlong, NULL, 8, 0};
+static StructMember stVUL_unsignedlong1 = {&stVUL_unsignedlong2, (Type *) &stunsignedlong, NULL, 4, 0};
+static StructMember stVUL_unsignedlong0 = {&stVUL_unsignedlong1, (Type *) &stunsignedlong, NULL, 0, 0};
+
+static StructMember stVSL_signedlong3 = {NULL, (Type *) &stsignedlong, NULL, 12, 0};
+static StructMember stVSL_signedlong2 = {&stVSL_signedlong3, (Type *) &stsignedlong, NULL, 8, 0};
+static StructMember stVSL_signedlong1 = {&stVSL_signedlong2, (Type *) &stsignedlong, NULL, 4, 0};
+static StructMember stVSL_signedlong0 = {&stVSL_signedlong1, (Type *) &stsignedlong, NULL, 0, 0};
+
+static StructMember stVF_float3 = {NULL, (Type *) &stfloat, NULL, 12, 0};
+static StructMember stVF_float2 = {&stVF_float3, (Type *) &stfloat, NULL, 8, 0};
+static StructMember stVF_float1 = {&stVF_float2, (Type *) &stfloat, NULL, 4, 0};
+static StructMember stVF_float0 = {&stVF_float1, (Type *) &stfloat, NULL, 0, 0};
+
+TypeStruct stvectorunsignedchar = {TYPESTRUCT, 16, NULL, &stVUC_unsignedchar0, STRUCT_VECTOR_UCHAR, 16};
+TypeStruct stvectorsignedchar = {TYPESTRUCT, 16, NULL, &stVSC_signedchar0, STRUCT_VECTOR_SCHAR, 16};
+TypeStruct stvectorboolchar = {TYPESTRUCT, 16, NULL, &stVSC_signedchar0, STRUCT_VECTOR_BCHAR, 16};
+
+TypeStruct stvectorunsignedshort = {TYPESTRUCT, 16, NULL, &stVUS_unsignedshort0, STRUCT_VECTOR_USHORT, 16};
+TypeStruct stvectorsignedshort = {TYPESTRUCT, 16, NULL, &stVSS_signedshort0, STRUCT_VECTOR_SSHORT, 16};
+TypeStruct stvectorboolshort = {TYPESTRUCT, 16, NULL, &stVSS_signedshort0, STRUCT_VECTOR_BSHORT, 16};
+
+TypeStruct stvectorunsignedlong = {TYPESTRUCT, 16, NULL, &stVUL_unsignedlong0, STRUCT_VECTOR_UINT, 16};
+TypeStruct stvectorsignedlong = {TYPESTRUCT, 16, NULL, &stVSL_signedlong0, STRUCT_VECTOR_SINT, 16};
+TypeStruct stvectorboollong = {TYPESTRUCT, 16, NULL, &stVSL_signedlong0, STRUCT_VECTOR_BINT, 16};
+
+TypeStruct stvectorfloat = {TYPESTRUCT, 16, NULL, &stVF_float0, STRUCT_VECTOR_FLOAT, 16};
+
+TypeStruct stvectorpixel = {TYPESTRUCT, 16, NULL, &stVUS_unsignedshort0, STRUCT_VECTOR_PIXEL, 16};
+
+TypeStruct stvector = {TYPESTRUCT, 16, NULL, NULL, STRUCT_VECTOR_UINT, 16};
+
+static SInt32 cmach_structoffset;
+static UInt8 cmach_structalign;
+static short cmach_curbfsize;
+static short cmach_curbfbasesize;
+static int cmach_curbfoffset;
+
+static short cmach_packsize[] = {
+ 1, 2, 4, 8, 16
+};
+
+// forward declarations
+static SInt16 CMach_GetQualifiedTypeAlign(Type *type, Boolean flag);
+static SInt16 CMach_GetMemberAlignment(Type *type, SInt32 align, Boolean flag);
+
+void CMach_Configure(void) {
+}
+
+SInt32 CMach_GetQUALalign(UInt32 qual) {
+ SInt32 result = 0;
+ UInt32 chk;
+
+ if ((chk = (qual & Q_ALIGNED_MASK))) {
+ if (chk == Q_ALIGNED_1)
+ result = 1;
+ else if (chk == Q_ALIGNED_2)
+ result = 2;
+ else if (chk == Q_ALIGNED_4)
+ result = 4;
+ else if (chk == Q_ALIGNED_8)
+ result = 8;
+ else if (chk == Q_ALIGNED_16)
+ result = 16;
+ else if (chk == Q_ALIGNED_32)
+ result = 32;
+ else if (chk == Q_ALIGNED_64)
+ result = 64;
+ else if (chk == Q_ALIGNED_128)
+ result = 128;
+ else if (chk == Q_ALIGNED_256)
+ result = 256;
+ else if (chk == Q_ALIGNED_512)
+ result = 512;
+ else if (chk == Q_ALIGNED_1024)
+ result = 1024;
+ else if (chk == Q_ALIGNED_2048)
+ result = 2048;
+ else if (chk == Q_ALIGNED_4096)
+ result = 4096;
+ else if (chk == Q_ALIGNED_8192)
+ result = 8192;
+ else
+ CError_FATAL(226);
+ }
+
+ return result;
+}
+
+SInt32 CMach_ArgumentAlignment(Type *type) {
+ char save_align_mode;
+ UInt8 save_oldalignment;
+ SInt32 align;
+
+ save_align_mode = copts.structalignment;
+ save_oldalignment = copts.oldalignment;
+ copts.structalignment = AlignMode2_PPC;
+ copts.oldalignment = 0;
+ align = CMach_GetQualifiedTypeAlign(type, 0);
+ copts.structalignment = save_align_mode;
+ copts.oldalignment = save_oldalignment;
+
+ if (type->type == TYPESTRUCT && !TYPE_STRUCT(type)->members) {
+ if (TYPE_STRUCT(type)->align > align)
+ return TYPE_STRUCT(type)->align;
+ else
+ return align;
+ } else {
+ return align;
+ }
+}
+
+// TODO: investigate if this returns SInt16 actually
+SInt32 CMach_AllocationAlignment(Type *type, UInt32 qual) {
+ SInt32 align;
+ SInt32 qualalign;
+ SInt32 argalign;
+ SInt32 anotheralign;
+
+ qualalign = CMach_GetQUALalign(qual);
+ align = CMach_GetQualifiedTypeAlign(type, 1);
+ if (qualalign > align)
+ align = qualalign;
+ argalign = CMach_ArgumentAlignment(type);
+ if (argalign > align)
+ align = argalign;
+
+ switch (type->type) {
+ case TYPEVOID:
+ case TYPEMEMBERPOINTER:
+ case TYPEPOINTER:
+ anotheralign = 4;
+ break;
+ default:
+ anotheralign = 1;
+ }
+ if (anotheralign > align)
+ align = anotheralign;
+
+ if (copts.optimizationlevel > 0) {
+ if (type->type == TYPEARRAY || (type->type == TYPESTRUCT && (TYPE_STRUCT(type)->stype < STRUCT_VECTOR_UCHAR || TYPE_STRUCT(type)->stype > STRUCT_VECTOR_PIXEL)) || type->type == TYPECLASS || (type->type == TYPEMEMBERPOINTER && (UInt32) type->size == 12)) {
+ return (copts.min_struct_alignment > align) ? copts.min_struct_alignment : align;
+ }
+ }
+
+ return align;
+}
+
+CInt64 CMach_CalcIntDiadic(Type *type, CInt64 left, short op, CInt64 right) {
+ if (is_unsigned(type)) {
+ switch (type->size) {
+ case 1:
+ CInt64_ConvertUInt8(&left);
+ CInt64_ConvertUInt8(&right);
+ break;
+ case 2:
+ CInt64_ConvertUInt16(&left);
+ CInt64_ConvertUInt16(&right);
+ break;
+ case 4:
+ CInt64_ConvertUInt32(&left);
+ CInt64_ConvertUInt32(&right);
+ break;
+ case 8:
+ break;
+ default:
+ CError_FATAL(327);
+ }
+
+ switch (op) {
+ case '*':
+ left = CInt64_MulU(left, right);
+ break;
+ case '/':
+ if (CInt64_IsZero(&right))
+ CError_Warning(CErrorStr139);
+ else
+ left = CInt64_DivU(left, right);
+ break;
+ case '%':
+ if (CInt64_IsZero(&right))
+ CError_Warning(CErrorStr139);
+ else
+ left = CInt64_ModU(left, right);
+ break;
+ case '+':
+ left = CInt64_Add(left, right);
+ break;
+ case '-':
+ left = CInt64_Sub(left, right);
+ break;
+ case TK_SHL:
+ left = CInt64_Shl(left, right);
+ break;
+ case TK_SHR:
+ left = CInt64_ShrU(left, right);
+ break;
+ case '<':
+ CInt64_SetLong(&left, CInt64_LessU(left, right));
+ break;
+ case '>':
+ CInt64_SetLong(&left, CInt64_GreaterU(left, right));
+ break;
+ case TK_LESS_EQUAL:
+ CInt64_SetLong(&left, CInt64_LessEqualU(left, right));
+ break;
+ case TK_GREATER_EQUAL:
+ CInt64_SetLong(&left, CInt64_GreaterEqualU(left, right));
+ break;
+ case TK_LOGICAL_EQ:
+ CInt64_SetLong(&left, CInt64_Equal(left, right));
+ break;
+ case TK_LOGICAL_NE:
+ CInt64_SetLong(&left, CInt64_NotEqual(left, right));
+ break;
+ case '&':
+ left = CInt64_And(left, right);
+ break;
+ case '^':
+ left = CInt64_Xor(left, right);
+ break;
+ case '|':
+ left = CInt64_Or(left, right);
+ break;
+ case TK_LOGICAL_AND:
+ CInt64_SetLong(&left, (!CInt64_IsZero(&left) && !CInt64_IsZero(&right)));
+ break;
+ case TK_LOGICAL_OR:
+ CInt64_SetLong(&left, (!CInt64_IsZero(&left) || !CInt64_IsZero(&right)));
+ break;
+ default:
+ CError_Error(CErrorStr120);
+ }
+
+ switch (type->size) {
+ case 1:
+ CInt64_ConvertUInt8(&left);
+ break;
+ case 2:
+ CInt64_ConvertUInt16(&left);
+ break;
+ case 4:
+ CInt64_ConvertUInt32(&left);
+ break;
+ case 8:
+ break;
+ }
+ } else {
+ switch (type->size) {
+ case 1:
+ CInt64_ConvertInt8(&left);
+ CInt64_ConvertInt8(&right);
+ break;
+ case 2:
+ CInt64_ConvertInt16(&left);
+ CInt64_ConvertInt16(&right);
+ break;
+ case 4:
+ CInt64_ConvertInt32(&left);
+ CInt64_ConvertInt32(&right);
+ break;
+ case 8:
+ break;
+ default:
+ CError_FATAL(389);
+ }
+
+ switch (op) {
+ case '*':
+ left = CInt64_Mul(left, right);
+ break;
+ case '/':
+ if (CInt64_IsZero(&right))
+ CError_Warning(CErrorStr139);
+ else
+ left = CInt64_Div(left, right);
+ break;
+ case '%':
+ if (CInt64_IsZero(&right))
+ CError_Warning(CErrorStr139);
+ else
+ left = CInt64_Mod(left, right);
+ break;
+ case '+':
+ left = CInt64_Add(left, right);
+ break;
+ case '-':
+ left = CInt64_Sub(left, right);
+ break;
+ case TK_SHL:
+ left = CInt64_Shl(left, right);
+ break;
+ case TK_SHR:
+ left = CInt64_Shr(left, right);
+ break;
+ case '<':
+ CInt64_SetLong(&left, CInt64_Less(left, right));
+ break;
+ case '>':
+ CInt64_SetLong(&left, CInt64_Greater(left, right));
+ break;
+ case TK_LESS_EQUAL:
+ CInt64_SetLong(&left, CInt64_LessEqual(left, right));
+ break;
+ case TK_GREATER_EQUAL:
+ CInt64_SetLong(&left, CInt64_GreaterEqual(left, right));
+ break;
+ case TK_LOGICAL_EQ:
+ CInt64_SetLong(&left, CInt64_Equal(left, right));
+ break;
+ case TK_LOGICAL_NE:
+ CInt64_SetLong(&left, CInt64_NotEqual(left, right));
+ break;
+ case '&':
+ left = CInt64_And(left, right);
+ break;
+ case '^':
+ left = CInt64_Xor(left, right);
+ break;
+ case '|':
+ left = CInt64_Or(left, right);
+ break;
+ case TK_LOGICAL_AND:
+ CInt64_SetLong(&left, (!CInt64_IsZero(&left) && !CInt64_IsZero(&right)));
+ break;
+ case TK_LOGICAL_OR:
+ CInt64_SetLong(&left, (!CInt64_IsZero(&left) || !CInt64_IsZero(&right)));
+ break;
+ default:
+ CError_Error(CErrorStr120);
+ }
+
+ switch (type->size) {
+ case 1:
+ CInt64_ConvertInt8(&left);
+ break;
+ case 2:
+ CInt64_ConvertInt16(&left);
+ break;
+ case 4:
+ CInt64_ConvertInt32(&left);
+ break;
+ case 8:
+ break;
+ }
+ }
+
+ return left;
+}
+
+CInt64 CMach_CalcIntMonadic(Type *type, short op, CInt64 val) {
+ if (is_unsigned(type)) {
+ switch (type->size) {
+ case 1:
+ CInt64_ConvertUInt8(&val);
+ break;
+ case 2:
+ CInt64_ConvertUInt16(&val);
+ break;
+ case 4:
+ CInt64_ConvertUInt32(&val);
+ break;
+ case 8:
+ break;
+ default:
+ CError_FATAL(448);
+ }
+
+ switch (op) {
+ case '-':
+ val = CInt64_Neg(val);
+ break;
+ case '~':
+ val = CInt64_Inv(val);
+ break;
+ case '!':
+ val = CInt64_Not(val);
+ break;
+ default:
+ CError_Error(CErrorStr120);
+ }
+
+ switch (type->size) {
+ case 1:
+ CInt64_ConvertUInt8(&val);
+ break;
+ case 2:
+ CInt64_ConvertUInt16(&val);
+ break;
+ case 4:
+ CInt64_ConvertUInt32(&val);
+ break;
+ case 8:
+ break;
+ }
+ } else {
+ switch (type->size) {
+ case 1:
+ CInt64_ConvertInt8(&val);
+ break;
+ case 2:
+ CInt64_ConvertInt16(&val);
+ break;
+ case 4:
+ CInt64_ConvertInt32(&val);
+ break;
+ case 8:
+ break;
+ default:
+ CError_FATAL(478);
+ }
+
+ switch (op) {
+ case '-':
+ val = CInt64_Neg(val);
+ break;
+ case '~':
+ val = CInt64_Inv(val);
+ break;
+ case '!':
+ val = CInt64_Not(val);
+ break;
+ default:
+ CError_Error(CErrorStr120);
+ }
+
+ switch (type->size) {
+ case 1:
+ CInt64_ConvertInt8(&val);
+ break;
+ case 2:
+ CInt64_ConvertInt16(&val);
+ break;
+ case 4:
+ CInt64_ConvertInt32(&val);
+ break;
+ case 8:
+ break;
+ }
+ }
+
+ return val;
+}
+
+CInt64 CMach_CalcIntConvertFromFloat(Type *type, Float fval) {
+ CInt64 result;
+
+ if ((type->type == TYPEINT || type->type == TYPEENUM) && (type->size == 8)) {
+ if (is_unsigned(type))
+ CInt64_ConvertUFromLongDouble(&result, fval.value);
+ else
+ CInt64_ConvertFromLongDouble(&result, fval.value);
+ } else {
+ if (is_unsigned(type))
+ CInt64_SetULong(&result, fval.value);
+ else
+ CInt64_SetLong(&result, fval.value);
+ }
+
+ return result;
+}
+
+void CMach_InitIntMem(Type *type, CInt64 val, void *mem) {
+ SInt32 lg;
+ SInt16 sh;
+ SInt8 ch;
+
+ switch (type->type) {
+ case TYPEINT:
+ switch (type->size) {
+ case 1:
+ ch = CInt64_GetULong(&val);
+ memcpy(mem, &ch, 1);
+ break;
+ case 2:
+ sh = CTool_EndianConvertWord16(CInt64_GetULong(&val));
+ memcpy(mem, &sh, 2);
+ break;
+ case 4:
+ lg = CTool_EndianConvertWord32(CInt64_GetULong(&val));
+ memcpy(mem, &lg, 4);
+ break;
+ case 8:
+ CTool_EndianConvertWord64(val, mem);
+ break;
+ default:
+ CError_FATAL(566);
+ }
+ break;
+ default:
+ CError_FATAL(570);
+ }
+}
+
+void CMach_InitVectorMem(Type *type, MWVector128 val, void *mem, Boolean flag) {
+ unsigned char uc[16];
+ unsigned short us[8];
+ unsigned int ul[4];
+ float f[4];
+ int i;
+
+ switch (type->type) {
+ case TYPESTRUCT:
+ switch (TYPE_STRUCT(type)->stype) {
+ case STRUCT_VECTOR_UCHAR:
+ case STRUCT_VECTOR_SCHAR:
+ case STRUCT_VECTOR_BCHAR:
+ for (i = 0; i < 16; i++)
+ uc[i] = val.uc[i];
+ memcpy(mem, uc, 16);
+ break;
+ case STRUCT_VECTOR_USHORT:
+ case STRUCT_VECTOR_SSHORT:
+ case STRUCT_VECTOR_BSHORT:
+ case STRUCT_VECTOR_PIXEL:
+ for (i = 0; i < 8; i++)
+ us[i] = val.us[i];
+ memcpy(mem, us, 16);
+ break;
+ case STRUCT_VECTOR_UINT:
+ case STRUCT_VECTOR_SINT:
+ case STRUCT_VECTOR_BINT:
+ for (i = 0; i < 4; i++)
+ ul[i] = val.ul[i];
+ memcpy(mem, ul, 16);
+ break;
+ case STRUCT_VECTOR_FLOAT:
+ for (i = 0; i < 4; i++)
+ f[i] = val.f[i];
+ memcpy(mem, f, 16);
+ break;
+ default:
+ CError_FATAL(655);
+ }
+ break;
+ default:
+ CError_FATAL(659);
+ }
+}
+
+Float CMach_CalcFloatDiadic(Type *type, Float left, short op, Float right) {
+ switch (op) {
+ case '+':
+ left.value += right.value;
+ break;
+ case '-':
+ left.value -= right.value;
+ break;
+ case '*':
+ left.value *= right.value;
+ break;
+ case '/':
+ left.value /= right.value;
+ break;
+ default:
+ CError_FATAL(679);
+ }
+
+ return CMach_CalcFloatConvert(type, left);
+}
+
+Float CMach_CalcFloatMonadic(Type *type, short op, Float fval) {
+ if (op != '-')
+ CError_FATAL(692);
+
+ fval.value = -fval.value;
+ return CMach_CalcFloatConvert(type, fval);
+}
+
+Boolean CMach_CalcFloatDiadicBool(Type *type, Float left, short op, Float right) {
+ switch (op) {
+ case TK_LOGICAL_EQ:
+ return left.value == right.value;
+ case TK_LOGICAL_NE:
+ return left.value != right.value;
+ case TK_LESS_EQUAL:
+ return left.value <= right.value;
+ case TK_GREATER_EQUAL:
+ return left.value >= right.value;
+ case '>':
+ return left.value > right.value;
+ case '<':
+ return left.value < right.value;
+ default:
+ CError_FATAL(714);
+ return 0;
+ }
+}
+
+Boolean CMach_CalcVectorDiadicBool(Type *type, MWVector128 *left, short op, MWVector128 *right) {
+ switch (op) {
+ case TK_LOGICAL_EQ:
+ return (left->ul[0] == right->ul[0]) && (left->ul[1] == right->ul[1]) && (left->ul[2] == right->ul[2]) && (left->ul[3] == right->ul[3]);
+ case TK_LOGICAL_NE:
+ return (left->ul[0] != right->ul[0]) && (left->ul[1] != right->ul[1]) && (left->ul[2] != right->ul[2]) && (left->ul[3] != right->ul[3]);
+ default:
+ CError_FATAL(740);
+ return 0;
+ }
+}
+
+char *CMach_FloatScan(char *input, Float *result, Boolean *fail) {
+ double resultval;
+ char *outpos;
+
+ if (!(outpos = ScanFloat(input, &resultval, fail)))
+ CError_ErrorTerm(CErrorStr154);
+
+ if (*fail)
+ result->value = 0.0;
+ else
+ result->value = resultval;
+
+ return outpos;
+}
+
+Float CMach_CalcFloatConvertFromInt(Type *type, CInt64 val) {
+ Float result;
+
+ if ((type->type == TYPEINT || type->type == TYPEENUM) && (type->size == 8)) {
+ if (is_unsigned(type))
+ result.value = CInt64_ConvertUToLongDouble(&val);
+ else
+ result.value = CInt64_ConvertToLongDouble(&val);
+ } else {
+ if (is_unsigned(type))
+ result.value = val.lo;
+ else
+ result.value = (SInt32) val.lo;
+ }
+
+ return result;
+}
+
+Float CMach_CalcFloatConvert(Type *type, Float fval) {
+ switch (type->size) {
+ case 4:
+ fval.value = (float) fval.value;
+ break;
+ case 8:
+ fval.value = (double) fval.value;
+ break;
+ case 10:
+ case 12:
+ break;
+ default:
+ CError_FATAL(801);
+ }
+ return fval;
+}
+
+Boolean CMach_FloatIsZero(Float fval) {
+ return fval.value == 0.0;
+}
+
+Boolean CMach_FloatIsOne(Float fval) {
+ return fval.value == 1.0;
+}
+
+Boolean CMach_FloatIsNegOne(Float fval) {
+ return fval.value == -1.0;
+}
+
+void CMach_InitFloatMem(Type *type, Float val, void *mem) {
+ float f;
+ double d;
+
+ if (type->type == TYPEFLOAT) {
+ switch (type->size) {
+ case 4:
+ f = val.value;
+ memcpy(mem, &f, 4);
+ CTool_EndianConvertMem(mem, 4);
+ return;
+ case 8:
+ d = val.value;
+ memcpy(mem, &d, 8);
+ CTool_EndianConvertMem(mem, 8);
+ return;
+ }
+ }
+
+ CError_FATAL(866);
+}
+
+void CMach_PrintFloat(char *buf, Float val) {
+ double f;
+ CMach_InitFloatMem((Type *) &stshortdouble, val, &f);
+ sprintf(buf, "%g", f);
+}
+
+void CMach_PragmaParams(void) {
+ if (copts.warn_illpragma)
+ CError_Warning(CErrorStr186, 0);
+
+ while (notendofline())
+ lex();
+}
+
+void CMach_AdjustFuntionArgs() {
+ // not called so we will never know what the args should have been :(
+}
+
+static SInt32 CMach_GetPPCTypeAlign(Type *type, Boolean flag1, Boolean flag2) {
+ ClassList *base;
+ ObjMemberVar *ivar;
+ StructMember *member;
+ SInt32 best;
+ SInt32 ivarAlign;
+ SInt32 qualAlign;
+
+ SInt32 align = CMach_GetQualifiedTypeAlign(type, flag2);
+ if (align <= 8) {
+ while (type->type == TYPEARRAY)
+ type = TYPE_POINTER(type)->target;
+
+ if (flag1) {
+ if (type->type == TYPEFLOAT && type->size > 4 && align < 8)
+ return 8;
+ } else if (align == 8) {
+ if (type->type == TYPECLASS) {
+ best = 4;
+ for (base = TYPE_CLASS(type)->bases; base; base = base->next) {
+ if (base->base->align > best)
+ best = base->base->align;
+ }
+ for (ivar = TYPE_CLASS(type)->ivars; ivar; ivar = ivar->next) {
+ ivarAlign = CMach_GetPPCTypeAlign(ivar->type, 0, flag2);
+ if (ivarAlign > best)
+ best = ivarAlign;
+ if (flag2) {
+ qualAlign = CMach_GetQUALalign(ivar->qual);
+ if (qualAlign > best)
+ best = qualAlign;
+ }
+ }
+ return best;
+ }
+ if (type->type == TYPESTRUCT) {
+ best = 4;
+ for (member = TYPE_STRUCT(type)->members; member; member = member->next) {
+ ivarAlign = CMach_GetPPCTypeAlign(member->type, 0, flag2);
+ if (ivarAlign > best)
+ best = ivarAlign;
+ if (flag2) {
+ qualAlign = CMach_GetQUALalign(member->qual);
+ if (qualAlign > best)
+ best = qualAlign;
+ }
+ }
+ return best;
+ }
+ }
+ }
+
+ return align;
+}
+
+static SInt16 CMach_GetQualifiedStructAlign(const TypeStruct *tstruct, Boolean flag) {
+ StructMember *member;
+ SInt32 best;
+ SInt32 align;
+ Boolean isFirst;
+
+ if (tstruct->stype >= STRUCT_VECTOR_UCHAR && tstruct->stype <= STRUCT_VECTOR_PIXEL)
+ return 16;
+
+ switch (copts.structalignment) {
+ case AlignMode3_1Byte:
+ case AlignMode8_Packed:
+ return 1;
+ case AlignMode0_Mac68k:
+ return 2;
+ case AlignMode1_Mac68k4byte:
+ return (tstruct->size <= 2) ? 2 : 4;
+ }
+
+ if (tstruct->size <= 1)
+ return 1;
+
+ best = 1;
+ switch (copts.structalignment) {
+ default:
+ CError_FATAL(1026);
+ case AlignMode4_2Byte:
+ case AlignMode5_4Byte:
+ case AlignMode6_8Byte:
+ case AlignMode7_16Byte:
+ for (member = tstruct->members; member; member = member->next) {
+ align = CMach_GetQualifiedTypeAlign(member->type, flag);
+ if (align > best)
+ best = align;
+ if (flag) {
+ align = CMach_GetQUALalign(member->qual);
+ if (align > best)
+ best = align;
+ }
+ }
+ return best;
+ case AlignMode2_PPC:
+ if (copts.oldalignment) {
+ for (member = tstruct->members; member; member = member->next) {
+ align = CMach_GetQualifiedTypeAlign(member->type, flag);
+ if (align > best)
+ best = align;
+ if (flag) {
+ align = CMach_GetQUALalign(member->qual);
+ if (align > best)
+ best = align;
+ }
+ }
+ } else if (TYPE_STRUCT(tstruct)->stype == STRUCT_TYPE_UNION) {
+ for (member = tstruct->members; member; member = member->next) {
+ align = CMach_GetPPCTypeAlign(member->type, 1, flag);
+ if (align > best)
+ best = align;
+ if (flag) {
+ align = CMach_GetQUALalign(member->qual);
+ if (align > best)
+ best = align;
+ }
+ }
+ } else {
+ isFirst = 1;
+ for (member = tstruct->members; member; member = member->next) {
+ align = CMach_GetPPCTypeAlign(member->type, isFirst || (best >= 8), flag);
+ if (align > best)
+ best = align;
+ if (flag) {
+ align = CMach_GetQUALalign(member->qual);
+ if (align > best)
+ best = align;
+ }
+ isFirst = 0;
+ }
+ }
+ return best;
+ }
+}
+
+SInt16 CMach_GetStructAlign(TypeStruct *tstruct) {
+ return CMach_GetQualifiedStructAlign(tstruct, 1);
+}
+
+static SInt16 CMach_GetQualifiedClassAlign(TypeClass *tclass, Boolean flag) {
+ ClassList *base;
+ ObjMemberVar *ivar;
+ SInt32 best;
+ SInt32 align;
+ Boolean isFirst;
+
+ switch (copts.structalignment) {
+ case AlignMode3_1Byte:
+ case AlignMode8_Packed:
+ return 1;
+ case AlignMode0_Mac68k:
+ return 2;
+ case AlignMode1_Mac68k4byte:
+ return (tclass->size <= 2) ? 2 : 4;
+ }
+ if (tclass->size <= 1)
+ return 1;
+ best = 1;
+ switch (copts.structalignment) {
+ default:
+ CError_FATAL(1149);
+ case AlignMode4_2Byte:
+ case AlignMode5_4Byte:
+ case AlignMode6_8Byte:
+ case AlignMode7_16Byte:
+ for (base = tclass->bases; base; base = base->next) {
+ if ((align = base->base->align) > best)
+ best = align;
+ }
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ align = CMach_GetMemberAlignment(ivar->type, flag ? CMach_GetQUALalign(ivar->qual) : 0, flag);
+ if (align > best)
+ best = align;
+ }
+ return best;
+ case AlignMode2_PPC:
+ best = 1;
+ if (copts.oldalignment) {
+ for (base = tclass->bases; base; base = base->next) {
+ if ((align = base->base->align) > best)
+ best = align;
+ }
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ align = CMach_GetMemberAlignment(ivar->type, flag ? CMach_GetQUALalign(ivar->qual) : 0, flag);
+ if (align > best)
+ best = align;
+ }
+ } else {
+ isFirst = 1;
+ for (base = tclass->bases; base; base = base->next) {
+ if ((align = base->base->align) > best)
+ best = align;
+ isFirst = 0;
+ }
+ if (tclass->mode == 1) {
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ align = CMach_GetPPCTypeAlign(ivar->type, 1, flag);
+ if (align > best)
+ best = align;
+ if (flag) {
+ align = CMach_GetQUALalign(ivar->qual);
+ if (align > best)
+ best = align;
+ }
+ }
+ } else {
+ for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
+ if (ivar->offset && align != 8)
+ isFirst = 0;
+ align = CMach_GetPPCTypeAlign(ivar->type, isFirst || (best >= 8), flag);
+ if (align > best)
+ best = align;
+ if (flag) {
+ align = CMach_GetQUALalign(ivar->qual);
+ if (align > best)
+ best = align;
+ }
+ }
+ }
+ }
+ return best;
+ }
+}
+
+SInt16 CMach_GetClassAlign(TypeClass *tclass) {
+ return CMach_GetQualifiedClassAlign(tclass, 1);
+}
+
+static SInt16 CMach_GetWinTypeAlign(Type *type) {
+ int packoffs = copts.structalignment - 3;
+ SInt32 align = cmach_packsize[packoffs];
+ if (type->size < align)
+ align = type->size;
+ return align;
+}
+
+static SInt16 CMach_GetWinMinimizeAlign(SInt16 align) {
+ int packoffs = copts.structalignment - 3;
+ SInt16 minimum = cmach_packsize[packoffs];
+ if (minimum < align)
+ align = minimum;
+ return align;
+}
+
+static SInt16 CMach_GetQualifiedTypeAlign(Type *type, Boolean flag) {
+ Boolean isWin;
+ SInt16 align;
+
+ if (type->type == TYPESTRUCT && TYPE_STRUCT(type)->stype >= STRUCT_VECTOR_UCHAR && TYPE_STRUCT(type)->stype <= STRUCT_VECTOR_PIXEL)
+ return 16;
+
+ switch (copts.structalignment) {
+ case AlignMode3_1Byte:
+ case AlignMode8_Packed:
+ return 1;
+ case AlignMode4_2Byte:
+ case AlignMode5_4Byte:
+ case AlignMode6_8Byte:
+ case AlignMode7_16Byte:
+ isWin = 1;
+ break;
+ default:
+ isWin = 0;
+ break;
+ }
+
+restart:
+ switch (type->type) {
+ case TYPEVOID:
+ return 0;
+ case TYPEFUNC:
+ return 0;
+ case TYPEENUM:
+ type = TYPE_ENUM(type)->enumtype;
+ case TYPEINT:
+ if (isWin)
+ return CMach_GetWinTypeAlign(type);
+ if (type->size == 1)
+ return 1;
+ if (copts.oldalignment && type->size == 8)
+ return 8;
+ if (copts.structalignment != AlignMode0_Mac68k && type->size >= 4)
+ return 4;
+ return 2;
+ case TYPEFLOAT:
+ if (isWin)
+ return CMach_GetWinTypeAlign(type);
+ switch (copts.structalignment) {
+ case AlignMode0_Mac68k:
+ return 2;
+ case AlignMode1_Mac68k4byte:
+ return 4;
+ case AlignMode2_PPC:
+ if (copts.oldalignment && type->size > 4)
+ return 8;
+ return 4;
+ default:
+ CError_FATAL(1346);
+ }
+ case TYPEMEMBERPOINTER:
+ case TYPEPOINTER:
+ if (isWin)
+ return CMach_GetWinTypeAlign(type);
+ if (copts.structalignment == AlignMode0_Mac68k)
+ return 2;
+ else
+ return 4;
+ case TYPEARRAY:
+ if (copts.alignarraymembers) {
+ if (isWin)
+ return CMach_GetWinTypeAlign(type);
+ if (type->size == 1)
+ return 1;
+ if (copts.structalignment == AlignMode0_Mac68k || type->size <= 2)
+ return 2;
+ if (copts.structalignment == AlignMode1_Mac68k4byte || type->size < 8)
+ return 4;
+ align = CMach_GetQualifiedTypeAlign(TYPE_POINTER(type)->target, flag);
+ if (align > 4)
+ return align;
+ else
+ return 4;
+ } else {
+ type = TYPE_POINTER(type)->target;
+ goto restart;
+ }
+ case TYPESTRUCT:
+ if (flag)
+ align = TYPE_STRUCT(type)->align;
+ else
+ align = CMach_GetQualifiedStructAlign(TYPE_STRUCT(type), flag);
+ if (isWin)
+ return CMach_GetWinMinimizeAlign(align);
+ else
+ return align;
+ case TYPECLASS:
+ if (flag)
+ align = TYPE_CLASS(type)->align;
+ else
+ align = CMach_GetQualifiedClassAlign(TYPE_CLASS(type), flag);
+ if (isWin)
+ return CMach_GetWinMinimizeAlign(align);
+ else
+ return align;
+ case TYPEBITFIELD:
+ type = TYPE_BITFIELD(type)->bitfieldtype;
+ goto restart;
+ case TYPETEMPLATE:
+ return 1;
+ default:
+ CError_FATAL(1392);
+ return 0;
+ }
+}
+
+SInt16 CMach_GetTypeAlign(Type *type) {
+ return CMach_GetQualifiedTypeAlign(type, 1);
+}
+
+static SInt16 CMach_GetMemberAlignment(Type *type, SInt32 var, Boolean flag) {
+ SInt32 align;
+
+ align = CMach_GetQualifiedTypeAlign(type, flag);
+ if (align < 1)
+ align = 1;
+
+ if (IS_TYPE_VECTOR(type) && align < 16)
+ align = 16;
+
+ switch (copts.structalignment) {
+ case AlignMode8_Packed:
+ align = 1;
+ break;
+ case AlignMode0_Mac68k:
+ if (align > 2)
+ align = 2;
+ break;
+ case AlignMode1_Mac68k4byte:
+ if (align > 4)
+ align = 4;
+ break;
+ case AlignMode2_PPC:
+ if (!copts.oldalignment)
+ align = CMach_GetPPCTypeAlign(type, !cmach_structoffset || (cmach_structalign >= 8), flag);
+ if (var > align)
+ align = var;
+ break;
+ }
+
+ if (align > cmach_structalign)
+ cmach_structalign = align;
+ return align;
+}
+
+SInt16 CMach_MemberAlignValue(Type *type, SInt32 var) {
+ SInt16 align = CMach_GetMemberAlignment(type, 0, 1);
+ if (align <= 1)
+ return 0;
+
+ return (align - 1) & (align - (var & (align - 1)));
+}
+
+static SInt16 MemberAlignValue(Type *type, SInt32 var1, SInt32 var2) {
+ SInt16 align = CMach_GetMemberAlignment(type, var2, 1);
+ return (align - 1) & (align - (var1 & (align - 1)));
+}
+
+void CMach_StructLayoutInitOffset(SInt32 offset) {
+ cmach_structoffset = offset;
+ cmach_structalign = 4;
+ cmach_curbfsize = 0;
+}
+
+SInt32 CMach_StructLayoutGetCurSize(void) {
+ return cmach_structoffset;
+}
+
+SInt32 CMach_StructLayoutGetOffset(Type *type, UInt32 qual) {
+ SInt32 align;
+ SInt32 offset;
+
+ qual = CParser_GetTypeQualifiers(type, qual);
+
+ cmach_curbfsize = 0;
+ align = MemberAlignValue(type, cmach_structoffset, CMach_GetQUALalign(qual));
+ offset = cmach_structoffset + align;
+ cmach_structoffset = offset + type->size;
+ return offset;
+}
+
+SInt32 CMach_StructLayoutBitfield(TypeBitfield *tbitfield, UInt32 qual) {
+ SInt16 align;
+ SInt16 padding_at_start;
+ SInt16 basesize;
+ SInt16 basesize_bits;
+ SInt16 required_alignment;
+ SInt16 r4;
+
+ padding_at_start = 0;
+ required_alignment = 0;
+ align = CMach_GetQUALalign(qual);
+ if (align <= tbitfield->bitfieldtype->size)
+ align = 0;
+
+ switch (tbitfield->bitfieldtype->size) {
+ case 1:
+ basesize = 1;
+ basesize_bits = 8;
+ required_alignment = 0;
+ break;
+ case 2:
+ basesize = 2;
+ basesize_bits = 16;
+ required_alignment = 2;
+ break;
+ case 4:
+ if (copts.structalignment != AlignMode0_Mac68k && copts.structalignment != AlignMode4_2Byte)
+ required_alignment = 4;
+ else
+ required_alignment = 2;
+ basesize = 4;
+ basesize_bits = 32;
+ break;
+ default:
+ CError_FATAL(1620);
+ }
+
+ switch (copts.structalignment) {
+ case AlignMode3_1Byte:
+ case AlignMode8_Packed:
+ required_alignment = 0;
+ break;
+ }
+
+ r4 = required_alignment;
+ if (align > required_alignment)
+ r4 = align;
+ if (r4 && (cmach_structoffset & (r4 - 1)))
+ padding_at_start = r4 - (cmach_structoffset & (r4 - 1));
+
+ if (!cmach_curbfsize) {
+ cmach_structoffset += padding_at_start;
+ if (!tbitfield->bitlength)
+ return cmach_structoffset;
+ cmach_curbfsize = tbitfield->bitlength;
+ cmach_curbfbasesize = basesize;
+ cmach_curbfoffset = cmach_structoffset;
+ cmach_structoffset += basesize;
+ tbitfield->offset = 0;
+ return cmach_curbfoffset;
+ } else {
+ if (!tbitfield->bitlength || (cmach_curbfsize + tbitfield->bitlength) > basesize_bits || cmach_curbfbasesize != basesize) {
+ cmach_structoffset += padding_at_start;
+ cmach_curbfsize = 0;
+ cmach_curbfbasesize = basesize;
+ if (!tbitfield->bitlength)
+ return cmach_structoffset;
+ cmach_curbfoffset = cmach_structoffset;
+ cmach_structoffset += basesize;
+ }
+ tbitfield->offset = cmach_curbfsize;
+ cmach_curbfsize += tbitfield->bitlength;
+ return cmach_curbfoffset;
+ }
+}
+
+static Boolean CMach_IsTrivialClass(TypeClass *tclass) {
+ return !CClass_Constructor(tclass);
+}
+
+UInt8 CMach_GetFunctionResultClass(TypeFunc *tfunc) {
+ switch (tfunc->functype->type) {
+ case TYPESTRUCT:
+ if (tfunc->functype->type == TYPESTRUCT && TYPE_STRUCT(tfunc->functype)->stype >= STRUCT_VECTOR_UCHAR && TYPE_STRUCT(tfunc->functype)->stype <= STRUCT_VECTOR_PIXEL)
+ return 0;
+ case TYPECLASS:
+ case TYPEMEMBERPOINTER:
+ return CMach_PassResultInHiddenArg(tfunc->functype) != 0;
+ default:
+ return 0;
+ }
+}
+
+Boolean CMach_PassResultInHiddenArg(Type *type) {
+ switch (type->type) {
+ case TYPESTRUCT:
+ if (TYPE_STRUCT(type)->stype >= STRUCT_VECTOR_UCHAR && TYPE_STRUCT(type)->stype <= STRUCT_VECTOR_PIXEL)
+ return 0;
+ else
+ return 1;
+ case TYPECLASS:
+ return 1;
+ case TYPEMEMBERPOINTER:
+ return (type->size != 4);
+ default:
+ return 0;
+ }
+}
+
+char *CMach_GetCPU(void) {
+ switch (copts.processor) {
+ case CPU_PPC401: return "__PPC401__";
+ case CPU_PPC403: return "__PPC403__";
+ case CPU_PPC505: return "__PPC505__";
+ case CPU_PPC509: return "__PPC509__";
+ case CPU_PPC555: return "__PPC555__";
+ case CPU_PPC556: return "__PPC556__";
+ case CPU_PPC565: return "__PPC565__";
+ case CPU_PPC601: return "__PPC601__";
+ case CPU_PPC602: return "__PPC602__";
+ case CPU_PPC603: return "__PPC603__";
+ case CPU_PPC603e: return "__PPC603e__";
+ case CPU_PPC604: return "__PPC604__";
+ case CPU_PPC604e: return "__PPC604e__";
+ case CPU_PPC740: return "__PPC740__";
+ case CPU_PPC750: return "__PPC750__";
+ case CPU_PPC801: return "__PPC801__";
+ case CPU_PPC821: return "__PPC821__";
+ case CPU_PPC823: return "__PPC823__";
+ case CPU_PPC850: return "__PPC850__";
+ case CPU_PPC860: return "__PPC860__";
+ case CPU_PPC7400: return "__PPC7400__";
+ case CPU_PPC7450: return "__PPC7450__";
+ case CPU_PPC8240: return "__PPC8240__";
+ case CPU_PPC8260: return "__PPC8260__";
+ case CPU_PPCGEKKO: return "__PPCGEKKO__";
+ case CPU_PPCELF: return "__PPCELF__";
+ default: return NULL;
+ }
+}
+
+Boolean CMach_FloatIsPowerOf2(Float flt) {
+ return (flt.value == 2.0) ||
+ (flt.value == 4.0) ||
+ (flt.value == 8.0) ||
+ (flt.value == 16.0) ||
+ (flt.value == 32.0) ||
+ (flt.value == 64.0) ||
+ (flt.value == 128.0) ||
+ (flt.value == 256.0) ||
+ (flt.value == 512.0) ||
+ (flt.value == 1024.0);
+}
+
+Float CMach_FloatReciprocal(Float flt) {
+ flt.value = 1.0 / flt.value;
+ return flt;
+}
+
+SInt32 CMach_RoundedSizeOf(Object *object) {
+ SInt32 size = object->type->size;
+ SInt32 align = CMach_GetTypeAlign(object->type) - 1;
+ return (size + align) & ~align;
+}
+
+void CMach_ReInitRuntimeObjects(void) {
+ HashNameNode *e0 = GetHashNameNodeExport("[0]");
+ HashNameNode *e1 = GetHashNameNodeExport("[1]");
+ HashNameNode *e2 = GetHashNameNodeExport("[2]");
+ HashNameNode *e3 = GetHashNameNodeExport("[3]");
+ HashNameNode *e4 = GetHashNameNodeExport("[4]");
+ HashNameNode *e5 = GetHashNameNodeExport("[5]");
+ HashNameNode *e6 = GetHashNameNodeExport("[6]");
+ HashNameNode *e7 = GetHashNameNodeExport("[7]");
+ HashNameNode *e8 = GetHashNameNodeExport("[8]");
+ HashNameNode *e9 = GetHashNameNodeExport("[9]");
+ HashNameNode *e10 = GetHashNameNodeExport("[10]");
+ HashNameNode *e11 = GetHashNameNodeExport("[11]");
+ HashNameNode *e12 = GetHashNameNodeExport("[12]");
+ HashNameNode *e13 = GetHashNameNodeExport("[13]");
+ HashNameNode *e14 = GetHashNameNodeExport("[14]");
+ HashNameNode *e15 = GetHashNameNodeExport("[15]");
+ HashNameNode *vuc = GetHashNameNodeExport("vector unsigned char");
+ HashNameNode *vus = GetHashNameNodeExport("vector unsigned short");
+ HashNameNode *vui = GetHashNameNodeExport("vector unsigned int");
+ HashNameNode *vsc = GetHashNameNodeExport("vector signed char");
+ HashNameNode *vss = GetHashNameNodeExport("vector signed short");
+ HashNameNode *vsi = GetHashNameNodeExport("vector signed int");
+ HashNameNode *vbc = GetHashNameNodeExport("vector bool char");
+ HashNameNode *vbs = GetHashNameNodeExport("vector bool short");
+ HashNameNode *vbi = GetHashNameNodeExport("vector bool int");
+ HashNameNode *vf = GetHashNameNodeExport("vector float");
+ HashNameNode *vp = GetHashNameNodeExport("vector pixel");
+
+ stvectorunsignedchar.name = vuc;
+ stvectorunsignedshort.name = vus;
+ stvectorunsignedlong.name = vui;
+ stvectorsignedchar.name = vsc;
+ stvectorsignedshort.name = vss;
+ stvectorsignedlong.name = vsi;
+ stvectorboolchar.name = vbc;
+ stvectorboolshort.name = vbs;
+ stvectorboollong.name = vbi;
+ stvectorfloat.name = vf;
+ stvectorpixel.name = vp;
+
+ stVUC_unsignedchar0.name = e0;
+ stVUC_unsignedchar1.name = e1;
+ stVUC_unsignedchar2.name = e2;
+ stVUC_unsignedchar3.name = e3;
+ stVUC_unsignedchar4.name = e4;
+ stVUC_unsignedchar5.name = e5;
+ stVUC_unsignedchar6.name = e6;
+ stVUC_unsignedchar7.name = e7;
+ stVUC_unsignedchar8.name = e8;
+ stVUC_unsignedchar9.name = e9;
+ stVUC_unsignedchar10.name = e10;
+ stVUC_unsignedchar11.name = e11;
+ stVUC_unsignedchar12.name = e12;
+ stVUC_unsignedchar13.name = e13;
+ stVUC_unsignedchar14.name = e14;
+ stVUC_unsignedchar15.name = e15;
+ stVSC_signedchar0.name = e0;
+ stVSC_signedchar1.name = e1;
+ stVSC_signedchar2.name = e2;
+ stVSC_signedchar3.name = e3;
+ stVSC_signedchar4.name = e4;
+ stVSC_signedchar5.name = e5;
+ stVSC_signedchar6.name = e6;
+ stVSC_signedchar7.name = e7;
+ stVSC_signedchar8.name = e8;
+ stVSC_signedchar9.name = e9;
+ stVSC_signedchar10.name = e10;
+ stVSC_signedchar11.name = e11;
+ stVSC_signedchar12.name = e12;
+ stVSC_signedchar13.name = e13;
+ stVSC_signedchar14.name = e14;
+ stVSC_signedchar15.name = e15;
+
+ stVUS_unsignedshort0.name = e0;
+ stVUS_unsignedshort1.name = e1;
+ stVUS_unsignedshort2.name = e2;
+ stVUS_unsignedshort3.name = e3;
+ stVUS_unsignedshort4.name = e4;
+ stVUS_unsignedshort5.name = e5;
+ stVUS_unsignedshort6.name = e6;
+ stVUS_unsignedshort7.name = e7;
+ stVSS_signedshort0.name = e0;
+ stVSS_signedshort1.name = e1;
+ stVSS_signedshort2.name = e2;
+ stVSS_signedshort3.name = e3;
+ stVSS_signedshort4.name = e4;
+ stVSS_signedshort5.name = e5;
+ stVSS_signedshort6.name = e6;
+ stVSS_signedshort7.name = e7;
+
+ stVUL_unsignedlong0.name = e0;
+ stVUL_unsignedlong1.name = e1;
+ stVUL_unsignedlong2.name = e2;
+ stVUL_unsignedlong3.name = e3;
+ stVSL_signedlong0.name = e0;
+ stVSL_signedlong1.name = e1;
+ stVSL_signedlong2.name = e2;
+ stVSL_signedlong3.name = e3;
+
+ stVF_float0.name = e0;
+ stVF_float1.name = e1;
+ stVF_float2.name = e2;
+ stVF_float3.name = e3;
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/CodeGen.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/CodeGen.c
new file mode 100644
index 0000000..d3bac77
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/CodeGen.c
@@ -0,0 +1,2437 @@
+#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/COptimizer.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/Coloring.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/DumpIR.h"
+#include "compiler/Exceptions.h"
+#include "compiler/InlineAsmPPC.h"
+#include "compiler/Intrinsics.h"
+#include "compiler/InstrSelection.h"
+#include "compiler/GlobalOptimizer.h"
+#include "compiler/ObjGenMachO.h"
+#include "compiler/Operands.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeAssembly.h"
+#include "compiler/PCodeInfo.h"
+#include "compiler/PCodeListing.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/Peephole.h"
+#include "compiler/PPCError.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/Scheduler.h"
+#include "compiler/StackFrame.h"
+#include "compiler/Switch.h"
+#include "compiler/TOC.h"
+#include "compiler/ValueNumbering.h"
+#include "compiler/enode.h"
+#include "compiler/objc.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/tokens.h"
+#include "compiler/types.h"
+
+static Macro powcM;
+static Macro __powcM;
+static Macro ppc_cpu;
+static Macro profM;
+static Macro hostM;
+static Macro bendM;
+static Macro _ppc_M;
+static Macro longI;
+static Macro IEEED;
+Macro vecM;
+Macro altivecM;
+static Macro macM2;
+static Macro appleM;
+static Macro optM;
+static Macro alignM;
+static Macro _machM;
+static Macro archM;
+static Macro dynM;
+static Macro ppcM;
+Object *gFunction;
+static ObjectList *temps;
+CLabel *returnlabel;
+CLabel *cleanreturnlabel;
+Boolean needs_cleanup;
+Statement *current_statement;
+int has_catch_blocks;
+int disable_optimizer;
+SInt32 current_linenumber;
+Boolean has_altivec_arrays;
+short high_reg;
+short low_reg;
+short high_offset;
+short low_offset;
+short low_reg2;
+short high_reg2;
+PCodeLabel *pic_base_pcodelabel;
+Object *dyld_stub_binding_helper;
+Object *rt_cvt_fp2unsigned;
+Object *rt_profile_entry;
+Object *rt_profile_exit;
+Object *rt_div2i;
+Object *rt_div2u;
+Object *rt_mod2i;
+Object *rt_mod2u;
+Object *rt_shr2i;
+Object *rt_shr2u;
+Object *rt_shl2i;
+Object *rt_cvt_ull_dbl;
+Object *rt_cvt_sll_dbl;
+Object *rt_cvt_ull_flt;
+Object *rt_cvt_sll_flt;
+Object *rt_cvt_dbl_usll;
+static heaperror_t saveheaperror;
+
+enum {
+ GPRLimit = 10,
+ FPRLimit = 13,
+ VRLimit = 13
+};
+
+// forward decls
+static void CodeGen_heaperror(void);
+
+VarInfo *CodeGen_GetNewVarInfo(void) {
+ VarInfo *vi;
+
+ vi = lalloc(sizeof(VarInfo));
+ memclrw(vi, sizeof(VarInfo));
+
+ vi->deftoken = *CPrep_CurStreamElement();
+ vi->varnumber = localcount++;
+
+ return vi;
+}
+
+Object *maketemporary(Type *type) {
+ ObjectList *list;
+ Object *obj;
+
+ for (list = temps; list; list = list->next) {
+ obj = list->object;
+ if (obj->u.var.uid == 0 && obj->type == type) {
+ obj->u.var.uid = 1;
+ return obj;
+ }
+ }
+
+ obj = lalloc(sizeof(Object));
+ memclrw(obj, sizeof(Object));
+ obj->otype = OT_OBJECT;
+ obj->access = ACCESSPUBLIC;
+ obj->datatype = DLOCAL;
+ obj->type = type;
+ obj->name = CParser_GetUniqueName();
+ obj->u.var.info = CodeGen_GetNewVarInfo();
+ obj->u.var.uid = 1;
+
+ list = lalloc(sizeof(ObjectList));
+ memclrw(list, sizeof(ObjectList));
+ list->next = temps;
+ list->object = obj;
+ temps = list;
+
+ return obj;
+}
+
+static void free_temporaries(void) {
+ ObjectList *list;
+
+ for (list = temps; list; list = list->next)
+ list->object->u.var.uid = 0;
+}
+
+static void allocate_temporaries(void) {
+ ObjectList *list;
+
+ for (list = temps; list; list = list->next)
+ assign_local_memory(list->object);
+}
+
+void process_arguments(ArgumentProcessor func, Boolean flag) {
+ short gpr = 3;
+ short fpr = 1;
+ short vr = 2;
+ Type *type;
+ ObjectList *list;
+
+ for (list = arguments; list; list = list->next) {
+ type = list->object->type;
+ if (IS_TYPE_FLOAT(type)) {
+ func(list->object, (fpr <= FPRLimit) ? fpr : 0);
+ fpr++;
+ if (type->size == 4)
+ gpr++;
+ else
+ gpr += 2;
+ } else if (IS_TYPE_VECTOR(type)) {
+ func(list->object, (vr <= VRLimit) ? vr : 0);
+ vr++;
+ if (flag) {
+ if ((vr - 1) == 2)
+ gpr = 9;
+ else if ((vr - 1) > 2)
+ gpr = 11;
+ }
+ } else {
+ func(list->object, (gpr <= GPRLimit) ? gpr : 0);
+ if (TYPE_FITS_IN_REGISTER(type)) {
+ if (type->size <= 4)
+ gpr += 1;
+ else
+ gpr += 2;
+ } else {
+ gpr += (type->size >> 2);
+ if (type->size & 3)
+ gpr++;
+ }
+ }
+ }
+
+ last_argument_register[RegClass_GPR] = gpr - 1;
+ last_argument_register[RegClass_FPR] = fpr - 1;
+ last_argument_register[RegClass_VR] = vr - 1;
+ if (flag)
+ move_varargs_to_memory();
+}
+
+static void retain_argument_register(Object *obj, short reg) {
+ VarInfo *vi = Registers_GetVarInfo(obj);
+ Type *type = obj->type;
+
+ if (reg && !vi->noregister && vi->used) {
+ if (TYPE_FITS_IN_REGISTER(type)) {
+ if (type->size <= 4) {
+ retain_register(obj, RegClass_GPR, reg);
+ } else if (reg < GPRLimit) {
+ if (copts.littleendian)
+ retain_GPR_pair(obj, reg, reg + 1);
+ else
+ retain_GPR_pair(obj, reg + 1, reg);
+ }
+ } else if (IS_TYPE_FLOAT(type)) {
+ retain_register(obj, RegClass_FPR, reg);
+ } else if (IS_TYPE_VECTOR(type)) {
+ retain_register(obj, RegClass_VR, reg);
+ }
+ }
+}
+
+static void allocate_local_vregs(void) {
+ ObjectList *list;
+ Object *obj;
+ VarInfo *vi;
+
+ if (copts.codegen_pic && uses_globals && assignable_registers[RegClass_GPR]) {
+ if (assignable_registers[RegClass_GPR]) {
+ vi = pic_base.u.var.info;
+ vi->reg = 0;
+ assign_register_by_type(&pic_base);
+ pic_base_reg = vi->reg;
+ CError_ASSERT(497, pic_base_reg);
+ } else {
+ CError_FATAL(500);
+ }
+ } else {
+ pic_base_reg = 0;
+ }
+
+ for (list = exceptionlist; list; list = list->next) {
+ obj = list->object;
+ vi = Registers_GetVarInfo(obj);
+
+ if (vi->used && !vi->noregister) {
+ if (!OBJ_GET_TARGET_VOLATILE(obj) && !vi->reg)
+ assign_register_by_type(obj);
+ }
+ }
+
+ set_last_exception_registers();
+
+ for (list = arguments; list; list = list->next) {
+ obj = list->object;
+ vi = Registers_GetVarInfo(obj);
+
+ if (vi->used && !vi->noregister) {
+ if (!OBJ_GET_TARGET_VOLATILE(obj) && !vi->reg)
+ assign_register_by_type(obj);
+ }
+ }
+
+ for (list = locals; list; list = list->next) {
+ obj = list->object;
+ if (!IsTempName(obj->name)) {
+ vi = Registers_GetVarInfo(obj);
+
+ if (vi->used && !vi->noregister) {
+ if (!OBJ_GET_TARGET_VOLATILE(obj) && !vi->reg)
+ assign_register_by_type(obj);
+ }
+ }
+ }
+
+ open_fe_temp_registers();
+
+ for (list = locals; list; list = list->next) {
+ obj = list->object;
+ if (IsTempName(obj->name)) {
+ vi = Registers_GetVarInfo(obj);
+
+ if (vi->used && !vi->noregister) {
+ if (!OBJ_GET_TARGET_VOLATILE(obj) && !vi->reg)
+ assign_register_by_type(obj);
+ }
+ }
+ }
+
+ for (list = toclist; list; list = list->next) {
+ obj = list->object;
+ vi = Registers_GetVarInfo(obj);
+
+ if (!vi->reg && vi->used && vi->usage > 1)
+ assign_register_by_type(obj);
+ }
+}
+
+static void allocate_local_GPRs(void) {
+ ObjectList *list;
+ Object *obj;
+ Object *winning_obj;
+ SInt32 winning_usage;
+ VarInfo *vi;
+ Type *type;
+
+ if (copts.codegen_pic && uses_globals && assignable_registers[RegClass_GPR]) {
+ vi = pic_base.u.var.info;
+ vi->reg = 0;
+ assign_register_by_type(&pic_base);
+ pic_base_reg = vi->reg;
+ CError_ASSERT(605, pic_base_reg);
+ } else {
+ pic_base_reg = 0;
+ }
+
+ while (assignable_registers[RegClass_GPR]) {
+ winning_obj = NULL;
+ winning_usage = -1;
+ if (!(disable_optimizer & 2)) {
+ for (list = arguments; list; list = list->next) {
+ obj = list->object;
+ vi = Registers_GetVarInfo(obj);
+ type = obj->type;
+ if (vi->flags & VarInfoFlag40)
+ vi->usage = 100000;
+ if (!vi->reg && vi->used && !vi->noregister) {
+ if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) {
+ if (TYPE_FITS_IN_REGISTER(type) && (!TYPE_IS_8BYTES(type) || assignable_registers[RegClass_GPR] >= 2)) {
+ winning_obj = obj;
+ winning_usage = vi->usage;
+ }
+ }
+ }
+ }
+ }
+ if (!(disable_optimizer & 2)) {
+ for (list = locals; list; list = list->next) {
+ obj = list->object;
+ vi = Registers_GetVarInfo(obj);
+ type = obj->type;
+ if (vi->flags & VarInfoFlag40)
+ vi->usage = 100000;
+ if (!vi->reg && vi->used && !vi->noregister) {
+ if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) {
+ if (TYPE_FITS_IN_REGISTER(type) && (!TYPE_IS_8BYTES(type) || assignable_registers[RegClass_GPR] >= 2)) {
+ winning_obj = obj;
+ winning_usage = vi->usage;
+ }
+ }
+ }
+ }
+ }
+ for (list = toclist; list; list = list->next) {
+ obj = list->object;
+ vi = Registers_GetVarInfo(obj);
+ if (vi->flags & VarInfoFlag40)
+ vi->usage = 100000;
+ if (!vi->reg && vi->used) {
+ if (vi->usage >= winning_usage && vi->usage >= 3) {
+ winning_obj = obj;
+ winning_usage = vi->usage;
+ }
+ }
+ }
+
+ if (!winning_obj)
+ break;
+
+ assign_register_by_type(winning_obj);
+ CError_ASSERT(698, Registers_GetVarInfo(winning_obj)->flags & VarInfoFlag2);
+ }
+}
+
+static void allocate_local_FPRs(void) {
+ ObjectList *list;
+ Object *obj;
+ Object *winning_obj;
+ SInt32 winning_usage;
+ VarInfo *vi;
+ Type *type;
+
+ while (assignable_registers[RegClass_FPR]) {
+ winning_obj = NULL;
+ winning_usage = -1;
+ if (!(disable_optimizer & 2)) {
+ for (list = arguments; list; list = list->next) {
+ obj = list->object;
+ type = obj->type;
+ vi = Registers_GetVarInfo(obj);
+ if (vi->flags & VarInfoFlag40)
+ vi->usage = 100000;
+ if (!vi->reg && vi->used && !vi->noregister) {
+ if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) {
+ if (IS_TYPE_FLOAT(type)) {
+ winning_obj = obj;
+ winning_usage = vi->usage;
+ }
+ }
+ }
+ }
+ }
+ if (!(disable_optimizer & 2)) {
+ for (list = locals; list; list = list->next) {
+ obj = list->object;
+ vi = Registers_GetVarInfo(obj);
+ if (vi->flags & VarInfoFlag40)
+ vi->usage = 100000;
+ if (!vi->reg && vi->used && !vi->noregister) {
+ if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) {
+ if (IS_TYPE_FLOAT(obj->type)) {
+ winning_obj = obj;
+ winning_usage = vi->usage;
+ }
+ }
+ }
+ }
+ }
+
+ if (!winning_obj)
+ break;
+
+ assign_register_by_type(winning_obj);
+ CError_ASSERT(782, Registers_GetVarInfo(winning_obj)->flags & VarInfoFlag2);
+ }
+}
+
+static void allocate_local_VRs(void) {
+ ObjectList *list;
+ Object *obj;
+ Object *winning_obj;
+ SInt32 winning_usage;
+ VarInfo *vi;
+
+ while (assignable_registers[RegClass_VR]) {
+ winning_obj = NULL;
+ winning_usage = -1;
+ if (!(disable_optimizer & 2)) {
+ for (list = arguments; list; list = list->next) {
+ obj = list->object;
+ vi = Registers_GetVarInfo(obj);
+ if (vi->flags & VarInfoFlag40)
+ vi->usage = 100000;
+ if (!vi->reg && vi->used && !vi->noregister) {
+ if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) {
+ if (IS_TYPE_VECTOR(obj->type)) {
+ winning_obj = obj;
+ winning_usage = vi->usage;
+ }
+ }
+ }
+ }
+ }
+ if (!(disable_optimizer & 2)) {
+ for (list = locals; list; list = list->next) {
+ obj = list->object;
+ vi = Registers_GetVarInfo(obj);
+ if (vi->flags & VarInfoFlag40)
+ vi->usage = 100000;
+ if (!vi->reg && vi->used && !vi->noregister) {
+ if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) {
+ if (IS_TYPE_VECTOR(obj->type)) {
+ winning_obj = obj;
+ winning_usage = vi->usage;
+ }
+ }
+ }
+ }
+ }
+
+ if (!winning_obj)
+ break;
+
+ assign_register_by_type(winning_obj);
+ CError_ASSERT(846, Registers_GetVarInfo(winning_obj)->flags & VarInfoFlag2);
+ }
+}
+
+static void allocate_locals(void) {
+ has_altivec_arrays = 0;
+
+ if (!requires_frame && !optimizing)
+ process_arguments(retain_argument_register, 0);
+
+ if (optimizing) {
+ allocate_local_vregs();
+ } else {
+ allocate_local_GPRs();
+ allocate_local_FPRs();
+ allocate_local_VRs();
+ }
+
+ assign_locals_to_memory(locals);
+}
+
+void move_assigned_argument(Object *obj, short reg) {
+ VarInfo *vi;
+ Type *type;
+ SInt32 bytesLeft;
+ SInt32 offset;
+
+ vi = Registers_GetVarInfo(obj);
+ type = obj->type;
+ CError_ASSERT(901, obj->datatype == DLOCAL);
+
+ if (!vi->used)
+ return;
+
+ if (reg) {
+ if (vi->reg) {
+ if (TYPE_IS_8BYTES(type)) {
+ if (copts.littleendian) {
+ if (vi->reg != reg)
+ emitpcode(PC_MR, vi->reg, reg);
+ if (reg < GPRLimit) {
+ CError_FAIL(916, (vi->regHi == reg) || (vi->reg == (reg + 1)));
+ if (vi->regHi != (reg + 1))
+ emitpcode(PC_MR, vi->regHi, reg + 1);
+ } else {
+ load_store_register(PC_LWZ, vi->regHi, local_base_register(obj), obj, high_offset);
+ }
+ } else {
+ if (vi->regHi != reg)
+ emitpcode(PC_MR, vi->regHi, reg);
+ if (reg < GPRLimit) {
+ CError_FAIL(931, (vi->reg == reg) || (vi->regHi == (reg + 1)));
+ if (vi->reg != (reg + 1))
+ emitpcode(PC_MR, vi->reg, reg + 1);
+ } else {
+ load_store_register(PC_LWZ, vi->reg, local_base_register(obj), obj, low_offset);
+ }
+ }
+ } else if (vi->reg != reg) {
+ if (IS_TYPE_FLOAT(type)) {
+ emitpcode(PC_FMR, vi->reg, reg);
+ } else if (IS_TYPE_VECTOR(type)) {
+ emitpcode(PC_VMR, vi->reg, reg);
+ } else {
+ emitpcode(PC_MR, vi->reg, reg);
+ }
+ }
+ } else {
+ if (IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type)) {
+ load_store_register(PC_STW, reg, local_base_register(obj), obj, 0);
+ } else if (IS_TYPE_INT(type) || IS_TYPE_ENUM(type)) {
+ switch (type->size) {
+ case 1:
+ load_store_register(PC_STB, reg, local_base_register(obj), obj, 0);
+ break;
+ case 2:
+ load_store_register(PC_STH, reg, local_base_register(obj), obj, 0);
+ break;
+ case 4:
+ load_store_register(PC_STW, reg, local_base_register(obj), obj, 0);
+ break;
+ case 8:
+ load_store_register(PC_STW, reg, local_base_register(obj), obj, 0);
+ if (reg < GPRLimit)
+ load_store_register(PC_STW, reg + 1, local_base_register(obj), obj, 4);
+ break;
+ default:
+ CError_FATAL(993);
+ }
+ } else if (IS_TYPE_FLOAT(type)) {
+ load_store_register((type->size == 4) ? PC_STFS : PC_STFD, reg, local_base_register(obj), obj, 0);
+ } else if (IS_TYPE_VECTOR(type)) {
+ load_store_register(PC_STVX, reg, local_base_register(obj), obj, 0);
+ } else {
+ bytesLeft = (11 - reg) * 4;
+ if (bytesLeft > obj->type->size)
+ bytesLeft = obj->type->size;
+ offset = 0;
+ while (bytesLeft > 0) {
+ load_store_register(PC_STW, reg, local_base_register(obj), obj, offset);
+ reg++;
+ offset += 4;
+ bytesLeft -= 4;
+ }
+ }
+ }
+ } else {
+ if (vi->reg) {
+ if (IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type)) {
+ load_store_register(PC_LWZ, vi->reg, local_base_register(obj), obj, 0);
+ } else if (IS_TYPE_FLOAT(type)) {
+ load_store_register((type->size == 4) ? PC_LFS : PC_LFD, vi->reg, local_base_register(obj), obj, 0);
+ } else if (IS_TYPE_VECTOR(type)) {
+ load_store_register(PC_LVX, vi->reg, local_base_register(obj), obj, 0);
+ } else {
+ switch (type->size) {
+ case 1:
+ load_store_register(PC_LBZ, vi->reg, local_base_register(obj), obj, 0);
+ break;
+ case 2:
+ load_store_register(is_unsigned(type) ? PC_LHZ : PC_LHA, vi->reg, local_base_register(obj), obj, 0);
+ break;
+ case 4:
+ load_store_register(PC_LWZ, vi->reg, local_base_register(obj), obj, 0);
+ break;
+ case 8:
+ load_store_register(PC_LWZ, vi->regHi, local_base_register(obj), obj, high_offset);
+ load_store_register(PC_LWZ, vi->reg, local_base_register(obj), obj, low_offset);
+ break;
+ default:
+ CError_FATAL(1095);
+ }
+ }
+ } else if (!optimizing) {
+ local_base_register(obj);
+ }
+ }
+}
+
+static void load_TOC_pointers(void) {
+ VarInfo *vi;
+ 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, pic_base_pcodelabel);
+ pcsetlinkbit(pc);
+ pcsetsideeffects(pc);
+ appendpcode(pclastblock, pc);
+ pcbranch(pclastblock, pic_base_pcodelabel);
+ makepcblock();
+ pclabel(pclastblock, pic_base_pcodelabel);
+ emitpcode(PC_MFLR, pic_base_reg);
+ }
+
+ 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:
+ CError_FATAL(1206);
+ }
+ }
+ }
+}
+
+static int has_vararglist(Object *funcobj) {
+ FuncArg *arg;
+
+ arg = TYPE_FUNC(funcobj->type)->args;
+ while (arg && arg != &elipsis)
+ arg = arg->next;
+
+ return (arg == &elipsis);
+}
+
+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) {
+ for (stmt = stmt->next; stmt; stmt = stmt->next) {
+ if (stmt->type > ST_LABEL)
+ return 0;
+ }
+ return 1;
+}
+
+static void newstatement(SInt32 sourceoffset, SInt32 value, int flag) {
+ PCodeBlock *block = pclastblock;
+
+ pcloopweight = value;
+ if (!block->pcodeCount)
+ block->loopWeight = value;
+
+ if (block->pcodeCount > 100)
+ branch_label(makepclabel());
+
+ if (flag)
+ block->flags |= fPCBlockFlag4000;
+}
+
+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);
+ CError_ASSERT(1397, 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());
+ CError_ASSERT(1568, 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;
+
+ CError_ASSERT(1595, 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;
+ SInt32 size;
+
+ CodeGen_InitialSanityCheck();
+ if (!saveheaperror) {
+ saveheaperror = getheaperror();
+ setheaperror(CodeGen_heaperror);
+ }
+
+ if (cparamblkptr->precompile == 1)
+ CError_Error(CErrorStr180);
+
+ if (!func) {
+ func = createstaticinitobject();
+ } else {
+#ifdef CW_CLT
+ if (func && func->name)
+ PrintProgressFunction(func->name->name);
+#endif
+ }
+
+ 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->next);
+ if (copts.debuglisting)
+ DumpIR(statements, func);
+
+ if (copts.profile) {
+ makes_call = 1;
+ requires_frame = 1;
+ }
+
+ initpcode();
+
+ pclabel(prologue = makepcblock(), makepclabel());
+ prologue->flags |= fIsProlog;
+
+ 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_factor || copts.altivec_model)
+ branch_label(makepclabel());
+
+ load_TOC_pointers();
+
+ if (copts.profile)
+ callprofiler(CMangler_GetLinkName(func)->name);
+
+ assign_labels(statements->next);
+ open_temp_registers();
+
+ for (stmt = statements->next; 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, (SwitchInfo *) stmt->label);
+ break;
+ case ST_BEGINCATCH:
+ capturestackpointer(stmt->expr->data.objref);
+ break;
+ case ST_ENDCATCHDTOR:
+ CError_ASSERT(2056, stmt->expr->data.objref->datatype == DLOCAL);
+ add_immediate(3, local_base_register(stmt->expr->data.objref), stmt->expr->data.objref, 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) {
+ if (((InlineAsm *) stmt->expr)->flags & IAFlag1) {
+ CError_FATAL(2076);
+ } else {
+ branch_label(makepclabel());
+ InlineAsm_TranslateIRtoPCode(stmt);
+ }
+ }
+ break;
+ case ST_BEGINLOOP:
+ CError_FATAL(2086);
+ break;
+ case ST_ENDLOOP:
+ CError_FATAL(2090);
+ break;
+ default:
+ CError_FATAL(2094);
+ }
+ check_temp_registers();
+ }
+
+ close_temp_registers();
+ labelstatement(returnlabel);
+
+ current_statement = NULL;
+
+ epilogue = pclastblock;
+ pclastblock->flags |= fIsEpilogue;
+
+ 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_factor == 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_factor == 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_factor) {
+ 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_factor) {
+ 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.filesyminfo;
+ save_peephole = copts.peephole;
+ save_traceback = copts.traceback;
+
+ CodeGen_InitialSanityCheck();
+ CError_ASSERT(2270, 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.filesyminfo = 0;
+ copts.peephole = 0;
+ copts.traceback = 0;
+ assemblefunction(thunkobj, NULL);
+ copts.filesyminfo = 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();
+}
+
+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();
+ return 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.filesyminfo;
+ save_peephole = copts.peephole;
+ save_traceback = copts.traceback;
+
+ CodeGen_InitialSanityCheck();
+ memclrw(&opnd, sizeof(Operand));
+ CError_ASSERT(2528, 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) {
+ CError_FATAL(2562);
+ } 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.filesyminfo = 0;
+ copts.peephole = 0;
+ copts.traceback = 0;
+ assemblefunction(a, NULL);
+ copts.filesyminfo = 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(CErrorStr176);
+ }
+}
+
+static void CodeGen_EOLCheck(void) {
+ short t;
+
+ if (plex() != TK_EOL) {
+ CPrep_Error(CErrorStr113);
+ do {
+ t = plex();
+ } while (t != TK_EOL && t != 0);
+ }
+}
+
+static void schedule_for(int what) {
+ CPrep_PushOption(OPT_OFFSET(scheduling), what);
+ if (copts.schedule_factor == 0)
+ CPrep_PushOption(OPT_OFFSET(schedule_factor), 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(scheduling));
+ CPrep_PopOption(OPT_OFFSET(schedule_factor));
+ return;
+ } else if (!strcmp(tkidentifier->name, "off")) {
+ CPrep_PushOption(OPT_OFFSET(schedule_factor), 0);
+ return;
+ } else if (!strcmp(tkidentifier->name, "once")) {
+ CPrep_PushOption(OPT_OFFSET(schedule_factor), 1);
+ return;
+ } else if (!strcmp(tkidentifier->name, "twice")) {
+ CPrep_PushOption(OPT_OFFSET(schedule_factor), 2);
+ return;
+ } else if (!strcmp(tkidentifier->name, "on")) {
+ CPrep_PushOption(OPT_OFFSET(schedule_factor), 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(PPCErrorStr115);
+ return;
+ }
+ CPrep_Error(CErrorStr186);
+ 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(CErrorStr186);
+ return;
+ }
+ schedule_for(cpu);
+ return;
+ }
+
+ if (copts.warn_illpragma)
+ CPrep_Warning(CErrorStr186);
+}
+
+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(CErrorStr154);
+ 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(CErrorStr186);
+ return 0;
+ } else {
+ if (copts.warn_illpragma)
+ CPrep_Warning(CErrorStr186);
+ }
+
+ 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(CErrorStr186);
+ }
+ } 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(CErrorStr186);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr186);
+ }
+ 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.unroll_speculative = 0;
+ } else if (!strcmp(tkidentifier->name, "on")) {
+ copts.unroll_speculative = 1;
+ } else {
+ CError_Error(CErrorStr186);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr186);
+ }
+ CodeGen_EOLCheck();
+ return;
+ }
+
+ if (!strcmp(name->name, "ppc_unroll_instructions_limit")) {
+ t = plex();
+ if (t == TK_INTCONST) {
+ copts.unroll_instr_limit = CInt64_GetULong(&tkintconst);
+ if (copts.unroll_instr_limit < 0) {
+ copts.unroll_instr_limit = 0;
+ CError_Error(CErrorStr186);
+ }
+ } else if (t == TK_IDENTIFIER) {
+ if (!strcmp(tkidentifier->name, "off")) {
+ copts.unroll_instr_limit = 0;
+ } else if (!strcmp(tkidentifier->name, "on")) {
+ copts.unroll_instr_limit = 70;
+ } else {
+ CError_Error(CErrorStr186);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr186);
+ }
+ 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(CErrorStr186);
+ } else if (value > 255) {
+ copts.gen_fsel = 255;
+ CError_Error(CErrorStr186);
+ } 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(CErrorStr186);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr186);
+ }
+ CodeGen_EOLCheck();
+ return;
+ }
+
+ if (!strcmp(name->name, "ppc_unroll_factor_limit")) {
+ t = plex();
+ if (t == TK_INTCONST) {
+ copts.unroll_factor_limit = CInt64_GetULong(&tkintconst);
+ if (copts.unroll_factor_limit < 0) {
+ copts.unroll_factor_limit = 0;
+ CError_Error(CErrorStr186);
+ }
+ } else if (t == TK_IDENTIFIER) {
+ if (!strcmp(tkidentifier->name, "off")) {
+ copts.unroll_factor_limit = 0;
+ } else if (!strcmp(tkidentifier->name, "on")) {
+ copts.unroll_factor_limit = 10;
+ } else {
+ CError_Error(CErrorStr186);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr186);
+ }
+ 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(CErrorStr186);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr186);
+ }
+ 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(CErrorStr186);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr186);
+ }
+ 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(function_align), value);
+ break;
+ default:
+ PPCError_Warning(PPCErrorStr161);
+ CodeGen_EOLCheck();
+ return;
+ }
+ } else if (t == TK_IDENTIFIER && !strcmp(tkidentifier->name, "reset")) {
+ CPrep_PopOption(OPT_OFFSET(function_align));
+ } else {
+ PPCError_Warning(PPCErrorStr161);
+ }
+ CodeGen_EOLCheck();
+ return;
+ }
+
+ if (!strcmp(name->name, "processor")) {
+ if (cscope_currentfunc) {
+ PPCError_Warning(PPCErrorStr156, "pragma processor");
+ return;
+ }
+ t = plex();
+ if (t == TK_INTCONST) {
+ switch (CInt64_GetULong(&tkintconst)) {
+ case 401:
+ copts.processor = 0;
+ break;
+ case 403:
+ copts.processor = 1;
+ break;
+ case 505:
+ copts.processor = 2;
+ break;
+ case 509:
+ copts.processor = 3;
+ break;
+ case 555:
+ copts.processor = 4;
+ break;
+ case 556:
+ copts.processor = 25;
+ break;
+ case 565:
+ copts.processor = 26;
+ break;
+ case 601:
+ copts.processor = 5;
+ break;
+ case 602:
+ copts.processor = 6;
+ break;
+ case 8240:
+ copts.processor = 18;
+ break;
+ case 8260:
+ copts.processor = 19;
+ break;
+ case 603:
+ copts.processor = 7;
+ break;
+ case 604:
+ copts.processor = 9;
+ break;
+ case 740:
+ copts.processor = 11;
+ break;
+ case 750:
+ copts.processor = 12;
+ break;
+ case 801:
+ copts.processor = 13;
+ break;
+ case 821:
+ copts.processor = 14;
+ break;
+ case 823:
+ copts.processor = 15;
+ break;
+ case 850:
+ copts.processor = 16;
+ break;
+ case 860:
+ copts.processor = 17;
+ break;
+ case 7400:
+ copts.processor = 21;
+ break;
+ default:
+ PPCError_Warning(PPCErrorStr208);
+ CodeGen_EOLCheck();
+ return;
+ }
+ } else if (t == TK_IDENTIFIER) {
+ if (!strcmp(tkidentifier->name, "generic"))
+ copts.processor = 20;
+ else if (!strcmp(tkidentifier->name, "603e"))
+ copts.processor = 8;
+ else if (!strcmp(tkidentifier->name, "604e"))
+ copts.processor = 10;
+ else if (!strcmp(tkidentifier->name, "PPC603e"))
+ copts.processor = 8;
+ else if (!strcmp(tkidentifier->name, "PPC604e"))
+ copts.processor = 10;
+ else
+ PPCError_Warning(PPCErrorStr208);
+ } else {
+ PPCError_Warning(PPCErrorStr208);
+ }
+
+ 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(min_struct_alignment), value);
+ break;
+ default:
+ PPCError_Warning(PPCErrorStr191);
+ CodeGen_EOLCheck();
+ return;
+ }
+ } else if (t == TK_IDENTIFIER) {
+ if (!strcmp(tkidentifier->name, "reset"))
+ CPrep_PopOption(OPT_OFFSET(min_struct_alignment));
+ else if (!strcmp(tkidentifier->name, "on"))
+ CPrep_PushOption(OPT_OFFSET(min_struct_alignment), 4);
+ else if (!strcmp(tkidentifier->name, "off"))
+ CPrep_PushOption(OPT_OFFSET(min_struct_alignment), 1);
+ } else {
+ PPCError_Warning(PPCErrorStr161);
+ }
+
+ 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(CErrorStr186);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr186);
+ }
+
+ 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(CErrorStr186);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr186);
+ }
+
+ 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(PPCErrorStr189);
+ copts.codegen_pic = 0;
+ }
+ } else {
+ CError_Error(CErrorStr186);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr186);
+ }
+
+ 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(CErrorStr186);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr186);
+ }
+
+ 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(CErrorStr186);
+ return;
+ }
+ } else {
+ CError_Error(CErrorStr186);
+ }
+
+ 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(CErrorStr186);
+ }
+
+ CodeGen_EOLCheck();
+ return;
+ }
+
+ if (copts.warn_illpragma)
+ CPrep_Warning(CErrorStr186);
+
+ if (plex() != TK_EOL) {
+ do {
+ t = plex();
+ } while (t != TK_EOL && 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.globaloptimizer = 1;
+}
+
+SInt32 CodeGen_objc_method_self_offset(ObjCMethod *meth) {
+ SInt32 size;
+
+ if (!meth->return_type) {
+ size = 4;
+ } else if (
+ IS_TYPE_ARRAY(meth->return_type) ||
+ IS_TYPE_NONVECTOR_STRUCT(meth->return_type) ||
+ IS_TYPE_CLASS(meth->return_type) ||
+ IS_TYPE_12BYTES_MEMBERPOINTER(meth->return_type)
+ )
+ {
+ size = 8;
+ } else {
+ size = meth->return_type->size;
+ }
+
+ if (size == 0)
+ size = 1;
+
+ return (size + 3) & ~3;
+}
+
+SInt32 CodeGen_objc_method_sel_offset(ObjCMethod *meth) {
+ return (CodeGen_objc_method_self_offset(meth) + 7) & ~3;
+}
+
+SInt32 CodeGen_objc_method_arg_offset(ObjCMethod *meth, ObjCMethodArg *arg) {
+ SInt32 pos;
+ ObjCMethodArg *scan;
+
+ pos = CodeGen_objc_method_sel_offset(meth) + 4;
+ for (scan = meth->selector_args; scan; scan = scan->next) {
+ if (scan == arg)
+ return pos;
+
+ if (scan->type == NULL)
+ pos += 4;
+ else
+ pos += scan->type->size;
+
+ pos = (pos + 3) & ~3;
+ }
+
+ return 0;
+}
+
+SInt32 CodeGen_objc_method_args_size(ObjCMethod *meth) {
+ SInt32 size;
+ ObjCMethodArg *scan;
+
+ size = CodeGen_objc_method_self_offset(meth);
+ for (scan = meth->selector_args; scan; scan = scan->next) {
+ if (scan->next == NULL && scan->type == NULL)
+ return size;
+
+ size = (size + 3) & ~3;
+ if (scan->type == NULL)
+ size += 4;
+ else
+ size += scan->type->size;
+ }
+
+ return size;
+}
+
+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_VECTOR_UCHAR:
+ case STRUCT_VECTOR_SCHAR:
+ case STRUCT_VECTOR_BCHAR:
+ case STRUCT_VECTOR_USHORT:
+ case STRUCT_VECTOR_SSHORT:
+ case STRUCT_VECTOR_BSHORT:
+ case STRUCT_VECTOR_UINT:
+ case STRUCT_VECTOR_SINT:
+ case STRUCT_VECTOR_BINT:
+ case STRUCT_VECTOR_FLOAT:
+ case STRUCT_VECTOR_PIXEL:
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = type;
+ expr->flags = flags;
+ return expr;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+short CodeGen_AssignCheck(const ENode *expr, const Type *type, Boolean flag1, Boolean flag2) {
+ short result;
+ const 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_VECTOR_UCHAR:
+ case STRUCT_VECTOR_SCHAR:
+ case STRUCT_VECTOR_BCHAR:
+ if (i < 15) {
+ PPCError_Error(PPCErrorStr110, type, 0);
+ } else if (i > 15) {
+ PPCError_Error(PPCErrorStr111, 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(PPCErrorStr112);
+ break;
+ }
+
+ if (copts.pedantic) {
+ if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_UCHAR) {
+ if (!CInt64_IsInURange(v, 1))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ } else {
+ if (!CInt64_IsInRange(v, 1))
+ PPCError_Warning(PPCErrorStr113, 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_VECTOR_UCHAR) {
+ if (!CInt64_IsInURange(v, 1))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ } else {
+ if (!CInt64_IsInRange(v, 1))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ }
+ }
+ vec->uc[0] = (UInt8) v.lo;
+ } else {
+ PPCError_Error(PPCErrorStr112);
+ break;
+ }
+ result = 1;
+ }
+ break;
+
+ case STRUCT_VECTOR_USHORT:
+ case STRUCT_VECTOR_SSHORT:
+ case STRUCT_VECTOR_BSHORT:
+ case STRUCT_VECTOR_PIXEL:
+ if (i < 7) {
+ PPCError_Error(PPCErrorStr110, type, 0);
+ } else if (i > 7) {
+ PPCError_Error(PPCErrorStr111, 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(PPCErrorStr112);
+ break;
+ }
+
+ if (copts.pedantic) {
+ if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_USHORT || TYPE_STRUCT(type)->stype == STRUCT_VECTOR_PIXEL) {
+ if (!CInt64_IsInURange(v, 2))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ } else {
+ if (!CInt64_IsInRange(v, 2))
+ PPCError_Warning(PPCErrorStr113, 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_VECTOR_USHORT || TYPE_STRUCT(type)->stype == STRUCT_VECTOR_PIXEL) {
+ if (!CInt64_IsInURange(v, 2))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ } else {
+ if (!CInt64_IsInRange(v, 2))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ }
+ }
+ vec->us[0] = (UInt16) v.lo;
+ } else {
+ PPCError_Error(PPCErrorStr112);
+ break;
+ }
+ result = 1;
+ }
+ break;
+
+ case STRUCT_VECTOR_UINT:
+ case STRUCT_VECTOR_SINT:
+ case STRUCT_VECTOR_BINT:
+ if (i < 3) {
+ PPCError_Error(PPCErrorStr110, type, 0);
+ } else if (i > 3) {
+ PPCError_Error(PPCErrorStr111, 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(PPCErrorStr112);
+ break;
+ }
+
+ if (copts.pedantic) {
+ if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_UINT) {
+ if (!CInt64_IsInURange(v, 4))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ } else {
+ if (!CInt64_IsInRange(v, 4))
+ PPCError_Warning(PPCErrorStr113, 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_VECTOR_UINT) {
+ if (!CInt64_IsInURange(v, 4))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ } else {
+ if (!CInt64_IsInRange(v, 4))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ }
+ }
+ vec->ul[0] = v.lo;
+ } else {
+ PPCError_Error(PPCErrorStr112);
+ break;
+ }
+ result = 1;
+ }
+ break;
+
+ case STRUCT_VECTOR_FLOAT:
+ if (i < 3) {
+ PPCError_Error(PPCErrorStr110, type, 0);
+ } else if (i > 3) {
+ PPCError_Error(PPCErrorStr111, 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(PPCErrorStr112);
+ 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(PPCErrorStr112);
+ 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_VECTOR_UCHAR:
+ case STRUCT_VECTOR_SCHAR:
+ case STRUCT_VECTOR_BCHAR:
+ {
+ CInt64 v = expr->data.intval;
+ if (copts.pedantic) {
+ if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_UCHAR) {
+ if (!CInt64_IsInURange(v, 1))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ } else {
+ if (!CInt64_IsInRange(v, 1))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ }
+ }
+ while (i < 16)
+ vec->uc[i++] = (UInt8) v.lo;
+ result = 1;
+ break;
+ }
+ case STRUCT_VECTOR_USHORT:
+ case STRUCT_VECTOR_SSHORT:
+ case STRUCT_VECTOR_BSHORT:
+ case STRUCT_VECTOR_PIXEL:
+ {
+ CInt64 v = expr->data.intval;
+ if (copts.pedantic) {
+ if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_USHORT || TYPE_STRUCT(type)->stype == STRUCT_VECTOR_PIXEL) {
+ if (!CInt64_IsInURange(v, 2))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ } else {
+ if (!CInt64_IsInRange(v, 2))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ }
+ }
+ while (i < 8)
+ vec->us[i++] = (UInt16) v.lo;
+ result = 1;
+ break;
+ }
+ case STRUCT_VECTOR_UINT:
+ case STRUCT_VECTOR_SINT:
+ case STRUCT_VECTOR_BINT:
+ {
+ CInt64 v = expr->data.intval;
+ if (copts.pedantic) {
+ if (TYPE_STRUCT(type)->stype == STRUCT_VECTOR_UINT) {
+ if (!CInt64_IsInURange(v, 4))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ } else {
+ if (!CInt64_IsInRange(v, 4))
+ PPCError_Warning(PPCErrorStr113, type, 0);
+ }
+ }
+ while (i < 4)
+ vec->ul[i++] = v.lo;
+ result = 1;
+ break;
+ }
+ case STRUCT_VECTOR_FLOAT:
+ {
+ Float fv;
+ if (!CInt64_IsInRange(expr->data.intval, 4)) {
+ PPCError_Error(PPCErrorStr112);
+ 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(PPCErrorStr112);
+ }
+ } else if (ENODE_IS(expr, EFLOATCONST)) {
+ switch (TYPE_STRUCT(type)->stype) {
+ default:
+ PPCError_Error(PPCErrorStr112);
+ break;
+ case STRUCT_VECTOR_FLOAT:
+ {
+ 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(PPCErrorStr112);
+ } else if (!ENODE_IS(expr, EVECTOR128CONST)) {
+ PPCError_Error(PPCErrorStr112);
+ }
+
+ 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.structalignment == AlignMode2_PPC)
+ CPrep_InsertSpecialMacro(&alignM, "__NATURAL_ALIGNMENT__");
+
+ if (!copts.ANSIstrict)
+ 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.ANSIstrict && macro == &ppcM) return "1";
+ if (macro == &_ppc_M) return "1";
+
+ CError_FATAL(4801);
+ 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/BackEnd/PowerPC/CodeGenerator/Exceptions.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Exceptions.c
new file mode 100644
index 0000000..14627cf
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Exceptions.c
@@ -0,0 +1,857 @@
+#include "compiler/Exceptions.h"
+#include "compiler/CError.h"
+#include "compiler/CException.h"
+#include "compiler/CInit.h"
+#include "compiler/CFunc.h"
+#include "compiler/CParser.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/ObjGenMachO.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/StackFrame.h"
+#include "compiler/objects.h"
+
+static PCAction *pc_actions;
+static PCAction *last_pc_action;
+EANode *DAG[EAT_NACTIONS];
+static GList exceptmodule;
+static OLinkList *except_refs;
+static OLinkList *last_except_ref;
+
+static EANode *makeEAnode(ExceptionAction *ea) {
+ EANode *prev;
+ EANode *node;
+
+ for (node = DAG[ea->type]; node; node = node->dagListNext) {
+ if (node->action == ea)
+ return node;
+ }
+
+ if (ea->prev)
+ prev = makeEAnode(ea->prev);
+ else
+ prev = NULL;
+
+ for (node = DAG[ea->type]; node; node = node->dagListNext) {
+ if (node->prev == prev && CExcept_ActionCompare(node->action, ea))
+ return node;
+ }
+
+ node = lalloc(sizeof(EANode));
+ node->prev = prev;
+ node->action = ea;
+ node->count = 0;
+ node->xE = 0;
+
+ node->dagListNext = DAG[ea->type];
+ DAG[ea->type] = node;
+
+ if (prev)
+ prev->count++;
+ return node;
+}
+
+static void addrelocation(Object *obj, SInt32 offset) {
+ OLinkList *ref;
+
+ ref = lalloc(sizeof(OLinkList));
+ ref->next = NULL;
+ ref->obj = obj;
+ ref->offset = offset;
+ ref->somevalue = 0;
+ if (except_refs)
+ last_except_ref->next = ref;
+ else
+ except_refs = ref;
+ last_except_ref = ref;
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct AABC {
+ UInt8 a;
+ UInt8 b;
+ UInt16 c;
+ UInt32 d;
+} AABC;
+
+typedef struct AACC {
+ UInt8 a;
+ UInt8 b;
+ UInt32 c;
+ UInt32 d;
+} AACC;
+
+typedef struct AABBC {
+ UInt8 a;
+ UInt8 b;
+ UInt16 c;
+ UInt16 d;
+ UInt32 e;
+} AABBC;
+
+typedef struct AABCC {
+ UInt8 a;
+ UInt8 b;
+ UInt16 c;
+ UInt32 d;
+ UInt32 e;
+} AABCC;
+
+typedef struct AACCC {
+ UInt8 a;
+ UInt8 b;
+ UInt32 c;
+ UInt32 d;
+ UInt32 e;
+} AACCC;
+
+typedef struct AABBBC {
+ UInt8 a;
+ UInt8 b;
+ UInt16 c;
+ UInt16 d;
+ UInt16 e;
+ UInt32 f;
+} AABBBC;
+
+typedef struct AABBCC {
+ UInt8 a;
+ UInt8 b;
+ UInt16 c;
+ UInt16 d;
+ UInt32 e;
+ UInt32 f;
+} AABBCC;
+
+typedef struct AACCCC {
+ UInt8 a;
+ UInt8 b;
+ UInt32 c;
+ UInt32 d;
+ UInt32 e;
+ UInt32 f;
+} AACCCC;
+
+typedef struct AABCCCC {
+ UInt8 a;
+ UInt8 b;
+ UInt16 c;
+ UInt32 d;
+ UInt32 e;
+ UInt32 f;
+ UInt32 g;
+} AABCCCC;
+
+typedef struct AACCCCC {
+ UInt8 a;
+ UInt8 b;
+ UInt32 c;
+ UInt32 d;
+ UInt32 e;
+ UInt32 f;
+ UInt32 g;
+} AACCCCC;
+
+typedef struct AAB {
+ UInt8 a;
+ UInt8 b;
+ UInt16 c;
+} AAB;
+
+typedef struct AAC {
+ UInt8 a;
+ UInt8 b;
+ UInt32 c;
+} AAC;
+
+typedef struct AA {
+ UInt8 a;
+ UInt8 b;
+} AA;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void allocateactioninfo(EANode *node) {
+ ExceptionAction *ea;
+ SInt32 offset;
+ UInt32 flag26;
+ int reg;
+ int reg2;
+
+ while (node && (node->xE == 0 || node->prev == NULL)) {
+ offset = exceptmodule.size;
+ if (node->xE == 0)
+ node->xE = offset;
+
+ flag26 = node->prev ? 0 : 0x80;
+
+ ea = node->action;
+
+ switch (ea->type) {
+ case EAT_NOP:
+ CError_FATAL(146);
+ break;
+ case EAT_DESTROYLOCAL: {
+ if (local_is_16bit_offset(ea->data.destroy_local.local)) {
+ AABC e;
+ e.a = flag26 | 2;
+ e.b = 0;
+ e.c = CTool_EndianConvertWord16(local_offset_16(ea->data.destroy_local.local));
+ e.d = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_local.dtor, offset + 4);
+ } else {
+ AACC e;
+ e.a = flag26 | 0x11;
+ e.b = 0;
+ e.c = CTool_EndianConvertWord32(local_offset_32(ea->data.destroy_local.local));
+ e.d = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_local.dtor, offset + 6);
+ }
+ break;
+ }
+ case EAT_DESTROYLOCALCOND: {
+ reg = OBJECT_REG(ea->data.destroy_local_cond.cond);
+ if (
+ (reg || local_is_16bit_offset(ea->data.destroy_local_cond.cond)) &&
+ local_is_16bit_offset(ea->data.destroy_local_cond.local)
+ )
+ {
+ AABBC e;
+ e.a = flag26 | 3;
+ e.b = (reg != 0) << 7;
+ e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_local_cond.cond));
+ e.d = CTool_EndianConvertWord16(local_offset_16(ea->data.destroy_local_cond.local));
+ e.e = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_local_cond.dtor, offset + 6);
+ } else {
+ AACCC e;
+ e.a = flag26 | 0x12;
+ e.b = (reg != 0) << 7;
+ e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_local_cond.cond));
+ e.d = CTool_EndianConvertWord32(local_offset_32(ea->data.destroy_local_cond.local));
+ e.e = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_local_cond.dtor, offset + 10);
+ }
+ break;
+ }
+ case EAT_DESTROYLOCALOFFSET: {
+ if (local_is_16bit_offset(ea->data.destroy_local_offset.local)) {
+ AABC e;
+ e.a = flag26 | 2;
+ e.b = 0;
+ e.c = CTool_EndianConvertWord16(ea->data.destroy_local_offset.offset + local_offset_16(ea->data.destroy_local_offset.local));
+ e.d = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_local_offset.dtor, offset + 4);
+ } else {
+ AACC e;
+ e.a = flag26 | 0x11;
+ e.b = 0;
+ e.c = CTool_EndianConvertWord32(ea->data.destroy_local_offset.offset + local_offset_32(ea->data.destroy_local_offset.local));
+ e.d = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_local_offset.dtor, offset + 6);
+ }
+ break;
+ }
+ case EAT_DESTROYLOCALPOINTER: {
+ reg = OBJECT_REG(ea->data.destroy_local_pointer.pointer);
+ if (reg || local_is_16bit_offset(ea->data.destroy_local_pointer.pointer)) {
+ AABC e;
+ e.a = flag26 | 4;
+ e.b = (reg != 0) << 7;
+ e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_local_pointer.pointer));
+ e.d = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_local_pointer.dtor, offset + 4);
+ } else {
+ AACC e;
+ e.a = flag26 | 0x13;
+ e.b = (reg != 0) << 7;
+ e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_local_pointer.pointer));
+ e.d = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_local_pointer.dtor, offset + 6);
+ }
+ break;
+ }
+ case EAT_DESTROYLOCALARRAY: {
+ if (local_is_16bit_offset(ea->data.destroy_local_array.localarray)) {
+ AABBBC e;
+ e.a = flag26 | 5;
+ e.b = 0;
+ e.c = CTool_EndianConvertWord16(local_offset_16(ea->data.destroy_local_array.localarray));
+ e.d = CTool_EndianConvertWord16(ea->data.destroy_local_array.elements);
+ e.e = CTool_EndianConvertWord16(ea->data.destroy_local_array.element_size);
+ e.f = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_local_array.dtor, offset + 8);
+ } else {
+ AACCCC e;
+ e.a = flag26 | 0x14;
+ e.b = 0;
+ e.c = CTool_EndianConvertWord32(local_offset_32(ea->data.destroy_local_array.localarray));
+ e.d = CTool_EndianConvertWord32(ea->data.destroy_local_array.elements);
+ e.e = CTool_EndianConvertWord32(ea->data.destroy_local_array.element_size);
+ e.f = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_local_array.dtor, offset + 14);
+ }
+ break;
+ }
+ case EAT_DESTROYMEMBER: {
+ reg = OBJECT_REG(ea->data.destroy_member.objectptr);
+ if (reg || local_is_16bit_offset(ea->data.destroy_member.objectptr)) {
+ AABCC e;
+ e.a = flag26 | 7;
+ e.b = (reg != 0) << 7;
+ e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_member.objectptr));
+ e.d = CTool_EndianConvertWord32(ea->data.destroy_member.offset);
+ e.e = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_member.dtor, offset + 8);
+ } else {
+ AACCC e;
+ e.a = flag26 | 0x16;
+ e.b = (reg != 0) << 7;
+ e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_member.objectptr));
+ e.d = CTool_EndianConvertWord32(ea->data.destroy_member.offset);
+ e.e = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_member.dtor, offset + 10);
+ }
+ break;
+ }
+ case EAT_DESTROYBASE: {
+ reg = OBJECT_REG(ea->data.destroy_member.objectptr);
+ if (reg || local_is_16bit_offset(ea->data.destroy_member.objectptr)) {
+ AABCC e;
+ e.a = flag26 | 6;
+ e.b = (reg != 0) << 7;
+ e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_member.objectptr));
+ e.d = CTool_EndianConvertWord32(ea->data.destroy_member.offset);
+ e.e = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_member.dtor, offset + 8);
+ } else {
+ AACCC e;
+ e.a = flag26 | 0x15;
+ e.b = (reg != 0) << 7;
+ e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_member.objectptr));
+ e.d = CTool_EndianConvertWord32(ea->data.destroy_member.offset);
+ e.e = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_member.dtor, offset + 10);
+ }
+ break;
+ }
+ case EAT_DESTROYMEMBERCOND: {
+ reg = OBJECT_REG(ea->data.destroy_member_cond.cond);
+ reg2 = OBJECT_REG(ea->data.destroy_member_cond.objectptr);
+ if (
+ (reg || local_is_16bit_offset(ea->data.destroy_member_cond.cond)) &&
+ (reg2 || local_is_16bit_offset(ea->data.destroy_member_cond.objectptr))
+ )
+ {
+ AABBCC e;
+ e.a = flag26 | 8;
+ e.b = ((reg ? 1 : 0) << 7) | ((reg2 ? 1 : 0) << 6);
+ e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_member_cond.cond));
+ e.d = CTool_EndianConvertWord16(reg2 ? reg2 : local_offset_16(ea->data.destroy_member_cond.objectptr));
+ e.e = CTool_EndianConvertWord32(ea->data.destroy_member_cond.offset);
+ e.f = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_member_cond.dtor, offset + 10);
+ } else {
+ AACCCC e;
+ e.a = flag26 | 0x17;
+ e.b = ((reg ? 1 : 0) << 7) | ((reg2 ? 1 : 0) << 6);
+ e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_member_cond.cond));
+ e.d = CTool_EndianConvertWord32(reg2 ? reg2 : local_offset_32(ea->data.destroy_member_cond.objectptr));
+ e.e = CTool_EndianConvertWord32(ea->data.destroy_member_cond.offset);
+ e.f = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_member_cond.dtor, offset + 14);
+ }
+ break;
+ }
+ case EAT_DESTROYMEMBERARRAY: {
+ reg = OBJECT_REG(ea->data.destroy_member_array.objectptr);
+ if (reg || local_is_16bit_offset(ea->data.destroy_member_array.objectptr)) {
+ AABCCCC e;
+ e.a = flag26 | 9;
+ e.b = (reg != 0) << 7;
+ e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_member_array.objectptr));
+ e.d = CTool_EndianConvertWord32(ea->data.destroy_member_array.offset);
+ e.e = CTool_EndianConvertWord32(ea->data.destroy_member_array.elements);
+ e.f = CTool_EndianConvertWord32(ea->data.destroy_member_array.element_size);
+ e.g = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_member_array.dtor, offset + 16);
+ } else {
+ AACCCCC e;
+ e.a = flag26 | 0x18;
+ e.b = (reg != 0) << 7;
+ e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_member_array.objectptr));
+ e.d = CTool_EndianConvertWord32(ea->data.destroy_member_array.offset);
+ e.e = CTool_EndianConvertWord32(ea->data.destroy_member_array.elements);
+ e.f = CTool_EndianConvertWord32(ea->data.destroy_member_array.element_size);
+ e.g = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.destroy_member_array.dtor, offset + 18);
+ }
+ break;
+ }
+ case EAT_DELETEPOINTER:
+ case EAT_DELETELOCALPOINTER: {
+ reg = OBJECT_REG(ea->data.delete_pointer.pointerobject);
+ if (reg || local_is_16bit_offset(ea->data.delete_pointer.pointerobject)) {
+ AABC e;
+ e.a = flag26 | 0xA;
+ e.b = (reg != 0) << 7;
+ e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.delete_pointer.pointerobject));
+ e.d = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.delete_pointer.deletefunc, offset + 4);
+ } else {
+ AACC e;
+ e.a = flag26 | 0x19;
+ e.b = (reg != 0) << 7;
+ e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.delete_pointer.pointerobject));
+ e.d = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.delete_pointer.deletefunc, offset + 6);
+ }
+ break;
+ }
+ case EAT_DELETEPOINTERCOND: {
+ reg = OBJECT_REG(ea->data.delete_pointer_cond.cond);
+ reg2 = OBJECT_REG(ea->data.delete_pointer_cond.pointerobject);
+ if (
+ (reg || local_is_16bit_offset(ea->data.delete_pointer_cond.cond)) &&
+ (reg2 || local_is_16bit_offset(ea->data.delete_pointer_cond.pointerobject))
+ )
+ {
+ AABBC e;
+ e.a = flag26 | 0xB;
+ e.b = ((reg ? 1 : 0) << 7) | ((reg2 ? 1 : 0) << 6);
+ e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.delete_pointer_cond.cond));
+ e.d = CTool_EndianConvertWord16(reg2 ? reg2 : local_offset_16(ea->data.delete_pointer_cond.pointerobject));
+ e.e = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.delete_pointer_cond.deletefunc, offset + 6);
+ } else {
+ AACCC e;
+ e.a = flag26 | 0x1A;
+ e.b = ((reg ? 1 : 0) << 7) | ((reg2 ? 1 : 0) << 6);
+ e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.delete_pointer_cond.cond));
+ e.d = CTool_EndianConvertWord32(reg2 ? reg2 : local_offset_32(ea->data.delete_pointer_cond.pointerobject));
+ e.e = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ addrelocation(ea->data.delete_pointer_cond.deletefunc, offset + 10);
+ }
+ break;
+ }
+ case EAT_CATCHBLOCK: {
+ AACCC e;
+ e.a = flag26 | 0x10;
+ e.b = 0;
+ e.c = 0;
+ if (ea->data.catch_block.catch_label->pclabel)
+ e.d = CTool_EndianConvertWord32(ea->data.catch_block.catch_label->pclabel->block->codeOffset);
+ else
+ e.d = 0;
+ e.e = CTool_EndianConvertWord32(local_offset_16(ea->data.catch_block.catch_info_object));
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ if (ea->data.catch_block.catch_typeid)
+ addrelocation(ea->data.catch_block.catch_typeid, offset + 2);
+ break;
+ }
+ case EAT_ACTIVECATCHBLOCK: {
+ if (local_is_16bit_offset(ea->data.active_catch_block.catch_info_object)) {
+ AAB e;
+ e.a = flag26 | 0xD;
+ e.b = 0;
+ e.c = CTool_EndianConvertWord16(local_offset_16(ea->data.active_catch_block.catch_info_object));
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ } else {
+ AAC e;
+ e.a = flag26 | 0x1B;
+ e.b = 0;
+ e.c = CTool_EndianConvertWord32(local_offset_32(ea->data.active_catch_block.catch_info_object));
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ }
+ break;
+ }
+ case EAT_SPECIFICATION: {
+ AABCC e;
+ int i;
+
+ e.a = flag26 | 0xF;
+ e.b = 0;
+ e.c = CTool_EndianConvertWord16(ea->data.specification.unexp_ids);
+ if (ea->data.specification.unexp_label->pclabel)
+ e.d = CTool_EndianConvertWord32(ea->data.specification.unexp_label->pclabel->block->codeOffset);
+ e.e = CTool_EndianConvertWord32(local_offset_16(ea->data.specification.unexp_info_object));
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+
+ for (i = 0; i < ea->data.specification.unexp_ids; i++) {
+ addrelocation(ea->data.specification.unexp_id[i], 12 + i * 4 + offset);
+ AppendGListLong(&exceptmodule, 0);
+ }
+ break;
+ }
+ case EAT_TERMINATE: {
+ AA e;
+ e.a = flag26 | 0xE;
+ e.b = 0;
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ break;
+ }
+ default:
+ CError_FATAL(671);
+ }
+
+ node = node->prev;
+ }
+
+ if (node) {
+ AAB e;
+ e.a = 1;
+ e.b = 0;
+ e.c = CTool_EndianConvertWord16(node->xE);
+ AppendGListData(&exceptmodule, &e, sizeof(e));
+ }
+}
+
+static UInt32 findPC(PCode *instr) {
+ UInt32 pc = instr->block->codeOffset;
+ instr = instr->prevPCode;
+ while (instr) {
+ instr = instr->prevPCode;
+ pc += 4;
+ }
+ CError_ASSERT(704, FITS_IN_USHORT(pc));
+ return pc;
+}
+
+static UInt32 findPC_long(PCode *instr) {
+ UInt32 pc = instr->block->codeOffset;
+ instr = instr->prevPCode;
+ while (instr) {
+ instr = instr->prevPCode;
+ pc += 4;
+ }
+ return pc;
+}
+
+void initializeexceptiontables(void) {
+ int i;
+
+ for (i = 0; i < EAT_NACTIONS; i++)
+ DAG[i] = NULL;
+
+ pc_actions = last_pc_action = NULL;
+ except_refs = last_except_ref = NULL;
+}
+
+int countexceptionactionregisters(ExceptionAction *actions) {
+ int count = 0;
+
+ while (actions) {
+ switch (actions->type) {
+ case EAT_DESTROYLOCALCOND:
+ if (OBJECT_REG(actions->data.destroy_local_cond.cond))
+ count++;
+ break;
+ case EAT_DESTROYLOCALPOINTER:
+ if (OBJECT_REG(actions->data.destroy_local_pointer.pointer))
+ count++;
+ break;
+ case EAT_DESTROYMEMBER:
+ if (OBJECT_REG(actions->data.destroy_member.objectptr))
+ count++;
+ break;
+ case EAT_DESTROYBASE:
+ if (OBJECT_REG(actions->data.destroy_base.objectptr))
+ count++;
+ break;
+ case EAT_DESTROYMEMBERCOND:
+ if (OBJECT_REG(actions->data.destroy_member_cond.cond))
+ count++;
+ if (OBJECT_REG(actions->data.destroy_member_cond.objectptr))
+ count++;
+ break;
+ case EAT_DESTROYMEMBERARRAY:
+ if (OBJECT_REG(actions->data.destroy_member_array.objectptr))
+ count++;
+ break;
+ case EAT_DELETEPOINTER:
+ case EAT_DELETELOCALPOINTER:
+ if (OBJECT_REG(actions->data.delete_pointer.pointerobject))
+ count++;
+ break;
+ case EAT_DELETEPOINTERCOND:
+ if (OBJECT_REG(actions->data.delete_pointer_cond.cond))
+ count++;
+ if (OBJECT_REG(actions->data.delete_pointer_cond.pointerobject))
+ count++;
+ break;
+ }
+ actions = actions->prev;
+ }
+
+ return count;
+}
+
+void noteexceptionactionregisters(ExceptionAction *actions, PCodeArg *ops) {
+ Object *obj;
+ int reg;
+
+ while (actions) {
+ switch (actions->type) {
+ case EAT_DESTROYLOCALCOND:
+ if ((reg = OBJECT_REG(obj = actions->data.destroy_local_cond.cond))) {
+ ops->kind = PCOp_REGISTER;
+ ops->arg = obj->u.var.info->rclass;
+ ops->data.reg.reg = reg;
+ ops->data.reg.effect = EffectRead | Effect8;
+ ops++;
+ }
+ break;
+ case EAT_DESTROYLOCALPOINTER:
+ if ((reg = OBJECT_REG(obj = actions->data.destroy_local_pointer.pointer))) {
+ ops->kind = PCOp_REGISTER;
+ ops->arg = obj->u.var.info->rclass;
+ ops->data.reg.reg = reg;
+ ops->data.reg.effect = EffectRead | Effect8;
+ ops++;
+ }
+ break;
+ case EAT_DESTROYMEMBER:
+ if ((reg = OBJECT_REG(obj = actions->data.destroy_member.objectptr))) {
+ ops->kind = PCOp_REGISTER;
+ ops->arg = obj->u.var.info->rclass;
+ ops->data.reg.reg = reg;
+ ops->data.reg.effect = EffectRead | Effect8;
+ ops++;
+ }
+ break;
+ case EAT_DESTROYBASE:
+ if ((reg = OBJECT_REG(obj = actions->data.destroy_base.objectptr))) {
+ ops->kind = PCOp_REGISTER;
+ ops->arg = obj->u.var.info->rclass;
+ ops->data.reg.reg = reg;
+ ops->data.reg.effect = EffectRead | Effect8;
+ ops++;
+ }
+ break;
+ case EAT_DESTROYMEMBERCOND:
+ if ((reg = OBJECT_REG(obj = actions->data.destroy_member_cond.cond))) {
+ ops->kind = PCOp_REGISTER;
+ ops->arg = obj->u.var.info->rclass;
+ ops->data.reg.reg = reg;
+ ops->data.reg.effect = EffectRead | Effect8;
+ ops++;
+ }
+ if ((reg = OBJECT_REG(obj = actions->data.destroy_member_cond.objectptr))) {
+ ops->kind = PCOp_REGISTER;
+ ops->arg = obj->u.var.info->rclass;
+ ops->data.reg.reg = reg;
+ ops->data.reg.effect = EffectRead | Effect8;
+ ops++;
+ }
+ break;
+ case EAT_DESTROYMEMBERARRAY:
+ if ((reg = OBJECT_REG(obj = actions->data.destroy_member_array.objectptr))) {
+ ops->kind = PCOp_REGISTER;
+ ops->arg = obj->u.var.info->rclass;
+ ops->data.reg.reg = reg;
+ ops->data.reg.effect = EffectRead | Effect8;
+ ops++;
+ }
+ break;
+ case EAT_DELETEPOINTER:
+ case EAT_DELETELOCALPOINTER:
+ if ((reg = OBJECT_REG(obj = actions->data.delete_pointer.pointerobject))) {
+ ops->kind = PCOp_REGISTER;
+ ops->arg = obj->u.var.info->rclass;
+ ops->data.reg.reg = reg;
+ ops->data.reg.effect = EffectRead | Effect8;
+ ops++;
+ }
+ break;
+ case EAT_DELETEPOINTERCOND:
+ if ((reg = OBJECT_REG(obj = actions->data.delete_pointer_cond.cond))) {
+ ops->kind = PCOp_REGISTER;
+ ops->arg = obj->u.var.info->rclass;
+ ops->data.reg.reg = reg;
+ ops->data.reg.effect = EffectRead | Effect8;
+ ops++;
+ }
+ if ((reg = OBJECT_REG(obj = actions->data.delete_pointer_cond.pointerobject))) {
+ ops->kind = PCOp_REGISTER;
+ ops->arg = obj->u.var.info->rclass;
+ ops->data.reg.reg = reg;
+ ops->data.reg.effect = EffectRead | Effect8;
+ ops++;
+ }
+ break;
+ }
+ actions = actions->prev;
+ }
+}
+
+void recordexceptionactions(PCode *instr, ExceptionAction *actions) {
+ PCAction *pca;
+
+ if (!actions && (!last_pc_action || !last_pc_action->actions))
+ return;
+
+ pca = lalloc(sizeof(PCAction));
+ pca->next = NULL;
+ pca->firstInstr = pca->lastInstr = instr;
+ pca->actions = actions;
+ pca->prev = last_pc_action;
+ if (last_pc_action)
+ last_pc_action->next = pca;
+ else
+ pc_actions = pca;
+ last_pc_action = pca;
+
+ branch_label(makepclabel());
+ while (actions) {
+ if (actions->type == EAT_CATCHBLOCK && actions->data.catch_block.catch_label->pclabel)
+ pcbranch(instr->block, actions->data.catch_block.catch_label->pclabel);
+ else if (actions->type == EAT_SPECIFICATION && actions->data.specification.unexp_label->pclabel)
+ pcbranch(instr->block, actions->data.specification.unexp_label->pclabel);
+ actions = actions->prev;
+ }
+}
+
+static void deleteexceptionaction(PCAction *pca) {
+ if (pca->prev)
+ pca->prev->next = pca->next;
+ else
+ pc_actions = pca->next;
+
+ if (pca->next)
+ pca->next->prev = pca->prev;
+}
+
+static int mergeexceptionactions(void) {
+ int count;
+ PCAction *pca;
+ PCAction *prev;
+
+ if (!pc_actions)
+ return 0;
+
+ for (pca = pc_actions; pca; pca = pca->next) {
+ if (pca->firstInstr->block->flags & fDeleted)
+ deleteexceptionaction(pca);
+ }
+
+ if (!(pca = pc_actions))
+ return 0;
+
+ while (pca) {
+ pca->node = pca->actions ? makeEAnode(pca->actions) : NULL;
+ pca = pca->next;
+ }
+
+ prev = pc_actions;
+ for (pca = pc_actions->next; pca; pca = pca->next) {
+ if (pca->node == prev->node) {
+ prev->lastInstr = pca->lastInstr;
+ deleteexceptionaction(pca);
+ } else {
+ prev = pca;
+ }
+ }
+
+ count = 0;
+ for (pca = pc_actions; pca; pca = pca->next) {
+ if (!pca->actions)
+ deleteexceptionaction(pca);
+ else
+ count++;
+ }
+
+ return count;
+}
+
+typedef struct ExceptionThing {
+ UInt32 x0;
+ UInt16 x4;
+ UInt16 x6;
+} ExceptionThing;
+
+void dumpexceptiontables(Object *function, SInt32 codesize) {
+ PCAction *pca;
+ UInt32 insn_start;
+ UInt32 insn_count;
+ UInt16 *sh;
+ ExceptionThing *thing;
+ int count;
+
+ count = mergeexceptionactions();
+ InitGList(&exceptmodule, 256);
+ AppendGListNoData(&exceptmodule, 8 * count + 4);
+ AppendGListLong(&exceptmodule, 0);
+
+ for (pca = pc_actions; pca; pca = pca->next) {
+ if (pca->node->count == 0 && pca->node->xE == 0)
+ allocateactioninfo(pca->node);
+ }
+
+ sh = (UInt16 *) *exceptmodule.data;
+ if (copts.altivec_model && used_nonvolatile_registers[RegClass_VR]) {
+ sh[0] =
+ CTool_EndianConvertWord16(
+ (used_nonvolatile_registers[RegClass_GPR] << 11) |
+ ((used_nonvolatile_registers[RegClass_FPR] & 0x1F) << 6) |
+ (((used_nonvolatile_registers[RegClass_CRFIELD] != 0) & 1) << 5) |
+ ((dynamic_stack & 1) << 4) |
+ 8);
+ sh[0] |= 4;
+ if (copts.altivec_vrsave)
+ sh[1] = CTool_EndianConvertWord16((used_nonvolatile_registers[RegClass_VR] << 11) | 0x400);
+ else
+ sh[1] = CTool_EndianConvertWord16((used_nonvolatile_registers[RegClass_VR] & 0x1F) << 11);
+ } else {
+ sh[0] =
+ CTool_EndianConvertWord16(
+ (used_nonvolatile_registers[RegClass_GPR] << 11) |
+ ((used_nonvolatile_registers[RegClass_FPR] & 0x1F) << 6) |
+ (((used_nonvolatile_registers[RegClass_CRFIELD] != 0) & 1) << 5) |
+ ((dynamic_stack & 1) << 4) |
+ 8);
+ sh[1] = 0;
+ }
+
+ thing = (ExceptionThing *) (sh + 2);
+ pca = pc_actions;
+ while (pca) {
+ insn_start = findPC_long(pca->firstInstr);
+ insn_count = (findPC_long(pca->lastInstr) - insn_start) / 4;
+ CError_ASSERT(1203, (insn_count & 0xFFFF0000) == 0);
+ thing->x0 = CTool_EndianConvertWord32(insn_start + 4);
+ thing->x4 = CTool_EndianConvertWord16(insn_count);
+ thing->x6 = CTool_EndianConvertWord16(pca->node->xE);
+ pca = pca->next;
+ thing++;
+ }
+
+ LockGList(&exceptmodule);
+ ObjGen_DeclareExceptionTables(function, codesize, *exceptmodule.data, exceptmodule.size, except_refs);
+ FreeGList(&exceptmodule);
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/FunctionCalls.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/FunctionCalls.c
new file mode 100644
index 0000000..67d7443
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/FunctionCalls.c
@@ -0,0 +1,642 @@
+#include "compiler/FunctionCalls.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/InstrSelection.h"
+#include "compiler/Operands.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/Registers.h"
+#include "compiler/StackFrame.h"
+#include "compiler/StructMoves.h"
+#include "compiler/types.h"
+
+enum {
+ AIF_PassInGPR = 1,
+ AIF_PassInFPR = 2,
+ AIF_PassOnStack = 4,
+ AIF_ExtendTo32Bits = 8,
+ AIF_ForceDoublePrecision = 0x10,
+ AIF_PassInVR = 0x20,
+ AIF_PassMask = AIF_PassInGPR | AIF_PassInFPR | AIF_PassOnStack | AIF_PassInVR
+};
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct ArgInfo {
+ struct ArgInfo *next;
+ ENode *expr;
+ Operand opnd;
+ SInt32 offset;
+ short gpr;
+ short gprHi;
+ short fpr;
+ short vr;
+ short evaluated;
+ short flags;
+} ArgInfo;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+// forward decls
+static void branch_subroutine_indirect_ctr(Operand *addrOpnd, UInt32 *used_regs);
+
+static ArgInfo *make_arginfo(ENode *expr) {
+ ArgInfo *info = lalloc(sizeof(ArgInfo));
+ memclrw(info, sizeof(ArgInfo));
+
+ info->next = NULL;
+ info->expr = expr;
+ info->offset = -1;
+ info->gpr = -1;
+ info->gprHi = -1;
+ info->fpr = -1;
+ info->vr = -1;
+ info->evaluated = 0;
+ info->flags = 0;
+
+ return info;
+}
+
+static ArgInfo *analyze_arguments(ENode *funcref, ENodeList *arg_expr, FuncArg *arg, UInt32 *used_regs, Boolean *resultHasFloats, char has_varargs) {
+ ArgInfo *infos;
+ ArgInfo *info;
+ SInt32 displ;
+ SInt32 arg_size;
+ int gpr_counter;
+ int fpr_counter;
+ int vr_counter;
+ Type *type;
+ RegClass rclass;
+ Boolean spilledVectorFlag;
+
+ infos = NULL;
+ displ = 0;
+ gpr_counter = 3;
+ fpr_counter = 1;
+ vr_counter = 2;
+
+ for (rclass = 0; rclass < RegClassMax; rclass++)
+ used_regs[rclass] = 0;
+ *resultHasFloats = 0;
+
+ while (arg_expr) {
+ if (arg_expr->node == funcref) {
+ arg_expr = arg_expr->next;
+ arg = arg->next;
+ continue;
+ }
+
+ type = arg_expr->node->rtype;
+ if (infos) {
+ info->next = make_arginfo(arg_expr->node);
+ info = info->next;
+ } else {
+ infos = info = make_arginfo(arg_expr->node);
+ }
+
+ arg_size = 0;
+ if (IS_TYPE_VECTOR(type)) {
+ if (arg == &elipsis) {
+ spilledVectorFlag = 1;
+ info->flags |= AIF_PassOnStack;
+ } else {
+ spilledVectorFlag = 0;
+ if (vr_counter <= 13) {
+ info->flags |= AIF_PassInVR;
+ info->vr = vr_counter;
+ used_regs[RegClass_VR] |= 1 << vr_counter;
+ } else {
+ spilledVectorFlag = 1;
+ info->flags |= AIF_PassOnStack;
+ }
+ }
+
+ if (has_varargs) {
+ if (gpr_counter < 10) {
+ gpr_counter = ((gpr_counter - 2) & ~3) + 5;
+ if (arg == &elipsis && gpr_counter < 10) {
+ info->flags |= AIF_PassInGPR;
+ info->gpr = gpr_counter;
+ used_regs[RegClass_GPR] |= (15 << gpr_counter) & 0x7E0;
+ }
+ gpr_counter += 4;
+ }
+ spilledVectorFlag = 1;
+ }
+
+ if (spilledVectorFlag)
+ arg_size = 16;
+ vr_counter++;
+ } else if (IS_TYPE_FLOAT(type)) {
+ *resultHasFloats = 1;
+ if (!arg || arg == &oldstyle) {
+ if (fpr_counter <= 13) {
+ info->flags |= AIF_PassInFPR;
+ info->fpr = fpr_counter;
+ used_regs[RegClass_FPR] |= 1 << fpr_counter;
+ } else {
+ info->flags |= AIF_PassOnStack | AIF_ForceDoublePrecision;
+ }
+ arg_size = 8;
+ fpr_counter++;
+ gpr_counter += 2;
+ } else if (arg == &elipsis) {
+ if (gpr_counter < 10) {
+ info->flags |= AIF_PassInGPR;
+ info->gpr = gpr_counter;
+ used_regs[RegClass_GPR] |= 3 << gpr_counter;
+ } else if (gpr_counter == 10) {
+ info->flags |= AIF_PassInGPR | AIF_PassOnStack | AIF_ForceDoublePrecision;
+ info->gpr = gpr_counter;
+ used_regs[RegClass_GPR] |= 3 << gpr_counter;
+ } else {
+ info->flags |= AIF_PassOnStack | AIF_ForceDoublePrecision;
+ }
+ arg_size = 8;
+ fpr_counter++;
+ gpr_counter += 2;
+ } else {
+ if (fpr_counter <= 13) {
+ info->flags |= AIF_PassInFPR;
+ info->fpr = fpr_counter;
+ used_regs[RegClass_FPR] |= 1 << fpr_counter;
+ } else {
+ info->flags |= AIF_PassOnStack;
+ }
+
+ if (type->size == 4) {
+ arg_size = 4;
+ gpr_counter++;
+ } else {
+ arg_size = 8;
+ gpr_counter += 2;
+ }
+
+ fpr_counter++;
+ }
+ } else if (TYPE_IS_8BYTES(type)) {
+ if (gpr_counter <= 10) {
+ info->flags |= AIF_PassInGPR;
+ if (copts.littleendian) {
+ info->gpr = gpr_counter;
+ info->gprHi = gpr_counter + 1;
+ } else {
+ info->gpr = gpr_counter + 1;
+ info->gprHi = gpr_counter;
+ }
+ used_regs[RegClass_GPR] |= 1 << gpr_counter;
+ if ((gpr_counter + 1) <= 10)
+ used_regs[RegClass_GPR] |= 1 << (gpr_counter + 1);
+ } else {
+ info->flags |= AIF_PassOnStack;
+ }
+
+ arg_size = 8;
+ gpr_counter += 2;
+ } else if (TYPE_FITS_IN_REGISTER(type)) {
+ if ((!arg || arg == &elipsis || arg == &oldstyle) && type->size < 4)
+ info->flags |= AIF_ExtendTo32Bits;
+
+ if (gpr_counter <= 10) {
+ info->flags |= AIF_PassInGPR;
+ info->gpr = gpr_counter;
+ used_regs[RegClass_GPR] |= 1 << gpr_counter;
+ } else {
+ info->flags |= AIF_PassOnStack;
+ }
+
+ arg_size = 4;
+ gpr_counter++;
+ } else if (IS_TYPE_ARRAY(type) || IS_TYPE_NONVECTOR_STRUCT(type) || IS_TYPE_CLASS(type) ||
+ IS_TYPE_12BYTES_MEMBERPOINTER(type)) {
+ SInt32 gprs_needed = (type->size >> 2) + ((type->size & 3) != 0);
+ if (gpr_counter <= 10) {
+ if ((gpr_counter + gprs_needed - 1) <= 10) {
+ info->flags |= AIF_PassInGPR;
+ info->gpr = gpr_counter;
+ used_regs[RegClass_GPR] |= ((1 << gprs_needed) - 1) << gpr_counter;
+ } else {
+ info->flags |= AIF_PassInGPR | AIF_PassOnStack;
+ info->gpr = gpr_counter;
+ used_regs[RegClass_GPR] |= ((1 << (11 - gpr_counter)) - 1) << gpr_counter;
+ }
+ } else {
+ info->flags |= AIF_PassOnStack;
+ }
+
+ gpr_counter += gprs_needed;
+ arg_size = type->size;
+ } else {
+ CError_FATAL(421);
+ }
+
+ displ = set_out_param_displ(displ, type, info->flags & AIF_PassOnStack, &info->offset, arg_size);
+
+ arg_expr = arg_expr->next;
+ if (arg && arg != &elipsis && arg != &oldstyle)
+ arg = arg->next;
+ }
+
+ update_out_param_size(displ);
+
+ return infos;
+}
+
+static void pass_in_memory(ArgInfo *info) {
+ Type *type;
+ Operand opnd;
+
+ type = info->expr->rtype;
+ memclrw(&opnd, sizeof(Operand));
+
+ if (TYPE_FITS_IN_REGISTER(type)) {
+ if (TYPE_IS_8BYTES(type)) {
+ if (!info->evaluated)
+ GEN_NODE(info->expr, &info->opnd);
+ coerce_to_register_pair(&info->opnd, type, 0, 0);
+
+ load_store_register(
+ PC_STW, info->opnd.reg, 1,
+ NULL, low_offset + out_param_displ_to_offset(info->offset));
+ load_store_register(
+ PC_STW, info->opnd.regHi, 1,
+ NULL, high_offset + out_param_displ_to_offset(info->offset));
+ } else {
+ if (!info->evaluated)
+ GEN_NODE(info->expr, &info->opnd);
+ if (info->flags & AIF_ExtendTo32Bits)
+ extend32(&info->opnd, type, 0);
+ ENSURE_GPR(&info->opnd, type, 0);
+
+ load_store_register(
+ PC_STW, info->opnd.reg, 1,
+ NULL, out_param_displ_to_offset(info->offset));
+ }
+ } else if (IS_TYPE_FLOAT(type)) {
+ if (!info->evaluated)
+ GEN_NODE(info->expr, &info->opnd);
+ ENSURE_FPR(&info->opnd, type, 0);
+
+ if (type->size == 4 && !(info->flags & AIF_ForceDoublePrecision)) {
+ load_store_register(
+ PC_STFS, info->opnd.reg, 1,
+ NULL, out_param_displ_to_offset(info->offset));
+ } else {
+ load_store_register(
+ PC_STFD, info->opnd.reg, 1,
+ NULL, out_param_displ_to_offset(info->offset));
+ }
+ } else if (IS_TYPE_VECTOR(type)) {
+ if (!info->evaluated)
+ GEN_NODE(info->expr, &info->opnd);
+ ENSURE_VR(&info->opnd, type, 0);
+
+ load_store_register(
+ PC_STVX, info->opnd.reg, 1,
+ NULL, out_param_displ_to_offset(info->offset));
+ } else {
+ opnd.optype = OpndType_IndirectGPR_ImmOffset;
+ opnd.reg = 1;
+ opnd.object = NULL;
+ opnd.immOffset = out_param_displ_to_offset(info->offset);
+
+ if (!info->evaluated)
+ GEN_NODE(info->expr, &info->opnd);
+
+ move_block(&opnd, &info->opnd, type->size, CMach_ArgumentAlignment(type));
+ }
+}
+
+static void pass_in_register(ArgInfo *info) {
+ Type *type;
+
+ type = info->expr->rtype;
+
+ if ((info->flags & AIF_PassMask) == AIF_PassInFPR) {
+ if (!info->evaluated)
+ GEN_NODE_TO_REG(info->expr, info->fpr, 0, &info->opnd);
+ ENSURE_FPR(&info->opnd, type, info->fpr);
+ if (info->opnd.reg != info->fpr)
+ emitpcode(PC_FMR, info->fpr, info->opnd.reg);
+ } else if ((info->flags & AIF_PassMask) == AIF_PassInVR) {
+ if (!info->evaluated)
+ GEN_NODE_TO_REG(info->expr, info->vr, 0, &info->opnd);
+ ENSURE_VR(&info->opnd, type, info->vr);
+ if (info->opnd.reg != info->vr)
+ emitpcode(PC_VMR, info->vr, info->opnd.reg);
+ } else if (TYPE_FITS_IN_REGISTER(type)) {
+ if (TYPE_IS_8BYTES(type)) {
+ if (!info->evaluated)
+ GEN_NODE_TO_REG(info->expr, info->gpr, info->gprHi, &info->opnd);
+ coerce_to_register_pair(&info->opnd, type, info->gpr, info->gprHi);
+ if (copts.littleendian) {
+ if (info->gprHi > 10) {
+ load_store_register(
+ PC_STW, info->opnd.regHi, 1,
+ NULL, high_offset + out_param_displ_to_offset(info->offset));
+ }
+ } else {
+ if (info->gpr > 10) {
+ load_store_register(
+ PC_STW, info->opnd.reg, 1,
+ NULL, low_offset + out_param_displ_to_offset(info->offset));
+ }
+ }
+ } else {
+ if (!info->evaluated)
+ GEN_NODE_TO_REG(info->expr, info->gpr, 0, &info->opnd);
+ if (info->flags & AIF_ExtendTo32Bits)
+ extend32(&info->opnd, type, info->gpr);
+ ENSURE_GPR(&info->opnd, type, info->gpr);
+ if (info->opnd.reg != info->gpr)
+ emitpcode(PC_MR, info->gpr, info->opnd.reg);
+ }
+ } else if (IS_TYPE_FLOAT(type)) {
+ if (!info->evaluated)
+ GEN_NODE(info->expr, &info->opnd);
+
+ if (type->size != 4 && info->opnd.optype == OpndType_IndirectGPR_ImmOffset) {
+ load_store_register(
+ PC_LWZ, info->gpr, info->opnd.reg,
+ info->opnd.object, info->opnd.immOffset);
+ load_store_register(
+ PC_LWZ, info->gpr + 1, info->opnd.reg,
+ info->opnd.object, info->opnd.immOffset + 4);
+ } else {
+ ENSURE_FPR(&info->opnd, type, 0);
+ load_store_register(
+ PC_STFD, info->opnd.reg, 1,
+ NULL, out_param_displ_to_offset(info->offset));
+ load_store_register(
+ PC_LWZ, info->gpr, 1,
+ NULL, out_param_displ_to_offset(info->offset));
+ load_store_register(
+ PC_LWZ, info->gpr + 1, 1,
+ NULL, out_param_displ_to_offset(info->offset) + 4);
+ }
+ } else if (IS_TYPE_VECTOR(type)) {
+ if (!info->evaluated)
+ GEN_NODE(info->expr, &info->opnd);
+
+ if (info->opnd.optype == OpndType_IndirectGPR_ImmOffset) {
+ load_store_register(
+ PC_LWZ, info->gpr, info->opnd.reg,
+ info->opnd.object, info->opnd.immOffset);
+ load_store_register(
+ PC_LWZ, info->gpr + 1, info->opnd.reg,
+ info->opnd.object, info->opnd.immOffset + 4);
+ if ((info->gpr + 2) < 10) {
+ load_store_register(
+ PC_LWZ, info->gpr + 2, info->opnd.reg,
+ info->opnd.object, info->opnd.immOffset + 8);
+ load_store_register(
+ PC_LWZ, info->gpr + 3, info->opnd.reg,
+ info->opnd.object, info->opnd.immOffset + 12);
+ }
+ } else {
+ ENSURE_VR(&info->opnd, type, 0);
+ load_store_register(
+ PC_STVX, info->opnd.reg, 1,
+ NULL, out_param_displ_to_offset(info->offset));
+ load_store_register(
+ PC_LWZ, info->gpr, 1,
+ NULL, out_param_displ_to_offset(info->offset));
+ load_store_register(
+ PC_LWZ, info->gpr + 1, 1,
+ NULL, out_param_displ_to_offset(info->offset) + 4);
+ if ((info->gpr + 2) < 10) {
+ load_store_register(
+ PC_LWZ, info->gpr + 2, 1,
+ NULL, out_param_displ_to_offset(info->offset) + 8);
+ load_store_register(
+ PC_LWZ, info->gpr + 3, 1,
+ NULL, out_param_displ_to_offset(info->offset) + 12);
+ }
+ }
+ } else {
+ if (!info->evaluated)
+ GEN_NODE(info->expr, &info->opnd);
+
+ if (type->size <= 4) {
+ if (info->opnd.optype == OpndType_IndirectSymbol)
+ coerce_to_addressable(&info->opnd);
+
+ if (info->opnd.optype == OpndType_IndirectGPR_ImmOffset) {
+ load_store_register(
+ PC_LWZ, info->gpr, info->opnd.reg,
+ info->opnd.object, info->opnd.immOffset);
+ } else if (info->opnd.optype == OpndType_IndirectGPR_Indexed) {
+ emitpcode(
+ PC_LWZX, info->gpr, info->opnd.reg,
+ info->opnd.regOffset);
+ }
+ } else {
+ SInt32 gprs_needed = (type->size >> 2) + ((type->size & 3) != 0);
+ SInt32 i;
+
+ make_addressable(&info->opnd, gprs_needed * 4, 12);
+ for (i = 0; i < gprs_needed; i++) {
+ if (info->opnd.reg != (info->gpr + i)) {
+ load_store_register(
+ PC_LWZ, info->gpr + i, info->opnd.reg,
+ info->opnd.object, info->opnd.immOffset + i * 4);
+ }
+ }
+
+ if (info->opnd.reg >= info->gpr && info->opnd.reg < (info->gpr + gprs_needed)) {
+ load_store_register(
+ PC_LWZ, info->opnd.reg, info->opnd.reg,
+ info->opnd.object, info->opnd.immOffset + (info->opnd.reg - info->gpr) * 4);
+ }
+ }
+ }
+}
+
+static void pass_in_register_and_memory(ArgInfo *info) {
+ Type *type;
+ int gpr;
+ SInt32 offset;
+
+ type = info->expr->rtype;
+ gpr = info->gpr;
+ offset = 0;
+ while (offset < type->size && gpr <= 10) {
+ load_store_register(
+ PC_LWZ, gpr, 1,
+ NULL, offset + out_param_displ_to_offset(info->offset));
+ gpr++;
+ offset += 4;
+ }
+}
+
+static Boolean needs_TOC_reload(Object *func) {
+ return 0;
+}
+
+static void load_virtual_function(TypeClass *tclass, SInt32 offset, int reg, Operand *opnd) {
+ if (tclass->flags & CLASS_HANDLEOBJECT) {
+ load_store_register(PC_LWZ, 12, reg, NULL, 0);
+ load_store_register(PC_LWZ, 12, 12, NULL, tclass->vtable->offset);
+ } else {
+ load_store_register(PC_LWZ, 12, reg, NULL, tclass->vtable->offset);
+ }
+ load_store_register(PC_LWZ, 12, 12, NULL, offset);
+ opnd->optype = OpndType_GPR;
+ opnd->reg = 12;
+}
+
+static void branch_subroutine_indirect(Object *func, Operand *addrOpnd, UInt32 *used_regs) {
+ if (addrOpnd->reg != 12)
+ emitpcode(PC_MR, 12, addrOpnd->reg);
+
+ used_regs[RegClass_GPR] |= 1 << 12;
+ branch_subroutine(func, 1, used_regs);
+}
+
+static void evaluate_nested_function_calls(ArgInfo *info) {
+ ArgInfo *scan;
+
+ scan = info->next;
+ while (scan && !scan->expr->hascall)
+ scan = scan->next;
+
+ if (scan)
+ evaluate_nested_function_calls(scan);
+
+ if (info->expr->hascall) {
+ GEN_NODE(info->expr, &info->opnd);
+ info->evaluated = 1;
+ }
+}
+
+void call_function(ENode *expr, Operand *output) {
+ ArgInfo *infos; // r31
+ ENode *funcref = expr->data.funccall.funcref; // r27
+ Type *resultType = expr->data.funccall.functype->functype; // r26
+ ENode *node = NULL; // r25
+ char has_varargs; // r24
+ ArgInfo *info; // r22
+ Operand opnd;
+ UInt32 used_regs[RegClassMax] = {0};
+ Boolean has_floats;
+ FuncArg *arg;
+
+ memclrw(&opnd, sizeof(Operand));
+
+ has_varargs = 0;
+ for (arg = expr->data.funccall.functype->args; arg; arg = arg->next) {
+ if (arg == &elipsis) {
+ has_varargs = 1;
+ break;
+ }
+ }
+
+ if (expr->data.funccall.functype->flags & FUNC_FLAGS_80) {
+ if (CMach_PassResultInHiddenArg(resultType))
+ node = expr->data.funccall.args->next->node;
+ else
+ node = expr->data.funccall.args->node;
+ }
+
+ infos = analyze_arguments(
+ node,
+ expr->data.funccall.args,
+ expr->data.funccall.functype->args,
+ used_regs,
+ &has_floats,
+ has_varargs);
+
+ if (infos)
+ evaluate_nested_function_calls(infos);
+
+ if (funcref->hascall) {
+ GEN_NODE_TO_GPR(funcref, &opnd, TYPE(&void_ptr), 0);
+ } else if (node && node->hascall) {
+ GEN_NODE_TO_GPR(node, &opnd, TYPE(&void_ptr), 0);
+ }
+
+ for (info = infos; info; info = info->next) {
+ if (info->flags & AIF_PassOnStack)
+ pass_in_memory(info);
+ }
+ for (info = infos; info; info = info->next) {
+ if ((info->flags & AIF_PassMask) == (AIF_PassInGPR | AIF_PassOnStack))
+ pass_in_register_and_memory(info);
+ }
+ for (info = infos; info; info = info->next) {
+ int flag = info->flags & AIF_PassMask;
+ if (
+ flag == AIF_PassInGPR ||
+ flag == AIF_PassInFPR ||
+ flag == AIF_PassInVR
+ )
+ pass_in_register(info);
+ }
+
+ if (funcref->type == EOBJREF) {
+ TypeClass *tclass;
+ SInt32 vfOffset;
+ if (CParser_IsVirtualFunction(funcref->data.objref, &tclass, &vfOffset)) {
+ load_virtual_function(
+ tclass,
+ vfOffset,
+ CMach_PassResultInHiddenArg(resultType) ? Register4 : Register3,
+ &opnd
+ );
+ branch_subroutine_indirect_ctr(&opnd, used_regs);
+ } else if (node) {
+ if (!node->hascall) {
+ GEN_NODE_TO_REG(node, 12, 0, &opnd);
+ ENSURE_GPR(&opnd, TYPE(&void_ptr), 12);
+ }
+ branch_subroutine_indirect(funcref->data.objref, &opnd, used_regs);
+ } else {
+ branch_subroutine(funcref->data.objref, needs_TOC_reload(funcref->data.objref), used_regs);
+ }
+ } else {
+ if (!funcref->hascall)
+ GEN_NODE_TO_REG(funcref, 12, 0, &opnd);
+ ENSURE_GPR(&opnd, TYPE(&void_ptr), 12);
+ branch_subroutine_indirect_ctr(&opnd, used_regs);
+ }
+
+ if (IS_TYPE_FLOAT(resultType)) {
+ output->optype = OpndType_FPR;
+ output->reg = used_virtual_registers[RegClass_FPR]++;
+ emitpcode(PC_FMR, output->reg, 1);
+ } else if (IS_TYPE_VECTOR(resultType)) {
+ output->optype = OpndType_VR;
+ output->reg = used_virtual_registers[RegClass_VR]++;
+ emitpcode(PC_VMR, output->reg, 2);
+ } else if (TYPE_FITS_IN_REGISTER(resultType)) {
+ if (resultType->size > 4) {
+ output->optype = OpndType_GPRPair;
+ output->reg = used_virtual_registers[RegClass_GPR]++;
+ output->regHi = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_MR, output->reg, low_reg);
+ emitpcode(PC_MR, output->regHi, high_reg);
+ } else {
+ output->optype = OpndType_GPR;
+ output->reg = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_MR, output->reg, 3);
+ }
+ } else {
+ output->optype = OpndType_Absolute;
+ output->immediate = 0;
+ }
+}
+
+static void branch_subroutine_indirect_ctr(Operand *addrOpnd, UInt32 *used_regs) {
+ if (addrOpnd->reg != 12)
+ emitpcode(PC_MR, 12, addrOpnd->reg);
+
+ emitpcode(PC_MTCTR, 12);
+ used_regs[RegClass_GPR] |= 1 << 12;
+ branch_subroutine_ctr(used_regs);
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/InstrSelection.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/InstrSelection.c
new file mode 100644
index 0000000..359c980
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/InstrSelection.c
@@ -0,0 +1,5348 @@
+#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/CompilerTools.h"
+#include "compiler/FunctionCalls.h"
+#include "compiler/Intrinsics.h"
+#include "compiler/Operands.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/StructMoves.h"
+#include "compiler/TOC.h"
+#include "compiler/enode.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+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;
+ CError_ASSERT(250, 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);
+
+ 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);
+
+ 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:
+ CError_FATAL(456);
+ }
+ 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)) {
+ CError_FATAL(681);
+ }
+}
+
+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.optimizesize && 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.optimizesize && 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.optimizesize && 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 {
+ CError_FATAL(1759);
+ }
+ 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:
+ CError_FATAL(1810);
+ }
+ 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 {
+ CError_FATAL(2224);
+ }
+}
+
+void gen_BITFIELD(ENode *expr, short outputReg, short outputRegHi, Operand *output) {
+ CError_FATAL(2238);
+}
+
+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) {
+ CError_FATAL(2294);
+}
+
+void gen_STRINGCONST(ENode *expr, short outputReg, short outputRegHi, Operand *output) {
+ CError_FATAL(2308);
+}
+
+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 fneg_reg2;
+ int fneg_reg3;
+ 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:
+ CError_FATAL(2780);
+ }
+
+ 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_reg2 = ALLOC_FPR();
+ emitpcode(PC_FNEG, fneg_reg2, 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_reg2, 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_reg3 = op.reg;
+ if (flag) {
+ fneg_reg3 = ALLOC_FPR();
+ emitpcode(PC_FNEG, fneg_reg3, op.reg);
+ }
+
+ final_reg = outputReg ? outputReg : ALLOC_FPR();
+ emitpcode(PC_FSEL, final_reg, fneg_reg3, op1.reg, op2.reg);
+ break;
+ default:
+ CError_FATAL(2862);
+ }
+
+ 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);
+ output->optype = OpndType_GPR;
+ output->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 {
+ CError_FATAL(3119);
+ }
+
+ 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:
+ CError_FATAL(3168);
+ }
+ }
+
+ 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));
+
+ CError_ASSERT(3704, ENODE_IS(expr1, EINDIRECT));
+ CError_ASSERT(3705, 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:
+ CError_FATAL(3744);
+ }
+
+ 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:
+ CError_FATAL(2862);
+ }
+
+ 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));
+ CError_ASSERT(3966, ENODE_IS(expr1, EINDIRECT));
+ CError_ASSERT(3968, 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);
+ CError_ASSERT(3979, outputReg);
+
+ GEN_NODE(expr1, &op1);
+ op3 = op1;
+
+ CError_ASSERT(3986, 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) {
+ if (is_intrinsic_function_call(expr))
+ call_intrinsic_function(expr, outputReg, output);
+ else
+ call_function(expr, 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) {
+ CError_FATAL(4160);
+}
+
+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.optimizesize && 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();
+ CError_ASSERT(4853, 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();
+ CError_ASSERT(4883, 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:
+ CError_FATAL(5160);
+ }
+}
+
+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);
+ CError_ASSERT(5190, 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:
+ CError_FATAL(5206);
+ }
+}
+
+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 condOp;
+ int finalReg;
+ int tmpReg;
+ int tmpReg2;
+ int tmpReg3;
+ int tmpReg4;
+ int a;
+ int b;
+
+ left = cond->data.diadic.left;
+ right = cond->data.diadic.right;
+ memclrw(&condOp, sizeof(Operand));
+
+ if (!IS_TYPE_FLOAT(left->rtype)) {
+ Operand op1;
+ Operand op2;
+ Operand opTmp;
+ memclrw(&op1, sizeof(Operand));
+ memclrw(&op2, sizeof(Operand));
+ memclrw(&opTmp, sizeof(Operand));
+
+ if (right->hascall) {
+ GEN_NODE(right, &op2);
+ if (!IS_INT_CONST_ZERO(right)) {
+ if (right->rtype->size < 4)
+ extend32(&op2, right->rtype, 0);
+ ENSURE_GPR(&op2, right->rtype, 0);
+ }
+
+ GEN_NODE(left, &op1);
+ if (left->rtype->size < 4)
+ extend32(&op1, left->rtype, 0);
+ ENSURE_GPR(&op1, left->rtype, 0);
+ } else {
+ GEN_NODE(left, &op1);
+ ENSURE_GPR(&op1, left->rtype, 0);
+ if (left->rtype->size < 4)
+ extend32(&op1, left->rtype, 0);
+
+ GEN_NODE(right, &op2);
+ if (!IS_INT_CONST_ZERO(right)) {
+ if (right->rtype->size < 4)
+ extend32(&op2, right->rtype, 0);
+ ENSURE_GPR(&op2, right->rtype, 0);
+ }
+ }
+
+ switch (cond->type) {
+ case EEQU:
+ if (
+ copts.peephole &&
+ IS_INT_CONST(right) &&
+ pclastblock->pcodeCount > 0 &&
+ pclastblock->lastPCode->op == PC_RLWINM &&
+ pclastblock->lastPCode->args[0].data.reg.reg == op1.reg
+ )
+ {
+ PCode *pc = pclastblock->lastPCode;
+ SInt32 a = pc->args[2].data.imm.value;
+ SInt32 b = pc->args[3].data.imm.value;
+ SInt32 value = right->data.intval.lo;
+ if (b == pc->args[4].data.imm.value) {
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+
+ if (value != (value & 1)) {
+ emitpcode(PC_LI, finalReg, 0);
+ } else if (value == 0) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(
+ PC_RLWINM, tmpReg,
+ pc->args[1].data.reg.reg,
+ (a + b + 1) & 31, 31, 31);
+ emitpcode(PC_XORI, finalReg, tmpReg, 1);
+ } else if (value == 1) {
+ emitpcode(
+ PC_RLWINM, finalReg,
+ pc->args[1].data.reg.reg,
+ (a + b + 1) & 31, 31, 31);
+ } else {
+ CError_FATAL(5434);
+ }
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+ }
+
+ if (IS_INT_CONST_ZERO(right)) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_CNTLZW, tmpReg, op1.reg, 0);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_RLWINM, finalReg, tmpReg, 27, 5, 31);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ } else {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg, op1.reg, op2.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_CNTLZW, tmpReg2, tmpReg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_RLWINM, finalReg, tmpReg2, 27, 5, 31);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ case ENOTEQU:
+ if (
+ copts.peephole &&
+ IS_INT_CONST(right) &&
+ pclastblock->pcodeCount > 0 &&
+ pclastblock->lastPCode->op == PC_RLWINM &&
+ pclastblock->lastPCode->args[0].data.reg.reg == op1.reg
+ )
+ {
+ PCode *pc = pclastblock->lastPCode;
+ SInt32 a = pc->args[2].data.imm.value;
+ SInt32 b = pc->args[3].data.imm.value;
+ SInt32 value = right->data.intval.lo;
+ if (b == pc->args[4].data.imm.value) {
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+
+ if (value != (value & 1)) {
+ emitpcode(PC_LI, finalReg, 1);
+ } else if (value == 0) {
+ emitpcode(
+ PC_RLWINM, finalReg,
+ pc->args[1].data.reg.reg,
+ (a + b + 1) & 31, 31, 31);
+ } else if (value == 1) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(
+ PC_RLWINM, tmpReg,
+ pc->args[1].data.reg.reg,
+ (a + b + 1) & 31, 31, 31);
+ emitpcode(PC_XORI, finalReg, tmpReg, 1);
+ } else {
+ CError_FATAL(5503);
+ }
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+ }
+
+ if (IS_INT_CONST_ZERO(right)) {
+ if (copts.optimizesize) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_ADDIC, tmpReg, op1.reg, -1);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SUBFE, finalReg, tmpReg, op1.reg);
+ } else {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_NEG, tmpReg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_OR, tmpReg2, tmpReg, op1.reg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_RLWINM, finalReg, tmpReg2, 1, 31, 31);
+ }
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ if (copts.optimizesize) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg, op1.reg, op2.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_ADDIC, tmpReg2, tmpReg, -1);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SUBFE, finalReg, tmpReg2, tmpReg);
+ } else {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg, op1.reg, op2.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg2, op2.reg, op1.reg);
+ tmpReg3 = ALLOC_GPR();
+ emitpcode(PC_OR, tmpReg3, tmpReg, tmpReg2);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_RLWINM, finalReg, tmpReg3, 1, 31, 31);
+ }
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+
+ case EGREATEREQU:
+ if (!is_unsigned(left->rtype) && IS_INT_CONST_ZERO(right)) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_RLWINM, tmpReg, op1.reg, 1, 31, 31);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_XORI, finalReg, tmpReg, 1);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+ opTmp = op2;
+ op2 = op1;
+ op1 = opTmp;
+
+ case ELESSEQU:
+ if (is_unsigned(left->rtype)) {
+ if (copts.optimizesize) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_LI, tmpReg, -1);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_SUBFC, tmpReg2, op1.reg, op2.reg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SUBFZE, finalReg, tmpReg);
+ } else {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg, op1.reg, op2.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_ORC, tmpReg2, op2.reg, op1.reg);
+ tmpReg3 = ALLOC_GPR();
+ emitpcode(PC_RLWINM, tmpReg3, tmpReg, 31, 1, 31);
+ tmpReg4 = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg4, tmpReg3, tmpReg2);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_RLWINM, finalReg, tmpReg4, 1, 31, 31);
+ }
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ if (IS_INT_CONST_ZERO(right)) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_LI, tmpReg, 1);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_CNTLZW, tmpReg2, op1.reg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_RLWNM, finalReg, tmpReg, tmpReg2, 31, 31);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_SRAWI, tmpReg2, op2.reg, 31);
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_RLWINM, tmpReg, op1.reg, 1, 31, 31);
+ tmpReg3 = ALLOC_GPR();
+ emitpcode(PC_SUBFC, tmpReg3, op1.reg, op2.reg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_ADDE, finalReg, tmpReg2, tmpReg);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+
+ case EGREATER:
+ if (!is_unsigned(left->rtype) && IS_INT_CONST_ZERO(right)) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_NEG, tmpReg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_ANDC, tmpReg2, tmpReg, op1.reg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_RLWINM, finalReg, tmpReg2, 1, 31, 31);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ opTmp = op2;
+ op2 = op1;
+ op1 = opTmp;
+
+ case ELESS:
+ if (is_unsigned(left->rtype)) {
+ if (left->rtype->size <= 2) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg, op2.reg, op1.reg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_RLWINM, finalReg, tmpReg, 1, 31, 31);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ } else {
+ if (copts.optimizesize) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBFC, tmpReg, op2.reg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_SUBFE, tmpReg2, tmpReg, tmpReg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_NEG, finalReg, tmpReg2);
+ } else {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_XOR, tmpReg, op2.reg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_CNTLZW, tmpReg2, tmpReg);
+ tmpReg3 = ALLOC_GPR();
+ emitpcode(PC_SLW, tmpReg3, op2.reg, tmpReg2);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_RLWINM, finalReg, tmpReg3, 1, 31, 31);
+ }
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+ return;
+ }
+
+ if (IS_INT_CONST_ZERO(right)) {
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_RLWINM, finalReg, op1.reg, 1, 31, 31);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_XOR, tmpReg, op2.reg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_SRAWI, tmpReg2, tmpReg, 1);
+ tmpReg3 = ALLOC_GPR();
+ emitpcode(PC_AND, tmpReg3, tmpReg, op2.reg);
+ tmpReg4 = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg4, tmpReg3, tmpReg2);
+
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_RLWINM, finalReg, tmpReg4, 1, 31, 31);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+
+ default:
+ CError_FATAL(5777);
+ }
+ }
+
+ gen_condition(cond, &condOp);
+ emitpcode(PC_MFCR, tmpReg = used_virtual_registers[RegClass_GPR]++);
+ a = 0;
+ b = condOp.reg * 4;
+ switch (condOp.regOffset) {
+ case ENOTEQU:
+ a = 1;
+ case EEQU:
+ b += 2;
+ break;
+ case EGREATEREQU:
+ a = 1;
+ break;
+ case ELESSEQU:
+ a = 1;
+ case EGREATER:
+ b += 1;
+ break;
+ }
+
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ if (a) {
+ emitpcode(PC_RLWINM, tmpReg, tmpReg, b + 1, 31, 31);
+ emitpcode(PC_XORI, finalReg, tmpReg, 1);
+ } else {
+ emitpcode(PC_RLWINM, finalReg, tmpReg, b + 1, 31, 31);
+ }
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+}
+
+void gen_negated_condition_gpr(ENode *cond, Operand *output, short outputReg) {
+ ENode *left;
+ ENode *right;
+ Operand op1;
+ Operand op2;
+ Operand opTmp;
+ int finalReg;
+ int tmpReg;
+ int tmpReg2;
+ int tmpReg3;
+
+ left = cond->data.diadic.left;
+ right = cond->data.diadic.right;
+ CError_ASSERT(5843, TYPE_FITS_IN_REGISTER(left->rtype) && TYPE_FITS_IN_REGISTER(right->rtype));
+
+ memclrw(&op1, sizeof(Operand));
+ memclrw(&op2, sizeof(Operand));
+ memclrw(&opTmp, sizeof(Operand));
+
+ if (right->hascall) {
+ GEN_NODE(right, &op2);
+ if (!IS_INT_CONST_ZERO(right)) {
+ if (right->rtype->size < 4)
+ extend32(&op2, right->rtype, 0);
+ ENSURE_GPR(&op2, right->rtype, 0);
+ }
+
+ GEN_NODE(left, &op1);
+ if (left->rtype->size < 4)
+ extend32(&op1, left->rtype, 0);
+ ENSURE_GPR(&op1, left->rtype, 0);
+ } else {
+ GEN_NODE(left, &op1);
+ ENSURE_GPR(&op1, left->rtype, 0);
+ if (left->rtype->size < 4)
+ extend32(&op1, left->rtype, 0);
+
+ GEN_NODE(right, &op2);
+ if (!IS_INT_CONST_ZERO(right)) {
+ if (right->rtype->size < 4)
+ extend32(&op2, right->rtype, 0);
+ ENSURE_GPR(&op2, right->rtype, 0);
+ }
+ }
+
+ switch (cond->type) {
+ case EEQU:
+ if (
+ copts.peephole &&
+ IS_INT_CONST(right) &&
+ pclastblock->pcodeCount > 0 &&
+ pclastblock->lastPCode->op == PC_RLWINM &&
+ pclastblock->lastPCode->args[0].data.reg.reg == op1.reg
+ )
+ {
+ PCode *pc = pclastblock->lastPCode;
+ SInt32 a = pc->args[2].data.imm.value;
+ SInt32 b = pc->args[3].data.imm.value;
+ SInt32 value = right->data.intval.lo;
+ if (b == pc->args[4].data.imm.value) {
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+
+ if (value != (value & 1)) {
+ emitpcode(PC_LI, finalReg, 0);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ if (value == 0) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(
+ PC_RLWINM, tmpReg,
+ pc->args[1].data.reg.reg,
+ (a + b + 1) & 31, 31, 31);
+ emitpcode(PC_ADDI, finalReg, tmpReg, 0, -1);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ if (value == 1) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(
+ PC_RLWINM,
+ tmpReg,
+ pc->args[1].data.reg.reg,
+ (a + b + 1) & 31,
+ 31,
+ 31);
+ emitpcode(PC_NEG, finalReg, tmpReg);
+ output->optype = OpndType_GPR;
+ output->reg = tmpReg; // bug???
+ return;
+ }
+
+ CError_FATAL(5923);
+ }
+ }
+
+ if (IS_INT_CONST_ZERO(right)) {
+ if (copts.optimizesize) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_ADDIC, tmpReg, op1.reg, -1);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SUBFE, finalReg, tmpReg, tmpReg);
+ } else {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_CNTLZW, tmpReg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_RLWINM, tmpReg2, tmpReg, 27, 31, 31);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_NEG, finalReg, tmpReg2);
+ }
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ if (copts.optimizesize) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg, op2.reg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_ADDIC, tmpReg2, tmpReg, -1);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SUBFE, finalReg, tmpReg2, tmpReg2);
+ } else {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg, op2.reg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg2, op1.reg, op2.reg);
+ tmpReg3 = ALLOC_GPR();
+ emitpcode(PC_NOR, tmpReg3, tmpReg, tmpReg2);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SRAWI, finalReg, tmpReg3, 31);
+ }
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+
+ case ENOTEQU:
+ if (
+ copts.peephole &&
+ IS_INT_CONST(right) &&
+ pclastblock->pcodeCount > 0 &&
+ pclastblock->lastPCode->op == PC_RLWINM &&
+ pclastblock->lastPCode->args[0].data.reg.reg == op1.reg
+ )
+ {
+ PCode *pc = pclastblock->lastPCode;
+ SInt32 a = pc->args[2].data.imm.value;
+ SInt32 b = pc->args[3].data.imm.value;
+ SInt32 value = right->data.intval.lo;
+ if (b == pc->args[4].data.imm.value) {
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+
+ if (value != (value & 1)) {
+ emitpcode(PC_LI, finalReg, -1);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ if (value == 0) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(
+ PC_RLWINM, tmpReg,
+ pc->args[1].data.reg.reg,
+ (a + b + 1) & 31, 31, 31);
+ emitpcode(PC_NEG, finalReg, tmpReg);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ if (value == 1) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(
+ PC_RLWINM, tmpReg,
+ pc->args[1].data.reg.reg,
+ (a + b + 1) & 31, 31, 31);
+ emitpcode(PC_ADDI, finalReg, tmpReg, 0, -1);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ CError_FATAL(6031);
+ }
+ }
+
+ if (IS_INT_CONST_ZERO(right)) {
+ if (copts.optimizesize) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBFIC, tmpReg, op1.reg, 0);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SUBFE, finalReg, tmpReg, tmpReg);
+ } else {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_NEG, tmpReg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_OR, tmpReg2, tmpReg, op1.reg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SRAWI, finalReg, tmpReg2, 31);
+ }
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ if (copts.optimizesize) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg, op2.reg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_SUBFIC, tmpReg2, tmpReg, 0);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SUBFE, finalReg, tmpReg2, tmpReg2);
+ } else {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg, op2.reg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg2, op1.reg, op2.reg);
+ tmpReg3 = ALLOC_GPR();
+ emitpcode(PC_OR, tmpReg3, tmpReg, tmpReg2);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SRAWI, finalReg, tmpReg3, 31);
+ }
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+
+ case EGREATEREQU:
+ if (!is_unsigned(left->rtype) && IS_INT_CONST_ZERO(right)) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_RLWINM, tmpReg, op1.reg, 1, 31, 31);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_ADDI, finalReg, tmpReg, 0, -1);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+ opTmp = op2;
+ op2 = op1;
+ op1 = opTmp;
+
+ case ELESSEQU:
+ if (is_unsigned(left->rtype)) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBFC, tmpReg, op1.reg, op2.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_ADDZE, tmpReg2, op1.reg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SUBF, finalReg, tmpReg2, op1.reg);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ if (IS_INT_CONST_ZERO(right)) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_NEG, tmpReg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_ORC, tmpReg2, op1.reg, tmpReg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SRAWI, finalReg, tmpReg2, 31);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_XORIS, tmpReg, op1.reg, 0x8000);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_SUBF, tmpReg2, op1.reg, op2.reg);
+ tmpReg3 = ALLOC_GPR();
+ emitpcode(PC_ADDC, tmpReg3, tmpReg2, tmpReg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SUBFE, finalReg, tmpReg3, tmpReg3);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+
+ case EGREATER:
+ if (!is_unsigned(left->rtype) && IS_INT_CONST_ZERO(right)) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_NEG, tmpReg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_ANDC, tmpReg2, tmpReg, op1.reg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SRAWI, finalReg, tmpReg2, 31);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+ opTmp = op2;
+ op2 = op1;
+ op1 = opTmp;
+
+ case ELESS:
+ if (is_unsigned(left->rtype)) {
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBFC, tmpReg, op2.reg, op1.reg);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SUBFE, finalReg, tmpReg, tmpReg);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ if (IS_INT_CONST_ZERO(right)) {
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SRAWI, finalReg, op1.reg, 31);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+ }
+
+ tmpReg = ALLOC_GPR();
+ emitpcode(PC_SUBFC, tmpReg, op2.reg, op1.reg);
+ tmpReg2 = ALLOC_GPR();
+ emitpcode(PC_RLWINM, tmpReg2, op2.reg, 1, 31, 31);
+ tmpReg3 = ALLOC_GPR();
+ emitpcode(PC_RLWINM, tmpReg3, op1.reg, 1, 31, 31);
+ finalReg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_SUBFE, finalReg, tmpReg3, tmpReg2);
+ output->optype = OpndType_GPR;
+ output->reg = finalReg;
+ return;
+
+ default:
+ CError_FATAL(6240);
+ }
+}
+
+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) {
+ int postIncFlag;
+ short postIncReg;
+ Operand op;
+ SInt32 postIncValue;
+
+ memclrw(&op, sizeof(Operand));
+
+ postIncFlag = ispostincrementopportunity(left, &op, &postIncValue);
+ if (!postIncFlag) {
+ GEN_NODE(left, &op);
+ if (op.optype != OpndType_CRField) {
+ if (left->rtype->size < 4)
+ extend32(&op, left->rtype, 0);
+ else
+ ENSURE_GPR(&op, left->rtype, 0);
+ }
+ } else {
+ postIncReg = op.reg;
+ if (left->rtype->size < 4)
+ extend32(&op, left->rtype, 0);
+ ENSURE_GPR(&op, left->rtype, 0);
+ }
+
+ if (op.optype == OpndType_CRField) {
+ if (
+ (nt == EEQU && value == 1) ||
+ (nt == ENOTEQU && value == 0) ||
+ (nt == EGREATER && value == 0) ||
+ (nt == EGREATEREQU && value == 1)
+ )
+ {
+ *output = op;
+ return;
+ }
+
+ if (
+ (nt == EEQU && value == 0) ||
+ (nt == ENOTEQU && value == 1) ||
+ (nt == ELESS && value == 1) ||
+ (nt == ELESSEQU && value == 0)
+ )
+ {
+ *output = op;
+ switch (op.regOffset) {
+ case EEQU:
+ output->regOffset = ENOTEQU;
+ return;
+ case ENOTEQU:
+ output->regOffset = EEQU;
+ return;
+ case ELESS:
+ output->regOffset = EGREATEREQU;
+ return;
+ case EGREATER:
+ output->regOffset = ELESSEQU;
+ return;
+ case ELESSEQU:
+ output->regOffset = EGREATER;
+ return;
+ case EGREATEREQU:
+ output->regOffset = ELESS;
+ return;
+ }
+ }
+
+ ENSURE_GPR(&op, left->rtype, 0);
+ }
+
+ if (
+ copts.peephole &&
+ value == 0 &&
+ pclastblock->pcodeCount > 0 &&
+ pclastblock->lastPCode->op != PC_RLWINM &&
+ (PCODE_FLAG_SET_F(pclastblock->lastPCode) & (fIsMove | fSideEffects | fCanSetRecordBit | fOpTypeGPR)) == (fCanSetRecordBit | fOpTypeGPR) &&
+ pclastblock->lastPCode->args[0].data.reg.reg == op.reg &&
+ (!is_unsigned(left->rtype) || nt == EEQU || nt == ENOTEQU)
+ )
+ {
+ pcsetrecordbit(pclastblock->lastPCode);
+ } else {
+ emitpcode(is_unsigned(left->rtype) ? PC_CMPLI : PC_CMPI, 0, op.reg, value);
+ }
+
+ if (postIncFlag)
+ add_register_immediate(postIncReg, postIncReg, postIncValue);
+
+ output->optype = OpndType_CRField;
+ output->reg = 0;
+ output->regOffset = nt;
+}
+
+void compare_immediate_long(short nt, ENode *left, SInt32 value, Operand *output) {
+ int postIncFlag;
+ short postIncReg;
+ int outputReg;
+ Operand op;
+ SInt32 postIncValue;
+
+ memclrw(&op, sizeof(Operand));
+
+ postIncFlag = ispostincrementopportunity(left, &op, &postIncValue);
+ if (!postIncFlag) {
+ GEN_NODE(left, &op);
+ } else {
+ postIncReg = op.reg;
+ }
+
+ if (left->rtype->size < 4)
+ extend32(&op, left->rtype, 0);
+ ENSURE_GPR(&op, left->rtype, 0);
+
+ outputReg = ALLOC_GPR();
+ emitpcode(PC_ADDIS, outputReg, op.reg, 0, (SInt16) (~(value >> 16) + 1));
+ emitpcode(PC_CMPLI, 0, outputReg, value & 0xFFFF);
+
+ if (postIncFlag)
+ add_register_immediate(postIncReg, postIncReg, postIncValue);
+
+ output->optype = OpndType_CRField;
+ output->reg = 0;
+ output->regOffset = nt;
+}
+
+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:
+ CError_ASSERT(6933, 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:
+ CError_FATAL(6979);
+ }
+
+ 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:
+ CError_FATAL(7211);
+ }
+
+ output->optype = OpndType_GPRPair;
+ output->reg = reg;
+ output->regHi = regHi;
+}
+
+void I8_gen_XOR(ENode *expr, short outputReg, short outputRegHi, Operand *output) {
+ ENode *left;
+ ENode *right;
+ short reg;
+ short regHi;
+ 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);
+ coerce_to_register_pair(&opright, right->rtype, 0, 0);
+
+ GEN_NODE(left, &opleft);
+ coerce_to_register_pair(&opleft, left->rtype, 0, 0);
+ } else {
+ GEN_NODE(left, &opleft);
+ coerce_to_register_pair(&opleft, left->rtype, 0, 0);
+
+ GEN_NODE(right, &opright);
+ coerce_to_register_pair(&opright, right->rtype, 0, 0);
+ }
+
+ CError_ASSERT(7254, opleft.optype == OpndType_GPRPair && opright.optype == OpndType_GPRPair);
+
+ reg = outputReg ? outputReg : ALLOC_GPR();
+ regHi = outputRegHi ? outputRegHi : ALLOC_GPR();
+
+ emitpcode(PC_XOR, reg, opleft.reg, opright.reg);
+ emitpcode(PC_XOR, regHi, opleft.regHi, opright.regHi);
+
+ output->optype = OpndType_GPRPair;
+ output->reg = reg;
+ output->regHi = regHi;
+}
+
+void I8_gen_OR(ENode *expr, short outputReg, short outputRegHi, Operand *output) {
+ ENode *left;
+ ENode *right;
+ short reg;
+ short regHi;
+ 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);
+ coerce_to_register_pair(&opright, right->rtype, 0, 0);
+
+ GEN_NODE(left, &opleft);
+ coerce_to_register_pair(&opleft, left->rtype, 0, 0);
+ } else {
+ GEN_NODE(left, &opleft);
+ coerce_to_register_pair(&opleft, left->rtype, 0, 0);
+
+ GEN_NODE(right, &opright);
+ coerce_to_register_pair(&opright, right->rtype, 0, 0);
+ }
+
+ CError_ASSERT(7304, opleft.optype == OpndType_GPRPair && opright.optype == OpndType_GPRPair);
+
+ reg = outputReg ? outputReg : ALLOC_GPR();
+ regHi = outputRegHi ? outputRegHi : ALLOC_GPR();
+
+ emitpcode(PC_OR, reg, opleft.reg, opright.reg);
+ emitpcode(PC_OR, regHi, opleft.regHi, opright.regHi);
+
+ output->optype = OpndType_GPRPair;
+ output->reg = reg;
+ output->regHi = regHi;
+}
+
+void I8_gen_AND(ENode *expr, short outputReg, short outputRegHi, Operand *output) {
+ ENode *left;
+ ENode *right;
+ short reg;
+ short regHi;
+ 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);
+ coerce_to_register_pair(&opright, right->rtype, 0, 0);
+
+ GEN_NODE(left, &opleft);
+ coerce_to_register_pair(&opleft, left->rtype, 0, 0);
+ } else {
+ GEN_NODE(left, &opleft);
+ coerce_to_register_pair(&opleft, left->rtype, 0, 0);
+
+ GEN_NODE(right, &opright);
+ coerce_to_register_pair(&opright, right->rtype, 0, 0);
+ }
+
+ CError_ASSERT(7354, opleft.optype == OpndType_GPRPair && opright.optype == OpndType_GPRPair);
+
+ reg = outputReg ? outputReg : ALLOC_GPR();
+ regHi = outputRegHi ? outputRegHi : ALLOC_GPR();
+
+ emitpcode(PC_AND, reg, opleft.reg, opright.reg);
+ emitpcode(PC_AND, regHi, opleft.regHi, opright.regHi);
+
+ output->optype = OpndType_GPRPair;
+ output->reg = reg;
+ output->regHi = regHi;
+}
+
+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)
+ CError_FATAL(7703);
+
+ 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 {
+ CError_FATAL(7732);
+ }
+}
+
+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)
+ CError_FATAL(7756);
+
+ 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 {
+ CError_FATAL(7866);
+ }
+}
+
+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))
+ CError_FATAL(7900);
+
+ 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:
+ CError_ASSERT(8097, 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:
+ CError_FATAL(8218);
+ }
+ }
+
+ 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
+ CError_FATAL(8328);
+ 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) {
+ CError_FATAL(8348);
+ } 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)) {
+ CError_FATAL(8376);
+ } 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;
+ }
+
+ CError_ASSERT(8446, !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:
+ CError_FATAL(8511);
+ }
+
+ output->reg = vi->reg;
+ output->regHi = vi->regHi;
+ output->object = NULL;
+ return;
+ }
+
+ if (ENODE_IS(inner, EBITFIELD)) {
+ CError_FATAL(8529);
+ 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;
+ }
+ }
+
+ CError_ASSERT(8704, 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:
+ CError_FATAL(8814);
+ }
+}
+
+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;
+ }
+
+ CError_ASSERT(8890, 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 {
+ CError_FATAL(8909);
+ }
+
+ 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)) {
+ CError_ASSERT(8976, 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 {
+ CError_FATAL(9018);
+ }
+ } 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);
+
+ CError_ASSERT(9048, 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 {
+ CError_FATAL(9074);
+ }
+
+ 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) {
+ CError_ASSERT(9171, 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);
+ CError_ASSERT(9200, 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)) {
+ CError_FATAL(9222);
+ 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 {
+ CError_FATAL(9256);
+ }
+ return;
+ }
+
+ CError_FATAL(9261);
+}
+
+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))
+ CError_FATAL(9282);
+
+ 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;
+ }
+
+ CError_FATAL(9298);
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Intrinsics.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Intrinsics.c
new file mode 100644
index 0000000..49334b8
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Intrinsics.c
@@ -0,0 +1,4894 @@
+#include "compiler/Intrinsics.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/CScope.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/FunctionCalls.h"
+#include "compiler/InstrSelection.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/PPCError.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/StackFrame.h"
+#include "compiler/StructMoves.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/types.h"
+
+Object *__memcpy_object;
+static Object *intrinsics[311];
+int VectorConditions; // unused?
+static Object *cur_intrinsic_object;
+
+static TypePointer stvectorunsignedchar_ptr = {TYPEPOINTER, 4, TYPE(&stvectorunsignedchar), 0};
+static TypePointer stvectorsignedchar_ptr = {TYPEPOINTER, 4, TYPE(&stvectorsignedchar), 0};
+static TypePointer stvectorboolchar_ptr = {TYPEPOINTER, 4, TYPE(&stvectorboolchar), 0};
+static TypePointer stvectorunsignedshort_ptr = {TYPEPOINTER, 4, TYPE(&stvectorunsignedshort), 0};
+static TypePointer stvectorsignedshort_ptr = {TYPEPOINTER, 4, TYPE(&stvectorsignedshort), 0};
+static TypePointer stvectorboolshort_ptr = {TYPEPOINTER, 4, TYPE(&stvectorboolshort), 0};
+static TypePointer stvectorunsignedlong_ptr = {TYPEPOINTER, 4, TYPE(&stvectorunsignedlong), 0};
+static TypePointer stvectorsignedlong_ptr = {TYPEPOINTER, 4, TYPE(&stvectorsignedlong), 0};
+static TypePointer stvectorboollong_ptr = {TYPEPOINTER, 4, TYPE(&stvectorboollong), 0};
+static TypePointer stvectorfloat_ptr = {TYPEPOINTER, 4, TYPE(&stvectorfloat), 0};
+static TypePointer stvectorpixel_ptr = {TYPEPOINTER, 4, TYPE(&stvectorpixel), 0};
+static TypePointer stunsignedchar_ptr = {TYPEPOINTER, 4, TYPE(&stunsignedchar), 0};
+static TypePointer stsignedchar_ptr = {TYPEPOINTER, 4, TYPE(&stsignedchar), 0};
+static TypePointer stunsignedshort_ptr = {TYPEPOINTER, 4, TYPE(&stunsignedshort), 0};
+static TypePointer stsignedshort_ptr = {TYPEPOINTER, 4, TYPE(&stsignedshort), 0};
+static TypePointer stunsignedlong_ptr = {TYPEPOINTER, 4, TYPE(&stunsignedlong), 0};
+static TypePointer stsignedlong_ptr = {TYPEPOINTER, 4, TYPE(&stsignedlong), 0};
+static TypePointer stunsignedint_ptr = {TYPEPOINTER, 4, TYPE(&stunsignedint), 0};
+static TypePointer stsignedint_ptr = {TYPEPOINTER, 4, TYPE(&stsignedint), 0};
+static TypePointer stfloat_ptr = {TYPEPOINTER, 4, TYPE(&stfloat), 0};
+
+// Verify1VectorArg2Ops
+typedef struct TypeTable22 {
+ Type *rtype;
+ Type *arg1;
+ int opcode1;
+ int opcode2;
+} TypeTable22;
+
+// VerifyNoVectorArgs
+typedef struct TypeTable11 {
+ Type *rtype;
+ int opcode;
+} TypeTable11;
+
+// Verify1VectorArg
+typedef struct TypeTable21 {
+ Type *rtype;
+ Type *arg1;
+ int opcode;
+} TypeTable21;
+
+// Verify2VectorArgs
+typedef struct TypeTable31 {
+ Type *rtype;
+ Type *arg1;
+ Type *arg2;
+ int opcode;
+} TypeTable31;
+
+// Verify3VectorArgs
+typedef struct TypeTable41 {
+ Type *rtype;
+ Type *arg1;
+ Type *arg2;
+ Type *arg3;
+ int opcode;
+} TypeTable41;
+
+static TypeTable31 vector_add_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VADDUBM,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VADDUBM,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VADDUBM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VADDUBM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VADDUBM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VADDUBM,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VADDUHM,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VADDUHM,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VADDUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VADDUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VADDUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VADDUHM,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VADDUWM,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VADDUWM,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VADDUWM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VADDUWM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VADDUWM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VADDUWM,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VADDFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_addc_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VADDCUW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_adds_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VADDUBS,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VADDUBS,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VADDUBS,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VADDSBS,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VADDSBS,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VADDSBS,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VADDUHS,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VADDUHS,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VADDUHS,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VADDSHS,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VADDSHS,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VADDSHS,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VADDUWS,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VADDUWS,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VADDUWS,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VADDSWS,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VADDSWS,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VADDSWS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_and_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VAND,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VAND,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VAND,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VAND,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VAND,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VAND,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VAND,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VAND,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VAND,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VAND,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VAND,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VAND,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VAND,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VAND,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VAND,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VAND,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VAND,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VAND,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VAND,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VAND,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VAND,
+ TYPE(&stvectorfloat), TYPE(&stvectorboollong), TYPE(&stvectorfloat), PC_VAND,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorboollong), PC_VAND,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VAND,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_andc_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VANDC,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VANDC,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VANDC,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VANDC,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VANDC,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VANDC,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VANDC,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VANDC,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VANDC,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VANDC,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VANDC,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VANDC,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VANDC,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VANDC,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VANDC,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VANDC,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VANDC,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VANDC,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VANDC,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VANDC,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VANDC,
+ TYPE(&stvectorfloat), TYPE(&stvectorboollong), TYPE(&stvectorfloat), PC_VANDC,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorboollong), PC_VANDC,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VANDC,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_avg_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VAVGUB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VAVGSB,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VAVGUH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VAVGSH,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VAVGUW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VAVGSW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable22 vector_ceil_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VRFIP, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable31 vector_cmpb_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPBFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_cmpeq_type_table[] = {
+ TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB,
+ TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB,
+ TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH,
+ TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH,
+ TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW,
+ TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPEQUW,
+ TYPE(&stvectorboollong), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPEQFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_cmpge_type_table[] = {
+ TYPE(&stvectorboollong), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_cmpgt_type_table[] = {
+ TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stvectorboollong), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_ctf_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), PC_VCFUX,
+ TYPE(&stvectorfloat), TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VCFSX,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_cts_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorfloat), TYPE(&stsignedint), PC_VCTSXS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_ctu_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorfloat), TYPE(&stsignedint), PC_VCTUXS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable22 vector_dss_type_table[] = {
+ TYPE(&stvoid), TYPE(&stsignedint), PC_DSS, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable11 vector_dssall_type_table[] = {
+ TYPE(&stvoid), PC_DSSALL,
+ NULL, 0
+};
+static TypeTable41 vector_datastream_type_table[] = {
+ TYPE(&stvoid), TYPE(&stvectorunsignedchar_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stvectorsignedchar_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stvectorboolchar_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stvectorunsignedshort_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stvectorsignedshort_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stvectorboolshort_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stvectorpixel_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stvectorunsignedlong_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stvectorsignedlong_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stvectorboollong_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stvectorfloat_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stunsignedchar_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stsignedchar_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stunsignedshort_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stsignedshort_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stunsignedint_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stsignedint_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stunsignedlong_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stsignedlong_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ TYPE(&stvoid), TYPE(&stfloat_ptr), TYPE(&stsignedint), TYPE(&stsignedint), PC_DST,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable22 vector_expte_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VEXPTEFP, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable22 vector_floor_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VRFIM, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable31 vector_load_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stvectorunsignedchar_ptr), PC_LVX,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_LVX,
+ TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stvectorsignedchar_ptr), PC_LVX,
+ TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_LVX,
+ TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stvectorboolchar_ptr), PC_LVX,
+ TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stvectorunsignedshort_ptr), PC_LVX,
+ TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_LVX,
+ TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stvectorsignedshort_ptr), PC_LVX,
+ TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_LVX,
+ TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stvectorboolshort_ptr), PC_LVX,
+ TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stvectorpixel_ptr), PC_LVX,
+ TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stvectorunsignedlong_ptr), PC_LVX,
+ TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_LVX,
+ TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_LVX,
+ TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stvectorsignedlong_ptr), PC_LVX,
+ TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_LVX,
+ TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_LVX,
+ TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stvectorboollong_ptr), PC_LVX,
+ TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stvectorfloat_ptr), PC_LVX,
+ TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_LVX,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_loade_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_LVEBX,
+ TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_LVEBX,
+ TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_LVEHX,
+ TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_LVEHX,
+ TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_LVEWX,
+ TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_LVEWX,
+ TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_LVEWX,
+ TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_LVEWX,
+ TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_LVEWX,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_loadl_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stvectorunsignedchar_ptr), PC_LVXL,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_LVXL,
+ TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stvectorsignedchar_ptr), PC_LVXL,
+ TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_LVXL,
+ TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stvectorboolchar_ptr), PC_LVXL,
+ TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stvectorunsignedshort_ptr), PC_LVXL,
+ TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_LVXL,
+ TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stvectorsignedshort_ptr), PC_LVXL,
+ TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_LVXL,
+ TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stvectorboolshort_ptr), PC_LVXL,
+ TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stvectorpixel_ptr), PC_LVXL,
+ TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stvectorunsignedlong_ptr), PC_LVXL,
+ TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_LVXL,
+ TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_LVXL,
+ TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stvectorsignedlong_ptr), PC_LVXL,
+ TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_LVXL,
+ TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_LVXL,
+ TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stvectorboollong_ptr), PC_LVXL,
+ TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stvectorfloat_ptr), PC_LVXL,
+ TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_LVXL,
+ NULL, NULL, NULL, 0
+};
+static TypeTable22 vector_loge_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VLOGEFP, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable31 vector_lvsl_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_LVSL,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_LVSL,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_LVSL,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_LVSL,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_LVSL,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_LVSL,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_LVSL,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_LVSL,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_LVSL,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_lvsr_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_LVSR,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_LVSR,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_LVSR,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_LVSR,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_LVSR,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_LVSR,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_LVSR,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_LVSR,
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_LVSR,
+ NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_madd_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMADDFP,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_madds_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMHADDSHS,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_max_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMAXUB,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VMAXUB,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VMAXUB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMAXSB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VMAXSB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VMAXSB,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMAXUH,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VMAXUH,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VMAXUH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMAXSH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VMAXSH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VMAXSH,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMAXUW,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VMAXUW,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VMAXUW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMAXSW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VMAXSW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VMAXSW,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMAXFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_mergeh_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGHB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMRGHB,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VMRGHB,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGHH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMRGHH,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VMRGHH,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VMRGHH,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMRGHW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMRGHW,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VMRGHW,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMRGHW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_mergel_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGLB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMRGLB,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VMRGLB,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGLH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMRGLH,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VMRGLH,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VMRGLH,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMRGLW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMRGLW,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VMRGLW,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMRGLW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable11 vector_mfvscr_type_table[] = {
+ TYPE(&stvectorunsignedshort), PC_MFVSCR,
+ NULL, 0
+};
+static TypeTable31 vector_min_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMINUB,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VMINUB,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VMINUB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMINSB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VMINSB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VMINSB,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMINUH,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VMINUH,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VMINUH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMINSH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VMINSH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VMINSH,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMINUW,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VMINUW,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VMINUW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMINSW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VMINSW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VMINSW,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMINFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_mladd_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMLADDUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMLADDUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMLADDUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMLADDUHM,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_mradds_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMHRADDSHS,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_msum_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedlong), PC_VMSUMUBM,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), PC_VMSUMUHM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorsignedlong), PC_VMSUMMBM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), PC_VMSUMSHM,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_msums_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), PC_VMSUMUHS,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), PC_VMSUMSHS,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable21 vector_mtvscr_type_table[] = {
+ TYPE(&stvoid), TYPE(&stvectorunsignedchar), PC_MTVSCR,
+ TYPE(&stvoid), TYPE(&stvectorsignedchar), PC_MTVSCR,
+ TYPE(&stvoid), TYPE(&stvectorboolchar), PC_MTVSCR,
+ TYPE(&stvoid), TYPE(&stvectorunsignedshort), PC_MTVSCR,
+ TYPE(&stvoid), TYPE(&stvectorsignedshort), PC_MTVSCR,
+ TYPE(&stvoid), TYPE(&stvectorboolshort), PC_MTVSCR,
+ TYPE(&stvoid), TYPE(&stvectorpixel), PC_MTVSCR,
+ TYPE(&stvoid), TYPE(&stvectorunsignedlong), PC_MTVSCR,
+ TYPE(&stvoid), TYPE(&stvectorsignedlong), PC_MTVSCR,
+ TYPE(&stvoid), TYPE(&stvectorboollong), PC_MTVSCR,
+ NULL, NULL, 0
+};
+static TypeTable31 vector_mule_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMULEUB,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMULESB,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMULEUH,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMULESH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_mulo_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMULOUB,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMULOSB,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMULOUH,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMULOSH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_nmsub_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VNMSUBFP,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_nor_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VNOR,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VNOR,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VNOR,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VNOR,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VNOR,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VNOR,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VNOR,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VNOR,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VNOR,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VNOR,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_or_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VOR,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VOR,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VOR,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VOR,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VOR,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VOR,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VOR,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VOR,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VOR,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VOR,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VOR,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VOR,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VOR,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VOR,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VOR,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VOR,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VOR,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VOR,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VOR,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VOR,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VOR,
+ TYPE(&stvectorfloat), TYPE(&stvectorboollong), TYPE(&stvectorfloat), PC_VOR,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorboollong), PC_VOR,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VOR,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_pack_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VPKUHUM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VPKUHUM,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VPKUHUM,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VPKUWUM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VPKUWUM,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VPKUWUM,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_packpx_type_table[] = {
+ TYPE(&stvectorpixel), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VPKPX,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_packs_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VPKUHUS,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VPKSHSS,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VPKUWUS,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VPKSWSS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_packsu_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VPKUHUS,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VPKSHUS,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VPKUWUS,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VPKSWUS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_perm_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VPERM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VPERM,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VPERM,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), PC_VPERM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), PC_VPERM,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedchar), PC_VPERM,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedchar), PC_VPERM,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), PC_VPERM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedchar), PC_VPERM,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedchar), PC_VPERM,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorunsignedchar), PC_VPERM,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable22 vector_re_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VREFP, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable31 vector_rl_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VRLB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VRLB,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VRLH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VRLH,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VRLW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VRLW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable22 vector_round_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VRFIN, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable22 vector_rsqrte_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VRSQRTEFP, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable41 vector_sel_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSEL,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VSEL,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSEL,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VSEL,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSEL,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VSEL,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSEL,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VSEL,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSEL,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VSEL,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSEL,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VSEL,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSEL,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VSEL,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSEL,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VSEL,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSEL,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VSEL,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorunsignedlong), PC_VSEL,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorboollong), PC_VSEL,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_sl_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSLB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSLB,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSLH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSLH,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSLW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSLW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_sld_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), PC_VSLDOI,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stsignedint), PC_VSLDOI,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), PC_VSLDOI,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stsignedint), PC_VSLDOI,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stsignedint), PC_VSLDOI,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), PC_VSLDOI,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VSLDOI,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stsignedint), PC_VSLDOI,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_sll_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSL,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), PC_VSL,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedlong), PC_VSL,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSL,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedshort), PC_VSL,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedlong), PC_VSL,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSL,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedshort), PC_VSL,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedlong), PC_VSL,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), PC_VSL,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSL,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), PC_VSL,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), PC_VSL,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSL,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedlong), PC_VSL,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedchar), PC_VSL,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSL,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedlong), PC_VSL,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedchar), PC_VSL,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedshort), PC_VSL,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedlong), PC_VSL,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), PC_VSL,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), PC_VSL,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSL,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedchar), PC_VSL,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedshort), PC_VSL,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSL,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedchar), PC_VSL,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedshort), PC_VSL,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSL,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_slo_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSLO,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorsignedchar), PC_VSLO,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSLO,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSLO,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), PC_VSLO,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorsignedchar), PC_VSLO,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), PC_VSLO,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), PC_VSLO,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedchar), PC_VSLO,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorsignedchar), PC_VSLO,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), PC_VSLO,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorsignedchar), PC_VSLO,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedchar), PC_VSLO,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedchar), PC_VSLO,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorunsignedchar), PC_VSLO,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorsignedchar), PC_VSLO,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_splat_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), PC_VSPLTB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stsignedint), PC_VSPLTB,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stsignedint), PC_VSPLTB,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), PC_VSPLTH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stsignedint), PC_VSPLTH,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stsignedint), PC_VSPLTH,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stsignedint), PC_VSPLTH,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), PC_VSPLTW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VSPLTW,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stsignedint), PC_VSPLTW,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stsignedint), PC_VSPLTW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable22 vector_splat_s8_type_table[] = {
+ TYPE(&stvectorsignedchar), TYPE(&stsignedint), PC_VSPLTISB, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable22 vector_splat_s16_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stsignedint), PC_VSPLTISH, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable22 vector_splat_s32_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VSPLTISW, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable22 vector_splat_u8_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), PC_VSPLTISB, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable22 vector_splat_u16_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stsignedint), PC_VSPLTISH, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable22 vector_splat_u32_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stsignedint), PC_VSPLTISW, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable31 vector_sr_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSRB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSRB,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSRH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSRH,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSRW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSRW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_sra_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSRAB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSRAB,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSRAH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSRAH,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSRAW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSRAW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_srl_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSR,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), PC_VSR,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedlong), PC_VSR,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSR,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedshort), PC_VSR,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedlong), PC_VSR,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSR,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedshort), PC_VSR,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedlong), PC_VSR,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), PC_VSR,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSR,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), PC_VSR,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), PC_VSR,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSR,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedlong), PC_VSR,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedchar), PC_VSR,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSR,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedlong), PC_VSR,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedchar), PC_VSR,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedshort), PC_VSR,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedlong), PC_VSR,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), PC_VSR,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), PC_VSR,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSR,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedchar), PC_VSR,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedshort), PC_VSR,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSR,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedchar), PC_VSR,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedshort), PC_VSR,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSR,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_sro_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSRO,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorsignedchar), PC_VSRO,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSRO,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSRO,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), PC_VSRO,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorsignedchar), PC_VSRO,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), PC_VSRO,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), PC_VSRO,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorunsignedchar), PC_VSRO,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorsignedchar), PC_VSRO,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), PC_VSRO,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorsignedchar), PC_VSRO,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedchar), PC_VSRO,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedchar), PC_VSRO,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorunsignedchar), PC_VSRO,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorsignedchar), PC_VSRO,
+ NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_st_type_table[] = {
+ TYPE(&stvoid), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stvectorunsignedchar_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stvectorsignedchar_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stvectorunsignedshort_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stvectorsignedshort_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stvectorunsignedlong_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stvectorsignedlong_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stvectorfloat_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stvectorpixel_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stvectorboolchar_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stvectorboolshort_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stvectorboollong_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVX,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVX,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_ste_type_table[] = {
+ TYPE(&stvoid), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVEBX,
+ TYPE(&stvoid), TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVEBX,
+ TYPE(&stvoid), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVEHX,
+ TYPE(&stvoid), TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVEHX,
+ TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVEHX,
+ TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVEHX,
+ TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVEBX,
+ TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVEBX,
+ TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVEHX,
+ TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVEHX,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVEWX,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_stl_type_table[] = {
+ TYPE(&stvoid), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stvectorunsignedchar_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stvectorsignedchar_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stvectorunsignedshort_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stvectorsignedshort_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stvectorunsignedlong_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stvectorsignedlong_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stvectorfloat_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stvectorpixel_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stvectorboolchar_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stvectorboolshort_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stvectorboollong_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVXL,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVXL,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_sub_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSUBUBM,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VSUBUBM,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSUBUBM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSUBUBM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VSUBUBM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VSUBUBM,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSUBUHM,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VSUBUHM,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSUBUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VSUBUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VSUBUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VSUBUHM,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSUBUWM,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VSUBUWM,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSUBUWM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUBUWM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VSUBUWM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VSUBUWM,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VSUBFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_subc_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSUBCUW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_subs_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSUBUBS,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VSUBUBS,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSUBUBS,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSUBSBS,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VSUBSBS,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VSUBSBS,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSUBUHS,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VSUBUHS,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSUBUHS,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VSUBSHS,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VSUBSHS,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VSUBSHS,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSUBUWS,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VSUBUWS,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSUBUWS,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUBSWS,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VSUBSWS,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VSUBSWS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_sum4s_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedlong), PC_VSUM4UBS,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedlong), PC_VSUM4SBS,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), PC_VSUM4SHS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_sum2s_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUM2SWS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_sums_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUMSWS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable22 vector_trunc_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VRFIZ, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable31 vector_unpack2sh_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGHB,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGHH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_unpack2sl_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGLB,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGLH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_unpack2uh_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGHB,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGHH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_unpack2ul_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGLB,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGLH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable21 vector_unpackh_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), PC_VUPKHSB,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolchar), PC_VUPKHSB,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorpixel), PC_VUPKHPX,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), PC_VUPKHSH,
+ TYPE(&stvectorboollong), TYPE(&stvectorboolshort), PC_VUPKHSH,
+ NULL, NULL, 0
+};
+static TypeTable21 vector_unpackl_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), PC_VUPKLSB,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolchar), PC_VUPKLSB,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorpixel), PC_VUPKLPX,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), PC_VUPKLSH,
+ TYPE(&stvectorboollong), TYPE(&stvectorboolshort), PC_VUPKLSH,
+ NULL, NULL, 0
+};
+static TypeTable31 vector_xor_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VXOR,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VXOR,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VXOR,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VXOR,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VXOR,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VXOR,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VXOR,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VXOR,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VXOR,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VXOR,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VXOR,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VXOR,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VXOR,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VXOR,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VXOR,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VXOR,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VXOR,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VXOR,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VXOR,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VXOR,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VXOR,
+ TYPE(&stvectorfloat), TYPE(&stvectorboollong), TYPE(&stvectorfloat), PC_VXOR,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorboollong), PC_VXOR,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VXOR,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_all_eq_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPEQFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_all_ge_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_all_gt_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_all_in_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPBFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_all_le_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_all_lt_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP
+};
+static TypeTable22 vector_all_nan_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), PC_VCMPEQFP, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable31 vector_all_ne_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPEQFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_all_nge_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_all_ngt_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_all_nle_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_all_nlt_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable22 vector_all_numeric_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), PC_VCMPEQFP, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable31 vector_any_eq_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPEQFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_any_ge_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_any_gt_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_any_le_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_any_lt_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable22 vector_any_nan_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), PC_VCMPEQFP, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable31 vector_any_ne_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VCMPEQUB,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VCMPEQUH,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VCMPEQUW,
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPEQFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_any_nge_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_any_ngt_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_any_nle_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGEFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_any_nlt_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable22 vector_any_numeric_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), PC_VCMPEQFP, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable31 vector_any_out_type_table[] = {
+ TYPE(&stsignedint), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPBFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vaddubm_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VADDUBM,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VADDUBM,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VADDUBM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VADDUBM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VADDUBM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VADDUBM,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vadduhm_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VADDUHM,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VADDUHM,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VADDUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VADDUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VADDUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VADDUHM,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vadduwm_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VADDUWM,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VADDUWM,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VADDUWM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VADDUWM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VADDUWM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VADDUWM,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vaddfp_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VADDFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vaddubs_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VADDUBS,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VADDUBS,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VADDUBS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vaddsbs_type_table[] = {
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VADDSBS,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VADDSBS,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VADDSBS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vadduhs_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VADDUHS,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VADDUHS,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VADDUHS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vaddshs_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VADDSHS,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VADDSHS,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VADDSHS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vadduws_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VADDUWS,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VADDUWS,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VADDUWS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vaddsws_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VADDSWS,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VADDSWS,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VADDSWS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vavgub_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VAVGUB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vavgsb_type_table[] = {
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VAVGSB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vavguh_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VAVGUH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vavgsh_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VAVGSH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vavguw_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VAVGUW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vavgsw_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VAVGSW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vcmpequb_type_table[] = {
+ TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPEQUB,
+ TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPEQUB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vcmpequh_type_table[] = {
+ TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPEQUH,
+ TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPEQUH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vcmpequw_type_table[] = {
+ TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPEQUW,
+ TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPEQUW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vcmpeqfp_type_table[] = {
+ TYPE(&stvectorboollong), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPEQFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vcmpgtub_type_table[] = {
+ TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VCMPGTUB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vcmpgtsb_type_table[] = {
+ TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VCMPGTSB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vcmpgtuh_type_table[] = {
+ TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VCMPGTUH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vcmpgtsh_type_table[] = {
+ TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VCMPGTSH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vcmpgtuw_type_table[] = {
+ TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VCMPGTUW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vcmpgtsw_type_table[] = {
+ TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VCMPGTSW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vcmpgtfp_type_table[] = {
+ TYPE(&stvectorboollong), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VCMPGTFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vcfux_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), PC_VCFUX,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vcfsx_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VCFSX,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_lvebx_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_LVEBX,
+ TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_LVEBX,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_lvehx_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_LVEHX,
+ TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_LVEHX,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_lvewx_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_LVEWX,
+ TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_LVEWX,
+ TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_LVEWX,
+ TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_LVEWX,
+ TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_LVEWX,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmaxub_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMAXUB,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VMAXUB,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VMAXUB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmaxsb_type_table[] = {
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMAXSB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VMAXSB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VMAXSB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmaxuh_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMAXUH,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VMAXUH,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VMAXUH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmaxsh_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMAXSH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VMAXSH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VMAXSH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmaxuw_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMAXUW,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VMAXUW,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VMAXUW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmaxsw_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMAXSW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VMAXSW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VMAXSW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmaxfp_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMAXFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmrghb_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGHB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMRGHB,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VMRGHB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmrghh_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGHH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMRGHH,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VMRGHH,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VMRGHH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmrghw_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMRGHW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMRGHW,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VMRGHW,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMRGHW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmrglb_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMRGLB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMRGLB,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), PC_VMRGLB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmrglh_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMRGLH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMRGLH,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VMRGLH,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stvectorpixel), PC_VMRGLH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmrglw_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMRGLW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMRGLW,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VMRGLW,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMRGLW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vminub_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMINUB,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VMINUB,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VMINUB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vminsb_type_table[] = {
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMINSB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VMINSB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VMINSB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vminuh_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMINUH,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VMINUH,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VMINUH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vminsh_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMINSH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VMINSH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VMINSH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vminuw_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VMINUW,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VMINUW,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VMINUW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vminsw_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VMINSW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VMINSW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VMINSW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vminfp_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VMINFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_vmsumubm_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedlong), PC_VMSUMUBM,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_vmsumuhm_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), PC_VMSUMUHM,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_vmsummbm_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorsignedlong), PC_VMSUMMBM,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_vmsumshm_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), PC_VMSUMSHM,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_vmsumuhs_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), PC_VMSUMUHS,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_vmsumshs_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), PC_VMSUMSHS,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmuleub_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMULEUB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmulesb_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMULESB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmuleuh_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMULEUH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmulesh_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMULESH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmuloub_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VMULOUB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmulosb_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VMULOSB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmulouh_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VMULOUH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vmulosh_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VMULOSH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vpkuhum_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VPKUHUM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VPKUHUM,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), PC_VPKUHUM,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vpkuwum_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VPKUWUM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VPKUWUM,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboollong), TYPE(&stvectorboollong), PC_VPKUWUM,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vpkuhus_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VPKUHUS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vpkshss_type_table[] = {
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VPKSHSS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vpkuwus_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VPKUWUS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vpkswss_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VPKSWSS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vpkshus_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VPKSHUS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vpkswus_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VPKSWUS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vrlb_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VRLB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VRLB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vrlh_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VRLH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VRLH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vrlw_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VRLW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VRLW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vslb_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSLB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSLB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vslh_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSLH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSLH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vslw_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSLW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSLW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vspltb_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), PC_VSPLTB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stsignedint), PC_VSPLTB,
+ TYPE(&stvectorboolchar), TYPE(&stvectorboolchar), TYPE(&stsignedint), PC_VSPLTB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsplth_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), PC_VSPLTH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stsignedint), PC_VSPLTH,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolshort), TYPE(&stsignedint), PC_VSPLTH,
+ TYPE(&stvectorpixel), TYPE(&stvectorpixel), TYPE(&stsignedint), PC_VSPLTH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vspltw_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), PC_VSPLTW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VSPLTW,
+ TYPE(&stvectorboollong), TYPE(&stvectorboollong), TYPE(&stsignedint), PC_VSPLTW,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stsignedint), PC_VSPLTW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable22 vector_vspltisb_type_table[] = {
+ TYPE(&stvectorsignedchar), TYPE(&stsignedint), PC_VSPLTISB, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable22 vector_vspltish_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stsignedint), PC_VSPLTISH, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable22 vector_vspltisw_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stsignedint), PC_VSPLTISW, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable31 vector_vsrb_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSRB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSRB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsrh_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSRH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSRH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsrw_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSRW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSRW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsrab_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSRAB,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorunsignedchar), PC_VSRAB,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsrah_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSRAH,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorunsignedshort), PC_VSRAH,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsraw_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSRAW,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorunsignedlong), PC_VSRAW,
+ NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_stvebx_type_table[] = {
+ TYPE(&stvoid), TYPE(&stvectorunsignedchar), TYPE(&stsignedint), TYPE(&stunsignedchar_ptr), PC_STVEBX,
+ TYPE(&stvoid), TYPE(&stvectorsignedchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVEBX,
+ TYPE(&stvoid), TYPE(&stvectorboolchar), TYPE(&stsignedint), TYPE(&stsignedchar_ptr), PC_STVEBX,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_stvehx_type_table[] = {
+ TYPE(&stvoid), TYPE(&stvectorunsignedshort), TYPE(&stsignedint), TYPE(&stunsignedshort_ptr), PC_STVEHX,
+ TYPE(&stvoid), TYPE(&stvectorsignedshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVEHX,
+ TYPE(&stvoid), TYPE(&stvectorboolshort), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVEHX,
+ TYPE(&stvoid), TYPE(&stvectorpixel), TYPE(&stsignedint), TYPE(&stsignedshort_ptr), PC_STVEHX,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable41 vector_stvewx_type_table[] = {
+ TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedint_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorunsignedlong), TYPE(&stsignedint), TYPE(&stunsignedlong_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorsignedlong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorfloat), TYPE(&stsignedint), TYPE(&stfloat_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedint_ptr), PC_STVEWX,
+ TYPE(&stvoid), TYPE(&stvectorboollong), TYPE(&stsignedint), TYPE(&stsignedlong_ptr), PC_STVEWX,
+ NULL, NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsububm_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSUBUBM,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VSUBUBM,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSUBUBM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSUBUBM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VSUBUBM,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VSUBUBM,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsubuhm_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSUBUHM,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VSUBUHM,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSUBUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VSUBUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VSUBUHM,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VSUBUHM,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsubuwm_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSUBUWM,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VSUBUWM,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSUBUWM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUBUWM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VSUBUWM,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VSUBUWM,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VSUBFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsubfp_type_table[] = {
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VSUBFP,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsububs_type_table[] = {
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), PC_VSUBUBS,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), PC_VSUBUBS,
+ TYPE(&stvectorunsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorunsignedchar), PC_VSUBUBS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsubsbs_type_table[] = {
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSUBSBS,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), PC_VSUBSBS,
+ TYPE(&stvectorsignedchar), TYPE(&stvectorboolchar), TYPE(&stvectorsignedchar), PC_VSUBSBS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsubuhs_type_table[] = {
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), PC_VSUBUHS,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), PC_VSUBUHS,
+ TYPE(&stvectorunsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorunsignedshort), PC_VSUBUHS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsubshs_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VSUBSHS,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), PC_VSUBSHS,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorboolshort), TYPE(&stvectorsignedshort), PC_VSUBSHS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsubuws_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), PC_VSUBUWS,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), PC_VSUBUWS,
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorunsignedlong), PC_VSUBUWS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsubsws_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUBSWS,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), PC_VSUBSWS,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorboollong), TYPE(&stvectorsignedlong), PC_VSUBSWS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsum4ubs_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorunsignedchar), TYPE(&stvectorunsignedlong), PC_VSUM4UBS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsum4sbs_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedchar), TYPE(&stvectorsignedlong), PC_VSUM4SBS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable31 vector_vsum4shs_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), TYPE(&stvectorsignedlong), PC_VSUM4SHS,
+ NULL, NULL, NULL, 0
+};
+static TypeTable21 vector_vupkhsb_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), PC_VUPKHSB,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolchar), PC_VUPKHSB,
+ NULL, NULL, 0
+};
+static TypeTable21 vector_vupklsb_type_table[] = {
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedchar), PC_VUPKLSB,
+ TYPE(&stvectorboolshort), TYPE(&stvectorboolchar), PC_VUPKLSB,
+ NULL, NULL, 0
+};
+static TypeTable22 vector_vupkhpx_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorpixel), PC_VUPKHPX, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable22 vector_vupklpx_type_table[] = {
+ TYPE(&stvectorunsignedlong), TYPE(&stvectorpixel), PC_VUPKLPX, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable21 vector_vupkhsh_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), PC_VUPKHSH,
+ TYPE(&stvectorboollong), TYPE(&stvectorboolshort), PC_VUPKHSH,
+ NULL, NULL, 0
+};
+static TypeTable21 vector_vupklsh_type_table[] = {
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedshort), PC_VUPKLSH,
+ TYPE(&stvectorboollong), TYPE(&stvectorboolshort), PC_VUPKLSH,
+ NULL, NULL, 0
+};
+static TypeTable22 vector_abs_type_table[] = {
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSUBUBM, PC_VMAXSB,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VSUBUHM, PC_VMAXSH,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUBUWM, PC_VMAXSW,
+ TYPE(&stvectorfloat), TYPE(&stvectorfloat), PC_VANDC, PC_B,
+ NULL, NULL, 0
+};
+static TypeTable22 vector_abss_type_table[] = {
+ TYPE(&stvectorsignedchar), TYPE(&stvectorsignedchar), PC_VSUBSBS, PC_VMAXSB,
+ TYPE(&stvectorsignedshort), TYPE(&stvectorsignedshort), PC_VSUBSHS, PC_VMAXSH,
+ TYPE(&stvectorsignedlong), TYPE(&stvectorsignedlong), PC_VSUBSWS, PC_VMAXSW,
+ NULL, NULL, 0
+};
+static void *typeTable[] = {
+ vector_add_type_table,
+ vector_addc_type_table,
+ vector_adds_type_table,
+ vector_and_type_table,
+ vector_andc_type_table,
+ vector_avg_type_table,
+ vector_ceil_type_table,
+ vector_cmpb_type_table,
+ vector_cmpeq_type_table,
+ vector_cmpge_type_table,
+ vector_cmpge_type_table,
+ vector_cmpgt_type_table,
+ vector_cmpgt_type_table,
+ vector_ctf_type_table,
+ vector_cts_type_table,
+ vector_ctu_type_table,
+ vector_dss_type_table,
+ vector_dssall_type_table,
+ vector_datastream_type_table,
+ vector_datastream_type_table,
+ vector_datastream_type_table,
+ vector_datastream_type_table,
+ vector_expte_type_table,
+ vector_floor_type_table,
+ vector_load_type_table,
+ vector_loade_type_table,
+ vector_loadl_type_table,
+ vector_loge_type_table,
+ vector_lvsl_type_table,
+ vector_lvsr_type_table,
+ vector_madd_type_table,
+ vector_madds_type_table,
+ vector_max_type_table,
+ vector_mergeh_type_table,
+ vector_mergel_type_table,
+ vector_mfvscr_type_table,
+ vector_min_type_table,
+ vector_mladd_type_table,
+ vector_mradds_type_table,
+ vector_msum_type_table,
+ vector_msums_type_table,
+ vector_mtvscr_type_table,
+ vector_mule_type_table,
+ vector_mulo_type_table,
+ vector_nmsub_type_table,
+ vector_nor_type_table,
+ vector_or_type_table,
+ vector_pack_type_table,
+ vector_packpx_type_table,
+ vector_packs_type_table,
+ vector_packsu_type_table,
+ vector_perm_type_table,
+ vector_re_type_table,
+ vector_rl_type_table,
+ vector_round_type_table,
+ vector_rsqrte_type_table,
+ vector_sel_type_table,
+ vector_sl_type_table,
+ vector_sld_type_table,
+ vector_sll_type_table,
+ vector_slo_type_table,
+ vector_splat_type_table,
+ vector_splat_s8_type_table,
+ vector_splat_s16_type_table,
+ vector_splat_s32_type_table,
+ vector_splat_u8_type_table,
+ vector_splat_u16_type_table,
+ vector_splat_u32_type_table,
+ vector_sr_type_table,
+ vector_sra_type_table,
+ vector_srl_type_table,
+ vector_sro_type_table,
+ vector_st_type_table,
+ vector_ste_type_table,
+ vector_stl_type_table,
+ vector_sub_type_table,
+ vector_subc_type_table,
+ vector_subs_type_table,
+ vector_sum4s_type_table,
+ vector_sum2s_type_table,
+ vector_sums_type_table,
+ vector_trunc_type_table,
+ vector_unpack2sh_type_table,
+ vector_unpack2sl_type_table,
+ vector_unpack2uh_type_table,
+ vector_unpack2ul_type_table,
+ vector_unpackh_type_table,
+ vector_unpackl_type_table,
+ vector_xor_type_table,
+ vector_all_eq_type_table,
+ vector_all_ge_type_table,
+ vector_all_gt_type_table,
+ vector_all_in_type_table,
+ vector_all_le_type_table,
+ vector_all_lt_type_table,
+ vector_all_nan_type_table,
+ vector_all_ne_type_table,
+ vector_all_nge_type_table,
+ vector_all_ngt_type_table,
+ vector_all_nle_type_table,
+ vector_all_nlt_type_table,
+ vector_all_numeric_type_table,
+ vector_any_eq_type_table,
+ vector_any_ge_type_table,
+ vector_any_gt_type_table,
+ vector_any_le_type_table,
+ vector_any_lt_type_table,
+ vector_any_nan_type_table,
+ vector_any_ne_type_table,
+ vector_any_nge_type_table,
+ vector_any_ngt_type_table,
+ vector_any_nle_type_table,
+ vector_any_nlt_type_table,
+ vector_any_numeric_type_table,
+ vector_any_out_type_table,
+ vector_vaddubm_type_table,
+ vector_vadduhm_type_table,
+ vector_vadduwm_type_table,
+ vector_vaddfp_type_table,
+ vector_addc_type_table,
+ vector_vaddubs_type_table,
+ vector_vaddsbs_type_table,
+ vector_vadduhs_type_table,
+ vector_vaddshs_type_table,
+ vector_vadduws_type_table,
+ vector_vaddsws_type_table,
+ vector_and_type_table,
+ vector_andc_type_table,
+ vector_vavgub_type_table,
+ vector_vavgsb_type_table,
+ vector_vavguh_type_table,
+ vector_vavgsh_type_table,
+ vector_vavguw_type_table,
+ vector_vavgsw_type_table,
+ vector_ceil_type_table,
+ vector_cmpb_type_table,
+ vector_vcmpequb_type_table,
+ vector_vcmpequh_type_table,
+ vector_vcmpequw_type_table,
+ vector_vcmpeqfp_type_table,
+ vector_cmpge_type_table,
+ vector_vcmpgtub_type_table,
+ vector_vcmpgtsb_type_table,
+ vector_vcmpgtuh_type_table,
+ vector_vcmpgtsh_type_table,
+ vector_vcmpgtuw_type_table,
+ vector_vcmpgtsw_type_table,
+ vector_vcmpgtfp_type_table,
+ vector_vcfux_type_table,
+ vector_vcfsx_type_table,
+ vector_cts_type_table,
+ vector_ctu_type_table,
+ vector_expte_type_table,
+ vector_floor_type_table,
+ vector_load_type_table,
+ vector_lvebx_type_table,
+ vector_lvehx_type_table,
+ vector_lvewx_type_table,
+ vector_loadl_type_table,
+ vector_loge_type_table,
+ vector_madd_type_table,
+ vector_madds_type_table,
+ vector_vmaxub_type_table,
+ vector_vmaxsb_type_table,
+ vector_vmaxuh_type_table,
+ vector_vmaxsh_type_table,
+ vector_vmaxuw_type_table,
+ vector_vmaxsw_type_table,
+ vector_vmaxfp_type_table,
+ vector_vmrghb_type_table,
+ vector_vmrghh_type_table,
+ vector_vmrghw_type_table,
+ vector_vmrglb_type_table,
+ vector_vmrglh_type_table,
+ vector_vmrglw_type_table,
+ vector_vminub_type_table,
+ vector_vminsb_type_table,
+ vector_vminuh_type_table,
+ vector_vminsh_type_table,
+ vector_vminuw_type_table,
+ vector_vminsw_type_table,
+ vector_vminfp_type_table,
+ vector_mladd_type_table,
+ vector_mradds_type_table,
+ vector_vmsumubm_type_table,
+ vector_vmsumuhm_type_table,
+ vector_vmsummbm_type_table,
+ vector_vmsumshm_type_table,
+ vector_vmsumuhs_type_table,
+ vector_vmsumshs_type_table,
+ vector_vmuleub_type_table,
+ vector_vmulesb_type_table,
+ vector_vmuleuh_type_table,
+ vector_vmulesh_type_table,
+ vector_vmuloub_type_table,
+ vector_vmulosb_type_table,
+ vector_vmulouh_type_table,
+ vector_vmulosh_type_table,
+ vector_nmsub_type_table,
+ vector_nor_type_table,
+ vector_or_type_table,
+ vector_vpkuhum_type_table,
+ vector_vpkuwum_type_table,
+ vector_packpx_type_table,
+ vector_vpkuhus_type_table,
+ vector_vpkshss_type_table,
+ vector_vpkuwus_type_table,
+ vector_vpkswss_type_table,
+ vector_vpkshus_type_table,
+ vector_vpkswus_type_table,
+ vector_perm_type_table,
+ vector_re_type_table,
+ vector_vrlb_type_table,
+ vector_vrlh_type_table,
+ vector_vrlw_type_table,
+ vector_round_type_table,
+ vector_rsqrte_type_table,
+ vector_sel_type_table,
+ vector_vslb_type_table,
+ vector_vslh_type_table,
+ vector_vslw_type_table,
+ vector_sld_type_table,
+ vector_sll_type_table,
+ vector_slo_type_table,
+ vector_vspltb_type_table,
+ vector_vsplth_type_table,
+ vector_vspltw_type_table,
+ vector_vspltisb_type_table,
+ vector_vspltish_type_table,
+ vector_vspltisw_type_table,
+ vector_vsrb_type_table,
+ vector_vsrh_type_table,
+ vector_vsrw_type_table,
+ vector_vsrab_type_table,
+ vector_vsrah_type_table,
+ vector_vsraw_type_table,
+ vector_srl_type_table,
+ vector_sro_type_table,
+ vector_st_type_table,
+ vector_stvebx_type_table,
+ vector_stvehx_type_table,
+ vector_stvewx_type_table,
+ vector_stl_type_table,
+ vector_vsububm_type_table,
+ vector_vsubuhm_type_table,
+ vector_vsubuwm_type_table,
+ vector_vsubfp_type_table,
+ vector_subc_type_table,
+ vector_vsububs_type_table,
+ vector_vsubsbs_type_table,
+ vector_vsubuhs_type_table,
+ vector_vsubshs_type_table,
+ vector_vsubuws_type_table,
+ vector_vsubsws_type_table,
+ vector_vsum4ubs_type_table,
+ vector_vsum4sbs_type_table,
+ vector_vsum4shs_type_table,
+ vector_sum2s_type_table,
+ vector_sums_type_table,
+ vector_trunc_type_table,
+ vector_vupkhsb_type_table,
+ vector_vupklsb_type_table,
+ vector_vupkhpx_type_table,
+ vector_vupklpx_type_table,
+ vector_vupkhsh_type_table,
+ vector_vupklsh_type_table,
+ vector_xor_type_table,
+ vector_abs_type_table,
+ vector_abss_type_table,
+ NULL
+};
+
+int is_intrinsic_function_call(ENode *funccall) {
+ ENode *funcref = funccall->data.funccall.funcref;
+ return
+ ENODE_IS(funcref, EOBJREF) &&
+ funcref->data.objref->datatype == DFUNC &&
+ (TYPE_FUNC(funcref->data.objref->type)->flags & FUNC_INTRINSIC);
+}
+
+static void abs_intrinsic(ENode *expr, short outputReg, Operand *output) {
+ int reg1;
+ int reg2;
+ Operand op;
+
+ memclrw(&op, sizeof(op));
+ GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0);
+
+ reg1 = ALLOC_GPR();
+ emitpcode(PC_SRAWI, reg1, op.reg, 31);
+
+ reg2 = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_XOR, reg2, reg1, op.reg);
+ emitpcode(PC_SUBF, reg2, reg1, reg2);
+
+ output->optype = OpndType_GPR;
+ output->reg = reg2;
+}
+
+static void setflm_intrinsic(ENode *expr, short outputReg, Operand *output, int flag) {
+ int reg;
+ Operand op;
+
+ memclrw(&op, sizeof(op));
+ GEN_NODE_TO_FPR(expr, &op, expr->rtype, 0);
+
+ if (!flag) {
+ output->optype = OpndType_FPR;
+ reg = (outputReg && outputReg != op.reg) ? outputReg : ALLOC_FPR();
+ emitpcode(PC_MFFS, output->reg = reg);
+ }
+
+ emitpcode(PC_MTFSF, 255, op.reg);
+}
+
+static void alloca_intrinsic(ENode *expr, short outputReg, Operand *output) {
+ int reg;
+ Operand op;
+
+ memclrw(&op, sizeof(op));
+
+ if (ENODE_IS(expr, EINTCONST)) {
+ reg = outputReg ? outputReg : ALLOC_GPR();
+ allocate_dynamic_stack_space(
+ 1, reg, ALLOC_GPR(), CInt64_GetULong(&expr->data.intval));
+ } else {
+ GEN_NODE_TO_GPR(expr, &op, expr->rtype, 0);
+ reg = outputReg ? outputReg : ALLOC_GPR();
+
+ emitpcode(PC_NEG, reg, op.reg);
+ emitpcode(PC_RLWINM, reg, reg, 0, 0, get_alloca_alignment());
+ allocate_dynamic_stack_space(0, reg, ALLOC_GPR(), 0);
+ }
+
+ output->optype = OpndType_GPR;
+ output->reg = reg;
+}
+
+static void load_bytereversed_intrinsic(Opcode opcode, ENode *expr1, ENode *expr2, short outputReg, Operand *output) {
+ int reg;
+ Operand op1;
+ Operand op2;
+
+ reg = outputReg ? outputReg : ALLOC_GPR();
+ memclrw(&op1, sizeof(op1));
+ memclrw(&op2, sizeof(op2));
+
+ if (ENODE_IS(expr2, EINTCONST) && expr2->data.intval.lo == 0) {
+ GEN_NODE(expr1, &op1);
+ if (op1.optype == OpndType_GPR_Indexed) {
+ emitpcode(opcode, reg, op1.reg, op1.regOffset);
+ } else {
+ ENSURE_GPR(&op1, expr1->rtype, 0);
+ emitpcode(opcode, reg, 0, op1.reg);
+ }
+ } else {
+ GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0);
+ GEN_NODE_TO_GPR(expr2, &op2, expr2->rtype, 0);
+ emitpcode(opcode, reg, op1.reg, op2.reg);
+ }
+
+ setpcodeflags(fSideEffects | ((expr1->flags | expr2->flags | output->flags) & (fIsConst | fIsVolatile)));
+ output->optype = OpndType_GPR;
+ output->reg = reg;
+}
+
+static void store_bytereversed_intrinsic(Opcode opcode, ENode *expr1, ENode *expr2, ENode *expr3) {
+ Operand op1;
+ Operand op2;
+ Operand op3;
+
+ memclrw(&op1, sizeof(op1));
+ memclrw(&op2, sizeof(op2));
+ memclrw(&op3, sizeof(op3));
+
+ if (ENODE_IS(expr3, EINTCONST) && expr3->data.intval.lo == 0) {
+ GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0);
+ GEN_NODE(expr2, &op2);
+ if (op2.optype == OpndType_GPR_Indexed) {
+ emitpcode(opcode, op1.reg, op2.reg, op2.regOffset);
+ } else {
+ ENSURE_GPR(&op2, expr2->rtype, 0);
+ emitpcode(opcode, op1.reg, 0, op2.reg);
+ }
+ } else {
+ GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0);
+ GEN_NODE_TO_GPR(expr2, &op2, expr2->rtype, 0);
+ GEN_NODE_TO_GPR(expr3, &op3, expr3->rtype, 0);
+ emitpcode(opcode, op1.reg, op2.reg, op3.reg);
+ }
+
+ setpcodeflags(fSideEffects | ((op1.flags | op2.flags | op3.flags) & (fIsConst | fIsVolatile)));
+}
+
+static void data_cache_block_intrinsic(Opcode opcode, ENode *expr1, ENode *expr2) {
+ Operand op1;
+ Operand op2;
+
+ memclrw(&op1, sizeof(op1));
+ memclrw(&op2, sizeof(op2));
+
+ if (ENODE_IS(expr2, EINTCONST) && expr2->data.intval.lo == 0) {
+ GEN_NODE(expr1, &op1);
+ if (op1.optype == OpndType_GPR_Indexed) {
+ emitpcode(opcode, op1.reg, op1.regOffset);
+ } else {
+ ENSURE_GPR(&op1, expr1->rtype, 0);
+ emitpcode(opcode, 0, op1.reg);
+ }
+ } else {
+ GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0);
+ GEN_NODE_TO_GPR(expr2, &op2, expr2->rtype, 0);
+ emitpcode(opcode, op1.reg, op2.reg);
+ }
+}
+
+static void memcpy_intrinsic(ENode *destexpr, ENode *srcexpr, SInt32 size, Boolean ignored, Operand *output) {
+ UInt32 qual;
+ Operand destOp;
+ Operand srcOp;
+
+ qual = 0;
+
+ memclrw(&destOp, sizeof(destOp));
+ memclrw(&srcOp, sizeof(srcOp));
+
+ GEN_NODE(srcexpr, &srcOp);
+ indirect(&srcOp, srcexpr);
+
+ GEN_NODE(destexpr, output);
+ destOp = *output;
+ indirect(&destOp, destexpr);
+
+ if (destOp.object)
+ qual = destOp.object->qual;
+
+ move_block(&destOp, &srcOp, size, destexpr->rtype ? CMach_AllocationAlignment(destexpr->rtype, qual) : 1);
+}
+
+static SInt32 checkconstintarg(ENode *expr, char *name, SInt32 min, SInt32 max, int argnum) {
+ SInt32 value;
+
+ if (!ENODE_IS(expr, EINTCONST))
+ PPCError_ErrorTerm(PPCErrorStr210, name, 3, max, argnum);
+
+ value = CInt64_GetULong(&expr->data.intval);
+
+ if (value < min) {
+ PPCError_Warning(PPCErrorStr211, name, argnum, value, min, max, min);
+ return min;
+ }
+
+ if (value > max) {
+ PPCError_Warning(PPCErrorStr211, name, argnum, value, min, max, value & max);
+ value = value & max;
+ }
+
+ return value;
+}
+
+static void rlwimi_intrinsic(ENode *expr1, ENode *expr2, ENode *expr3, ENode *expr4, ENode *expr5, short outputReg, Operand *output) {
+ SInt32 arg3;
+ SInt32 arg4;
+ SInt32 arg5;
+ Operand op1;
+ Operand op2;
+ int reg;
+ char *name = "__rlwimi";
+
+ memclrw(&op1, sizeof(op1));
+ memclrw(&op2, sizeof(op2));
+
+ arg3 = checkconstintarg(expr3, name, 0, 31, 3);
+ arg4 = checkconstintarg(expr4, name, 0, 31, 4);
+ arg5 = checkconstintarg(expr5, name, 0, 31, 5);
+
+ GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0);
+
+ GEN_NODE(expr2, &op2);
+ if (copts.optimizationlevel > 1) {
+ reg = ALLOC_GPR();
+ emitpcode(PC_MR, reg, op1.reg);
+ op1.reg = reg;
+ }
+ ENSURE_GPR(&op2, expr2->rtype, 0);
+
+ emitpcode(PC_RLWIMI, op1.reg, op2.reg, arg3, arg4, arg5);
+
+ output->optype = OpndType_GPR;
+ output->reg = op1.reg;
+}
+
+static void rlwinm_intrinsic(ENode *expr1, ENode *expr2, ENode *expr3, ENode *expr4, short outputReg, Operand *output) {
+ char *name = "__rlwinm";
+ short reg;
+ short arg2;
+ short arg3;
+ short arg4;
+ Operand op1;
+
+ memclrw(&op1, sizeof(op1));
+ arg2 = checkconstintarg(expr2, name, 0, 31, 2);
+ arg3 = checkconstintarg(expr3, name, 0, 31, 3);
+ arg4 = checkconstintarg(expr4, name, 0, 31, 4);
+
+ GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0);
+
+ reg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_RLWINM, reg, op1.reg, arg2, arg3, arg4);
+
+ output->optype = OpndType_GPR;
+ output->reg = reg;
+}
+
+static void rlwnm_intrinsic(ENode *expr1, ENode *expr2, ENode *expr3, ENode *expr4, short outputReg, Operand *output) {
+ short reg;
+ short arg3;
+ short arg4;
+ char *name = "__rlwnm";
+ Operand op1;
+ Operand op2;
+
+ memclrw(&op1, sizeof(op1));
+ memclrw(&op2, sizeof(op2));
+ arg3 = checkconstintarg(expr3, name, 0, 31, 3);
+ arg4 = checkconstintarg(expr4, name, 0, 31, 4);
+
+ GEN_NODE_TO_GPR(expr1, &op1, expr1->rtype, 0);
+ GEN_NODE_TO_GPR(expr2, &op2, expr2->rtype, 0);
+
+ reg = outputReg ? outputReg : ALLOC_GPR();
+ emitpcode(PC_RLWNM, reg, op1.reg, op2.reg, arg3, arg4);
+
+ output->optype = OpndType_GPR;
+ output->reg = reg;
+}
+
+static Boolean promotable_types_are_equal(Type *a, Type *b) {
+ if (a == b)
+ return 1;
+
+ if (a == TYPE(&stsignedint)) {
+ if (
+ b == TYPE(&stunsignedint) ||
+ b == TYPE(&stsignedchar) ||
+ b == TYPE(&stunsignedchar) ||
+ b == TYPE(&stsignedshort) ||
+ b == TYPE(&stunsignedshort) ||
+ b == TYPE(&stsignedlong) ||
+ b == TYPE(&stunsignedlong) ||
+ b == TYPE(&stbool)
+ )
+ return 1;
+ }
+
+ return 0;
+}
+
+static int Intrinsics_VerifyParameterCount(int wantedCount, ENodeList *args, HashNameNode *name) {
+ ENodeList *scan;
+ int count;
+
+ for (scan = args, count = 0; scan; scan = scan->next)
+ count++;
+
+ if (count != wantedCount) {
+ PPCError_Error(PPCErrorStr103, name->name, count, wantedCount);
+ return 0;
+ }
+
+ return 1;
+}
+
+static ENode *Intrinsics_CreateIntrinsicFunc(Object *func, ENodeList *args, Type *rtype) {
+ TypeFunc *tfunc;
+ ENodeList *scan;
+ ENode *expr;
+
+ tfunc = TYPE_FUNC(func->type);
+ CError_ASSERT(3741, IS_TYPE_FUNC(tfunc));
+
+ for (scan = args; scan; scan = scan->next) {
+ if (IS_TYPE_ARRAY(scan->node->rtype))
+ scan->node = CExpr_PointerGeneration(scan->node);
+ }
+
+ expr = lalloc(sizeof(ENode));
+ expr->type = EFUNCCALL;
+ expr->cost = 4;
+ expr->rtype = rtype;
+ expr->ignored = 0;
+ expr->flags = tfunc->qual & ENODE_FLAG_QUALS;
+ expr->data.funccall.funcref = create_objectrefnode(func);
+ expr->data.funccall.args = args;
+ expr->data.funccall.functype = tfunc;
+ return CExpr_AdjustFunctionCall(expr);
+}
+
+static Type *Intrinsics_Verify1VectorArg2Ops(Intrinsics id, ENodeList *args, HashNameNode *name) {
+ ENode *arg1;
+ TypeTable22 *table;
+ Type *typeA;
+ Type *typeB;
+ Type *rtype;
+
+ arg1 = args->node;
+
+ for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) {
+ typeB = arg1->rtype;
+ typeA = table->arg1;
+ if (IS_TYPE_POINTER(typeA) && IS_TYPE_POINTER(typeB)) {
+ typeA = TPTR_TARGET(typeA);
+ typeB = TPTR_TARGET(typeB);
+ }
+ if (promotable_types_are_equal(typeA, typeB))
+ break;
+ }
+
+ rtype = table->rtype;
+ if (!rtype) {
+ PPCError_Error(PPCErrorStr104, name->name, name->name, arg1->rtype, 0);
+ rtype = NULL;
+ }
+ return rtype;
+}
+
+static Type *Intrinsics_VerifyNoVectorArgs(Intrinsics id, HashNameNode *name) {
+ TypeTable11 *table = typeTable[id - Intrinsic_042];
+ return table->rtype;
+}
+
+static Type *Intrinsics_Verify1VectorArg(Intrinsics id, ENodeList *args, HashNameNode *name) {
+ ENode *arg1;
+ TypeTable21 *table;
+ Type *typeA;
+ Type *typeB;
+ Type *rtype;
+
+ arg1 = args->node;
+
+ for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) {
+ typeB = arg1->rtype;
+ typeA = table->arg1;
+ if (IS_TYPE_POINTER(typeA) && IS_TYPE_POINTER(typeB)) {
+ typeA = TPTR_TARGET(typeA);
+ typeB = TPTR_TARGET(typeB);
+ }
+ if (promotable_types_are_equal(typeA, typeB))
+ break;
+ }
+
+ switch (id) {
+ case Intrinsic_104:
+ case Intrinsic_105:
+ case Intrinsic_106:
+ case Intrinsic_107:
+ case Intrinsic_108:
+ case Intrinsic_109:
+ case Intrinsic_269:
+ case Intrinsic_270:
+ case Intrinsic_271:
+ if (ENODE_IS(arg1, EINTCONST)) {
+ SInt32 val = arg1->data.intval.lo;
+ if (val > 15 || val < -16) {
+ PPCError_Error(PPCErrorStr108, name->name, name->name, 5);
+ return NULL;
+ }
+ } else {
+ PPCError_Error(PPCErrorStr108, name->name, name->name, 5);
+ return NULL;
+ }
+ break;
+ case Intrinsic_058:
+ if (ENODE_IS(arg1, EINTCONST)) {
+ SInt32 val = arg1->data.intval.lo;
+ if (val > 3 || val < 0) {
+ PPCError_Error(PPCErrorStr108, name->name, name->name, 2);
+ return NULL;
+ }
+ } else {
+ PPCError_Error(PPCErrorStr108, name->name, name->name, 2);
+ return NULL;
+ }
+ break;
+ }
+
+ rtype = table->rtype;
+ if (!rtype) {
+ PPCError_Error(PPCErrorStr104, name->name, name->name, arg1->rtype, 0);
+ rtype = NULL;
+ }
+ return rtype;
+}
+
+static Type *Intrinsics_Verify2VectorArgs(Intrinsics id, ENodeList *args, HashNameNode *name) {
+ ENode *arg1;
+ ENode *arg2;
+ TypeTable31 *table;
+ Type *typeB1;
+ Type *typeB2;
+ Type *typeA1;
+ Type *typeA2;
+
+ arg1 = args->node;
+ arg2 = args->next->node;
+ table = typeTable[id - Intrinsic_042];
+
+ switch (id) {
+ case Intrinsic_055:
+ case Intrinsic_056:
+ case Intrinsic_057:
+ case Intrinsic_103:
+ case Intrinsic_190:
+ case Intrinsic_191:
+ case Intrinsic_192:
+ case Intrinsic_193:
+ case Intrinsic_266:
+ case Intrinsic_267:
+ case Intrinsic_268:
+ if (ENODE_IS(arg2, EINTCONST)) {
+ if (arg2->data.intval.lo > 31 || arg2->data.intval.hi < 0) {
+ PPCError_Error(PPCErrorStr108, name->name, name->name, 5);
+ return NULL;
+ }
+ } else {
+ PPCError_Error(PPCErrorStr108, name->name, name->name, 5);
+ return NULL;
+ }
+ break;
+ }
+
+ for (; table->rtype; table++) {
+ typeB1 = arg1->rtype;
+ typeB2 = arg2->rtype;
+ typeA1 = table->arg1;
+ typeA2 = table->arg2;
+ if (IS_TYPE_POINTER(typeA1) && IS_TYPE_POINTER(typeB1)) {
+ typeA1 = TPTR_TARGET(typeA1);
+ typeB1 = TPTR_TARGET(typeB1);
+ }
+ if (IS_TYPE_POINTER(typeA2) && IS_TYPE_POINTER(typeB2)) {
+ typeA2 = TPTR_TARGET(typeA2);
+ typeB2 = TPTR_TARGET(typeB2);
+ }
+ if (promotable_types_are_equal(typeA1, typeB1) &&
+ promotable_types_are_equal(typeA2, typeB2))
+ break;
+ }
+
+ if (!table->rtype) {
+ PPCError_Error(PPCErrorStr105, name->name, name->name, arg1->rtype, 0, arg2->rtype, 0);
+ return NULL;
+ }
+
+ switch (id) {
+ case Intrinsic_066:
+ case Intrinsic_067:
+ case Intrinsic_068:
+ if (arg2->flags & ENODE_FLAG_VOLATILE)
+ PPCError_Warning(PPCErrorStr178, name->name);
+ }
+
+ return table->rtype;
+}
+
+static Type *Intrinsics_Verify3VectorArgs(Intrinsics id, ENodeList *args, HashNameNode *name) {
+ ENode *arg1;
+ ENode *arg2;
+ ENode *arg3;
+ TypeTable41 *table;
+ Type *typeB1;
+ Type *typeB2;
+ Type *typeB3;
+ Type *typeA1;
+ Type *typeA2;
+ Type *typeA3;
+
+ arg1 = args->node;
+ arg2 = args->next->node;
+ arg3 = args->next->next->node;
+
+ for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) {
+ typeB1 = arg1->rtype;
+ typeB2 = arg2->rtype;
+ typeB3 = arg3->rtype;
+ typeA1 = table->arg1;
+ typeA2 = table->arg2;
+ typeA3 = table->arg3;
+ if (IS_TYPE_POINTER(typeA1) && IS_TYPE_POINTER(typeB1)) {
+ typeA1 = TPTR_TARGET(typeA1);
+ typeB1 = TPTR_TARGET(typeB1);
+ }
+ if (IS_TYPE_POINTER(typeA2) && IS_TYPE_POINTER(typeB2)) {
+ typeA2 = TPTR_TARGET(typeA2);
+ typeB2 = TPTR_TARGET(typeB2);
+ }
+ if (IS_TYPE_POINTER(typeA3) && IS_TYPE_POINTER(typeB3)) {
+ typeA3 = TPTR_TARGET(typeA3);
+ typeB3 = TPTR_TARGET(typeB3);
+ }
+ if (promotable_types_are_equal(typeA1, typeB1) &&
+ promotable_types_are_equal(typeA2, typeB2) &&
+ promotable_types_are_equal(typeA3, typeB3))
+ break;
+ }
+
+ switch (id) {
+ case Intrinsic_060:
+ case Intrinsic_061:
+ case Intrinsic_062:
+ case Intrinsic_063:
+ if (ENODE_IS(arg3, EINTCONST)) {
+ SInt32 val = arg3->data.intval.lo;
+ if (val > 3 || val < 0) {
+ PPCError_Error(PPCErrorStr108, name->name, name->name, 2);
+ return NULL;
+ }
+ } else {
+ PPCError_Error(PPCErrorStr108, name->name, name->name, 2);
+ return NULL;
+ }
+ break;
+ case Intrinsic_100:
+ case Intrinsic_263:
+ if (ENODE_IS(arg3, EINTCONST)) {
+ if (arg3->data.intval.lo > 15 || arg3->data.intval.hi < 0) {
+ PPCError_Error(PPCErrorStr108, name->name, name->name, 4);
+ return NULL;
+ }
+ } else {
+ PPCError_Error(PPCErrorStr108, name->name, name->name, 4);
+ return NULL;
+ }
+ break;
+ }
+
+ if (!table->rtype) {
+ PPCError_Error(PPCErrorStr106, name->name, name->name, arg1->rtype, 0, arg2->rtype, 0, arg3->rtype, 0);
+ return NULL;
+ }
+
+ switch (id) {
+ case Intrinsic_114:
+ case Intrinsic_115:
+ case Intrinsic_116:
+ if (arg3->flags & ENODE_FLAG_VOLATILE)
+ PPCError_Warning(PPCErrorStr178, name->name);
+ }
+
+ return table->rtype;
+}
+
+static Opcode Intrinsics_FindOpcodeNoArgs(Intrinsics id, ENode *funccall) {
+ TypeTable11 *table = typeTable[id - Intrinsic_042];
+ return table->opcode;
+}
+
+static Opcode Intrinsics_FindOpcode1Arg(Intrinsics id, ENode *funccall, ENode *arg1) {
+ TypeTable21 *table;
+ Type *typeA;
+ Type *typeB;
+
+ for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) {
+ typeB = arg1->rtype;
+ typeA = table->arg1;
+ if (IS_TYPE_POINTER(typeA) && IS_TYPE_POINTER(typeB)) {
+ typeA = TPTR_TARGET(typeA);
+ typeB = TPTR_TARGET(typeB);
+ }
+ if (promotable_types_are_equal(typeA, typeB))
+ break;
+ }
+
+ CError_ASSERT(4105, table->rtype);
+ return table->opcode;
+}
+
+static Opcode Intrinsics_FindOpcode2Args(Intrinsics id, ENode *funccall, ENode *arg1, ENode *arg2) {
+ TypeTable31 *table;
+ Type *typeB1;
+ Type *typeB2;
+ Type *typeA1;
+ Type *typeA2;
+
+ for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) {
+ typeB1 = arg1->rtype;
+ typeB2 = arg2->rtype;
+ typeA1 = table->arg1;
+ typeA2 = table->arg2;
+ if (IS_TYPE_POINTER(typeA1) && IS_TYPE_POINTER(typeB1)) {
+ typeA1 = TPTR_TARGET(typeA1);
+ typeB1 = TPTR_TARGET(typeB1);
+ }
+ if (IS_TYPE_POINTER(typeA2) && IS_TYPE_POINTER(typeB2)) {
+ typeA2 = TPTR_TARGET(typeA2);
+ typeB2 = TPTR_TARGET(typeB2);
+ }
+ if (promotable_types_are_equal(typeA1, typeB1) &&
+ promotable_types_are_equal(typeA2, typeB2))
+ break;
+ }
+
+ CError_ASSERT(4144, table->rtype);
+ return table->opcode;
+}
+
+static Opcode Intrinsics_FindOpcode3Args(Intrinsics id, ENode *funccall, ENode *arg1, ENode *arg2, ENode *arg3) {
+ TypeTable41 *table;
+ Type *typeB1;
+ Type *typeB2;
+ Type *typeB3;
+ Type *typeA1;
+ Type *typeA2;
+ Type *typeA3;
+
+ for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) {
+ typeB1 = arg1->rtype;
+ typeB2 = arg2->rtype;
+ typeB3 = arg3->rtype;
+ typeA1 = table->arg1;
+ typeA2 = table->arg2;
+ typeA3 = table->arg3;
+ if (IS_TYPE_POINTER(typeA1) && IS_TYPE_POINTER(typeB1)) {
+ typeA1 = TPTR_TARGET(typeA1);
+ typeB1 = TPTR_TARGET(typeB1);
+ }
+ if (IS_TYPE_POINTER(typeA2) && IS_TYPE_POINTER(typeB2)) {
+ typeA2 = TPTR_TARGET(typeA2);
+ typeB2 = TPTR_TARGET(typeB2);
+ }
+ if (IS_TYPE_POINTER(typeA3) && IS_TYPE_POINTER(typeB3)) {
+ typeA3 = TPTR_TARGET(typeA3);
+ typeB3 = TPTR_TARGET(typeB3);
+ }
+ if (promotable_types_are_equal(typeA1, typeB1) &&
+ promotable_types_are_equal(typeA2, typeB2) &&
+ promotable_types_are_equal(typeA3, typeB3))
+ break;
+ }
+
+ CError_ASSERT(4191, table->rtype);
+ return table->opcode;
+}
+
+static void vector_intrinsic_no_args(Opcode opcode) {
+ emitpcode(opcode);
+}
+
+static void vector_intrinsic_mfvscr(short outputReg, Opcode opcode, Operand *output) {
+ short reg;
+
+ reg = outputReg ? outputReg : ALLOC_VR();
+
+ emitpcode(opcode, reg);
+
+ output->optype = OpndType_VR;
+ output->reg = reg;
+}
+
+static void vector_intrinsic_1arg(ENode *arg1, short outputReg, Operand *output, Opcode opcode) {
+ Operand op1;
+ short reg;
+
+ memclrw(&op1, sizeof(op1));
+ GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0);
+
+ reg = outputReg ? outputReg : ALLOC_VR();
+
+ emitpcode(opcode, reg, op1.reg);
+
+ output->optype = OpndType_VR;
+ output->reg = reg;
+}
+
+static void vector_intrinsic_splats(ENode *arg1, short outputReg, Operand *output, Opcode opcode) {
+ Operand op1;
+ short reg;
+
+ memclrw(&op1, sizeof(op1));
+ CError_ASSERT(4253, ENODE_IS(arg1, EINTCONST));
+ GEN_NODE(arg1, &op1);
+
+ reg = outputReg ? outputReg : ALLOC_VR();
+
+ emitpcode(opcode, reg, op1.immediate);
+
+ output->optype = OpndType_VR;
+ output->reg = reg;
+}
+
+static void vector_intrinsic_splatu8(ENode *arg1, short outputReg, Operand *output, Opcode opcode) {
+ Operand op1;
+ short reg;
+
+ memclrw(&op1, sizeof(op1));
+ CError_ASSERT(4277, ENODE_IS(arg1, EINTCONST));
+ GEN_NODE(arg1, &op1);
+
+ reg = outputReg ? outputReg : ALLOC_VR();
+
+ emitpcode(opcode, reg, op1.immediate);
+
+ output->optype = OpndType_VR;
+ output->reg = reg;
+}
+
+static void vector_intrinsic_splatu16(ENode *arg1, short outputReg, Operand *output, Opcode opcode) {
+ Operand op1;
+ short reg;
+
+ memclrw(&op1, sizeof(op1));
+ CError_ASSERT(4301, ENODE_IS(arg1, EINTCONST));
+ GEN_NODE(arg1, &op1);
+
+ reg = outputReg ? outputReg : ALLOC_VR();
+
+ emitpcode(opcode, reg, op1.immediate);
+
+ output->optype = OpndType_VR;
+ output->reg = reg;
+}
+
+static void vector_intrinsic_splatu32(ENode *arg1, short outputReg, Operand *output, Opcode opcode) {
+ Operand op1;
+ short reg;
+
+ memclrw(&op1, sizeof(op1));
+ CError_ASSERT(4325, ENODE_IS(arg1, EINTCONST));
+ GEN_NODE(arg1, &op1);
+
+ reg = outputReg ? outputReg : ALLOC_VR();
+
+ emitpcode(opcode, reg, op1.immediate);
+
+ output->optype = OpndType_VR;
+ output->reg = reg;
+}
+
+static void vector_intrinsic_dss(ENode *arg1) {
+ Operand op1;
+
+ memclrw(&op1, sizeof(op1));
+ CError_ASSERT(4348, ENODE_IS(arg1, EINTCONST));
+ GEN_NODE(arg1, &op1);
+
+ emitpcode(PC_DSS, op1.immediate, 0);
+}
+
+static void vector_intrinsic_2args(ENode *arg1, ENode *arg2, short outputReg, Operand *output, Opcode opcode) {
+ Operand op1;
+ Operand op2;
+ short reg;
+
+ memclrw(&op1, sizeof(op1));
+ memclrw(&op2, sizeof(op2));
+ GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0);
+ GEN_NODE_TO_VR(arg2, &op2, arg2->rtype, 0);
+
+ reg = outputReg ? outputReg : ALLOC_VR();
+
+ emitpcode(opcode, reg, op1.reg, op2.reg);
+
+ output->optype = OpndType_VR;
+ output->reg = reg;
+}
+
+static void vector_intrinsic_2args1const(ENode *arg1, ENode *arg2, short outputReg, Operand *output, Opcode opcode) {
+ Operand op1;
+ Operand op2;
+ short reg;
+
+ memclrw(&op1, sizeof(op1));
+ memclrw(&op2, sizeof(op2));
+ CError_ASSERT(4393, ENODE_IS(arg2, EINTCONST));
+ GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0);
+ GEN_NODE(arg2, &op2);
+
+ reg = outputReg ? outputReg : ALLOC_VR();
+
+ emitpcode(opcode, reg, op1.reg, op2.immediate);
+
+ output->optype = OpndType_VR;
+ output->reg = reg;
+}
+
+static void vector_intrinsic_3args(ENode *arg1, ENode *arg2, ENode *arg3, short outputReg, Operand *output, Opcode opcode) {
+ Operand op1;
+ Operand op2;
+ Operand op3;
+ short reg;
+
+ memclrw(&op1, sizeof(op1));
+ memclrw(&op2, sizeof(op2));
+ memclrw(&op3, sizeof(op3));
+ GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0);
+ GEN_NODE_TO_VR(arg2, &op2, arg2->rtype, 0);
+ GEN_NODE_TO_VR(arg3, &op3, arg3->rtype, 0);
+
+ reg = outputReg ? outputReg : ALLOC_VR();
+
+ emitpcode(opcode, reg, op1.reg, op2.reg, op3.reg);
+
+ output->optype = OpndType_VR;
+ output->reg = reg;
+}
+
+static void vector_intrinsic_datastream(ENode *arg1, ENode *arg2, ENode *arg3, Opcode opcode) {
+ Operand op1;
+ Operand op2;
+
+ memclrw(&op1, sizeof(op1));
+ memclrw(&op2, sizeof(op2));
+ CError_ASSERT(4445, ENODE_IS(arg3, EINTCONST));
+ GEN_NODE_TO_GPR(arg1, &op1, arg1->rtype, 0);
+ GEN_NODE_TO_GPR(arg2, &op2, arg2->rtype, 0);
+
+ switch (opcode) {
+ case PC_DST:
+ case PC_DSTST:
+ emitpcode(opcode, op1.reg, op2.reg, arg3->data.intval.lo, 0);
+ break;
+ case PC_DSTT:
+ case PC_DSTSTT:
+ emitpcode(opcode, op1.reg, op2.reg, arg3->data.intval.lo);
+ break;
+ default:
+ CError_FATAL(4463);
+ }
+}
+
+static void vector_intrinsic_sld(ENode *arg1, ENode *arg2, ENode *arg3, short outputReg, Operand *output, Opcode opcode) {
+ Operand op1;
+ Operand op2;
+ short reg;
+
+ memclrw(&op1, sizeof(op1));
+ memclrw(&op2, sizeof(op2));
+ CError_ASSERT(4479, ENODE_IS(arg3, EINTCONST));
+ GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0);
+ GEN_NODE_TO_VR(arg2, &op2, arg2->rtype, 0);
+ reg = outputReg ? outputReg : ALLOC_VR();
+
+ emitpcode(opcode, reg, op1.reg, op2.reg, arg3->data.intval.lo);
+ output->optype = OpndType_VR;
+ output->reg = reg;
+}
+
+static void vector_intrinsic_load(ENode *arg1, ENode *arg2, short outputReg, Operand *output, Opcode opcode) {
+ Operand op1;
+ Operand op2;
+ short reg;
+
+ memclrw(&op1, sizeof(op1));
+ memclrw(&op2, sizeof(op2));
+
+ GEN_NODE(arg1, &op1);
+ if (op1.optype == OpndType_Absolute && op1.immediate == 0) {
+ op1.optype = OpndType_GPR;
+ op1.reg = 0;
+ } else {
+ ENSURE_GPR(&op1, arg1->rtype, 0);
+ }
+
+ GEN_NODE(arg2, &op2);
+ if (op2.optype == OpndType_Absolute && op2.immediate == 0 && op1.reg != 0) {
+ op2 = op1;
+ op1.optype = OpndType_GPR;
+ op1.reg = 0;
+ } else {
+ ENSURE_GPR(&op2, arg2->rtype, 0);
+ }
+
+ reg = outputReg ? outputReg : ALLOC_VR();
+
+ emitpcode(opcode, reg, op1.reg, op2.reg);
+ output->optype = OpndType_VR;
+ output->reg = reg;
+}
+
+static void vector_intrinsic_store(ENode *arg1, ENode *arg2, ENode *arg3, short outputReg, Operand *output, Opcode opcode) {
+ Operand op1;
+ Operand op2;
+ Operand op3;
+
+ memclrw(&op1, sizeof(op1));
+ memclrw(&op2, sizeof(op2));
+ memclrw(&op3, sizeof(op3));
+
+ GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0);
+
+ GEN_NODE(arg2, &op2);
+ if (op2.optype == OpndType_Absolute && op2.immediate == 0) {
+ op2.optype = OpndType_GPR;
+ op2.reg = 0;
+ } else {
+ ENSURE_GPR(&op2, arg2->rtype, 0);
+ }
+
+ GEN_NODE(arg3, &op3);
+ if (op3.optype == OpndType_Absolute && op3.immediate == 0 && op2.reg != 0) {
+ op3 = op2;
+ op2.optype = OpndType_GPR;
+ op2.reg = 0;
+ } else {
+ ENSURE_GPR(&op3, arg3->rtype, 0);
+ }
+
+ emitpcode(opcode, op1.reg, op2.reg, op3.reg);
+ output->optype = OpndType_VR;
+ output->reg = op1.reg;
+}
+
+static void vector_intrinsic_abs(Intrinsics id, ENode *funccall, ENode *arg1, short outputReg, Operand *output) {
+ TypeTable22 *table;
+ Type *typeA;
+ Type *typeB;
+ short reg1;
+ short reg2;
+ short reg3;
+ Operand op1;
+
+ for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) {
+ typeB = arg1->rtype;
+ typeA = table->arg1;
+ if (IS_TYPE_POINTER(typeA) && IS_TYPE_POINTER(typeB)) {
+ typeA = TPTR_TARGET(typeA);
+ typeB = TPTR_TARGET(typeB);
+ }
+ if (promotable_types_are_equal(typeA, typeB))
+ break;
+ }
+
+ CError_ASSERT(4617, table->rtype);
+
+ reg1 = ALLOC_VR();
+ reg2 = ALLOC_VR();
+ reg3 = outputReg ? outputReg : ALLOC_VR();
+
+ memclrw(&op1, sizeof(op1));
+ GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0);
+
+ if (arg1->rtype == TYPE(&stvectorfloat)) {
+ emitpcode(PC_VSPLTISW, reg1, -1);
+ emitpcode(PC_VSLW, reg2, reg1, reg1);
+ emitpcode(table->opcode1, reg3, op1.reg, reg2);
+ } else {
+ emitpcode(PC_VSPLTISB, reg1, 0);
+ emitpcode(table->opcode1, reg2, reg1, op1.reg);
+ emitpcode(table->opcode2, reg3, op1.reg, reg2);
+ }
+
+ output->optype = OpndType_VR;
+ output->reg = reg3;
+}
+
+static void vector_intrinsic_abss(Intrinsics id, ENode *funccall, ENode *arg1, short outputReg, Operand *output) {
+ TypeTable22 *table;
+ Type *typeA;
+ Type *typeB;
+ short reg1;
+ short reg2;
+ short reg3;
+ Operand op1;
+
+ for (table = typeTable[id - Intrinsic_042]; table->rtype; table++) {
+ typeB = arg1->rtype;
+ typeA = table->arg1;
+ if (IS_TYPE_POINTER(typeA) && IS_TYPE_POINTER(typeB)) {
+ typeA = TPTR_TARGET(typeA);
+ typeB = TPTR_TARGET(typeB);
+ }
+ if (promotable_types_are_equal(typeA, typeB))
+ break;
+ }
+
+ CError_ASSERT(4683, table->rtype);
+
+ reg1 = ALLOC_VR();
+ reg2 = ALLOC_VR();
+ reg3 = outputReg ? outputReg : ALLOC_VR();
+
+ memclrw(&op1, sizeof(op1));
+ GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0);
+
+ emitpcode(PC_VSPLTISB, reg1, 0);
+ emitpcode(table->opcode1, reg2, reg1, op1.reg);
+ emitpcode(table->opcode2, reg3, op1.reg, reg2);
+
+ output->optype = OpndType_VR;
+ output->reg = reg3;
+}
+
+static void vector_intrinsic_mtvscr(ENode *arg1, Operand *output, Opcode opcode) {
+ Operand op1;
+
+ memclrw(&op1, sizeof(op1));
+ GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0);
+ emitpcode(opcode, op1.reg);
+}
+
+static void vector_predicate_2args(ENode *arg1, ENode *arg2, short outputReg, Operand *output, Opcode opcode, Intrinsics id) {
+ Operand op1;
+ Operand op2;
+ short reg1;
+ short reg2;
+ short reg3;
+ Opcode cond;
+
+ memclrw(&op1, sizeof(op1));
+ memclrw(&op2, sizeof(op2));
+
+ GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0);
+ GEN_NODE_TO_VR(arg2, &op2, arg2->rtype, 0);
+
+ reg1 = ALLOC_VR();
+ reg2 = op1.reg;
+ reg3 = op2.reg;
+ if (
+ ((id == Intrinsic_132 || id == Intrinsic_145) && arg1->rtype != TYPE(&stvectorfloat)) ||
+ ((id == Intrinsic_135 || id == Intrinsic_147) && arg1->rtype == TYPE(&stvectorfloat)) ||
+ id == Intrinsic_136 ||
+ id == Intrinsic_148 ||
+ id == Intrinsic_153 ||
+ id == Intrinsic_141 ||
+ id == Intrinsic_142 ||
+ id == Intrinsic_154
+ )
+ {
+ reg3 = op1.reg;
+ reg2 = op2.reg;
+ }
+ emitpcode(opcode, reg1, reg2, reg3);
+ pcsetrecordbit(pclastblock->lastPCode);
+
+ if (arg1->rtype == TYPE(&stvectorfloat)) {
+ switch (id) {
+ case Intrinsic_131:
+ case Intrinsic_132:
+ case Intrinsic_133:
+ case Intrinsic_135:
+ case Intrinsic_136:
+ cond = ELESS;
+ break;
+ case Intrinsic_150:
+ case Intrinsic_151:
+ case Intrinsic_152:
+ case Intrinsic_153:
+ case Intrinsic_154:
+ cond = EGREATEREQU;
+ break;
+ case Intrinsic_134:
+ case Intrinsic_138:
+ case Intrinsic_139:
+ case Intrinsic_140:
+ case Intrinsic_141:
+ case Intrinsic_142:
+ cond = EEQU;
+ break;
+ case Intrinsic_144:
+ case Intrinsic_145:
+ case Intrinsic_146:
+ case Intrinsic_147:
+ case Intrinsic_148:
+ case Intrinsic_156:
+ cond = ENOTEQU;
+ break;
+ default:
+ CError_FATAL(4805);
+ }
+ } else {
+ switch (id) {
+ case Intrinsic_131:
+ case Intrinsic_133:
+ case Intrinsic_136:
+ cond = ELESS;
+ break;
+ case Intrinsic_144:
+ case Intrinsic_146:
+ case Intrinsic_148:
+ cond = ENOTEQU;
+ break;
+ case Intrinsic_132:
+ case Intrinsic_135:
+ case Intrinsic_138:
+ cond = EEQU;
+ break;
+ case Intrinsic_145:
+ case Intrinsic_147:
+ case Intrinsic_150:
+ cond = EGREATEREQU;
+ break;
+ default:
+ CError_FATAL(4834);
+ }
+ }
+
+ output->optype = OpndType_CRField;
+ output->reg = 6;
+ output->regOffset = cond;
+}
+
+static void vector_predicate_1arg(ENode *arg1, short outputReg, Operand *output, Opcode opcode, Intrinsics id) {
+ Operand op1;
+ short reg;
+ Opcode cond;
+
+ memclrw(&op1, sizeof(op1));
+
+ GEN_NODE_TO_VR(arg1, &op1, arg1->rtype, 0);
+
+ reg = ALLOC_VR();
+ emitpcode(opcode, reg, op1.reg, op1.reg);
+ pcsetrecordbit(pclastblock->lastPCode);
+
+ switch (id) {
+ case Intrinsic_143:
+ cond = ELESS;
+ break;
+ case Intrinsic_149:
+ cond = EGREATEREQU;
+ break;
+ case Intrinsic_137:
+ cond = EEQU;
+ break;
+ case Intrinsic_155:
+ cond = ENOTEQU;
+ break;
+ default:
+ CError_FATAL(4878);
+ }
+
+ output->optype = OpndType_CRField;
+ output->reg = 6;
+ output->regOffset = cond;
+}
+
+ENode *Intrinsics_HandleIntrinsicCall(Object *func, ENodeList *args) {
+ ENode *callexpr;
+ Type *rtype;
+ Intrinsics id;
+
+ callexpr = NULL;
+
+ if (copts.altivec_model) {
+ id = func->u.func.u.intrinsicid;
+ switch (id) {
+ case Intrinsic_060:
+ case Intrinsic_061:
+ case Intrinsic_062:
+ case Intrinsic_063:
+ case Intrinsic_072:
+ case Intrinsic_073:
+ case Intrinsic_079:
+ case Intrinsic_080:
+ case Intrinsic_081:
+ case Intrinsic_082:
+ case Intrinsic_086:
+ case Intrinsic_093:
+ case Intrinsic_098:
+ case Intrinsic_100:
+ case Intrinsic_114:
+ case Intrinsic_115:
+ case Intrinsic_116:
+ case Intrinsic_202:
+ case Intrinsic_203:
+ case Intrinsic_224:
+ case Intrinsic_225:
+ case Intrinsic_226:
+ case Intrinsic_227:
+ case Intrinsic_228:
+ case Intrinsic_229:
+ case Intrinsic_230:
+ case Intrinsic_231:
+ case Intrinsic_240:
+ case Intrinsic_252:
+ case Intrinsic_259:
+ case Intrinsic_263:
+ case Intrinsic_280:
+ case Intrinsic_281:
+ case Intrinsic_282:
+ case Intrinsic_283:
+ case Intrinsic_284:
+ if (Intrinsics_VerifyParameterCount(3, args, func->name)) {
+ if ((rtype = Intrinsics_Verify3VectorArgs(id, args, func->name)))
+ callexpr = Intrinsics_CreateIntrinsicFunc(func, args, rtype);
+ }
+ break;
+ case Intrinsic_042:
+ case Intrinsic_043:
+ case Intrinsic_044:
+ case Intrinsic_045:
+ case Intrinsic_046:
+ case Intrinsic_047:
+ case Intrinsic_049:
+ case Intrinsic_050:
+ case Intrinsic_051:
+ case Intrinsic_052:
+ case Intrinsic_053:
+ case Intrinsic_054:
+ case Intrinsic_055:
+ case Intrinsic_056:
+ case Intrinsic_057:
+ case Intrinsic_066:
+ case Intrinsic_067:
+ case Intrinsic_068:
+ case Intrinsic_070:
+ case Intrinsic_071:
+ case Intrinsic_074:
+ case Intrinsic_075:
+ case Intrinsic_076:
+ case Intrinsic_078:
+ case Intrinsic_084:
+ case Intrinsic_085:
+ case Intrinsic_087:
+ case Intrinsic_088:
+ case Intrinsic_089:
+ case Intrinsic_090:
+ case Intrinsic_091:
+ case Intrinsic_092:
+ case Intrinsic_095:
+ case Intrinsic_099:
+ case Intrinsic_101:
+ case Intrinsic_102:
+ case Intrinsic_103:
+ case Intrinsic_110:
+ case Intrinsic_111:
+ case Intrinsic_112:
+ case Intrinsic_113:
+ case Intrinsic_117:
+ case Intrinsic_118:
+ case Intrinsic_119:
+ case Intrinsic_120:
+ case Intrinsic_121:
+ case Intrinsic_122:
+ case Intrinsic_124:
+ case Intrinsic_125:
+ case Intrinsic_126:
+ case Intrinsic_127:
+ case Intrinsic_130:
+ case Intrinsic_131:
+ case Intrinsic_132:
+ case Intrinsic_133:
+ case Intrinsic_134:
+ case Intrinsic_135:
+ case Intrinsic_136:
+ case Intrinsic_138:
+ case Intrinsic_139:
+ case Intrinsic_140:
+ case Intrinsic_141:
+ case Intrinsic_142:
+ case Intrinsic_144:
+ case Intrinsic_145:
+ case Intrinsic_146:
+ case Intrinsic_147:
+ case Intrinsic_148:
+ case Intrinsic_150:
+ case Intrinsic_151:
+ case Intrinsic_152:
+ case Intrinsic_153:
+ case Intrinsic_154:
+ case Intrinsic_156:
+ case Intrinsic_157:
+ case Intrinsic_158:
+ case Intrinsic_159:
+ case Intrinsic_160:
+ case Intrinsic_161:
+ case Intrinsic_162:
+ case Intrinsic_163:
+ case Intrinsic_164:
+ case Intrinsic_165:
+ case Intrinsic_166:
+ case Intrinsic_167:
+ case Intrinsic_168:
+ case Intrinsic_169:
+ case Intrinsic_170:
+ case Intrinsic_171:
+ case Intrinsic_172:
+ case Intrinsic_173:
+ case Intrinsic_174:
+ case Intrinsic_175:
+ case Intrinsic_177:
+ case Intrinsic_178:
+ case Intrinsic_179:
+ case Intrinsic_180:
+ case Intrinsic_181:
+ case Intrinsic_182:
+ case Intrinsic_183:
+ case Intrinsic_184:
+ case Intrinsic_185:
+ case Intrinsic_186:
+ case Intrinsic_187:
+ case Intrinsic_188:
+ case Intrinsic_189:
+ case Intrinsic_190:
+ case Intrinsic_191:
+ case Intrinsic_192:
+ case Intrinsic_193:
+ case Intrinsic_196:
+ case Intrinsic_197:
+ case Intrinsic_198:
+ case Intrinsic_199:
+ case Intrinsic_200:
+ case Intrinsic_204:
+ case Intrinsic_205:
+ case Intrinsic_206:
+ case Intrinsic_207:
+ case Intrinsic_208:
+ case Intrinsic_209:
+ case Intrinsic_210:
+ case Intrinsic_211:
+ case Intrinsic_212:
+ case Intrinsic_213:
+ case Intrinsic_214:
+ case Intrinsic_215:
+ case Intrinsic_216:
+ case Intrinsic_217:
+ case Intrinsic_218:
+ case Intrinsic_219:
+ case Intrinsic_220:
+ case Intrinsic_221:
+ case Intrinsic_222:
+ case Intrinsic_223:
+ case Intrinsic_232:
+ case Intrinsic_233:
+ case Intrinsic_234:
+ case Intrinsic_235:
+ case Intrinsic_236:
+ case Intrinsic_237:
+ case Intrinsic_238:
+ case Intrinsic_239:
+ case Intrinsic_241:
+ case Intrinsic_242:
+ case Intrinsic_243:
+ case Intrinsic_244:
+ case Intrinsic_245:
+ case Intrinsic_246:
+ case Intrinsic_247:
+ case Intrinsic_248:
+ case Intrinsic_249:
+ case Intrinsic_250:
+ case Intrinsic_251:
+ case Intrinsic_254:
+ case Intrinsic_255:
+ case Intrinsic_256:
+ case Intrinsic_260:
+ case Intrinsic_261:
+ case Intrinsic_262:
+ case Intrinsic_264:
+ case Intrinsic_265:
+ case Intrinsic_266:
+ case Intrinsic_267:
+ case Intrinsic_268:
+ case Intrinsic_272:
+ case Intrinsic_273:
+ case Intrinsic_274:
+ case Intrinsic_275:
+ case Intrinsic_276:
+ case Intrinsic_277:
+ case Intrinsic_278:
+ case Intrinsic_279:
+ case Intrinsic_285:
+ case Intrinsic_286:
+ case Intrinsic_287:
+ case Intrinsic_288:
+ case Intrinsic_289:
+ case Intrinsic_290:
+ case Intrinsic_291:
+ case Intrinsic_292:
+ case Intrinsic_293:
+ case Intrinsic_294:
+ case Intrinsic_295:
+ case Intrinsic_296:
+ case Intrinsic_297:
+ case Intrinsic_298:
+ case Intrinsic_299:
+ case Intrinsic_300:
+ case Intrinsic_308:
+ if (Intrinsics_VerifyParameterCount(2, args, func->name)) {
+ if ((rtype = Intrinsics_Verify2VectorArgs(id, args, func->name)))
+ callexpr = Intrinsics_CreateIntrinsicFunc(func, args, rtype);
+ }
+ break;
+ case Intrinsic_048:
+ case Intrinsic_058:
+ case Intrinsic_064:
+ case Intrinsic_065:
+ case Intrinsic_069:
+ case Intrinsic_083:
+ case Intrinsic_094:
+ case Intrinsic_096:
+ case Intrinsic_097:
+ case Intrinsic_104:
+ case Intrinsic_105:
+ case Intrinsic_106:
+ case Intrinsic_107:
+ case Intrinsic_108:
+ case Intrinsic_109:
+ case Intrinsic_123:
+ case Intrinsic_128:
+ case Intrinsic_129:
+ case Intrinsic_137:
+ case Intrinsic_143:
+ case Intrinsic_149:
+ case Intrinsic_155:
+ case Intrinsic_176:
+ case Intrinsic_194:
+ case Intrinsic_195:
+ case Intrinsic_201:
+ case Intrinsic_253:
+ case Intrinsic_257:
+ case Intrinsic_258:
+ case Intrinsic_269:
+ case Intrinsic_270:
+ case Intrinsic_271:
+ case Intrinsic_301:
+ case Intrinsic_302:
+ case Intrinsic_303:
+ case Intrinsic_304:
+ case Intrinsic_305:
+ case Intrinsic_306:
+ case Intrinsic_307:
+ if (Intrinsics_VerifyParameterCount(1, args, func->name)) {
+ if ((rtype = Intrinsics_Verify1VectorArg(id, args, func->name)))
+ callexpr = Intrinsics_CreateIntrinsicFunc(func, args, rtype);
+ }
+ break;
+ case Intrinsic_059:
+ case Intrinsic_077:
+ if (Intrinsics_VerifyParameterCount(0, args, func->name)) {
+ if ((rtype = Intrinsics_VerifyNoVectorArgs(id, func->name)))
+ callexpr = Intrinsics_CreateIntrinsicFunc(func, args, rtype);
+ }
+ break;
+ case Intrinsic_309:
+ case Intrinsic_310:
+ if (Intrinsics_VerifyParameterCount(1, args, func->name)) {
+ if ((rtype = Intrinsics_Verify1VectorArg2Ops(id, args, func->name)))
+ callexpr = Intrinsics_CreateIntrinsicFunc(func, args, rtype);
+ }
+ break;
+ }
+ }
+
+ return callexpr;
+}
+
+void call_intrinsic_function(ENode *funccall, short outputReg, Operand *output) {
+ ENodeList *args;
+ Object *object;
+ Intrinsics id;
+ Opcode op;
+ short reg;
+
+ static Opcode opcode[MaxIntrinsics] = {
+ /* Intrinsic_000 */ PC_EIEIO,
+ /* Intrinsic_001 */ PC_SYNC,
+ /* Intrinsic_002 */ PC_ISYNC,
+ 0,
+ 0,
+ /* Intrinsic_005 */ PC_FABS,
+ /* Intrinsic_006 */ PC_FNABS,
+ 0,
+ 0,
+ /* Intrinsic_009 */ PC_CNTLZW,
+ /* Intrinsic_010 */ PC_LHBRX,
+ /* Intrinsic_011 */ PC_LWBRX,
+ /* Intrinsic_012 */ PC_STHBRX,
+ /* Intrinsic_013 */ PC_STWBRX,
+ /* Intrinsic_014 */ PC_DCBF,
+ /* Intrinsic_015 */ PC_DCBT,
+ /* Intrinsic_016 */ PC_DCBST,
+ /* Intrinsic_017 */ PC_DCBTST,
+ /* Intrinsic_018 */ PC_DCBZ,
+ /* Intrinsic_019 */ PC_MULHW,
+ /* Intrinsic_020 */ PC_MULHWU,
+ /* Intrinsic_021 */ PC_DIVW,
+ /* Intrinsic_022 */ PC_DIVWU,
+ /* Intrinsic_023 */ PC_FMADD,
+ /* Intrinsic_024 */ PC_FMSUB,
+ /* Intrinsic_025 */ PC_FNMADD,
+ /* Intrinsic_026 */ PC_FNMSUB,
+ /* Intrinsic_027 */ PC_FMADDS,
+ /* Intrinsic_028 */ PC_FMSUBS,
+ /* Intrinsic_029 */ PC_FNMADDS,
+ /* Intrinsic_030 */ PC_FNMSUBS,
+ /* Intrinsic_031 */ PC_MFFS,
+ /* Intrinsic_032 */ PC_FRES,
+ /* Intrinsic_033 */ PC_FRSQRTE,
+ /* Intrinsic_004 */ PC_FSEL,
+ 0,
+ 0,
+ /* Intrinsic_037 */ PC_RLWIMI,
+ /* Intrinsic_038 */ PC_RLWINM,
+ /* Intrinsic_039 */ PC_RLWNM,
+ /* Intrinsic_040 */ PC_FABS,
+ /* Intrinsic_041 */ PC_FNABS
+ };
+
+ args = funccall->data.funccall.args;
+ object = funccall->data.funccall.funcref->data.objref;
+ id = object->u.func.u.intrinsicid;
+ cur_intrinsic_object = object;
+
+ switch (id) {
+ case Intrinsic_000:
+ case Intrinsic_001:
+ case Intrinsic_002:
+ appendpcode(pclastblock, makepcode(opcode[id]));
+ output->optype = OpndType_Absolute;
+ break;
+ case Intrinsic_003:
+ case Intrinsic_004:
+ abs_intrinsic(args->node, outputReg, output);
+ break;
+ case Intrinsic_005:
+ case Intrinsic_006:
+ case Intrinsic_032:
+ case Intrinsic_033:
+ case Intrinsic_040:
+ case Intrinsic_041:
+ fp_unary_operator(opcode[id], args->node, outputReg, output);
+ break;
+ case Intrinsic_007:
+ setflm_intrinsic(args->node, outputReg, output, funccall->ignored);
+ break;
+ case Intrinsic_008:
+ alloca_intrinsic(args->node, outputReg, output);
+ break;
+ case Intrinsic_009:
+ unary_operator(PC_CNTLZW, args->node, outputReg, output);
+ break;
+ case Intrinsic_010:
+ case Intrinsic_011:
+ load_bytereversed_intrinsic(opcode[id], args->node, args->next->node, outputReg, output);
+ break;
+ case Intrinsic_012:
+ case Intrinsic_013:
+ store_bytereversed_intrinsic(opcode[id], args->node, args->next->node, args->next->next->node);
+ output->optype = OpndType_Absolute;
+ break;
+ case Intrinsic_014:
+ case Intrinsic_015:
+ case Intrinsic_016:
+ case Intrinsic_017:
+ case Intrinsic_018:
+ data_cache_block_intrinsic(opcode[id], args->node, args->next->node);
+ output->optype = OpndType_Absolute;
+ break;
+ case Intrinsic_019:
+ case Intrinsic_020:
+ case Intrinsic_021:
+ case Intrinsic_022:
+ binary_operator(opcode[id], args->node, args->next->node, outputReg, output);
+ break;
+ case Intrinsic_023:
+ case Intrinsic_024:
+ case Intrinsic_025:
+ case Intrinsic_026:
+ case Intrinsic_027:
+ case Intrinsic_028:
+ case Intrinsic_029:
+ case Intrinsic_030:
+ case Intrinsic_034:
+ fp_multiply_add(opcode[id],
+ args->node, args->next->node, args->next->next->node,
+ outputReg, output);
+ break;
+ case Intrinsic_031:
+ reg = outputReg ? outputReg : ALLOC_FPR();
+ emitpcode(PC_MFFS, output->reg = reg);
+ output->optype = OpndType_FPR;
+ break;
+ case Intrinsic_035:
+ call_function(funccall, output);
+ break;
+ case Intrinsic_036:
+ if (ENODE_IS(args->next->next->node, EINTCONST))
+ memcpy_intrinsic(
+ args->node, args->next->node, args->next->next->node->data.intval.lo,
+ funccall->ignored, output);
+ else
+ call_function(funccall, output);
+ break;
+ case Intrinsic_037:
+ rlwimi_intrinsic(
+ args->node,
+ args->next->node,
+ args->next->next->node,
+ args->next->next->next->node,
+ args->next->next->next->next->node,
+ outputReg, output);
+ break;
+ case Intrinsic_038:
+ rlwinm_intrinsic(
+ args->node,
+ args->next->node,
+ args->next->next->node,
+ args->next->next->next->node,
+ outputReg, output);
+ break;
+ case Intrinsic_039:
+ rlwnm_intrinsic(
+ args->node,
+ args->next->node,
+ args->next->next->node,
+ args->next->next->next->node,
+ outputReg, output);
+ break;
+ case Intrinsic_072:
+ case Intrinsic_073:
+ case Intrinsic_079:
+ case Intrinsic_080:
+ case Intrinsic_081:
+ case Intrinsic_082:
+ case Intrinsic_086:
+ case Intrinsic_093:
+ case Intrinsic_098:
+ case Intrinsic_202:
+ case Intrinsic_203:
+ case Intrinsic_224:
+ case Intrinsic_225:
+ case Intrinsic_226:
+ case Intrinsic_227:
+ case Intrinsic_228:
+ case Intrinsic_229:
+ case Intrinsic_230:
+ case Intrinsic_231:
+ case Intrinsic_240:
+ case Intrinsic_252:
+ case Intrinsic_259:
+ op = Intrinsics_FindOpcode3Args(id, funccall, args->node, args->next->node, args->next->next->node);
+ vector_intrinsic_3args(args->node, args->next->node, args->next->next->node, outputReg, output, op);
+ break;
+ case Intrinsic_100:
+ case Intrinsic_263:
+ op = Intrinsics_FindOpcode3Args(id, funccall, args->node, args->next->node, args->next->next->node);
+ vector_intrinsic_sld(args->node, args->next->node, args->next->next->node, outputReg, output, op);
+ break;
+ case Intrinsic_042:
+ case Intrinsic_043:
+ case Intrinsic_044:
+ case Intrinsic_045:
+ case Intrinsic_046:
+ case Intrinsic_047:
+ case Intrinsic_049:
+ case Intrinsic_050:
+ case Intrinsic_051:
+ case Intrinsic_053:
+ case Intrinsic_074:
+ case Intrinsic_075:
+ case Intrinsic_076:
+ case Intrinsic_078:
+ case Intrinsic_084:
+ case Intrinsic_085:
+ case Intrinsic_087:
+ case Intrinsic_088:
+ case Intrinsic_089:
+ case Intrinsic_090:
+ case Intrinsic_091:
+ case Intrinsic_092:
+ case Intrinsic_095:
+ case Intrinsic_099:
+ case Intrinsic_101:
+ case Intrinsic_102:
+ case Intrinsic_110:
+ case Intrinsic_111:
+ case Intrinsic_112:
+ case Intrinsic_113:
+ case Intrinsic_117:
+ case Intrinsic_118:
+ case Intrinsic_119:
+ case Intrinsic_120:
+ case Intrinsic_121:
+ case Intrinsic_122:
+ case Intrinsic_124:
+ case Intrinsic_125:
+ case Intrinsic_126:
+ case Intrinsic_127:
+ case Intrinsic_130:
+ case Intrinsic_157:
+ case Intrinsic_158:
+ case Intrinsic_159:
+ case Intrinsic_160:
+ case Intrinsic_161:
+ case Intrinsic_162:
+ case Intrinsic_163:
+ case Intrinsic_164:
+ case Intrinsic_165:
+ case Intrinsic_166:
+ case Intrinsic_167:
+ case Intrinsic_168:
+ case Intrinsic_169:
+ case Intrinsic_170:
+ case Intrinsic_171:
+ case Intrinsic_172:
+ case Intrinsic_173:
+ case Intrinsic_174:
+ case Intrinsic_175:
+ case Intrinsic_177:
+ case Intrinsic_178:
+ case Intrinsic_179:
+ case Intrinsic_180:
+ case Intrinsic_181:
+ case Intrinsic_182:
+ case Intrinsic_183:
+ case Intrinsic_184:
+ case Intrinsic_185:
+ case Intrinsic_186:
+ case Intrinsic_187:
+ case Intrinsic_188:
+ case Intrinsic_189:
+ case Intrinsic_204:
+ case Intrinsic_205:
+ case Intrinsic_206:
+ case Intrinsic_207:
+ case Intrinsic_208:
+ case Intrinsic_209:
+ case Intrinsic_210:
+ case Intrinsic_211:
+ case Intrinsic_212:
+ case Intrinsic_213:
+ case Intrinsic_214:
+ case Intrinsic_215:
+ case Intrinsic_216:
+ case Intrinsic_217:
+ case Intrinsic_218:
+ case Intrinsic_219:
+ case Intrinsic_220:
+ case Intrinsic_221:
+ case Intrinsic_222:
+ case Intrinsic_223:
+ case Intrinsic_232:
+ case Intrinsic_233:
+ case Intrinsic_234:
+ case Intrinsic_235:
+ case Intrinsic_236:
+ case Intrinsic_237:
+ case Intrinsic_238:
+ case Intrinsic_239:
+ case Intrinsic_241:
+ case Intrinsic_242:
+ case Intrinsic_243:
+ case Intrinsic_244:
+ case Intrinsic_245:
+ case Intrinsic_246:
+ case Intrinsic_247:
+ case Intrinsic_248:
+ case Intrinsic_249:
+ case Intrinsic_250:
+ case Intrinsic_251:
+ case Intrinsic_254:
+ case Intrinsic_255:
+ case Intrinsic_256:
+ case Intrinsic_260:
+ case Intrinsic_261:
+ case Intrinsic_262:
+ case Intrinsic_264:
+ case Intrinsic_265:
+ case Intrinsic_272:
+ case Intrinsic_273:
+ case Intrinsic_274:
+ case Intrinsic_275:
+ case Intrinsic_276:
+ case Intrinsic_277:
+ case Intrinsic_278:
+ case Intrinsic_279:
+ case Intrinsic_285:
+ case Intrinsic_286:
+ case Intrinsic_287:
+ case Intrinsic_288:
+ case Intrinsic_289:
+ case Intrinsic_290:
+ case Intrinsic_291:
+ case Intrinsic_292:
+ case Intrinsic_293:
+ case Intrinsic_294:
+ case Intrinsic_295:
+ case Intrinsic_296:
+ case Intrinsic_297:
+ case Intrinsic_298:
+ case Intrinsic_299:
+ case Intrinsic_300:
+ case Intrinsic_308:
+ op = Intrinsics_FindOpcode2Args(id, funccall, args->node, args->next->node);
+ vector_intrinsic_2args(args->node, args->next->node, outputReg, output, op);
+ break;
+ case Intrinsic_048:
+ case Intrinsic_064:
+ case Intrinsic_065:
+ case Intrinsic_069:
+ case Intrinsic_094:
+ case Intrinsic_096:
+ case Intrinsic_097:
+ case Intrinsic_123:
+ case Intrinsic_128:
+ case Intrinsic_129:
+ case Intrinsic_176:
+ case Intrinsic_194:
+ case Intrinsic_195:
+ case Intrinsic_201:
+ case Intrinsic_253:
+ case Intrinsic_257:
+ case Intrinsic_258:
+ case Intrinsic_301:
+ case Intrinsic_302:
+ case Intrinsic_303:
+ case Intrinsic_304:
+ case Intrinsic_305:
+ case Intrinsic_306:
+ case Intrinsic_307:
+ op = Intrinsics_FindOpcode1Arg(id, funccall, args->node);
+ vector_intrinsic_1arg(args->node, outputReg, output, op);
+ break;
+ case Intrinsic_055:
+ case Intrinsic_056:
+ case Intrinsic_057:
+ case Intrinsic_103:
+ case Intrinsic_190:
+ case Intrinsic_191:
+ case Intrinsic_192:
+ case Intrinsic_193:
+ case Intrinsic_266:
+ case Intrinsic_267:
+ case Intrinsic_268:
+ op = Intrinsics_FindOpcode2Args(id, funccall, args->node, args->next->node);
+ vector_intrinsic_2args1const(args->node, args->next->node, outputReg, output, op);
+ break;
+ case Intrinsic_104:
+ case Intrinsic_105:
+ case Intrinsic_106:
+ case Intrinsic_269:
+ case Intrinsic_270:
+ case Intrinsic_271:
+ op = Intrinsics_FindOpcode1Arg(id, funccall, args->node);
+ vector_intrinsic_splats(args->node, outputReg, output, op);
+ break;
+ case Intrinsic_107:
+ op = Intrinsics_FindOpcode1Arg(id, funccall, args->node);
+ vector_intrinsic_splatu8(args->node, outputReg, output, op);
+ break;
+ case Intrinsic_108:
+ op = Intrinsics_FindOpcode1Arg(id, funccall, args->node);
+ vector_intrinsic_splatu16(args->node, outputReg, output, op);
+ break;
+ case Intrinsic_109:
+ op = Intrinsics_FindOpcode1Arg(id, funccall, args->node);
+ vector_intrinsic_splatu32(args->node, outputReg, output, op);
+ break;
+ case Intrinsic_083:
+ vector_intrinsic_mtvscr(args->node, output, PC_MTVSCR);
+ break;
+ case Intrinsic_077:
+ op = Intrinsics_FindOpcodeNoArgs(id, funccall);
+ vector_intrinsic_mfvscr(outputReg, op, output);
+ break;
+ case Intrinsic_058:
+ vector_intrinsic_dss(args->node);
+ break;
+ case Intrinsic_059:
+ op = Intrinsics_FindOpcodeNoArgs(id, funccall);
+ vector_intrinsic_no_args(op);
+ break;
+ case Intrinsic_060:
+ case Intrinsic_061:
+ case Intrinsic_062:
+ case Intrinsic_063:
+ switch (id) {
+ case Intrinsic_060:
+ op = PC_DST;
+ break;
+ case Intrinsic_061:
+ op = PC_DSTST;
+ break;
+ case Intrinsic_062:
+ op = PC_DSTSTT;
+ break;
+ case Intrinsic_063:
+ op = PC_DSTT;
+ break;
+ }
+ vector_intrinsic_datastream(args->node, args->next->node, args->next->next->node, op);
+ break;
+ case Intrinsic_066:
+ case Intrinsic_067:
+ case Intrinsic_068:
+ case Intrinsic_070:
+ case Intrinsic_071:
+ case Intrinsic_196:
+ case Intrinsic_197:
+ case Intrinsic_198:
+ case Intrinsic_199:
+ case Intrinsic_200:
+ op = Intrinsics_FindOpcode2Args(id, funccall, args->node, args->next->node);
+ vector_intrinsic_load(args->node, args->next->node, outputReg, output, op);
+ break;
+ case Intrinsic_114:
+ case Intrinsic_115:
+ case Intrinsic_116:
+ case Intrinsic_280:
+ case Intrinsic_281:
+ case Intrinsic_282:
+ case Intrinsic_283:
+ case Intrinsic_284:
+ op = Intrinsics_FindOpcode3Args(id, funccall, args->node, args->next->node, args->next->next->node);
+ vector_intrinsic_store(args->node, args->next->node, args->next->next->node, outputReg, output, op);
+ break;
+ case Intrinsic_131:
+ case Intrinsic_132:
+ case Intrinsic_133:
+ case Intrinsic_134:
+ case Intrinsic_135:
+ case Intrinsic_136:
+ case Intrinsic_138:
+ case Intrinsic_139:
+ case Intrinsic_140:
+ case Intrinsic_141:
+ case Intrinsic_142:
+ case Intrinsic_144:
+ case Intrinsic_145:
+ case Intrinsic_146:
+ case Intrinsic_147:
+ case Intrinsic_148:
+ case Intrinsic_150:
+ case Intrinsic_151:
+ case Intrinsic_152:
+ case Intrinsic_153:
+ case Intrinsic_154:
+ case Intrinsic_156:
+ op = Intrinsics_FindOpcode2Args(id, funccall, args->node, args->next->node);
+ vector_predicate_2args(args->node, args->next->node, outputReg, output, op, id);
+ break;
+ case Intrinsic_137:
+ case Intrinsic_143:
+ case Intrinsic_149:
+ case Intrinsic_155:
+ op = Intrinsics_FindOpcode1Arg(id, funccall, args->node);
+ vector_predicate_1arg(args->node, outputReg, output, op, id);
+ break;
+ case Intrinsic_309:
+ vector_intrinsic_abs(id, funccall, args->node, outputReg, output);
+ break;
+ case Intrinsic_310:
+ vector_intrinsic_abss(id, funccall, args->node, outputReg, output);
+ break;
+ case Intrinsic_052:
+ case Intrinsic_054:
+ op = Intrinsics_FindOpcode2Args(id, funccall, args->node, args->next->node);
+ vector_intrinsic_2args(args->node, args->next->node, outputReg, output, op);
+ break;
+ default:
+ CError_FATAL(6152);
+ }
+}
+
+void Intrinsics_SetupRuntimeObjects(void) {
+ static TypePointer char_ptr = {TYPEPOINTER, 4, TYPE(&stchar), 0};
+ Boolean savecpp;
+ int i;
+
+ savecpp = copts.cplusplus;
+ copts.cplusplus = 0;
+
+ for (i = 0; i < MaxIntrinsics; i++)
+ intrinsics[i] = NULL;
+
+ intrinsics[Intrinsic_000] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__eieio"), 0, 0);
+ intrinsics[Intrinsic_001] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__sync"), 0, 0);
+ intrinsics[Intrinsic_002] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__isync"), 0, 0);
+ intrinsics[Intrinsic_003] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__abs"), 0, 1, &stsignedint);
+ intrinsics[Intrinsic_004] = CParser_NewRTFunc(TYPE(&stsignedlong), GetHashNameNodeExport("__labs"), 0, 1, &stsignedlong);
+ intrinsics[Intrinsic_005] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fabs"), 0, 1, &stdouble);
+ intrinsics[Intrinsic_006] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fnabs"), 0, 1, &stdouble);
+ intrinsics[Intrinsic_007] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__setflm"), 0, 1, &stdouble);
+ intrinsics[Intrinsic_033] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__frsqrte"), 0, 1, &stdouble);
+ intrinsics[Intrinsic_008] = CParser_NewRTFunc(TYPE(&void_ptr), GetHashNameNodeExport("__alloca"), 0, 1, &stunsignedint);
+ intrinsics[Intrinsic_009] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__cntlzw"), 0, 1, &stunsignedint);
+ intrinsics[Intrinsic_010] = CParser_NewRTFunc(TYPE(&stunsignedint), GetHashNameNodeExport("__lhbrx"), 0, 2, &void_ptr, &stsignedint);
+ intrinsics[Intrinsic_011] = CParser_NewRTFunc(TYPE(&stunsignedint), GetHashNameNodeExport("__lwbrx"), 0, 2, &void_ptr, &stsignedint);
+ intrinsics[Intrinsic_012] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__sthbrx"), 0, 3, &stunsignedshort, &void_ptr, &stsignedint);
+ intrinsics[Intrinsic_013] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__stwbrx"), 0, 3, &stunsignedint, &void_ptr, &stsignedint);
+ intrinsics[Intrinsic_014] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__dcbf"), 0, 2, &void_ptr, &stsignedint);
+ intrinsics[Intrinsic_015] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__dcbt"), 0, 2, &void_ptr, &stsignedint);
+ intrinsics[Intrinsic_016] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__dcbst"), 0, 2, &void_ptr, &stsignedint);
+ intrinsics[Intrinsic_017] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__dcbtst"), 0, 2, &void_ptr, &stsignedint);
+ intrinsics[Intrinsic_018] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("__dcbz"), 0, 2, &void_ptr, &stsignedint);
+ intrinsics[Intrinsic_019] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__mulhw"), 0, 2, &stsignedint, &stsignedint);
+ intrinsics[Intrinsic_020] = CParser_NewRTFunc(TYPE(&stunsignedint), GetHashNameNodeExport("__mulhwu"), 0, 2, &stunsignedint, &stunsignedint);
+ intrinsics[Intrinsic_021] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__divw"), 0, 2, &stsignedint, &stsignedint);
+ intrinsics[Intrinsic_022] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__divwu"), 0, 2, &stsignedint, &stsignedint);
+ intrinsics[Intrinsic_023] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fmadd"), 0, 3, &stdouble, &stdouble, &stdouble);
+ intrinsics[Intrinsic_024] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fmsub"), 0, 3, &stdouble, &stdouble, &stdouble);
+ intrinsics[Intrinsic_025] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fnmadd"), 0, 3, &stdouble, &stdouble, &stdouble);
+ intrinsics[Intrinsic_026] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fnmsub"), 0, 3, &stdouble, &stdouble, &stdouble);
+ intrinsics[Intrinsic_034] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__fsel"), 0, 3, &stdouble, &stdouble, &stdouble);
+ intrinsics[Intrinsic_027] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fmadds"), 0, 3, &stfloat, &stfloat, &stfloat);
+ intrinsics[Intrinsic_028] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fmsubs"), 0, 3, &stfloat, &stfloat, &stfloat);
+ intrinsics[Intrinsic_029] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fnmadds"), 0, 3, &stfloat, &stfloat, &stfloat);
+ intrinsics[Intrinsic_030] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fnmsubs"), 0, 3, &stfloat, &stfloat, &stfloat);
+ intrinsics[Intrinsic_031] = CParser_NewRTFunc(TYPE(&stdouble), GetHashNameNodeExport("__mffs"), 0, 0);
+ intrinsics[Intrinsic_032] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fres"), 0, 1, &stfloat);
+ intrinsics[Intrinsic_040] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fabsf"), 0, 1, &stfloat);
+ intrinsics[Intrinsic_041] = CParser_NewRTFunc(TYPE(&stfloat), GetHashNameNodeExport("__fnabsf"), 0, 1, &stfloat);
+ intrinsics[Intrinsic_035] = CParser_NewRTFunc(TYPE(&char_ptr), GetHashNameNodeExport("__strcpy"), 0, 2, &char_ptr, &char_ptr);
+ TYPE_FUNC(intrinsics[Intrinsic_035]->type)->args->next->qual |= Q_CONST;
+ intrinsics[Intrinsic_036] = CParser_NewRTFunc(TYPE(&void_ptr), GetHashNameNodeExport("__memcpy"), 0, 3, &void_ptr, &void_ptr, &stunsignedlong);
+ __memcpy_object = intrinsics[Intrinsic_036];
+ TYPE_FUNC(intrinsics[Intrinsic_036]->type)->args->next->qual |= Q_CONST;
+ intrinsics[Intrinsic_037] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__rlwimi"), 0, 5, &stsignedint, &stsignedint, &stsignedint, &stsignedint, &stsignedint);
+ intrinsics[Intrinsic_038] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__rlwinm"), 0, 4, &stsignedint, &stsignedint, &stsignedint, &stsignedint);
+ intrinsics[Intrinsic_039] = CParser_NewRTFunc(TYPE(&stsignedint), GetHashNameNodeExport("__rlwnm"), 0, 4, &stsignedint, &stsignedint, &stsignedint, &stsignedint);
+ intrinsics[Intrinsic_042] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_add"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_043] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_addc"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_044] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_adds"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_045] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_and"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_046] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_andc"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_047] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_avg"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_048] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_ceil"), 0, 1, &stvector);
+ intrinsics[Intrinsic_049] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cmpb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_050] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cmpeq"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_051] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cmpge"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_052] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cmple"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_053] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cmpgt"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_054] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cmplt"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_055] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_ctf"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_056] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_cts"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_057] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_ctu"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_058] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("vec_dss"), 0, 1, &stsignedint);
+ intrinsics[Intrinsic_059] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("vec_dssall"), 0, 0);
+ intrinsics[Intrinsic_060] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("vec_dst"), 0, 3, &stvector, &stsignedint, &stsignedint);
+ intrinsics[Intrinsic_061] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("vec_dstst"), 0, 3, &stvector, &stsignedint, &stsignedint);
+ intrinsics[Intrinsic_062] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("vec_dststt"), 0, 3, &stvector, &stsignedint, &stsignedint);
+ intrinsics[Intrinsic_063] = CParser_NewRTFunc(&stvoid, GetHashNameNodeExport("vec_dstt"), 0, 3, &stvector, &stsignedint, &stsignedint);
+ intrinsics[Intrinsic_064] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_expte"), 0, 1, &stvector);
+ intrinsics[Intrinsic_065] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_floor"), 0, 1, &stvector);
+ intrinsics[Intrinsic_066] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_ld"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_067] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lde"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_068] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_ldl"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_069] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_loge"), 0, 1, &stvector);
+ intrinsics[Intrinsic_070] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvsl"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_071] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvsr"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_072] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_madd"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_073] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_madds"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_074] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_max"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_075] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mergeh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_076] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mergel"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_077] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mfvscr"), 0, 0);
+ intrinsics[Intrinsic_078] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_min"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_079] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mladd"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_080] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mradds"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_081] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_msum"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_082] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_msums"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_083] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mtvscr"), 0, 1, &stvector);
+ intrinsics[Intrinsic_084] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mule"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_085] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_mulo"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_086] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_nmsub"), 0, 2, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_087] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_nor"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_088] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_or"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_089] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_pack"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_090] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_packpx"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_091] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_packs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_092] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_packsu"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_093] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_perm"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_094] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_re"), 0, 1, &stvector);
+ intrinsics[Intrinsic_095] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_rl"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_096] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_round"), 0, 1, &stvector);
+ intrinsics[Intrinsic_097] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_rsqrte"), 0, 1, &stvector);
+ intrinsics[Intrinsic_098] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sel"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_099] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sl"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_100] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sld"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_101] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sll"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_102] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_slo"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_103] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_104] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat_s8"), 0, 1, &stvector);
+ intrinsics[Intrinsic_105] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat_s16"), 0, 1, &stvector);
+ intrinsics[Intrinsic_106] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat_s32"), 0, 1, &stvector);
+ intrinsics[Intrinsic_107] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat_u8"), 0, 1, &stvector);
+ intrinsics[Intrinsic_108] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat_u16"), 0, 1, &stvector);
+ intrinsics[Intrinsic_109] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_splat_u32"), 0, 1, &stvector);
+ intrinsics[Intrinsic_110] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sr"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_111] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sra"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_112] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_srl"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_113] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sro"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_114] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_st"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_115] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_ste"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_116] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_stl"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_117] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sub"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_118] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_subc"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_119] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_subs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_120] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sum4s"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_121] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sum2s"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_122] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_sums"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_123] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_trunc"), 0, 1, &stvector);
+ intrinsics[Intrinsic_124] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_unpack2sh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_125] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_unpack2sl"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_126] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_unpack2uh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_127] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_unpack2ul"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_128] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_unpackh"), 0, 1, &stvector);
+ intrinsics[Intrinsic_129] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_unpackl"), 0, 1, &stvector);
+ intrinsics[Intrinsic_130] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_xor"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_131] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_eq"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_132] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_ge"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_133] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_gt"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_134] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_in"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_135] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_le"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_136] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_lt"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_137] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_nan"), 0, 1, &stvector);
+ intrinsics[Intrinsic_138] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_ne"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_139] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_nge"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_140] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_ngt"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_141] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_nle"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_142] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_nlt"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_143] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_all_numeric"), 0, 1, &stvector);
+ intrinsics[Intrinsic_144] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_eq"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_145] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_ge"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_146] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_gt"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_147] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_le"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_148] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_lt"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_149] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_nan"), 0, 1, &stvector);
+ intrinsics[Intrinsic_150] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_ne"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_151] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_nge"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_152] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_ngt"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_153] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_nle"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_154] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_nlt"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_155] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_numeric"), 0, 1, &stvector);
+ intrinsics[Intrinsic_156] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_any_out"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_157] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddubm"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_158] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vadduhm"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_159] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vadduwm"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_160] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddfp"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_161] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddcuw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_162] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddubs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_163] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddsbs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_164] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vadduhs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_165] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddshs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_166] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vadduws"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_167] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vaddsws"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_168] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vand"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_169] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vandc"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_170] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vavgub"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_171] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vavgsb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_172] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vavguh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_173] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vavgsh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_174] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vavguw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_175] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vavgsw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_176] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrfip"), 0, 1, &stvector);
+ intrinsics[Intrinsic_177] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpbfp"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_178] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpequb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_179] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpequh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_180] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpequw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_181] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpeqfp"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_182] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgefp"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_183] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtub"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_184] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtsb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_185] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtuh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_186] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtsh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_187] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtuw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_188] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtsw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_189] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcmpgtfp"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_190] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcfux"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_191] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vcfsx"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_192] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vctsxs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_193] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vctuxs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_194] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vexptefp"), 0, 1, &stvector);
+ intrinsics[Intrinsic_195] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrfim"), 0, 1, &stvector);
+ intrinsics[Intrinsic_196] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvx"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_197] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvebx"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_198] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvehx"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_199] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvewx"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_200] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_lvxl"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_201] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vlogefp"), 0, 1, &stvector);
+ intrinsics[Intrinsic_202] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaddfp"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_203] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmhaddshs"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_204] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxub"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_205] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxsb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_206] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxuh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_207] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxsh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_208] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxuw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_209] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxsw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_210] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmaxfp"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_211] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmrghb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_212] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmrghh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_213] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmrghw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_214] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmrglb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_215] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmrglh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_216] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmrglw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_217] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminub"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_218] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminsb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_219] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminuh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_220] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminsh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_221] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminuw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_222] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminsw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_223] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vminfp"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_224] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmladduhm"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_225] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmhraddshs"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_226] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmsumubm"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_227] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmsumuhm"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_228] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmsummbm"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_229] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmsumshm"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_230] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmsumuhs"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_231] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmsumshs"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_232] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmuleub"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_233] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmulesb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_234] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmuleuh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_235] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmulesh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_236] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmuloub"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_237] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmulosb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_238] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmulouh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_239] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vmulosh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_240] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vnmsubfp"), 0, 2, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_241] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vnor"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_242] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vor"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_243] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkuhum"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_244] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkuwum"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_245] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkpx"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_246] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkuhus"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_247] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkshss"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_248] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkuwus"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_249] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkswss"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_250] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkshus"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_251] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vpkswus"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_252] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vperm"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_253] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrefp"), 0, 1, &stvector);
+ intrinsics[Intrinsic_254] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrlb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_255] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrlh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_256] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrlw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_257] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrfin"), 0, 1, &stvector);
+ intrinsics[Intrinsic_258] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrsqrtefp"), 0, 1, &stvector);
+ intrinsics[Intrinsic_259] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsel"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_260] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vslb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_261] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vslh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_262] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vslw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_263] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsldoi"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_264] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsl"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_265] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vslo"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_266] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vspltb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_267] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsplth"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_268] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vspltw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_269] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vspltisb"), 0, 1, &stvector);
+ intrinsics[Intrinsic_270] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vspltish"), 0, 1, &stvector);
+ intrinsics[Intrinsic_271] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vspltisw"), 0, 1, &stvector);
+ intrinsics[Intrinsic_272] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsrb"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_273] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsrh"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_274] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsrw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_275] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsrab"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_276] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsrah"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_277] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsraw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_278] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsr"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_279] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsro"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_280] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_stvx"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_281] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_stvebx"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_282] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_stvehx"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_283] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_stvewx"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_284] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_stvxl"), 0, 3, &stvector, &stvector, &stvector);
+ intrinsics[Intrinsic_285] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsububm"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_286] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubuhm"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_287] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubuwm"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_288] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubfp"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_289] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubcuw"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_290] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsububs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_291] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubsbs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_292] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubuhs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_293] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubshs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_294] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubuws"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_295] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsubsws"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_296] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsum4ubs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_297] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsum4sbs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_298] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsum4shs"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_299] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsum2sws"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_300] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vsumsws"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_301] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vrfiz"), 0, 1, &stvector);
+ intrinsics[Intrinsic_302] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vupkhsb"), 0, 1, &stvector);
+ intrinsics[Intrinsic_303] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vupklsb"), 0, 1, &stvector);
+ intrinsics[Intrinsic_304] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vupkhpx"), 0, 1, &stvector);
+ intrinsics[Intrinsic_305] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vupklpx"), 0, 1, &stvector);
+ intrinsics[Intrinsic_306] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vupkhsh"), 0, 1, &stvector);
+ intrinsics[Intrinsic_307] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vupklsh"), 0, 1, &stvector);
+ intrinsics[Intrinsic_308] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_vxor"), 0, 2, &stvector, &stvector);
+ intrinsics[Intrinsic_309] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_abs"), 0, 1, &stvector);
+ intrinsics[Intrinsic_310] = CParser_NewRTFunc(TYPE(&stvector), GetHashNameNodeExport("vec_abss"), 0, 1, &stvector);
+
+ for (i = 0; i < MaxIntrinsics; i++) {
+ CError_ASSERT(6600, intrinsics[i]);
+ intrinsics[i]->u.func.u.intrinsicid = i;
+ TYPE_FUNC(intrinsics[i]->type)->flags |= FUNC_INTRINSIC;
+ CScope_AddGlobalObject(intrinsics[i]);
+ }
+
+ copts.cplusplus = savecpp;
+}
+
+static Object *CheckRuntimeObject(char *name) {
+ NameSpaceName *nsname = CScope_FindNameSpaceName(cscope_root, GetHashNameNodeExport(name));
+
+ if (!nsname)
+ return NULL;
+
+ if (nsname->first.object && nsname->first.next == NULL)
+ return OBJECT(nsname->first.object);
+
+ return NULL;
+}
+
+Boolean Intrinsics_ReInitRuntimeObjects(Boolean flag) {
+ if (flag) {
+ if (!(intrinsics[Intrinsic_000] = CheckRuntimeObject("__eieio"))) return 0;
+ if (!(intrinsics[Intrinsic_001] = CheckRuntimeObject("__sync"))) return 0;
+ if (!(intrinsics[Intrinsic_002] = CheckRuntimeObject("__isync"))) return 0;
+ if (!(intrinsics[Intrinsic_003] = CheckRuntimeObject("__abs"))) return 0;
+ if (!(intrinsics[Intrinsic_004] = CheckRuntimeObject("__labs"))) return 0;
+ if (!(intrinsics[Intrinsic_005] = CheckRuntimeObject("__fabs"))) return 0;
+ if (!(intrinsics[Intrinsic_006] = CheckRuntimeObject("__fnabs"))) return 0;
+ if (!(intrinsics[Intrinsic_007] = CheckRuntimeObject("__setflm"))) return 0;
+ if (!(intrinsics[Intrinsic_033] = CheckRuntimeObject("__frsqrte"))) return 0;
+ if (!(intrinsics[Intrinsic_008] = CheckRuntimeObject("__alloca"))) return 0;
+ if (!(intrinsics[Intrinsic_009] = CheckRuntimeObject("__cntlzw"))) return 0;
+ if (!(intrinsics[Intrinsic_010] = CheckRuntimeObject("__lhbrx"))) return 0;
+ if (!(intrinsics[Intrinsic_011] = CheckRuntimeObject("__lwbrx"))) return 0;
+ if (!(intrinsics[Intrinsic_012] = CheckRuntimeObject("__sthbrx"))) return 0;
+ if (!(intrinsics[Intrinsic_013] = CheckRuntimeObject("__stwbrx"))) return 0;
+ if (!(intrinsics[Intrinsic_014] = CheckRuntimeObject("__dcbf"))) return 0;
+ if (!(intrinsics[Intrinsic_015] = CheckRuntimeObject("__dcbt"))) return 0;
+ if (!(intrinsics[Intrinsic_016] = CheckRuntimeObject("__dcbst"))) return 0;
+ if (!(intrinsics[Intrinsic_017] = CheckRuntimeObject("__dcbtst"))) return 0;
+ if (!(intrinsics[Intrinsic_018] = CheckRuntimeObject("__dcbz"))) return 0;
+ if (!(intrinsics[Intrinsic_019] = CheckRuntimeObject("__mulhw"))) return 0;
+ if (!(intrinsics[Intrinsic_020] = CheckRuntimeObject("__mulhwu"))) return 0;
+ if (!(intrinsics[Intrinsic_021] = CheckRuntimeObject("__divw"))) return 0;
+ if (!(intrinsics[Intrinsic_022] = CheckRuntimeObject("__divwu"))) return 0;
+ if (!(intrinsics[Intrinsic_023] = CheckRuntimeObject("__fmadd"))) return 0;
+ if (!(intrinsics[Intrinsic_024] = CheckRuntimeObject("__fmsub"))) return 0;
+ if (!(intrinsics[Intrinsic_025] = CheckRuntimeObject("__fnmadd"))) return 0;
+ if (!(intrinsics[Intrinsic_026] = CheckRuntimeObject("__fnmsub"))) return 0;
+ if (!(intrinsics[Intrinsic_034] = CheckRuntimeObject("__fsel"))) return 0;
+ if (!(intrinsics[Intrinsic_027] = CheckRuntimeObject("__fmadds"))) return 0;
+ if (!(intrinsics[Intrinsic_028] = CheckRuntimeObject("__fmsubs"))) return 0;
+ if (!(intrinsics[Intrinsic_029] = CheckRuntimeObject("__fnmadds"))) return 0;
+ if (!(intrinsics[Intrinsic_030] = CheckRuntimeObject("__fnmsubs"))) return 0;
+ if (!(intrinsics[Intrinsic_031] = CheckRuntimeObject("__mffs"))) return 0;
+ if (!(intrinsics[Intrinsic_032] = CheckRuntimeObject("__fres"))) return 0;
+ if (!(intrinsics[Intrinsic_040] = CheckRuntimeObject("__fabsf"))) return 0;
+ if (!(intrinsics[Intrinsic_041] = CheckRuntimeObject("__fnabsf"))) return 0;
+ if (!(intrinsics[Intrinsic_035] = CheckRuntimeObject("__strcpy"))) return 0;
+ if (!(intrinsics[Intrinsic_037] = CheckRuntimeObject("__rlwimi"))) return 0;
+ if (!(intrinsics[Intrinsic_038] = CheckRuntimeObject("__rlwinm"))) return 0;
+ if (!(intrinsics[Intrinsic_039] = CheckRuntimeObject("__rlwnm"))) return 0;
+ if (!(intrinsics[Intrinsic_042] = CheckRuntimeObject("vec_add"))) return 0;
+ if (!(intrinsics[Intrinsic_043] = CheckRuntimeObject("vec_addc"))) return 0;
+ if (!(intrinsics[Intrinsic_044] = CheckRuntimeObject("vec_adds"))) return 0;
+ if (!(intrinsics[Intrinsic_045] = CheckRuntimeObject("vec_and"))) return 0;
+ if (!(intrinsics[Intrinsic_046] = CheckRuntimeObject("vec_andc"))) return 0;
+ if (!(intrinsics[Intrinsic_047] = CheckRuntimeObject("vec_avg"))) return 0;
+ if (!(intrinsics[Intrinsic_048] = CheckRuntimeObject("vec_ceil"))) return 0;
+ if (!(intrinsics[Intrinsic_049] = CheckRuntimeObject("vec_cmpb"))) return 0;
+ if (!(intrinsics[Intrinsic_050] = CheckRuntimeObject("vec_cmpeq"))) return 0;
+ if (!(intrinsics[Intrinsic_051] = CheckRuntimeObject("vec_cmpge"))) return 0;
+ if (!(intrinsics[Intrinsic_052] = CheckRuntimeObject("vec_cmple"))) return 0;
+ if (!(intrinsics[Intrinsic_053] = CheckRuntimeObject("vec_cmpgt"))) return 0;
+ if (!(intrinsics[Intrinsic_054] = CheckRuntimeObject("vec_cmplt"))) return 0;
+ if (!(intrinsics[Intrinsic_055] = CheckRuntimeObject("vec_ctf"))) return 0;
+ if (!(intrinsics[Intrinsic_056] = CheckRuntimeObject("vec_cts"))) return 0;
+ if (!(intrinsics[Intrinsic_057] = CheckRuntimeObject("vec_ctu"))) return 0;
+ if (!(intrinsics[Intrinsic_064] = CheckRuntimeObject("vec_expte"))) return 0;
+ if (!(intrinsics[Intrinsic_065] = CheckRuntimeObject("vec_floor"))) return 0;
+ if (!(intrinsics[Intrinsic_066] = CheckRuntimeObject("vec_ld"))) return 0;
+ if (!(intrinsics[Intrinsic_067] = CheckRuntimeObject("vec_lde"))) return 0;
+ if (!(intrinsics[Intrinsic_068] = CheckRuntimeObject("vec_ldl"))) return 0;
+ if (!(intrinsics[Intrinsic_069] = CheckRuntimeObject("vec_loge"))) return 0;
+ if (!(intrinsics[Intrinsic_070] = CheckRuntimeObject("vec_lvsl"))) return 0;
+ if (!(intrinsics[Intrinsic_071] = CheckRuntimeObject("vec_lvsr"))) return 0;
+ if (!(intrinsics[Intrinsic_072] = CheckRuntimeObject("vec_madd"))) return 0;
+ if (!(intrinsics[Intrinsic_073] = CheckRuntimeObject("vec_madds"))) return 0;
+ if (!(intrinsics[Intrinsic_074] = CheckRuntimeObject("vec_max"))) return 0;
+ if (!(intrinsics[Intrinsic_075] = CheckRuntimeObject("vec_mergeh"))) return 0;
+ if (!(intrinsics[Intrinsic_076] = CheckRuntimeObject("vec_mergel"))) return 0;
+ if (!(intrinsics[Intrinsic_077] = CheckRuntimeObject("vec_mfvscr"))) return 0;
+ if (!(intrinsics[Intrinsic_078] = CheckRuntimeObject("vec_min"))) return 0;
+ if (!(intrinsics[Intrinsic_079] = CheckRuntimeObject("vec_mladd"))) return 0;
+ if (!(intrinsics[Intrinsic_080] = CheckRuntimeObject("vec_mradds"))) return 0;
+ if (!(intrinsics[Intrinsic_081] = CheckRuntimeObject("vec_msum"))) return 0;
+ if (!(intrinsics[Intrinsic_082] = CheckRuntimeObject("vec_msums"))) return 0;
+ if (!(intrinsics[Intrinsic_083] = CheckRuntimeObject("vec_mtvscr"))) return 0;
+ if (!(intrinsics[Intrinsic_084] = CheckRuntimeObject("vec_mule"))) return 0;
+ if (!(intrinsics[Intrinsic_085] = CheckRuntimeObject("vec_mulo"))) return 0;
+ if (!(intrinsics[Intrinsic_086] = CheckRuntimeObject("vec_nmsub"))) return 0;
+ if (!(intrinsics[Intrinsic_087] = CheckRuntimeObject("vec_nor"))) return 0;
+ if (!(intrinsics[Intrinsic_088] = CheckRuntimeObject("vec_or"))) return 0;
+ if (!(intrinsics[Intrinsic_089] = CheckRuntimeObject("vec_pack"))) return 0;
+ if (!(intrinsics[Intrinsic_090] = CheckRuntimeObject("vec_packpx"))) return 0;
+ if (!(intrinsics[Intrinsic_091] = CheckRuntimeObject("vec_packs"))) return 0;
+ if (!(intrinsics[Intrinsic_092] = CheckRuntimeObject("vec_packsu"))) return 0;
+ if (!(intrinsics[Intrinsic_093] = CheckRuntimeObject("vec_perm"))) return 0;
+ if (!(intrinsics[Intrinsic_094] = CheckRuntimeObject("vec_re"))) return 0;
+ if (!(intrinsics[Intrinsic_095] = CheckRuntimeObject("vec_rl"))) return 0;
+ if (!(intrinsics[Intrinsic_096] = CheckRuntimeObject("vec_round"))) return 0;
+ if (!(intrinsics[Intrinsic_097] = CheckRuntimeObject("vec_rsqrte"))) return 0;
+ if (!(intrinsics[Intrinsic_098] = CheckRuntimeObject("vec_sel"))) return 0;
+ if (!(intrinsics[Intrinsic_099] = CheckRuntimeObject("vec_sl"))) return 0;
+ if (!(intrinsics[Intrinsic_100] = CheckRuntimeObject("vec_sld"))) return 0;
+ if (!(intrinsics[Intrinsic_101] = CheckRuntimeObject("vec_sll"))) return 0;
+ if (!(intrinsics[Intrinsic_102] = CheckRuntimeObject("vec_slo"))) return 0;
+ if (!(intrinsics[Intrinsic_103] = CheckRuntimeObject("vec_splat"))) return 0;
+ if (!(intrinsics[Intrinsic_104] = CheckRuntimeObject("vec_splat_s8"))) return 0;
+ if (!(intrinsics[Intrinsic_105] = CheckRuntimeObject("vec_splat_s16"))) return 0;
+ if (!(intrinsics[Intrinsic_106] = CheckRuntimeObject("vec_splat_s32"))) return 0;
+ if (!(intrinsics[Intrinsic_107] = CheckRuntimeObject("vec_splat_u8"))) return 0;
+ if (!(intrinsics[Intrinsic_108] = CheckRuntimeObject("vec_splat_u16"))) return 0;
+ if (!(intrinsics[Intrinsic_109] = CheckRuntimeObject("vec_splat_u32"))) return 0;
+ if (!(intrinsics[Intrinsic_110] = CheckRuntimeObject("vec_sr"))) return 0;
+ if (!(intrinsics[Intrinsic_111] = CheckRuntimeObject("vec_sra"))) return 0;
+ if (!(intrinsics[Intrinsic_112] = CheckRuntimeObject("vec_srl"))) return 0;
+ if (!(intrinsics[Intrinsic_113] = CheckRuntimeObject("vec_sro"))) return 0;
+ if (!(intrinsics[Intrinsic_114] = CheckRuntimeObject("vec_st"))) return 0;
+ if (!(intrinsics[Intrinsic_115] = CheckRuntimeObject("vec_ste"))) return 0;
+ if (!(intrinsics[Intrinsic_116] = CheckRuntimeObject("vec_stl"))) return 0;
+ if (!(intrinsics[Intrinsic_117] = CheckRuntimeObject("vec_sub"))) return 0;
+ if (!(intrinsics[Intrinsic_118] = CheckRuntimeObject("vec_subc"))) return 0;
+ if (!(intrinsics[Intrinsic_119] = CheckRuntimeObject("vec_subs"))) return 0;
+ if (!(intrinsics[Intrinsic_120] = CheckRuntimeObject("vec_sum4s"))) return 0;
+ if (!(intrinsics[Intrinsic_121] = CheckRuntimeObject("vec_sum2s"))) return 0;
+ if (!(intrinsics[Intrinsic_122] = CheckRuntimeObject("vec_sums"))) return 0;
+ if (!(intrinsics[Intrinsic_123] = CheckRuntimeObject("vec_trunc"))) return 0;
+ if (!(intrinsics[Intrinsic_124] = CheckRuntimeObject("vec_unpack2sh"))) return 0;
+ if (!(intrinsics[Intrinsic_125] = CheckRuntimeObject("vec_unpack2sl"))) return 0;
+ if (!(intrinsics[Intrinsic_126] = CheckRuntimeObject("vec_unpack2uh"))) return 0;
+ if (!(intrinsics[Intrinsic_127] = CheckRuntimeObject("vec_unpack2ul"))) return 0;
+ if (!(intrinsics[Intrinsic_128] = CheckRuntimeObject("vec_unpackh"))) return 0;
+ if (!(intrinsics[Intrinsic_129] = CheckRuntimeObject("vec_unpackl"))) return 0;
+ if (!(intrinsics[Intrinsic_130] = CheckRuntimeObject("vec_xor"))) return 0;
+ if (!(intrinsics[Intrinsic_131] = CheckRuntimeObject("vec_all_eq"))) return 0;
+ if (!(intrinsics[Intrinsic_132] = CheckRuntimeObject("vec_all_ge"))) return 0;
+ if (!(intrinsics[Intrinsic_133] = CheckRuntimeObject("vec_all_gt"))) return 0;
+ if (!(intrinsics[Intrinsic_134] = CheckRuntimeObject("vec_all_in"))) return 0;
+ if (!(intrinsics[Intrinsic_135] = CheckRuntimeObject("vec_all_le"))) return 0;
+ if (!(intrinsics[Intrinsic_136] = CheckRuntimeObject("vec_all_lt"))) return 0;
+ if (!(intrinsics[Intrinsic_137] = CheckRuntimeObject("vec_all_nan"))) return 0;
+ if (!(intrinsics[Intrinsic_138] = CheckRuntimeObject("vec_all_ne"))) return 0;
+ if (!(intrinsics[Intrinsic_139] = CheckRuntimeObject("vec_all_nge"))) return 0;
+ if (!(intrinsics[Intrinsic_140] = CheckRuntimeObject("vec_all_ngt"))) return 0;
+ if (!(intrinsics[Intrinsic_141] = CheckRuntimeObject("vec_all_nle"))) return 0;
+ if (!(intrinsics[Intrinsic_142] = CheckRuntimeObject("vec_all_nlt"))) return 0;
+ if (!(intrinsics[Intrinsic_143] = CheckRuntimeObject("vec_all_numeric"))) return 0;
+ if (!(intrinsics[Intrinsic_144] = CheckRuntimeObject("vec_any_eq"))) return 0;
+ if (!(intrinsics[Intrinsic_145] = CheckRuntimeObject("vec_any_ge"))) return 0;
+ if (!(intrinsics[Intrinsic_146] = CheckRuntimeObject("vec_any_gt"))) return 0;
+ if (!(intrinsics[Intrinsic_147] = CheckRuntimeObject("vec_any_le"))) return 0;
+ if (!(intrinsics[Intrinsic_148] = CheckRuntimeObject("vec_any_lt"))) return 0;
+ if (!(intrinsics[Intrinsic_149] = CheckRuntimeObject("vec_any_nan"))) return 0;
+ if (!(intrinsics[Intrinsic_150] = CheckRuntimeObject("vec_any_ne"))) return 0;
+ if (!(intrinsics[Intrinsic_151] = CheckRuntimeObject("vec_any_nge"))) return 0;
+ if (!(intrinsics[Intrinsic_152] = CheckRuntimeObject("vec_any_ngt"))) return 0;
+ if (!(intrinsics[Intrinsic_153] = CheckRuntimeObject("vec_any_nle"))) return 0;
+ if (!(intrinsics[Intrinsic_154] = CheckRuntimeObject("vec_any_nlt"))) return 0;
+ if (!(intrinsics[Intrinsic_155] = CheckRuntimeObject("vec_any_numeric"))) return 0;
+ if (!(intrinsics[Intrinsic_156] = CheckRuntimeObject("vec_any_out"))) return 0;
+ if (!(intrinsics[Intrinsic_157] = CheckRuntimeObject("vec_vaddubm"))) return 0;
+ if (!(intrinsics[Intrinsic_158] = CheckRuntimeObject("vec_vadduhm"))) return 0;
+ if (!(intrinsics[Intrinsic_159] = CheckRuntimeObject("vec_vadduwm"))) return 0;
+ if (!(intrinsics[Intrinsic_160] = CheckRuntimeObject("vec_vaddfp"))) return 0;
+ if (!(intrinsics[Intrinsic_161] = CheckRuntimeObject("vec_vaddcuw"))) return 0;
+ if (!(intrinsics[Intrinsic_162] = CheckRuntimeObject("vec_vaddubs"))) return 0;
+ if (!(intrinsics[Intrinsic_163] = CheckRuntimeObject("vec_vaddubs"))) return 0;
+ if (!(intrinsics[Intrinsic_164] = CheckRuntimeObject("vec_vadduhs"))) return 0;
+ if (!(intrinsics[Intrinsic_165] = CheckRuntimeObject("vec_vadduhs"))) return 0;
+ if (!(intrinsics[Intrinsic_166] = CheckRuntimeObject("vec_vadduws"))) return 0;
+ if (!(intrinsics[Intrinsic_167] = CheckRuntimeObject("vec_vadduws"))) return 0;
+ if (!(intrinsics[Intrinsic_168] = CheckRuntimeObject("vec_vand"))) return 0;
+ if (!(intrinsics[Intrinsic_169] = CheckRuntimeObject("vec_vandc"))) return 0;
+ if (!(intrinsics[Intrinsic_170] = CheckRuntimeObject("vec_vavgub"))) return 0;
+ if (!(intrinsics[Intrinsic_171] = CheckRuntimeObject("vec_vavgsb"))) return 0;
+ if (!(intrinsics[Intrinsic_172] = CheckRuntimeObject("vec_vavguh"))) return 0;
+ if (!(intrinsics[Intrinsic_173] = CheckRuntimeObject("vec_vavgsh"))) return 0;
+ if (!(intrinsics[Intrinsic_174] = CheckRuntimeObject("vec_vavguw"))) return 0;
+ if (!(intrinsics[Intrinsic_175] = CheckRuntimeObject("vec_vavgsw"))) return 0;
+ if (!(intrinsics[Intrinsic_176] = CheckRuntimeObject("vec_vrfip"))) return 0;
+ if (!(intrinsics[Intrinsic_177] = CheckRuntimeObject("vec_vcmpbfp"))) return 0;
+ if (!(intrinsics[Intrinsic_178] = CheckRuntimeObject("vec_vcmpequb"))) return 0;
+ if (!(intrinsics[Intrinsic_179] = CheckRuntimeObject("vec_vcmpequh"))) return 0;
+ if (!(intrinsics[Intrinsic_180] = CheckRuntimeObject("vec_vcmpequw"))) return 0;
+ if (!(intrinsics[Intrinsic_181] = CheckRuntimeObject("vec_vcmpeqfp"))) return 0;
+ if (!(intrinsics[Intrinsic_182] = CheckRuntimeObject("vec_vcmpgefp"))) return 0;
+ if (!(intrinsics[Intrinsic_183] = CheckRuntimeObject("vec_vcmpgtub"))) return 0;
+ if (!(intrinsics[Intrinsic_184] = CheckRuntimeObject("vec_vcmpgtsb"))) return 0;
+ if (!(intrinsics[Intrinsic_185] = CheckRuntimeObject("vec_vcmpgtuh"))) return 0;
+ if (!(intrinsics[Intrinsic_186] = CheckRuntimeObject("vec_vcmpgtsh"))) return 0;
+ if (!(intrinsics[Intrinsic_187] = CheckRuntimeObject("vec_vcmpgtuw"))) return 0;
+ if (!(intrinsics[Intrinsic_188] = CheckRuntimeObject("vec_vcmpgtsw"))) return 0;
+ if (!(intrinsics[Intrinsic_189] = CheckRuntimeObject("vec_vcmpgtfp"))) return 0;
+ if (!(intrinsics[Intrinsic_190] = CheckRuntimeObject("vec_vcfux"))) return 0;
+ if (!(intrinsics[Intrinsic_191] = CheckRuntimeObject("vec_vcfsx"))) return 0;
+ if (!(intrinsics[Intrinsic_192] = CheckRuntimeObject("vec_vctsxs"))) return 0;
+ if (!(intrinsics[Intrinsic_193] = CheckRuntimeObject("vec_vctuxs"))) return 0;
+ if (!(intrinsics[Intrinsic_194] = CheckRuntimeObject("vec_vexptefp"))) return 0;
+ if (!(intrinsics[Intrinsic_195] = CheckRuntimeObject("vec_vrfim"))) return 0;
+ if (!(intrinsics[Intrinsic_196] = CheckRuntimeObject("vec_lvx"))) return 0;
+ if (!(intrinsics[Intrinsic_197] = CheckRuntimeObject("vec_lvebx"))) return 0;
+ if (!(intrinsics[Intrinsic_198] = CheckRuntimeObject("vec_lvehx"))) return 0;
+ if (!(intrinsics[Intrinsic_199] = CheckRuntimeObject("vec_lvewx"))) return 0;
+ if (!(intrinsics[Intrinsic_200] = CheckRuntimeObject("vec_lvxl"))) return 0;
+ if (!(intrinsics[Intrinsic_201] = CheckRuntimeObject("vec_vlogefp"))) return 0;
+ if (!(intrinsics[Intrinsic_202] = CheckRuntimeObject("vec_vmaddfp"))) return 0;
+ if (!(intrinsics[Intrinsic_203] = CheckRuntimeObject("vec_vmhaddshs"))) return 0;
+ if (!(intrinsics[Intrinsic_204] = CheckRuntimeObject("vec_vmaxub"))) return 0;
+ if (!(intrinsics[Intrinsic_205] = CheckRuntimeObject("vec_vmaxsb"))) return 0;
+ if (!(intrinsics[Intrinsic_206] = CheckRuntimeObject("vec_vmaxuh"))) return 0;
+ if (!(intrinsics[Intrinsic_207] = CheckRuntimeObject("vec_vmaxsh"))) return 0;
+ if (!(intrinsics[Intrinsic_208] = CheckRuntimeObject("vec_vmaxuw"))) return 0;
+ if (!(intrinsics[Intrinsic_209] = CheckRuntimeObject("vec_vmaxsw"))) return 0;
+ if (!(intrinsics[Intrinsic_210] = CheckRuntimeObject("vec_vmaxfp"))) return 0;
+ if (!(intrinsics[Intrinsic_211] = CheckRuntimeObject("vec_vmrghb"))) return 0;
+ if (!(intrinsics[Intrinsic_212] = CheckRuntimeObject("vec_vmrghh"))) return 0;
+ if (!(intrinsics[Intrinsic_213] = CheckRuntimeObject("vec_vmrghw"))) return 0;
+ if (!(intrinsics[Intrinsic_214] = CheckRuntimeObject("vec_vmrglb"))) return 0;
+ if (!(intrinsics[Intrinsic_215] = CheckRuntimeObject("vec_vmrglh"))) return 0;
+ if (!(intrinsics[Intrinsic_216] = CheckRuntimeObject("vec_vmrglw"))) return 0;
+ if (!(intrinsics[Intrinsic_204] = CheckRuntimeObject("vec_vminub"))) return 0;
+ if (!(intrinsics[Intrinsic_205] = CheckRuntimeObject("vec_vminsb"))) return 0;
+ if (!(intrinsics[Intrinsic_206] = CheckRuntimeObject("vec_vminuh"))) return 0;
+ if (!(intrinsics[Intrinsic_207] = CheckRuntimeObject("vec_vminsh"))) return 0;
+ if (!(intrinsics[Intrinsic_208] = CheckRuntimeObject("vec_vminuw"))) return 0;
+ if (!(intrinsics[Intrinsic_209] = CheckRuntimeObject("vec_vminsw"))) return 0;
+ if (!(intrinsics[Intrinsic_210] = CheckRuntimeObject("vec_vminfp"))) return 0;
+ if (!(intrinsics[Intrinsic_224] = CheckRuntimeObject("vec_vmladduhm"))) return 0;
+ if (!(intrinsics[Intrinsic_225] = CheckRuntimeObject("vec_vmhraddshs"))) return 0;
+ if (!(intrinsics[Intrinsic_226] = CheckRuntimeObject("vec_vmsumubm"))) return 0;
+ if (!(intrinsics[Intrinsic_227] = CheckRuntimeObject("vec_vmsumuhm"))) return 0;
+ if (!(intrinsics[Intrinsic_228] = CheckRuntimeObject("vec_vmsummbm"))) return 0;
+ if (!(intrinsics[Intrinsic_229] = CheckRuntimeObject("vec_vmsumshm"))) return 0;
+ if (!(intrinsics[Intrinsic_230] = CheckRuntimeObject("vec_vmsumuhs"))) return 0;
+ if (!(intrinsics[Intrinsic_231] = CheckRuntimeObject("vec_vmsumshs"))) return 0;
+ if (!(intrinsics[Intrinsic_232] = CheckRuntimeObject("vec_vmuleub"))) return 0;
+ if (!(intrinsics[Intrinsic_233] = CheckRuntimeObject("vec_vmulesb"))) return 0;
+ if (!(intrinsics[Intrinsic_234] = CheckRuntimeObject("vec_vmuleuh"))) return 0;
+ if (!(intrinsics[Intrinsic_235] = CheckRuntimeObject("vec_vmulesh"))) return 0;
+ if (!(intrinsics[Intrinsic_236] = CheckRuntimeObject("vec_vmuloub"))) return 0;
+ if (!(intrinsics[Intrinsic_237] = CheckRuntimeObject("vec_vmulosb"))) return 0;
+ if (!(intrinsics[Intrinsic_238] = CheckRuntimeObject("vec_vmulouh"))) return 0;
+ if (!(intrinsics[Intrinsic_239] = CheckRuntimeObject("vec_vmulosh"))) return 0;
+ if (!(intrinsics[Intrinsic_240] = CheckRuntimeObject("vec_vnmsubfp"))) return 0;
+ if (!(intrinsics[Intrinsic_241] = CheckRuntimeObject("vec_vnor"))) return 0;
+ if (!(intrinsics[Intrinsic_242] = CheckRuntimeObject("vec_vor"))) return 0;
+ if (!(intrinsics[Intrinsic_243] = CheckRuntimeObject("vec_vpkuhum"))) return 0;
+ if (!(intrinsics[Intrinsic_244] = CheckRuntimeObject("vec_vpkuwum"))) return 0;
+ if (!(intrinsics[Intrinsic_245] = CheckRuntimeObject("vec_vpkpx"))) return 0;
+ if (!(intrinsics[Intrinsic_246] = CheckRuntimeObject("vec_vpkuhus"))) return 0;
+ if (!(intrinsics[Intrinsic_247] = CheckRuntimeObject("vec_vpkshss"))) return 0;
+ if (!(intrinsics[Intrinsic_248] = CheckRuntimeObject("vec_vpkuwus"))) return 0;
+ if (!(intrinsics[Intrinsic_249] = CheckRuntimeObject("vec_vpkswss"))) return 0;
+ if (!(intrinsics[Intrinsic_250] = CheckRuntimeObject("vec_vpkshus"))) return 0;
+ if (!(intrinsics[Intrinsic_251] = CheckRuntimeObject("vec_vpkswus"))) return 0;
+ if (!(intrinsics[Intrinsic_252] = CheckRuntimeObject("vec_vperm"))) return 0;
+ if (!(intrinsics[Intrinsic_253] = CheckRuntimeObject("vec_vrefp"))) return 0;
+ if (!(intrinsics[Intrinsic_254] = CheckRuntimeObject("vec_vrlb"))) return 0;
+ if (!(intrinsics[Intrinsic_255] = CheckRuntimeObject("vec_vrlh"))) return 0;
+ if (!(intrinsics[Intrinsic_256] = CheckRuntimeObject("vec_vrlw"))) return 0;
+ if (!(intrinsics[Intrinsic_257] = CheckRuntimeObject("vec_vrfin"))) return 0;
+ if (!(intrinsics[Intrinsic_258] = CheckRuntimeObject("vec_vrsqrtefp"))) return 0;
+ if (!(intrinsics[Intrinsic_259] = CheckRuntimeObject("vec_vsel"))) return 0;
+ if (!(intrinsics[Intrinsic_260] = CheckRuntimeObject("vec_vslb"))) return 0;
+ if (!(intrinsics[Intrinsic_261] = CheckRuntimeObject("vec_vslh"))) return 0;
+ if (!(intrinsics[Intrinsic_262] = CheckRuntimeObject("vec_vslw"))) return 0;
+ if (!(intrinsics[Intrinsic_263] = CheckRuntimeObject("vec_vsldoi"))) return 0;
+ if (!(intrinsics[Intrinsic_264] = CheckRuntimeObject("vec_vsl"))) return 0;
+ if (!(intrinsics[Intrinsic_265] = CheckRuntimeObject("vec_vslo"))) return 0;
+ if (!(intrinsics[Intrinsic_266] = CheckRuntimeObject("vec_vspltb"))) return 0;
+ if (!(intrinsics[Intrinsic_267] = CheckRuntimeObject("vec_vsplth"))) return 0;
+ if (!(intrinsics[Intrinsic_268] = CheckRuntimeObject("vec_vspltw"))) return 0;
+ if (!(intrinsics[Intrinsic_269] = CheckRuntimeObject("vec_vspltisb"))) return 0;
+ if (!(intrinsics[Intrinsic_270] = CheckRuntimeObject("vec_vspltish"))) return 0;
+ if (!(intrinsics[Intrinsic_271] = CheckRuntimeObject("vec_vspltisw"))) return 0;
+ if (!(intrinsics[Intrinsic_272] = CheckRuntimeObject("vec_vsrb"))) return 0;
+ if (!(intrinsics[Intrinsic_273] = CheckRuntimeObject("vec_vsrh"))) return 0;
+ if (!(intrinsics[Intrinsic_274] = CheckRuntimeObject("vec_vsrw"))) return 0;
+ if (!(intrinsics[Intrinsic_275] = CheckRuntimeObject("vec_vsrab"))) return 0;
+ if (!(intrinsics[Intrinsic_276] = CheckRuntimeObject("vec_vsrah"))) return 0;
+ if (!(intrinsics[Intrinsic_277] = CheckRuntimeObject("vec_vsraw"))) return 0;
+ if (!(intrinsics[Intrinsic_278] = CheckRuntimeObject("vec_vsr"))) return 0;
+ if (!(intrinsics[Intrinsic_279] = CheckRuntimeObject("vec_vsro"))) return 0;
+ if (!(intrinsics[Intrinsic_280] = CheckRuntimeObject("vec_stvx"))) return 0;
+ if (!(intrinsics[Intrinsic_281] = CheckRuntimeObject("vec_stvebx"))) return 0;
+ if (!(intrinsics[Intrinsic_282] = CheckRuntimeObject("vec_stvehx"))) return 0;
+ if (!(intrinsics[Intrinsic_283] = CheckRuntimeObject("vec_stvewx"))) return 0;
+ if (!(intrinsics[Intrinsic_284] = CheckRuntimeObject("vec_stvxl"))) return 0;
+ if (!(intrinsics[Intrinsic_285] = CheckRuntimeObject("vec_vsububm"))) return 0;
+ if (!(intrinsics[Intrinsic_286] = CheckRuntimeObject("vec_vsubuhm"))) return 0;
+ if (!(intrinsics[Intrinsic_287] = CheckRuntimeObject("vec_vsubuwm"))) return 0;
+ if (!(intrinsics[Intrinsic_288] = CheckRuntimeObject("vec_vsubfp"))) return 0;
+ if (!(intrinsics[Intrinsic_289] = CheckRuntimeObject("vec_vsubcuw"))) return 0;
+ if (!(intrinsics[Intrinsic_290] = CheckRuntimeObject("vec_vsububs"))) return 0;
+ if (!(intrinsics[Intrinsic_291] = CheckRuntimeObject("vec_vsubsbs"))) return 0;
+ if (!(intrinsics[Intrinsic_292] = CheckRuntimeObject("vec_vsubuhs"))) return 0;
+ if (!(intrinsics[Intrinsic_293] = CheckRuntimeObject("vec_vsubshs"))) return 0;
+ if (!(intrinsics[Intrinsic_294] = CheckRuntimeObject("vec_vsubuws"))) return 0;
+ if (!(intrinsics[Intrinsic_295] = CheckRuntimeObject("vec_vsubsws"))) return 0;
+ if (!(intrinsics[Intrinsic_296] = CheckRuntimeObject("vec_vsum4ubs"))) return 0;
+ if (!(intrinsics[Intrinsic_297] = CheckRuntimeObject("vec_vsum4sbs"))) return 0;
+ if (!(intrinsics[Intrinsic_298] = CheckRuntimeObject("vec_vsum4shs"))) return 0;
+ if (!(intrinsics[Intrinsic_299] = CheckRuntimeObject("vec_vsum2sws"))) return 0;
+ if (!(intrinsics[Intrinsic_300] = CheckRuntimeObject("vec_vsumsws"))) return 0;
+ if (!(intrinsics[Intrinsic_301] = CheckRuntimeObject("vec_vrfiz"))) return 0;
+ if (!(intrinsics[Intrinsic_302] = CheckRuntimeObject("vec_vupkhsb"))) return 0;
+ if (!(intrinsics[Intrinsic_303] = CheckRuntimeObject("vec_vupklsb"))) return 0;
+ if (!(intrinsics[Intrinsic_304] = CheckRuntimeObject("vec_vupkhpx"))) return 0;
+ if (!(intrinsics[Intrinsic_305] = CheckRuntimeObject("vec_vupklpx"))) return 0;
+ if (!(intrinsics[Intrinsic_306] = CheckRuntimeObject("vec_vupkhsh"))) return 0;
+ if (!(intrinsics[Intrinsic_307] = CheckRuntimeObject("vec_vupklsh"))) return 0;
+ if (!(intrinsics[Intrinsic_308] = CheckRuntimeObject("vec_vxor"))) return 0;
+ if (!(intrinsics[Intrinsic_309] = CheckRuntimeObject("vec_abs"))) return 0;
+ if (!(intrinsics[Intrinsic_310] = CheckRuntimeObject("vec_abss"))) return 0;
+ }
+
+ return 1;
+}
+
+Boolean Intrinsics_IsPublicRuntimeObject(Object *object) {
+ int i;
+
+ for (i = 0; i < MaxIntrinsics; i++) {
+ if (object == intrinsics[i])
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Operands.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Operands.c
new file mode 100644
index 0000000..c5da285
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Operands.c
@@ -0,0 +1,1040 @@
+#include "compiler/Operands.h"
+#include "compiler/CError.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/Registers.h"
+#include "compiler/StackFrame.h"
+#include "compiler/TOC.h"
+#include "compiler/enode.h"
+#include "compiler/objects.h"
+
+unsigned long long uns_to_float_cc = 0x4330000000000000;
+unsigned long long int_to_float_cc = 0x4330000080000000;
+Float one_point_zero = {1.0};
+
+void load_immediate(short reg, SInt32 value) {
+ short tmpreg = reg;
+ short tmpreg2;
+
+ if (!FITS_IN_SHORT(value)) {
+ if (copts.optimizationlevel > 1 && LOW_PART_BUGGY(value))
+ tmpreg = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_LIS, tmpreg2 = tmpreg, 0, (short) HIGH_PART(value));
+ if (LOW_PART_BUGGY(value))
+ emitpcode(PC_ADDI, reg, tmpreg2, 0, LOW_PART(value));
+ } else {
+ emitpcode(PC_LI, reg, value);
+ }
+}
+
+static void set_op_flags(Operand *op, ENode *expr) {
+ CError_ASSERT(118, op);
+
+ if (expr) {
+ if (expr->type == EINTCONST) {
+ op->flags = 0;
+ if (expr->flags & ENODE_FLAG_VOLATILE)
+ op->flags |= OpndFlags_Volatile;
+ if (expr->flags & ENODE_FLAG_CONST)
+ op->flags |= OpndFlags_Const;
+ } else {
+ op->flags = CParserIsVolatileExpr(expr) ? OpndFlags_Volatile : 0;
+ op->flags |= CParserIsConstExpr(expr) ? OpndFlags_Const : 0;
+ }
+ } else {
+ op->flags = 0;
+ }
+}
+
+void symbol_operand(Operand *op, Object *obj) {
+ memclrw(op, sizeof(Operand));
+ op->optype = OpndType_Symbol;
+ op->object = obj;
+}
+
+void indirect(Operand *op, ENode *expr) {
+ switch (op->optype) {
+ case OpndType_GPRPair:
+ CError_FATAL(163);
+ case OpndType_CRField:
+ case OpndType_IndirectGPR_ImmOffset:
+ case OpndType_IndirectGPR_Indexed:
+ case OpndType_IndirectSymbol:
+ if (op->optype)
+ Coerce_to_register(op, TYPE(&void_ptr), 0);
+ case OpndType_GPR:
+ op->immOffset = 0;
+ op->object = NULL;
+ case OpndType_GPR_ImmOffset:
+ op->optype = OpndType_IndirectGPR_ImmOffset;
+ set_op_flags(op, expr);
+ break;
+ case OpndType_GPR_Indexed:
+ op->optype = OpndType_IndirectGPR_Indexed;
+ set_op_flags(op, expr);
+ break;
+ case OpndType_Absolute:
+ if (FITS_IN_SHORT(op->immediate)) {
+ op->reg = 0;
+ op->immOffset = op->immediate;
+ } else {
+ 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;
+ set_op_flags(op, expr);
+ break;
+ case OpndType_Symbol:
+ op->optype = OpndType_IndirectSymbol;
+ set_op_flags(op, expr);
+ break;
+ default:
+ CError_FATAL(215);
+ }
+}
+
+#define COMBO_OP(a, b) (b + (a * 11))
+
+void combine(Operand *opA, Operand *opB, short output_reg, Operand *opOut) {
+ Operand *tmp_op;
+ int tmp;
+
+ if (opA->optype == OpndType_Symbol || opA->optype == OpndType_IndirectSymbol)
+ coerce_to_addressable(opA);
+ if (opB->optype == OpndType_Symbol || opB->optype == OpndType_IndirectSymbol)
+ coerce_to_addressable(opB);
+
+ switch (COMBO_OP(opA->optype, opB->optype)) {
+ case COMBO_OP(OpndType_GPR, OpndType_GPR):
+ opOut->optype = OpndType_GPR_Indexed;
+ opOut->reg = opA->reg;
+ opOut->regOffset = opB->reg;
+ break;
+ case COMBO_OP(OpndType_GPR_ImmOffset, OpndType_GPR_ImmOffset):
+ if (FITS_IN_SHORT(opA->immOffset + opB->immOffset) && (!opA->object || !opB->object)) {
+ opB->immOffset += opA->immOffset;
+ if (!opB->object)
+ opB->object = opA->object;
+ } else {
+ tmp = (output_reg && (output_reg != opB->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ add_immediate(tmp, opA->reg, opA->object, opA->immOffset);
+ opA->reg = tmp;
+ }
+ case COMBO_OP(OpndType_GPR, OpndType_GPR_ImmOffset):
+ tmp_op = opA;
+ opA = opB;
+ opB = tmp_op;
+ case COMBO_OP(OpndType_GPR_ImmOffset, OpndType_GPR):
+ if (opA->reg == _FP_ || opA->reg == _CALLER_SP_) {
+ opOut->optype = OpndType_GPR_Indexed;
+ opOut->reg = (output_reg && (output_reg != opB->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ opOut->regOffset = opB->reg;
+ add_immediate(opOut->reg, opA->reg, opA->object, LOW_PART(opA->immOffset));
+ } else if (opB->reg == _FP_ || opB->reg == _CALLER_SP_) {
+ opOut->optype = OpndType_GPR_Indexed;
+ opOut->reg = (output_reg && (output_reg != opA->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ opOut->regOffset = opA->reg;
+ add_immediate(opOut->reg, opB->reg, opA->object, LOW_PART(opA->immOffset));
+ } else if (opA->object) {
+ opOut->optype = OpndType_GPR_Indexed;
+ opOut->reg = (output_reg && (output_reg != opB->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ opOut->regOffset = opB->reg;
+ add_immediate(opOut->reg, opA->reg, opA->object, LOW_PART(opA->immOffset));
+ } else {
+ opOut->optype = OpndType_GPR_ImmOffset;
+ opOut->reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ opOut->immOffset = opA->immOffset;
+ opOut->object = opA->object;
+ emitpcode(PC_ADD, opOut->reg, opA->reg, opB->reg);
+ }
+ break;
+ case COMBO_OP(OpndType_GPR, OpndType_GPR_Indexed):
+ tmp_op = opA;
+ opA = opB;
+ opB = tmp_op;
+ case COMBO_OP(OpndType_GPR_Indexed, OpndType_GPR):
+ opOut->optype = OpndType_GPR_Indexed;
+ opOut->reg = opA->reg;
+ opOut->regOffset = (output_reg && (output_reg != opA->reg)) ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_ADD, opOut->regOffset, opA->regOffset, opB->reg);
+ break;
+ case COMBO_OP(OpndType_GPR_ImmOffset, OpndType_GPR_Indexed):
+ tmp_op = opA;
+ opA = opB;
+ opB = tmp_op;
+ case COMBO_OP(OpndType_GPR_Indexed, OpndType_GPR_ImmOffset):
+ if (opB->object) {
+ opOut->optype = OpndType_GPR_Indexed;
+ opOut->reg = (output_reg && (output_reg != opB->reg)) ? output_reg
+ : used_virtual_registers[RegClass_GPR]++;
+ opOut->regOffset = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_ADD, opOut->reg, opA->reg, opA->regOffset);
+ add_immediate(opOut->regOffset, opB->reg, opB->object, opB->immOffset);
+ } else {
+ opOut->optype = OpndType_GPR_ImmOffset;
+ opOut->immOffset = opB->immOffset;
+ opOut->object = opB->object;
+ opOut->reg = (output_reg && (output_reg != opB->reg)) ? output_reg
+ : used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_ADD, opOut->reg, opA->reg, opA->regOffset);
+ emitpcode(PC_ADD, opOut->reg, opOut->reg, opB->reg);
+ }
+ break;
+ case COMBO_OP(OpndType_GPR_Indexed, OpndType_GPR_Indexed):
+ opOut->optype = OpndType_GPR_Indexed;
+ opOut->reg = opA->reg;
+ opOut->regOffset = (output_reg && (output_reg != opA->regOffset)) ? output_reg
+ : used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_ADD, opOut->regOffset, opB->reg, opB->regOffset);
+ emitpcode(PC_ADD, opOut->regOffset, opOut->regOffset, opA->regOffset);
+ break;
+ case COMBO_OP(OpndType_GPR_ImmOffset, OpndType_Absolute):
+ tmp_op = opA;
+ opA = opB;
+ opB = tmp_op;
+ case COMBO_OP(OpndType_Absolute, OpndType_GPR_ImmOffset):
+ if (!opB->object) {
+ opOut->optype = OpndType_GPR_ImmOffset;
+ opOut->reg = opB->reg;
+ opOut->immOffset = opB->immOffset;
+ opOut->object = opB->object;
+ 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->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->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->immediate));
+ }
+ }
+ }
+ break;
+ } 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->immediate);
+ break;
+ } else {
+ opOut->reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ add_immediate(opOut->reg, opB->reg, opB->object, opB->immOffset);
+ opB->optype = OpndType_GPR;
+ opB->reg = opOut->reg;
+ tmp_op = opA;
+ opA = opB;
+ opB = tmp_op;
+ }
+ case COMBO_OP(OpndType_GPR, OpndType_Absolute):
+ tmp_op = opA;
+ opA = opB;
+ opB = tmp_op;
+ case COMBO_OP(OpndType_Absolute, OpndType_GPR):
+ opOut->optype = (opA->immediate != 0) ? OpndType_GPR_ImmOffset : OpndType_GPR;
+ opOut->immOffset = LOW_PART(opA->immediate);
+ opOut->object = NULL;
+ 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->immediate));
+ }
+ break;
+ case COMBO_OP(OpndType_GPR_Indexed, OpndType_Absolute):
+ tmp_op = opA;
+ opA = opB;
+ opB = tmp_op;
+ case COMBO_OP(OpndType_Absolute, OpndType_GPR_Indexed):
+ 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->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->immediate));
+ if (LOW_PART_BUGGY(opA->immediate))
+ 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->immediate = opA->immediate + opB->immediate;
+ break;
+ default:
+ CError_FATAL(415);
+ }
+}
+
+void coerce_to_addressable(Operand *op) {
+ UInt32 offset;
+ short reg;
+ short flag;
+ short tmp;
+ Object *obj;
+
+ flag = 0;
+ obj = op->object;
+ tmp = 0;
+
+ switch (op->optype) {
+ case OpndType_GPR:
+ case OpndType_GPR_ImmOffset:
+ case OpndType_GPR_Indexed:
+ case OpndType_GPRPair:
+ case OpndType_Absolute:
+ case OpndType_VR:
+ case OpndType_CRField:
+ case OpndType_IndirectGPR_ImmOffset:
+ case OpndType_IndirectGPR_Indexed:
+ break;
+ case OpndType_IndirectSymbol:
+ flag = 1;
+ case OpndType_Symbol:
+ if (obj->datatype == DLOCAL) {
+ if (!local_is_16bit_offset(obj)) {
+ reg = used_virtual_registers[RegClass_GPR]++;
+ op_absolute_ha(reg, local_base_register(obj), obj, 0, 1);
+ op->optype = OpndType_GPR_ImmOffset;
+ op->reg = reg;
+ op->object = obj;
+ } else {
+ op->optype = OpndType_GPR_ImmOffset;
+ op->reg = local_base_register(obj);
+ op->object = obj;
+ }
+ } else if (obj->datatype == DABSOLUTE) {
+ offset = obj->u.address;
+ if (FITS_IN_SHORT(offset)) {
+ op->reg = 0;
+ op->immOffset = obj->u.address;
+ } else {
+ emitpcode(PC_LIS, op->reg = used_virtual_registers[RegClass_GPR]++, 0, (short) HIGH_PART(offset));
+ op->immOffset = LOW_PART(obj->u.address);
+ }
+ op->object = obj;
+ op->optype = OpndType_GPR_ImmOffset;
+ } else {
+ if (copts.codegen_pic)
+ tmp = pic_base_reg;
+ reg = used_virtual_registers[RegClass_GPR]++;
+ op_absolute_ha(reg, tmp, obj, 0, 1);
+ op->optype = OpndType_GPR_ImmOffset;
+ op->reg = reg;
+ }
+ if (flag) {
+ if (op->optype == OpndType_GPR_ImmOffset) {
+ op->optype = OpndType_IndirectGPR_ImmOffset;
+ } else {
+ CError_FATAL(563);
+ }
+ }
+ break;
+ default:
+ CError_FATAL(581);
+ }
+}
+
+void Coerce_to_register(Operand *op, Type *type, short output_reg) {
+ SInt32 offset;
+ Opcode opcode;
+ short reg;
+ short tmp;
+ short cond_neg;
+ short cond;
+ short bit_offset;
+ short bit_size;
+
+ if (TYPE_IS_8BYTES(type)) {
+ coerce_to_register_pair(op, type, output_reg, 0);
+ return;
+ }
+
+ coerce_to_addressable(op);
+ switch (op->optype) {
+ case OpndType_GPRPair:
+ return;
+ case OpndType_GPR:
+ return;
+ case OpndType_GPR_ImmOffset:
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ add_immediate(reg, op->reg, op->object, op->immOffset);
+ break;
+ case OpndType_GPR_Indexed:
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_ADD, reg, op->reg, op->regOffset);
+ break;
+ case OpndType_Absolute:
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ offset = op->immediate;
+ if (FITS_IN_SHORT(offset)) {
+ emitpcode(PC_LI, reg, offset);
+ } else {
+ tmp = reg;
+ if (copts.optimizationlevel > 1 && LOW_PART_BUGGY(offset))
+ tmp = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_LIS, tmp, 0, (short) HIGH_PART(offset));
+ if (LOW_PART_BUGGY(offset))
+ emitpcode(PC_ADDI, reg, tmp, 0, LOW_PART(offset));
+ }
+ break;
+ case OpndType_IndirectGPR_ImmOffset:
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ opcode = PC_LWZ;
+ if (IS_TYPE_INT(type) || IS_TYPE_ENUM(type)) {
+ switch (type->size) {
+ case 1:
+ opcode = PC_LBZ;
+ break;
+ case 2:
+ if (is_unsigned(type))
+ opcode = PC_LHZ;
+ else
+ opcode = PC_LHA;
+ break;
+ }
+ } else {
+ CError_ASSERT(680, IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type));
+ }
+ load_store_register(opcode, reg, op->reg, op->object, op->immOffset);
+ setpcodeflags(op->flags);
+ break;
+ case OpndType_IndirectGPR_Indexed:
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ opcode = PC_LWZX;
+ if (IS_TYPE_INT(type) || IS_TYPE_ENUM(type)) {
+ switch (type->size) {
+ case 1:
+ opcode = PC_LBZX;
+ break;
+ case 2:
+ if (is_unsigned(type))
+ opcode = PC_LHZX;
+ else
+ opcode = PC_LHAX;
+ break;
+ }
+ } else {
+ CError_ASSERT(724, IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type));
+ }
+ emitpcode(opcode, reg, op->reg, op->regOffset);
+ setpcodeflags(op->flags);
+ break;
+ case OpndType_CRField:
+ cond_neg = 0;
+ cond = 0;
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_MFCR, tmp = reg);
+ switch (op->regOffset) {
+ case ENOTEQU:
+ cond_neg = 1;
+ case EEQU:
+ cond = 2;
+ break;
+ case EGREATEREQU:
+ cond_neg = 1;
+ case ELESS:
+ cond = 0;
+ break;
+ case ELESSEQU:
+ cond_neg = 1;
+ case EGREATER:
+ cond = 1;
+ break;
+ default:
+ CError_FATAL(758);
+ }
+ bit_offset = cond + (op->reg << 2);
+ bit_size = 1;
+ emitpcode(PC_RLWINM, tmp, tmp, (bit_size + bit_offset) & 31, 32 - bit_size, 31);
+ if (cond_neg)
+ emitpcode(PC_XORI, tmp, tmp, 1);
+ break;
+ default:
+ CError_FATAL(769);
+ }
+
+ op->optype = OpndType_GPR;
+ op->reg = reg;
+}
+
+void coerce_to_register_pair(Operand *op, Type *type, short output_reg, short output_regHi) {
+ SInt32 offset;
+ short reg;
+ short regHi;
+ short tmp1;
+ short tmp2;
+
+ regHi = -1;
+
+ CError_ASSERT(794, TYPE_IS_8BYTES(type) || (IS_TYPE_STRUCT(type) && type->size == 8));
+
+ coerce_to_addressable(op);
+ switch (op->optype) {
+ case OpndType_GPRPair:
+ if (output_reg && !output_regHi)
+ output_regHi = used_virtual_registers[RegClass_GPR]++;
+ if (output_regHi && !output_reg)
+ output_reg = used_virtual_registers[RegClass_GPR]++;
+ if (op->reg != output_reg || op->regHi != output_regHi) {
+ tmp1 = output_reg ? output_reg : op->reg;
+ tmp2 = output_regHi ? output_regHi : op->regHi;
+ if (tmp1 != op->reg) {
+ if (tmp1 == op->regHi) {
+ CError_ASSERT(818, tmp1 != tmp2);
+ emitpcode(PC_MR, tmp2, op->regHi);
+ emitpcode(PC_MR, tmp1, op->reg);
+ } else {
+ emitpcode(PC_MR, tmp1, op->reg);
+ if (op->regHi != tmp2)
+ emitpcode(PC_MR, tmp2, op->regHi);
+ }
+ } else if (tmp2 != op->regHi) {
+ if (tmp2 == op->reg) {
+ CError_ASSERT(832, tmp1 != tmp2);
+ emitpcode(PC_MR, tmp1, op->reg);
+ emitpcode(PC_MR, tmp2, op->regHi);
+ } else {
+ emitpcode(PC_MR, tmp2, op->regHi);
+ if (op->reg != tmp1)
+ emitpcode(PC_MR, tmp1, op->reg);
+ }
+ }
+ }
+ reg = op->reg;
+ regHi = op->regHi;
+ break;
+ case OpndType_GPR:
+ CError_FATAL(849);
+ break;
+ case OpndType_GPR_ImmOffset:
+ CError_FATAL(852);
+ break;
+ case OpndType_GPR_Indexed:
+ CError_FATAL(855);
+ break;
+ case OpndType_Absolute:
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ offset = op->immediate;
+ if (FITS_IN_SHORT(offset)) {
+ emitpcode(PC_LI, reg, offset);
+ } else {
+ tmp1 = reg;
+ if (copts.optimizationlevel > 1 && LOW_PART_BUGGY(offset))
+ tmp1 = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_LIS, tmp1, 0, (short) HIGH_PART(offset));
+ if (LOW_PART_BUGGY(offset))
+ emitpcode(PC_ADDI, reg, tmp1, 0, LOW_PART(offset));
+ }
+ regHi = output_regHi ? output_regHi : used_virtual_registers[RegClass_GPR]++;
+ if (is_unsigned(type) || offset >= 0)
+ load_immediate(regHi, 0);
+ else
+ load_immediate(regHi, -1);
+ break;
+ case OpndType_IndirectGPR_ImmOffset:
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ regHi = output_regHi ? output_regHi : used_virtual_registers[RegClass_GPR]++;
+ if (op->reg == regHi) {
+ if (op->reg == reg) {
+ CError_FATAL(887);
+ } else {
+ load_store_register(PC_LWZ, reg, op->reg, op->object, op->immOffset + low_offset);
+ setpcodeflags(op->flags);
+ load_store_register(PC_LWZ, regHi, op->reg, op->object, op->immOffset + high_offset);
+ setpcodeflags(op->flags);
+ }
+ } else {
+ load_store_register(PC_LWZ, regHi, op->reg, op->object, op->immOffset + high_offset);
+ setpcodeflags(op->flags);
+ load_store_register(PC_LWZ, reg, op->reg, op->object, op->immOffset + low_offset);
+ setpcodeflags(op->flags);
+ }
+ break;
+ case OpndType_IndirectGPR_Indexed:
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ regHi = output_regHi ? output_regHi : used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_ADD, reg, op->reg, op->regOffset);
+ load_store_register(PC_LWZ, regHi, reg, NULL, high_offset);
+ setpcodeflags(op->flags);
+ load_store_register(PC_LWZ, reg, reg, NULL, low_offset);
+ setpcodeflags(op->flags);
+ break;
+ default:
+ CError_FATAL(912);
+ }
+
+ if (regHi == -1) {
+ CError_FATAL(916);
+ } else {
+ op->optype = OpndType_GPRPair;
+ op->reg = reg;
+ op->regHi = regHi;
+ }
+}
+
+void Coerce_to_fp_register(Operand *op, Type *type, short output_reg) {
+ short reg;
+
+ coerce_to_addressable(op);
+
+ switch (op->optype) {
+ case OpndType_FPR:
+ reg = op->reg;
+ break;
+ case OpndType_IndirectGPR_ImmOffset:
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_FPR]++;
+ load_store_register((type->size == 4) ? PC_LFS : PC_LFD, reg, op->reg, op->object, op->immOffset);
+ setpcodeflags(op->flags);
+ break;
+ case OpndType_IndirectGPR_Indexed:
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_FPR]++;
+ emitpcode((type->size == 4) ? PC_LFSX : PC_LFDX, reg, op->reg, op->regOffset, 0, 0x390);
+ setpcodeflags(op->flags);
+ break;
+ default:
+ CError_FATAL(986);
+ }
+
+ op->optype = OpndType_FPR;
+ op->reg = reg;
+}
+
+void Coerce_to_v_register(Operand *op, Type *type, short output_reg) {
+ short reg;
+
+ coerce_to_addressable(op);
+
+ switch (op->optype) {
+ case OpndType_VR:
+ reg = op->reg;
+ break;
+ case OpndType_IndirectGPR_ImmOffset:
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_VR]++;
+ load_store_register(PC_LVX, reg, op->reg, op->object, op->immOffset);
+ setpcodeflags(op->flags);
+ break;
+ case OpndType_IndirectGPR_Indexed:
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_VR]++;
+ emitpcode(PC_LVX, reg, op->reg, op->regOffset);
+ setpcodeflags(op->flags);
+ break;
+ case OpndType_Absolute:
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_VR]++;
+ switch (TYPE_STRUCT(type)->stype) {
+ case STRUCT_VECTOR_UCHAR:
+ case STRUCT_VECTOR_SCHAR:
+ case STRUCT_VECTOR_BCHAR:
+ emitpcode(PC_VSPLTISB, reg, op->immediate);
+ break;
+ case STRUCT_VECTOR_USHORT:
+ case STRUCT_VECTOR_SSHORT:
+ case STRUCT_VECTOR_BSHORT:
+ case STRUCT_VECTOR_PIXEL:
+ emitpcode(PC_VSPLTISH, reg, op->immediate);
+ break;
+ case STRUCT_VECTOR_UINT:
+ case STRUCT_VECTOR_SINT:
+ case STRUCT_VECTOR_BINT:
+ case STRUCT_VECTOR_FLOAT:
+ emitpcode(PC_VSPLTISW, reg, op->immediate);
+ break;
+ default:
+ CError_FATAL(1049);
+ }
+ op->optype = OpndType_VR;
+ op->reg = reg;
+ setpcodeflags(op->flags);
+ break;
+ default:
+ CError_FATAL(1059);
+ }
+
+ op->optype = OpndType_VR;
+ op->reg = reg;
+}
+
+void store(short reg, Operand *op, Type *type) {
+ Opcode opcode;
+
+ coerce_to_addressable(op);
+ switch (op->optype) {
+ case OpndType_IndirectGPR_ImmOffset:
+ opcode = PC_STW;
+ if (IS_TYPE_INT(type) || IS_TYPE_ENUM(type)) {
+ switch (type->size) {
+ case 1:
+ opcode = PC_STB;
+ break;
+ case 2:
+ opcode = PC_STH;
+ break;
+ }
+ } else {
+ CError_ASSERT(1171, IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type));
+ }
+ load_store_register(opcode, reg, op->reg, op->object, op->immOffset);
+ setpcodeflags(op->flags);
+ break;
+ case OpndType_IndirectGPR_Indexed:
+ opcode = PC_STWX;
+ if (IS_TYPE_INT(type) || IS_TYPE_ENUM(type)) {
+ switch (type->size) {
+ case 1:
+ opcode = PC_STBX;
+ break;
+ case 2:
+ opcode = PC_STHX;
+ break;
+ }
+ } else {
+ CError_ASSERT(1188, IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type));
+ }
+ emitpcode(opcode, reg, op->reg, op->regOffset);
+ setpcodeflags(op->flags);
+ break;
+ default:
+ CError_FATAL(1193);
+ }
+}
+
+void store_pair(short reg, short regHi, Operand *op, Type *type) {
+ short tmp;
+
+ CError_ASSERT(1208, TYPE_IS_8BYTES(type));
+
+ coerce_to_addressable(op);
+ switch (op->optype) {
+ case OpndType_IndirectGPR_ImmOffset:
+ load_store_register(PC_STW, reg, op->reg, op->object, op->immOffset + low_offset);
+ setpcodeflags(op->flags);
+ load_store_register(PC_STW, regHi, op->reg, op->object, op->immOffset + high_offset);
+ setpcodeflags(op->flags);
+ break;
+ case OpndType_IndirectGPR_Indexed:
+ tmp = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_ADD, tmp, op->reg, op->regOffset);
+ load_store_register(PC_STW, reg, tmp, NULL, low_offset);
+ setpcodeflags(op->flags);
+ load_store_register(PC_STW, regHi, tmp, NULL, high_offset);
+ setpcodeflags(op->flags);
+ break;
+ default:
+ CError_FATAL(1228);
+ }
+}
+
+void store_fp(short reg, Operand *op, Type *type) {
+ coerce_to_addressable(op);
+ switch (op->optype) {
+ case OpndType_IndirectGPR_ImmOffset:
+ load_store_register((type->size == 4) ? PC_STFS : PC_STFD, reg, op->reg, op->object, op->immOffset);
+ setpcodeflags(op->flags);
+ break;
+ case OpndType_IndirectGPR_Indexed:
+ emitpcode((type->size == 4) ? PC_STFSX : PC_STFDX, reg, op->reg, op->regOffset);
+ setpcodeflags(op->flags);
+ break;
+ default:
+ CError_FATAL(1259);
+ }
+}
+
+void store_v(short reg, Operand *op, Type *tstruct) {
+ coerce_to_addressable(op);
+ switch (op->optype) {
+ case OpndType_IndirectGPR_ImmOffset:
+ load_store_register(PC_STVX, reg, op->reg, op->object, op->immOffset);
+ setpcodeflags(op->flags);
+ break;
+ case OpndType_IndirectGPR_Indexed:
+ emitpcode(PC_STVX, reg, op->reg, op->regOffset);
+ setpcodeflags(op->flags);
+ break;
+ default:
+ CError_FATAL(1283);
+ }
+}
+
+static Boolean last_matches_rlwinm_or_exts(Operand *op, short opcode, short b, short c) {
+ PCode *pc;
+
+ if (pclastblock->pcodeCount <= 0)
+ return 0;
+
+ pc = pclastblock->lastPCode;
+ if (pc->args[0].kind != PCOp_REGISTER || pc->args[0].arg != RegClass_GPR || pc->args[0].data.reg.reg != op->reg)
+ return 0;
+
+ if (pc->op != opcode && (opcode != PC_EXTSH || pc->op != PC_EXTSB))
+ return 0;
+
+ if (opcode == PC_RLWINM) {
+ if (pc->args[2].data.imm.value != 0 || pc->args[3].data.imm.value != b || pc->args[4].data.imm.value != c)
+ return 0;
+ }
+
+ return 1;
+}
+
+void extend32(Operand *op, Type *type, short output_reg) {
+ int r28;
+ int reg;
+
+ r28 = op->optype >= OpndType_IndirectGPR_ImmOffset;
+ if (op->optype != OpndType_GPR)
+ Coerce_to_register(op, type, output_reg);
+
+ switch (type->size) {
+ case 1:
+ if (is_unsigned(type)) {
+ if (r28)
+ return;
+ if (last_matches_rlwinm_or_exts(op, PC_RLWINM, 24, 31))
+ return;
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_RLWINM, reg, op->reg, 0, 24, 31);
+ } else {
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ if (last_matches_rlwinm_or_exts(op, PC_EXTSB, 0, 0))
+ return;
+ emitpcode(PC_EXTSB, reg, op->reg);
+ }
+ break;
+ case 2:
+ if (r28)
+ return;
+ if (is_unsigned(type)) {
+ if (last_matches_rlwinm_or_exts(op, PC_RLWINM, 16, 31))
+ return;
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_RLWINM, reg, op->reg, 0, 16, 31);
+ } else {
+ if (last_matches_rlwinm_or_exts(op, PC_EXTSH, 0, 0))
+ return;
+ reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_EXTSH, reg, op->reg);
+ }
+ break;
+ default:
+ CError_FATAL(1389);
+ }
+
+ op->optype = OpndType_GPR;
+ op->reg = reg;
+}
+
+void extend64(Operand *op, Type *type, short output_reg, short output_regHi) {
+ short tmp;
+ short regHi;
+
+ if (op->optype != OpndType_GPR)
+ Coerce_to_register(op, type, output_reg);
+
+ regHi = output_regHi ? output_regHi : used_virtual_registers[RegClass_GPR]++;
+ if (regHi == op->reg) {
+ tmp = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_MR, tmp, op->reg);
+ op->reg = tmp;
+ }
+
+ if (is_unsigned(type))
+ load_immediate(regHi, 0);
+ else
+ emitpcode(PC_SRAWI, regHi, op->reg, 31);
+
+ op->optype = OpndType_GPRPair;
+ op->regHi = regHi;
+}
+
+void load_floating_constant(short reg, Type *type, Float *data) {
+ Object *object;
+ Object *indObject;
+ Operand op1;
+ Operand op2;
+ Operand op3;
+ SInt32 offset = 0;
+
+ memclrw(&op1, sizeof(Operand));
+
+ object = CreateFloatConst(type, data, &offset);
+ indObject = createIndirect(object, 0, 1);
+
+ if (indObject) {
+ symbol_operand(&op1, indObject);
+ indirect(&op1, NULL);
+ } else {
+ symbol_operand(&op1, object);
+ }
+
+ if (offset) {
+ op2 = op1;
+ memclrw(&op3, sizeof(Operand));
+ op3.optype = OpndType_Absolute;
+ op3.immediate = offset;
+ if (op2.optype != OpndType_GPR)
+ Coerce_to_register(&op2, TYPE(&void_ptr), 0);
+ combine(&op2, &op3, 0, &op1);
+ }
+
+ indirect(&op1, NULL);
+ if (op1.optype != OpndType_FPR)
+ Coerce_to_fp_register(&op1, type, reg);
+}
+
+void convert_integer_to_floating(Operand *op, Boolean is_single, short output_reg) {
+ Operand temp_op;
+ Float d;
+ int const_reg;
+ int tmp_reg;
+ int work_reg;
+ int result_reg;
+ Opcode opcode;
+
+ symbol_operand(&temp_op, maketemporary(TYPE(&stdouble)));
+ coerce_to_addressable(&temp_op);
+ d.value = *((double *) &int_to_float_cc);
+
+ const_reg = used_virtual_registers[RegClass_FPR]++;
+ load_floating_constant(const_reg, TYPE(&stdouble), &d);
+
+ tmp_reg = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_XORIS, tmp_reg, op->reg, 0x8000);
+ load_store_register(PC_STW, tmp_reg, temp_op.reg, temp_op.object, low_offset);
+
+ emitpcode(PC_LIS, tmp_reg = used_virtual_registers[RegClass_GPR]++, 0, 0x4330);
+ load_store_register(PC_STW, tmp_reg, temp_op.reg, temp_op.object, high_offset);
+
+ load_store_register(PC_LFD, work_reg = used_virtual_registers[RegClass_FPR]++, temp_op.reg, temp_op.object, 0);
+
+ result_reg = output_reg ? output_reg : used_virtual_registers[RegClass_FPR]++;
+ if (is_single != 0)
+ opcode = PC_FSUBS;
+ else
+ opcode = PC_FSUB;
+ emitpcode(opcode, result_reg, work_reg, const_reg);
+
+ op->optype = OpndType_FPR;
+ op->reg = result_reg;
+}
+
+void convert_unsigned_to_floating(Operand *op, Boolean is_single, short output_reg) {
+ Operand temp_op;
+ Float d;
+ int const_reg;
+ int tmp_reg;
+ int work_reg;
+ int result_reg;
+ Opcode opcode;
+
+ symbol_operand(&temp_op, maketemporary(TYPE(&stdouble)));
+ coerce_to_addressable(&temp_op);
+ d.value = *((double *) &uns_to_float_cc);
+
+ const_reg = used_virtual_registers[RegClass_FPR]++;
+ load_floating_constant(const_reg, TYPE(&stdouble), &d);
+
+ load_store_register(PC_STW, op->reg, temp_op.reg, temp_op.object, low_offset);
+
+ emitpcode(PC_LIS, tmp_reg = used_virtual_registers[RegClass_GPR]++, 0, 0x4330);
+ load_store_register(PC_STW, tmp_reg, temp_op.reg, temp_op.object, high_offset);
+
+ load_store_register(PC_LFD, work_reg = used_virtual_registers[RegClass_FPR]++, temp_op.reg, temp_op.object, 0);
+
+ result_reg = output_reg ? output_reg : used_virtual_registers[RegClass_FPR]++;
+ if (is_single != 0)
+ opcode = PC_FSUBS;
+ else
+ opcode = PC_FSUB;
+ emitpcode(opcode, result_reg, work_reg, const_reg);
+
+ op->optype = OpndType_FPR;
+ op->reg = result_reg;
+}
+
+void convert_floating_to_integer(Operand *op, short output_reg) {
+ Operand temp_op;
+ int tmp_reg;
+ int result_reg;
+
+ symbol_operand(&temp_op, maketemporary(TYPE(&stdouble)));
+ coerce_to_addressable(&temp_op);
+
+ tmp_reg = used_virtual_registers[RegClass_FPR]++;
+ emitpcode(PC_FCTIWZ, tmp_reg, op->reg);
+ load_store_register(PC_STFD, tmp_reg, temp_op.reg, temp_op.object, 0);
+
+ result_reg = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ load_store_register(PC_LWZ, result_reg, temp_op.reg, temp_op.object, low_offset);
+
+ op->optype = OpndType_GPR;
+ op->reg = result_reg;
+}
+
+void convert_floating_to_unsigned(Operand *op, short output_reg) {
+ static UInt32 used_regs[RegClassMax] = {0, 0, 0, 2, 0};
+
+ if (op->reg != 1)
+ emitpcode(PC_FMR, 1, op->reg);
+
+ branch_subroutine(rt_cvt_fp2unsigned, 0, used_regs);
+
+ op->optype = OpndType_GPR;
+ op->reg = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_MR, op->reg, 3);
+}
+
+void extract_bitfield(Operand *input_op, TypeBitfield *tbitfield, short output_reg, Operand *output_op) {
+ int r27;
+ int offset;
+ int tmp_reg;
+ int output;
+
+ offset = tbitfield->bitlength;
+ output = output_reg ? output_reg : used_virtual_registers[RegClass_GPR]++;
+ r27 = tbitfield->offset + (32 - (tbitfield->bitfieldtype->size * 8));
+ if (is_unsigned(tbitfield->bitfieldtype)) {
+ emitpcode(PC_RLWINM, output, input_op->reg, (r27 + offset) & 31, 32 - offset, 31);
+ } else if (r27 == 0) {
+ emitpcode(PC_SRAWI, output, input_op->reg, 32 - offset);
+ } else {
+ tmp_reg = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_RLWINM, tmp_reg, input_op->reg, r27 & 31, 0, offset);
+ emitpcode(PC_SRAWI, output, tmp_reg, 32 - offset);
+ }
+
+ output_op->optype = OpndType_GPR;
+ output_op->reg = output;
+}
+
+void insert_bitfield(short reg, Operand *op, TypeBitfield *tbitfield) {
+ int offset = tbitfield->bitlength;
+ int r7 = tbitfield->offset + (32 - (tbitfield->bitfieldtype->size * 8));
+ emitpcode(PC_RLWIMI, op->reg, reg, 32 - (r7 + offset), r7, r7 + offset - 1);
+}
+
+void load_address(short dest_reg, Operand *op) {
+ coerce_to_addressable(op);
+ if (op->optype == OpndType_IndirectGPR_ImmOffset) {
+ if (!op->immOffset && !op->object) {
+ if (op->reg != dest_reg)
+ emitpcode(PC_MR, dest_reg, op->reg);
+ } else {
+ add_immediate(dest_reg, op->reg, op->object, (SInt16) op->immOffset);
+ }
+ } else if (op->optype == OpndType_IndirectGPR_Indexed) {
+ emitpcode(PC_ADD, dest_reg, op->reg, op->regOffset);
+ } else {
+ CError_FATAL(1849);
+ }
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeAssembly.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeAssembly.c
new file mode 100644
index 0000000..368f8c5
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeAssembly.c
@@ -0,0 +1,1613 @@
+#include "compiler/PCodeAssembly.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CodeGen.h"
+#include "compiler/ObjGenMachO.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+#include "compiler/PCodeListing.h"
+#include "compiler/PPCError.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/StackFrame.h"
+#include "compiler/TOC.h"
+#include "compiler/objects.h"
+
+static UInt32 codebase;
+
+static SInt32 pcode_update_mem_labeldiff_imm(PCode *instr, const PCodeArg *op, WeirdOperand *wop) {
+ SInt32 offset;
+ Object *object;
+ UInt8 arg;
+
+ if (op->kind == PCOp_MEMORY) {
+ object = op->data.mem.obj;
+ offset = op->data.mem.offset;
+ switch (object->datatype) {
+ case DLOCAL:
+ switch ((UInt8) op->arg) {
+ case RefType_1:
+ offset += local_offset_16(object);
+ break;
+ case RefType_D:
+ offset = local_offset_lo(object, offset);
+ break;
+ case RefType_C:
+ offset = local_offset_ha(object, offset);
+ break;
+ default:
+ CError_FATAL(83);
+ }
+ break;
+ case DDATA:
+ case DFUNC:
+ case DVFUNC:
+ case DNONLAZYPTR:
+ switch ((UInt8) op->arg) {
+ case RefType_6:
+ wop->type = MW_RELOC_5_LO16;
+ break;
+ case RefType_2:
+ wop->type = MW_RELOC_3;
+ break;
+ case RefType_3:
+ wop->type = MW_RELOC_4;
+ break;
+ case RefType_8:
+ wop->type = MW_RELOC_7_HA16;
+ break;
+ case RefType_7:
+ wop->type = MW_RELOC_6_HI16;
+ break;
+ default:
+ CError_FATAL(135);
+ }
+
+ wop->x2 = object;
+ CError_ASSERT(144, offset == 0);
+ break;
+ default:
+ CError_FATAL(164);
+ }
+ } else if (op->kind == PCOp_LABELDIFF) {
+ arg = op->arg;
+
+ offset = op->data.labeldiff.labelA->block->codeOffset - op->data.labeldiff.labelB->block->codeOffset;
+ offset += op->data.labeldiff.offset;
+ if (arg == 1)
+ offset = -offset;
+
+ if (offset > 0x7FFF)
+ PPCError_Error(PPCErrorStr109);
+ else if (offset < -0x8000)
+ PPCError_Error(PPCErrorStr109);
+ } else if (op->kind == PCOp_IMMEDIATE) {
+ offset = op->data.imm.value;
+ } else {
+ CError_FATAL(193);
+ }
+
+ return offset;
+}
+
+UInt32 assemblepcode(PCode *instr, UInt32 offset, WeirdOperand *wop) {
+ UInt32 bits;
+
+ bits = opcodeinfo[instr->op].insn;
+ wop->type = -1;
+ wop->x6 = 0;
+
+ switch (instr->op) {
+ case PC_BL: {
+ int flag = PCODE_FLAG_SET_T(instr) & fAbsolute;
+ if (instr->args[0].kind == PCOp_MEMORY) {
+ bits |= instr->args[0].data.mem.offset & 0x3FFFFFC;
+ wop->type = MW_RELOC_2_BR24;
+ wop->x2 = instr->args[0].data.mem.obj;
+ if (flag == 0)
+ wop->type = MW_RELOC_2_BR24;
+ else
+ CError_FATAL(246);
+ } else if (instr->args[0].kind == PCOp_IMMEDIATE) {
+ bits |= instr->args[0].data.imm.value & 0x3FFFFFC;
+ if (flag)
+ bits |= 2;
+ } else {
+ bits |= (instr->args[0].data.label.label->block->codeOffset - offset) & 0x3FFFFFC;
+ if (flag)
+ CError_FATAL(261);
+ }
+ break;
+ }
+
+ case PC_B: {
+ int flag = PCODE_FLAG_SET_T(instr) & fAbsolute;
+ if (instr->args[0].kind == PCOp_MEMORY) {
+ bits |= instr->args[0].data.mem.offset & 0x3FFFFFC;
+ wop->x2 = instr->args[0].data.mem.obj;
+ if (flag == 0)
+ wop->type = MW_RELOC_2_BR24;
+ else
+ CError_FATAL(288);
+ } else if (instr->args[0].kind == PCOp_IMMEDIATE) {
+ bits |= instr->args[0].data.imm.value & 0x3FFFFFC;
+ if (flag)
+ bits |= 2;
+ } else {
+ bits |= (instr->args[0].data.label.label->block->codeOffset - offset) & 0x3FFFFFC;
+ if (flag)
+ CError_FATAL(302);
+ }
+ if (PCODE_FLAG_SET_T(instr) & fLink)
+ bits |= 1;
+ break;
+ }
+
+ case PC_BDNZ:
+ case PC_BDZ: {
+ int flag = PCODE_FLAG_SET_T(instr) & fAbsolute;
+ if (instr->args[0].kind == PCOp_MEMORY) {
+ bits |= instr->args[0].data.mem.offset & 0xFFFC;
+ wop->x2 = instr->args[0].data.mem.obj;
+ if (flag == 0)
+ wop->type = MW_RELOC_8;
+ else
+ CError_FATAL(333);
+ } else {
+ SInt32 value;
+ if (instr->args[0].kind == PCOp_IMMEDIATE)
+ value = instr->args[0].data.imm.value;
+ else
+ value = instr->args[0].data.label.label->block->codeOffset - offset;
+
+ bits |= value & 0xFFFF;
+ if (value < 0) {
+ if (PCODE_FLAG_SET_T(instr) & fBranchNotTaken)
+ bits |= 0x200000u;
+ } else {
+ if (PCODE_FLAG_SET_T(instr) & fBranchTaken)
+ bits |= 0x200000u;
+ }
+ }
+ if (PCODE_FLAG_SET_T(instr) & fLink)
+ bits |= 1;
+ break;
+ }
+
+ case PC_BC: {
+ int flag = PCODE_FLAG_SET_T(instr) & fAbsolute;
+ bits |= (instr->args[0].data.imm.value & 31) << 21;
+ bits |= ((instr->args[1].data.reg.reg * 4 + instr->args[2].data.imm.value) & 31) << 16;
+
+ if (instr->args[3].kind == PCOp_MEMORY) {
+ bits |= instr->args[3].data.mem.offset & 0xFFFC;
+ wop->x2 = instr->args[3].data.mem.obj;
+ if (flag == 0)
+ wop->type = MW_RELOC_8;
+ else
+ CError_FATAL(387);
+ } else {
+ SInt32 value;
+ if (instr->args[3].kind == PCOp_IMMEDIATE)
+ value = instr->args[3].data.imm.value;
+ else
+ value = instr->args[3].data.label.label->block->codeOffset - offset;
+
+ bits |= value & 0xFFFF;
+ if (value < 0) {
+ if (PCODE_FLAG_SET_T(instr) & fBranchNotTaken)
+ bits |= 0x200000u;
+ } else {
+ if (PCODE_FLAG_SET_T(instr) & fBranchTaken)
+ bits |= 0x200000u;
+ }
+ }
+ if (PCODE_FLAG_SET_T(instr) & fLink)
+ bits |= 1;
+ break;
+ }
+
+ case PC_BT:
+ case PC_BF:
+ case PC_BDNZT:
+ case PC_BDNZF:
+ case PC_BDZT:
+ case PC_BDZF: {
+ int flag = PCODE_FLAG_SET_T(instr) & fAbsolute;
+ bits |= ((instr->args[0].data.reg.reg * 4 + instr->args[1].data.imm.value) & 31) << 16;
+
+ if (instr->args[2].kind == PCOp_MEMORY) {
+ bits |= instr->args[2].data.mem.offset & 0xFFFC;
+ wop->x2 = instr->args[2].data.mem.obj;
+ if (flag == 0)
+ wop->type = MW_RELOC_8;
+ else
+ CError_FATAL(446);
+ } else {
+ SInt32 value;
+ if (instr->args[2].kind == PCOp_IMMEDIATE) {
+ value = instr->args[2].data.imm.value;
+ if (flag)
+ bits |= 2;
+ } else {
+ value = instr->args[2].data.label.label->block->codeOffset - offset;
+ CError_ASSERT(458, !flag);
+ }
+
+ bits |= value & 0xFFFF;
+
+ if (value < 0) {
+ if (PCODE_FLAG_SET_T(instr) & fBranchNotTaken)
+ bits |= 0x200000u;
+ } else {
+ if (PCODE_FLAG_SET_T(instr) & fBranchTaken)
+ bits |= 0x200000u;
+ }
+ }
+
+ if (PCODE_FLAG_SET_T(instr) & fLink)
+ bits |= 1;
+ break;
+ }
+
+ case PC_BTLR:
+ case PC_BTCTR:
+ case PC_BFLR:
+ case PC_BFCTR:
+ bits |= ((instr->args[0].data.reg.reg * 4 + instr->args[1].data.imm.value) & 31) << 16;
+ if (PCODE_FLAG_SET_T(instr) & fLink)
+ bits |= 1;
+ if (PCODE_FLAG_SET_T(instr) & fBranchTaken)
+ bits |= 0x200000u;
+ break;
+
+ case PC_BCLR:
+ case PC_BCCTR:
+ bits |= instr->args[0].data.imm.value << 21;
+ bits |= ((instr->args[1].data.reg.reg * 4 + instr->args[2].data.imm.value) & 31) << 16;
+ case PC_BLR:
+ case PC_BCTR:
+ case PC_BCTRL:
+ case PC_BLRL:
+ if (PCODE_FLAG_SET_T(instr) & fLink)
+ bits |= 1;
+ if (PCODE_FLAG_SET_T(instr) & fBranchTaken)
+ bits |= 0x200000u;
+ break;
+
+ case PC_CRAND:
+ case PC_CRANDC:
+ case PC_CREQV:
+ case PC_CRNAND:
+ case PC_CRNOR:
+ case PC_CROR:
+ case PC_CRORC:
+ case PC_CRXOR:
+ bits |= ((instr->args[0].data.reg.reg * 4 + instr->args[1].data.imm.value) & 31) << 21;
+ bits |= ((instr->args[2].data.reg.reg * 4 + instr->args[3].data.imm.value) & 31) << 16;
+ bits |= ((instr->args[4].data.reg.reg * 4 + instr->args[5].data.imm.value) & 31) << 11;
+ break;
+
+ case PC_MCRF:
+ bits |= instr->args[0].data.reg.reg << 23;
+ bits |= instr->args[1].data.reg.reg << 18;
+ break;
+
+ case PC_LBZ:
+ case PC_LBZU:
+ case PC_LHZ:
+ case PC_LHZU:
+ case PC_LHA:
+ case PC_LHAU:
+ case PC_LWZ:
+ case PC_LWZU:
+ case PC_LMW:
+ case PC_STB:
+ case PC_STBU:
+ case PC_STH:
+ case PC_STHU:
+ case PC_STW:
+ case PC_STWU:
+ case PC_STMW:
+ case PC_LFS:
+ case PC_LFSU:
+ case PC_LFD:
+ case PC_LFDU:
+ case PC_STFS:
+ case PC_STFSU:
+ case PC_STFD:
+ case PC_STFDU:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[2], wop) & 0xFFFF;
+ break;
+
+ case PC_LBZX:
+ case PC_LBZUX:
+ case PC_LHZX:
+ case PC_LHZUX:
+ case PC_LHAX:
+ case PC_LHAUX:
+ case PC_LHBRX:
+ case PC_LWZX:
+ case PC_LWZUX:
+ case PC_LWBRX:
+ case PC_STBX:
+ case PC_STBUX:
+ case PC_STHX:
+ case PC_STHUX:
+ case PC_STHBRX:
+ case PC_STWX:
+ case PC_STWUX:
+ case PC_STWBRX:
+ case PC_LFSX:
+ case PC_LFSUX:
+ case PC_LFDX:
+ case PC_LFDUX:
+ case PC_STFSX:
+ case PC_STFSUX:
+ case PC_STFDX:
+ case PC_STFDUX:
+ case PC_LWARX:
+ case PC_LSWX:
+ case PC_STFIWX:
+ case PC_STSWX:
+ case PC_STWCX:
+ case PC_ECIWX:
+ case PC_ECOWX:
+ case PC_DCREAD:
+ case PC_TLBSX:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_DCBF:
+ case PC_DCBST:
+ case PC_DCBT:
+ case PC_DCBTST:
+ case PC_DCBZ:
+ case PC_DCBI:
+ case PC_ICBI:
+ case PC_DCCCI:
+ case PC_ICBT:
+ case PC_ICCCI:
+ case PC_ICREAD:
+ case PC_DCBA:
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[1].data.reg.reg << 11;
+ break;
+
+ case PC_ADD:
+ case PC_ADDC:
+ case PC_ADDE:
+ case PC_DIVW:
+ case PC_DIVWU:
+ case PC_MULHW:
+ case PC_MULHWU:
+ case PC_MULLW:
+ case PC_SUBF:
+ case PC_SUBFC:
+ case PC_SUBFE:
+ bits |= instr->args[2].data.reg.reg << 11;
+ case PC_ADDME:
+ case PC_ADDZE:
+ case PC_NEG:
+ case PC_SUBFME:
+ case PC_SUBFZE:
+ case PC_MFROM:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ if (PCODE_FLAG_SET_F(instr) & fOverflow)
+ bits |= 0x400;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_ADDI:
+ case PC_ADDIC:
+ case PC_ADDICR:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[2], wop) & 0xFFFF;
+ break;
+
+ case PC_ADDIS:
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[2], wop) & 0xFFFF;
+ break;
+
+ case PC_MULLI:
+ case PC_SUBFIC:
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[2].data.imm.value & 0xFFFF;
+ break;
+
+ case PC_LI:
+ case PC_LIS:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[1], wop) & 0xFFFF;
+ break;
+
+ case PC_ANDI:
+ case PC_ANDIS:
+ case PC_ORI:
+ case PC_ORIS:
+ case PC_XORI:
+ case PC_XORIS:
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[1].data.reg.reg << 21;
+ bits |= pcode_update_mem_labeldiff_imm(instr, &instr->args[2], wop) & 0xFFFF;
+ break;
+
+ case PC_AND:
+ case PC_OR:
+ case PC_XOR:
+ case PC_NAND:
+ case PC_NOR:
+ case PC_EQV:
+ case PC_ANDC:
+ case PC_ORC:
+ case PC_SLW:
+ case PC_SRW:
+ case PC_SRAW:
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[1].data.reg.reg << 21;
+ bits |= instr->args[2].data.reg.reg << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_EXTSH:
+ case PC_EXTSB:
+ case PC_CNTLZW:
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[1].data.reg.reg << 21;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_MR:
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[1].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_NOT:
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[1].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_SRAWI:
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[1].data.reg.reg << 21;
+ bits |= (instr->args[2].data.imm.value & 31) << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_RLWINM:
+ case PC_RLWIMI:
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[1].data.reg.reg << 21;
+ bits |= (instr->args[2].data.imm.value & 31) << 11;
+ bits |= (instr->args[3].data.imm.value & 31) << 6;
+ bits |= (instr->args[4].data.imm.value & 31) << 1;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_RLWNM:
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[1].data.reg.reg << 21;
+ bits |= instr->args[2].data.reg.reg << 11;
+ bits |= (instr->args[3].data.imm.value & 31) << 6;
+ bits |= (instr->args[4].data.imm.value & 31) << 1;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_CMP:
+ case PC_CMPL:
+ bits |= instr->args[0].data.reg.reg << 23;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ break;
+
+ case PC_CMPI:
+ case PC_CMPLI:
+ bits |= instr->args[0].data.reg.reg << 23;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.imm.value & 0xFFFF;
+ break;
+
+ case PC_MTXER:
+ case PC_MTCTR:
+ case PC_MTLR:
+ case PC_MTMSR:
+ case PC_MFMSR:
+ case PC_MFXER:
+ case PC_MFCTR:
+ case PC_MFLR:
+ case PC_MFCR:
+ bits |= instr->args[0].data.reg.reg << 21;
+ break;
+
+ case PC_MFFS:
+ bits |= instr->args[0].data.reg.reg << 21;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_MTCRF:
+ bits |= instr->args[0].data.imm.value << 12;
+ bits |= instr->args[1].data.reg.reg << 21;
+ break;
+
+ case PC_MTFSF:
+ bits |= (instr->args[0].data.imm.value & 0xFF) << 17;
+ bits |= instr->args[1].data.reg.reg << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_FMR:
+ case PC_FABS:
+ case PC_FNEG:
+ case PC_FNABS:
+ case PC_FRES:
+ case PC_FRSQRTE:
+ case PC_FRSP:
+ case PC_FCTIW:
+ case PC_FCTIWZ:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_FADD:
+ case PC_FADDS:
+ case PC_FSUB:
+ case PC_FSUBS:
+ case PC_FDIV:
+ case PC_FDIVS:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_FMADD:
+ case PC_FMADDS:
+ case PC_FMSUB:
+ case PC_FMSUBS:
+ case PC_FNMADD:
+ case PC_FNMADDS:
+ case PC_FNMSUB:
+ case PC_FNMSUBS:
+ case PC_FSEL:
+ bits |= instr->args[3].data.reg.reg << 11;
+ case PC_FMUL:
+ case PC_FMULS:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 6;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_FCMPU:
+ case PC_FCMPO:
+ bits |= instr->args[0].data.reg.reg << 23;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ break;
+
+ case PC_MTSPR:
+ if (instr->args[0].kind == PCOp_REGISTER) {
+ CError_ASSERT(1027, instr->args[0].arg == RegClass_SPR);
+ CError_ASSERT(1028, instr->args[0].data.reg.reg < 4);
+ bits |= ((spr_to_sysreg[instr->args[0].data.reg.reg] & 0x1F) << 16) +
+ ((spr_to_sysreg[instr->args[0].data.reg.reg] & 0x3E0) << 6);
+ } else if (instr->args[0].kind == PCOp_SYSREG && instr->args[0].arg == 0) {
+ bits |= ((instr->args[0].data.reg.reg & 0x1F) << 16) +
+ ((instr->args[0].data.reg.reg & 0x3E0) << 6);
+ } else {
+ CError_FATAL(1033);
+ }
+
+ bits |= instr->args[1].data.reg.reg << 21;
+ break;
+
+ case PC_MTDCR:
+ if (instr->args[0].kind == PCOp_IMMEDIATE) {
+ bits |= ((instr->args[0].data.imm.value & 0x1F) << 16) +
+ ((instr->args[0].data.imm.value & 0x3E0) << 6);
+ } else {
+ CError_FATAL(1042);
+ }
+
+ bits |= instr->args[1].data.reg.reg << 21;
+ break;
+
+ case PC_MFSPR:
+ bits |= instr->args[0].data.reg.reg << 21;
+
+ if (instr->args[1].kind == PCOp_REGISTER && instr->args[1].arg == RegClass_SPR) {
+ CError_ASSERT(1055, instr->args[1].data.reg.reg < 4);
+ bits |= ((spr_to_sysreg[instr->args[1].data.reg.reg] & 0x1F) << 16) +
+ ((spr_to_sysreg[instr->args[1].data.reg.reg] & 0x3E0) << 6);
+ } else if (instr->args[1].kind == PCOp_SYSREG && instr->args[1].arg == 0) {
+ bits |= ((instr->args[1].data.reg.reg & 0x1F) << 16) +
+ ((instr->args[1].data.reg.reg & 0x3E0) << 6);
+ } else {
+ CError_FATAL(1060);
+ }
+ break;
+
+ case PC_MFDCR:
+ bits |= instr->args[0].data.reg.reg << 21;
+
+ if (instr->args[1].kind == PCOp_IMMEDIATE) {
+ bits |= ((instr->args[1].data.imm.value & 0x1F) << 16) +
+ ((instr->args[1].data.imm.value & 0x3E0) << 6);
+ } else {
+ CError_FATAL(1069);
+ }
+ break;
+
+ case PC_LSWI:
+ case PC_STSWI:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= (instr->args[2].data.imm.value & 31) << 11;
+ break;
+
+ case PC_MCRFS:
+ bits |= (instr->args[1].data.imm.value & 7) << 18;
+ case PC_MCRXR:
+ bits |= instr->args[0].data.reg.reg << 23;
+ break;
+
+ case PC_MFTB:
+ bits |= instr->args[0].data.reg.reg << 21;
+ if (instr->args[1].kind == PCOp_SYSREG && instr->args[1].arg == 0) {
+ if (instr->args[1].data.reg.reg == 284)
+ bits |= 0xC4000u;
+ else if (instr->args[1].data.reg.reg == 285)
+ bits |= 0xD4000u;
+ else
+ CError_FATAL(1100);
+ } else {
+ CError_FATAL(1103);
+ }
+ break;
+
+ case PC_MTSR:
+ bits |= instr->args[1].data.reg.reg << 21;
+ bits |= (instr->args[0].data.imm.value & 15) << 16;
+ break;
+
+ case PC_MFSR:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= (instr->args[1].data.imm.value & 15) << 16;
+ break;
+
+ case PC_MFSRIN:
+ case PC_MTSRIN:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 11;
+ break;
+
+ case PC_MTFSB0:
+ case PC_MTFSB1:
+ bits |= (instr->args[0].data.imm.value & 31) << 21;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_MTFSFI:
+ bits |= instr->args[0].data.reg.reg << 23;
+ bits |= (instr->args[1].data.imm.value & 15) << 12;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_FSQRT:
+ case PC_FSQRTS:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_TLBIE:
+ case PC_TLBLD:
+ case PC_TLBLI:
+ bits |= instr->args[0].data.reg.reg << 11;
+ break;
+
+ case PC_TW:
+ bits |= (instr->args[0].data.imm.value & 31) << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ break;
+
+ case PC_TWI:
+ bits |= (instr->args[0].data.imm.value & 31) << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.imm.value & 0xFFFF;
+ break;
+
+ case PC_OPWORD:
+ CError_ASSERT(1176, instr->args[0].kind != PCOp_MEMORY);
+ bits = pcode_update_mem_labeldiff_imm(instr, &instr->args[0], wop);
+ break;
+
+ case PC_MASKG:
+ case PC_MASKIR:
+ bits |= instr->args[1].data.reg.reg << 21;
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_LSCBX:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_DIV:
+ case PC_DIVS:
+ case PC_DOZ:
+ case PC_MUL:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ if (PCODE_FLAG_SET_F(instr) & fOverflow)
+ bits |= 0x400;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_NABS:
+ case PC_ABS:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ if (PCODE_FLAG_SET_F(instr) & fOverflow)
+ bits |= 0x400;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_CLCS:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_DOZI:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.imm.value & 0xFFFF;
+ break;
+
+ case PC_RLMI:
+ bits |= instr->args[1].data.reg.reg << 21;
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ bits |= (instr->args[3].data.imm.value & 31) << 6;
+ bits |= (instr->args[4].data.imm.value & 31) << 1;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_SLE:
+ case PC_SLEQ:
+ case PC_SLLQ:
+ case PC_SLQ:
+ case PC_SRAQ:
+ case PC_SRE:
+ case PC_SREA:
+ case PC_SREQ:
+ case PC_SRLQ:
+ case PC_SRQ:
+ case PC_RRIB:
+ bits |= instr->args[1].data.reg.reg << 21;
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_SLIQ:
+ case PC_SLLIQ:
+ case PC_SRAIQ:
+ case PC_SRIQ:
+ case PC_SRLIQ:
+ bits |= instr->args[1].data.reg.reg << 21;
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= (instr->args[2].data.imm.value & 31) << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 1;
+ break;
+
+ case PC_TLBRE:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= (instr->args[2].data.imm.value & 1) << 11;
+ break;
+
+ case PC_TLBWE:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= (instr->args[2].data.imm.value & 1) << 11;
+ break;
+
+ case PC_WRTEE:
+ bits |= instr->args[0].data.reg.reg << 21;
+ break;
+
+ case PC_WRTEEI:
+ bits |= instr->args[0].data.imm.value << 15;
+ break;
+
+ case PC_DSTT:
+ case PC_DSTSTT:
+ bits |= 0x2000000u;
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[1].data.reg.reg << 11;
+ bits |= (instr->args[2].data.imm.value & 3) << 21;
+ break;
+
+ case PC_DST:
+ case PC_DSTST:
+ bits |= (instr->args[3].data.imm.value & 1) << 25;
+ bits |= instr->args[0].data.reg.reg << 16;
+ bits |= instr->args[1].data.reg.reg << 11;
+ bits |= (instr->args[2].data.imm.value & 3) << 21;
+ break;
+
+ case PC_DSSALL:
+ bits |= 0x2000000u;
+ break;
+
+ case PC_DSS:
+ bits |= (instr->args[1].data.imm.value & 1) << 25;
+ bits |= (instr->args[0].data.imm.value & 3) << 21;
+ break;
+
+ case PC_LVEBX:
+ case PC_LVEHX:
+ case PC_LVEWX:
+ case PC_LVSL:
+ case PC_LVSR:
+ case PC_LVX:
+ case PC_LVXL:
+ case PC_STVEBX:
+ case PC_STVEHX:
+ case PC_STVEWX:
+ case PC_STVX:
+ case PC_STVXL:
+ case PC_VADDCUW:
+ case PC_VADDFP:
+ case PC_VADDSBS:
+ case PC_VADDSHS:
+ case PC_VADDSWS:
+ case PC_VADDUBM:
+ case PC_VADDUBS:
+ case PC_VADDUHM:
+ case PC_VADDUHS:
+ case PC_VADDUWM:
+ case PC_VADDUWS:
+ case PC_VAND:
+ case PC_VANDC:
+ case PC_VAVGSB:
+ case PC_VAVGSH:
+ case PC_VAVGSW:
+ case PC_VAVGUB:
+ case PC_VAVGUH:
+ case PC_VAVGUW:
+ case PC_VMAXFP:
+ case PC_VMAXSB:
+ case PC_VMAXSH:
+ case PC_VMAXSW:
+ case PC_VMAXUB:
+ case PC_VMAXUH:
+ case PC_VMAXUW:
+ case PC_VMINFP:
+ case PC_VMINSB:
+ case PC_VMINSH:
+ case PC_VMINSW:
+ case PC_VMINUB:
+ case PC_VMINUH:
+ case PC_VMINUW:
+ case PC_VMRGHB:
+ case PC_VMRGHH:
+ case PC_VMRGHW:
+ case PC_VMRGLB:
+ case PC_VMRGLH:
+ case PC_VMRGLW:
+ case PC_VMULESB:
+ case PC_VMULESH:
+ case PC_VMULEUB:
+ case PC_VMULEUH:
+ case PC_VMULOSB:
+ case PC_VMULOSH:
+ case PC_VMULOUB:
+ case PC_VMULOUH:
+ case PC_VNOR:
+ case PC_VOR:
+ case PC_VPKPX:
+ case PC_VPKSHSS:
+ case PC_VPKSHUS:
+ case PC_VPKSWSS:
+ case PC_VPKSWUS:
+ case PC_VPKUHUM:
+ case PC_VPKUHUS:
+ case PC_VPKUWUM:
+ case PC_VPKUWUS:
+ case PC_VRLB:
+ case PC_VRLH:
+ case PC_VRLW:
+ case PC_VSL:
+ case PC_VSLB:
+ case PC_VSLH:
+ case PC_VSLO:
+ case PC_VSLW:
+ case PC_VSR:
+ case PC_VSRAB:
+ case PC_VSRAH:
+ case PC_VSRAW:
+ case PC_VSRB:
+ case PC_VSRH:
+ case PC_VSRO:
+ case PC_VSRW:
+ case PC_VSUBCUW:
+ case PC_VSUBFP:
+ case PC_VSUBSBS:
+ case PC_VSUBSHS:
+ case PC_VSUBSWS:
+ case PC_VSUBUBM:
+ case PC_VSUBUBS:
+ case PC_VSUBUHM:
+ case PC_VSUBUHS:
+ case PC_VSUBUWM:
+ case PC_VSUBUWS:
+ case PC_VSUMSWS:
+ case PC_VSUM2SWS:
+ case PC_VSUM4SBS:
+ case PC_VSUM4SHS:
+ case PC_VSUM4UBS:
+ case PC_VXOR:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ break;
+
+ case PC_VCFSX:
+ case PC_VCFUX:
+ case PC_VCTSXS:
+ case PC_VCTUXS:
+ case PC_VSPLTB:
+ case PC_VSPLTH:
+ case PC_VSPLTW:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 11;
+ bits |= (instr->args[2].data.imm.value & 31) << 16;
+ break;
+
+ case PC_VEXPTEFP:
+ case PC_VLOGEFP:
+ case PC_VREFP:
+ case PC_VRFIM:
+ case PC_VRFIN:
+ case PC_VRFIP:
+ case PC_VRFIZ:
+ case PC_VRSQRTEFP:
+ case PC_VUPKHPX:
+ case PC_VUPKHSB:
+ case PC_VUPKHSH:
+ case PC_VUPKLPX:
+ case PC_VUPKLSB:
+ case PC_VUPKLSH:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 11;
+ break;
+
+ case PC_VCMPBFP:
+ case PC_VCMPEQFP:
+ case PC_VCMPEQUB:
+ case PC_VCMPEQUH:
+ case PC_VCMPEQUW:
+ case PC_VCMPGEFP:
+ case PC_VCMPGTFP:
+ case PC_VCMPGTSB:
+ case PC_VCMPGTSH:
+ case PC_VCMPGTSW:
+ case PC_VCMPGTUB:
+ case PC_VCMPGTUH:
+ case PC_VCMPGTUW:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ bits |= 0x400;
+ break;
+
+ case PC_VSPLTISB:
+ case PC_VSPLTISH:
+ case PC_VSPLTISW:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= (instr->args[1].data.imm.value & 31) << 16;
+ break;
+
+ case PC_VMHADDSHS:
+ case PC_VMHRADDSHS:
+ case PC_VMLADDUHM:
+ case PC_VMSUMMBM:
+ case PC_VMSUMSHM:
+ case PC_VMSUMSHS:
+ case PC_VMSUMUBM:
+ case PC_VMSUMUHM:
+ case PC_VMSUMUHS:
+ case PC_VPERM:
+ case PC_VSEL:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ bits |= instr->args[3].data.reg.reg << 6;
+ break;
+
+ case PC_VMADDFP:
+ case PC_VNMSUBFP:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 6;
+ bits |= instr->args[3].data.reg.reg << 11;
+ break;
+
+ case PC_VSLDOI:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[2].data.reg.reg << 11;
+ bits |= (instr->args[3].data.imm.value & 15) << 6;
+ break;
+
+ case PC_VMR:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[1].data.reg.reg << 11;
+ break;
+
+ case PC_VMRP:
+ bits |= instr->args[0].data.reg.reg << 21;
+ bits |= instr->args[1].data.reg.reg << 16;
+ bits |= instr->args[1].data.reg.reg << 11;
+ break;
+
+ case PC_MFVSCR:
+ bits |= instr->args[0].data.reg.reg << 21;
+ break;
+
+ case PC_MTVSCR:
+ bits |= instr->args[0].data.reg.reg << 11;
+ break;
+
+ case PC_EIEIO:
+ case PC_ISYNC:
+ case PC_SYNC:
+ case PC_RFI:
+ case PC_NOP:
+ case PC_SC:
+ case PC_TLBIA:
+ case PC_TLBSYNC:
+ case PC_TRAP:
+ case PC_DSA:
+ case PC_ESA:
+ case PC_RFCI:
+ break;
+
+ default:
+ CError_FATAL(2203);
+ }
+
+ return CTool_EndianConvertWord32(bits);
+}
+
+static PCode *targetinstruction(PCodeLabel *label) {
+ PCodeBlock *block = label->block;
+ while (block->pcodeCount == 0)
+ block = block->nextBlock;
+ return block->firstPCode;
+}
+
+static void invertybit(PCode *instr, SInt32 value) {
+ if (instr->op == PC_BC) {
+ if (instr->args[0].data.imm.value & 1) {
+ if (value < 0)
+ instr->flags |= fBranchNotTaken;
+ else
+ instr->flags |= fBranchTaken;
+ }
+ } else if (instr->op == PC_BCCTR || instr->op == PC_BCLR) {
+ if (instr->args[0].data.imm.value & 1)
+ instr->flags |= fBranchTaken;
+ }
+
+ if (PCODE_FLAG_SET_T(instr) & fBranchTaken)
+ instr->flags = (instr->flags & ~fBranchTaken) | fBranchNotTaken;
+ else if (PCODE_FLAG_SET_T(instr) & fBranchNotTaken)
+ instr->flags = (instr->flags & ~fBranchNotTaken) | fBranchTaken;
+ else if (value < 0)
+ instr->flags = (instr->flags & ~fBranchTaken) | fBranchNotTaken;
+ else
+ instr->flags = (instr->flags & ~fBranchNotTaken) | fBranchTaken;
+}
+
+static void insertlongbranches(SInt32 mask) {
+ PCodeBlock *block;
+ PCodeLabel *label;
+ SInt32 i;
+
+ i = 0;
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ block->codeOffset = i;
+ if (block->pcodeCount) {
+ i += block->pcodeCount * 4;
+ if (block->pcodeCount && (block->lastPCode->flags & fIsBranch))
+ i += 4;
+ }
+ }
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ if (block->pcodeCount && (block->lastPCode->flags & fIsBranch)) {
+ switch (block->lastPCode->op) {
+ case PC_BT:
+ case PC_BF:
+ i = block->codeOffset + ((block->pcodeCount - 1) * 4);
+ if (block->lastPCode->args[2].kind == PCOp_LABEL) {
+ label = block->lastPCode->args[2].data.label.label;
+ i = label->block->codeOffset - i;
+ if (i != ((SInt16) (i & mask))) {
+ block->lastPCode->op = (block->lastPCode->op == PC_BT) ? PC_BF : PC_BT;
+ block->lastPCode->args[2].data.label.label = block->nextBlock->labels;
+ invertybit(block->lastPCode, i);
+ appendpcode(block, makepcode(PC_B, label));
+ }
+ }
+ break;
+
+ case PC_BC:
+ i = block->codeOffset + ((block->pcodeCount - 1) * 4);
+ if (block->lastPCode->args[3].kind == PCOp_LABEL) {
+ label = block->lastPCode->args[3].data.label.label;
+ i = label->block->codeOffset - i;
+ invertybit(block->lastPCode, i);
+ if (i != ((SInt16) (i & mask))) {
+ switch (block->lastPCode->args[0].data.imm.value & 30) {
+ case 0:
+ case 2:
+ case 8:
+ case 10:
+ block->lastPCode->args[0].data.imm.value ^= 11;
+ block->lastPCode->args[3].data.label.label = block->nextBlock->labels;
+ break;
+ case 16:
+ case 18:
+ block->lastPCode->args[0].data.imm.value ^= 3;
+ block->lastPCode->args[3].data.label.label = block->nextBlock->labels;
+ break;
+ case 4:
+ case 12:
+ block->lastPCode->args[0].data.imm.value ^= 9;
+ block->lastPCode->args[3].data.label.label = block->nextBlock->labels;
+ break;
+ case 20:
+ deletepcode(block->lastPCode);
+ break;
+ default:
+ CError_FATAL(2368);
+ }
+
+ appendpcode(block, makepcode(PC_B, label));
+ }
+ }
+ break;
+
+ case PC_BDNZ:
+ case PC_BDZ:
+ i = block->codeOffset + ((block->pcodeCount - 1) * 4);
+ if (block->lastPCode->args[0].kind == PCOp_LABEL) {
+ label = block->lastPCode->args[0].data.label.label;
+ i = label->block->codeOffset - i;
+ if (i != ((SInt16) (i & mask))) {
+ switch (block->lastPCode->op) {
+ case PC_BDZ:
+ block->lastPCode->op = PC_BDNZ;
+ break;
+ case PC_BDNZ:
+ block->lastPCode->op = PC_BDZ;
+ break;
+ default:
+ CError_FATAL(2389);
+ }
+
+ block->lastPCode->args[0].data.label.label = block->nextBlock->labels;
+ invertybit(block->lastPCode, i);
+ appendpcode(block, makepcode(PC_B, label));
+ }
+ }
+ break;
+
+ case PC_BDNZT:
+ case PC_BDNZF:
+ case PC_BDZT:
+ case PC_BDZF:
+ i = block->codeOffset + ((block->pcodeCount - 1) * 4);
+ if (block->lastPCode->args[2].kind == PCOp_LABEL) {
+ label = block->lastPCode->args[2].data.label.label;
+ i = label->block->codeOffset - i;
+ if (i != ((SInt16) (i & mask))) {
+ switch (block->lastPCode->op) {
+ case PC_BDNZT:
+ block->lastPCode->op = PC_BDZF;
+ break;
+ case PC_BDNZF:
+ block->lastPCode->op = PC_BDZT;
+ break;
+ case PC_BDZT:
+ block->lastPCode->op = PC_BDNZF;
+ break;
+ case PC_BDZF:
+ block->lastPCode->op = PC_BDNZT;
+ break;
+ default:
+ CError_FATAL(2420);
+ }
+
+ block->lastPCode->args[2].data.label.label = block->nextBlock->labels;
+ invertybit(block->lastPCode, i);
+ appendpcode(block, makepcode(PC_B, label));
+ }
+ }
+ break;
+
+ }
+ }
+ }
+}
+
+SInt32 optimizefinalbranches(SInt32 codesize) {
+ PCodeBlock *block;
+ PCode *instr;
+ SInt32 offset;
+ int changed;
+ int deleted;
+ PCodeLabel *label;
+ PCode *target;
+
+ do {
+ changed = deleted = 0;
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ if (block->pcodeCount == 0)
+ continue;
+
+ instr = block->lastPCode;
+ if (!(instr->flags & fIsBranch))
+ continue;
+
+ offset = block->codeOffset + (block->pcodeCount - 1) * 4;
+
+ if (instr->op == PC_B && instr->args[0].kind == PCOp_LABEL) {
+ label = instr->args[0].data.label.label;
+ target = targetinstruction(label);
+
+ if (label->block->codeOffset == (offset + 4)) {
+ deletepcode(instr);
+ changed = deleted = 1;
+ } else if (target->op == PC_B) {
+ if (target->args[0].kind == PCOp_LABEL && target->args[0].data.label.label != instr->args[0].data.label.label) {
+ instr->args[0].data.label.label = target->args[0].data.label.label;
+ changed = 1;
+ }
+ } else if (target->op == PC_BLR) {
+ instr->op = PC_BLR;
+ changed = 1;
+ }
+ continue;
+ }
+
+ if ((instr->op == PC_BT || instr->op == PC_BF) && instr->args[2].kind == PCOp_LABEL) {
+ PCodeBlock *block2 = instr->block;
+ label = instr->args[2].data.label.label;
+ target = targetinstruction(label);
+
+ if (label->block->codeOffset == (offset + 4)) {
+ deletepcode(instr);
+ changed = deleted = 1;
+ } else if (target->op == PC_B) {
+ if (target->args[0].kind == PCOp_LABEL && target->args[0].data.label.label != instr->args[2].data.label.label) {
+ instr->args[2].data.label.label = target->args[0].data.label.label;
+ changed = 1;
+ }
+ } else if (copts.opt_bcc_lr_ctr) {
+ if (target->op == PC_BLR) {
+ if (instr->op == PC_BT)
+ instr->op = PC_BTLR;
+ else
+ instr->op = PC_BFLR;
+ instr->argCount = 2;
+ changed = 1;
+ } else if (target->op == PC_BCTR) {
+ if (instr->op == PC_BT)
+ instr->op = PC_BTCTR;
+ else
+ instr->op = PC_BFCTR;
+ instr->argCount = 2;
+ changed = 1;
+ } else if (
+ block2->nextBlock &&
+ block2->nextBlock->firstPCode &&
+ block2->nextBlock->firstPCode->op == PC_BLR &&
+ label->block->codeOffset == (offset + 8)
+ ) {
+ if (
+ block2->nextBlock->predecessors &&
+ block2->nextBlock->predecessors->block == block2 &&
+ !block2->nextBlock->predecessors->nextLink
+ ) {
+ if (instr->op == PC_BT)
+ instr->op = PC_BFLR;
+ else
+ instr->op = PC_BTLR;
+ change_num_operands(instr, 2);
+ deletepcode(block2->nextBlock->firstPCode);
+ changed = deleted = 1;
+ }
+ } else if (
+ block2->nextBlock &&
+ block2->nextBlock->firstPCode &&
+ block2->nextBlock->firstPCode->op == PC_BCTR &&
+ label->block->codeOffset == (offset + 8)
+ ) {
+ if (
+ block2->nextBlock->predecessors &&
+ block2->nextBlock->predecessors->block == block2 &&
+ !block2->nextBlock->predecessors->nextLink
+ ) {
+ if (instr->op == PC_BT)
+ instr->op = PC_BFCTR;
+ else
+ instr->op = PC_BTCTR;
+ change_num_operands(instr, 2);
+ deletepcode(block2->nextBlock->firstPCode);
+ changed = deleted = 1;
+ }
+ }
+ }
+ continue;
+ }
+
+ if (
+ instr->op == PC_BC &&
+ instr->args[3].kind == PCOp_LABEL &&
+ !(PCODE_FLAG_SET_T(instr) & (fSideEffects | fLink))
+ )
+ {
+ PCodeBlock *block2 = instr->block;
+ label = instr->args[3].data.label.label;
+ target = targetinstruction(label);
+
+ if (label->block->codeOffset == (offset + 4)) {
+ deletepcode(instr);
+ changed = deleted = 1;
+ } else if (target->op == PC_B) {
+ if (target->args[0].kind == PCOp_LABEL && target->args[0].data.label.label != instr->args[3].data.label.label) {
+ instr->args[3].data.label.label = target->args[0].data.label.label;
+ changed = 1;
+ }
+ } else if (copts.opt_bcc_lr_ctr) {
+ if (target->op == PC_BLR) {
+ instr->op = PC_BCLR;
+ instr->argCount = 3;
+ changed = 1;
+ } else if (target->op == PC_BCTR) {
+ instr->op = PC_BCCTR;
+ instr->argCount = 3;
+ changed = 1;
+ } else if (
+ block2->nextBlock &&
+ block2->nextBlock->firstPCode &&
+ block2->nextBlock->firstPCode->op == PC_BLR &&
+ label->block->codeOffset == (offset + 8)
+ ) {
+ SInt32 val = instr->args[0].data.imm.value & 30;
+ if (
+ block2->nextBlock->predecessors &&
+ block2->nextBlock->predecessors->block == block2 &&
+ !block2->nextBlock->predecessors->nextLink
+ ) {
+ if ((val & 30) == 4)
+ instr->args[0].data.imm.value = val | 12;
+ else if ((val & 30) == 12)
+ instr->args[0].data.imm.value = val & 23;
+ instr->op = PC_BCLR;
+ instr->argCount = 3;
+ deletepcode(block2->nextBlock->firstPCode);
+ changed = deleted = 1;
+ }
+ } else if (
+ block2->nextBlock &&
+ block2->nextBlock->firstPCode &&
+ block2->nextBlock->firstPCode->op == PC_BCTR &&
+ label->block->codeOffset == (offset + 8)
+ ) {
+ SInt32 val = instr->args[0].data.imm.value & 30;
+ if (
+ block2->nextBlock->predecessors &&
+ block2->nextBlock->predecessors->block == block2 &&
+ !block2->nextBlock->predecessors->nextLink
+ ) {
+ if ((val & 30) == 4)
+ instr->args[0].data.imm.value = val | 12;
+ else if ((val & 30) == 12)
+ instr->args[0].data.imm.value = val & 23;
+ instr->op = PC_BCCTR;
+ instr->argCount = 3;
+ deletepcode(block2->nextBlock->firstPCode);
+ changed = deleted = 1;
+ }
+ }
+ }
+ }
+ }
+
+ if (deleted)
+ codesize = pccomputeoffsets();
+ } while (changed);
+
+ return codesize;
+}
+
+static SInt32 insert_align_nops(Object *func, SInt32 codesize) {
+ PCodeBlock *block;
+ int changed;
+ PCodeBlock *prev;
+
+ do {
+ changed = 0;
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ if (
+ (block->flags & fPCBlockFlag6000) == fPCBlockFlag2000 &&
+ (block->codeOffset & 7) &&
+ block->pcodeCount < 8 &&
+ (prev = block->prevBlock) &&
+ !(prev->flags & fPCBlockFlag2000)
+ )
+ {
+ if (prev->lastPCode && prev->lastPCode->op == PC_NOP && !(prev->lastPCode->flags & fSideEffects)) {
+ deletepcode(prev->lastPCode);
+ } else {
+ PCode *nop = makepcode(PC_NOP);
+ nop->flags &= ~fSideEffects;
+ appendpcode(prev, nop);
+ }
+
+ codesize = pccomputeoffsets();
+ changed = 1;
+ }
+ }
+
+ if (changed) {
+ pclistblocks(CMangler_GetLinkName(func)->name, "AFTER INSERT ALIGN NOPs");
+ if (codesize > 32766) {
+ insertlongbranches(32766);
+ codesize = pccomputeoffsets();
+ }
+ }
+
+ } while (changed);
+
+ return codesize;
+}
+
+SInt32 assemblefunction(Object *func, EntryPoint *entrypoints) {
+ void *tbdata;
+ GList *gl;
+ PCodeBlock *block;
+ PCode *instr;
+ SInt32 offset2;
+ SInt32 codesize;
+ SInt32 tbsize;
+ SInt32 offset;
+ SectionHandle section;
+ EntryPoint *ep;
+ WeirdOperand wop;
+
+ codesize = pccomputeoffsets();
+ if (codesize <= 0)
+ PPCError_Error(PPCErrorStr190, func->name->name);
+
+ if (copts.peephole || copts.optimizationlevel >= 3)
+ codesize = optimizefinalbranches(codesize);
+
+ if (codesize > 32766) {
+ insertlongbranches(32766);
+ codesize = pccomputeoffsets();
+ }
+
+ if (copts.function_align > 4)
+ codesize = insert_align_nops(func, codesize);
+
+ tbsize = 0;
+ if (copts.traceback)
+ tbdata = generate_traceback(codesize, CMangler_GetLinkName(func)->name, &tbsize, func);
+
+ if (func->section == SECT_DEFAULT)
+ func->section = SECT_TEXT;
+
+ offset = tbsize;
+ section = ObjGen_DeclareCode(func, codesize + tbsize);
+ gl = ObjGen_GetSectionGList(section);
+
+ codebase = gl->size;
+ AppendGListNoData(gl, codesize + tbsize);
+
+ if (copts.filesyminfo) {
+ ObjGen_SymFunc(func);
+ ObjGen_Line(functionbodyoffset, 0);
+ ObjGen_DeclareSymInfo();
+ }
+
+ if (uses_globals && pic_base_reg)
+ ObjGen_DeclarePICBase(func, pic_base_pcodelabel->block->codeOffset);
+
+ if (entrypoints) {
+ for (ep = entrypoints; ep; ep = ep->next) {
+ ObjGen_DeclareEntry(ep->object, ep->block->codeOffset);
+ }
+ }
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ for (offset2 = block->codeOffset, instr = block->firstPCode; instr; instr = instr->nextPCode, offset2 += 4) {
+ if (copts.filesyminfo && instr->sourceoffset != -1)
+ ObjGen_Line(instr->sourceoffset, offset2);
+
+ *((UInt32 *) (*gl->data + codebase + offset2)) = assemblepcode(instr, offset2, &wop);
+
+ if (wop.type != -1)
+ ObjGen_RelocateObj(section, offset2, wop.x2, wop.type);
+ }
+ }
+
+ if (copts.filesyminfo)
+ ObjGenMach_SymFuncEnd(func, codesize);
+
+ if (copts.traceback)
+ memcpy(*gl->data + codebase + codesize, tbdata, offset);
+
+ if (copts.traceback)
+ return codesize + tbsize;
+ else
+ return codesize;
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeListing.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeListing.c
new file mode 100644
index 0000000..7a9fa13
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeListing.c
@@ -0,0 +1,536 @@
+#include "compiler/PCodeListing.h"
+#include "compiler/CError.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/Alias.h"
+#include "compiler/BitVectors.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/InterferenceGraph.h"
+#include "compiler/LiveInfo.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeAssembly.h"
+#include "compiler/Registers.h"
+#include "compiler/Scheduler.h"
+#include "compiler/objects.h"
+
+static FILE *pcfile;
+static int ptime;
+static int sourcetext;
+static int sourcetext_is_main;
+static int sourcelength;
+int pclist_bad_operand;
+
+static void formatdataflowset(char *name, UInt32 *vec, UInt32 size, char *format) {
+ UInt32 i;
+ UInt32 counter;
+ char *separator;
+
+ separator = "";
+ fprintf(pcfile, "%s = {", name);
+
+ for (i = 0, counter = 0; i < size; i++) {
+ if (bitvectorgetbit(i, vec)) {
+ if (i)
+ fprintf(pcfile, separator);
+ if (counter++ == 10) {
+ fprintf(pcfile, "\n\t\t");
+ counter = 0;
+ }
+ fprintf(pcfile, format, i);
+ separator = ",";
+ }
+ }
+
+ fprintf(pcfile, "}\n");
+}
+
+static void pclistblock(PCodeBlock *block, char *format, UInt32 vecSize) {
+ PCLink *link;
+ PCodeLabel *label;
+ int cpu;
+ int chr;
+ PCode *instr;
+ int offset;
+ int latency;
+ UInt32 opcode;
+ MachineInfo *mi;
+ char buf[500];
+ WeirdOperand dummyArg;
+
+ fprintf(pcfile, ":{%4.4x}::::::::::::::::::::::::::::::::::::::::LOOPWEIGHT=%" PRId32 "\n", block->flags, block->loopWeight);
+ fprintf(pcfile, "B%" PRId32 ": ", block->blockIndex);
+
+ fprintf(pcfile, "Successors = { ");
+ for (link = block->successors; link; link = link->nextLink) {
+ if (link->block)
+ fprintf(pcfile, "B%" PRId32 " ", link->block->blockIndex);
+ }
+ fprintf(pcfile, "} ");
+
+ fprintf(pcfile, "Predecessors = { ");
+ for (link = block->predecessors; link; link = link->nextLink) {
+ if (link->block)
+ fprintf(pcfile, "B%" PRId32 " ", link->block->blockIndex);
+ }
+
+ if (block->labels) {
+ fprintf(pcfile, "} Labels = { ");
+ for (label = block->labels; label; label = label->nextLabel)
+ fprintf(pcfile, "L%" PRId32 " ", label->index);
+ }
+
+ fprintf(pcfile, "}\n\n");
+
+ cpu = copts.scheduling;
+ if (cpu == 10) {
+ mi = &machine7450;
+ } else if (copts.altivec_model != 0 || cpu == 7) {
+ mi = &machine7400;
+ } else if (cpu == 2) {
+ mi = &machine603;
+ } else if (cpu == 5) {
+ mi = &machine603e;
+ } else if (cpu == 3) {
+ mi = &machine604;
+ } else if (cpu == 6) {
+ mi = &machine604;
+ } else if (cpu == 4) {
+ mi = &machine750;
+ } else if (cpu == 1) {
+ mi = &machine601;
+ } else if (cpu == 9) {
+ mi = &machine821;
+ } else {
+ mi = &machine603;
+ }
+
+ for (offset = block->codeOffset, instr = block->firstPCode; instr; instr = instr->nextPCode, offset += 4) {
+ latency = mi->latency(instr);
+ formatoperands(instr, buf, 1);
+ chr = (PCODE_FLAG_SET_F(instr) & fRecordBit) ? '.' : ' ';
+ if (coloring)
+ opcode = 0;
+ else
+ opcode = assemblepcode(instr, offset, &dummyArg);
+
+ fprintf(
+ pcfile,
+ " %.8" PRIX32 " %.8" PRIX32 " %4" PRId32 " %-7s%c %s\n",
+ offset, CTool_EndianConvertWord32(opcode), latency,
+ opcodeinfo[instr->op].name, chr, buf
+ );
+
+ if (instr->alias)
+ dumpalias(instr->alias, 0, 1, 0);
+ }
+
+ if (vecSize) {
+ fprintf(pcfile, "............................................................\n");
+ formatdataflowset("use", liveinfo[block->blockIndex].use, vecSize, format);
+ formatdataflowset("def", liveinfo[block->blockIndex].def, vecSize, format);
+ formatdataflowset("in ", liveinfo[block->blockIndex].in, vecSize, format);
+ formatdataflowset("out", liveinfo[block->blockIndex].out, vecSize, format);
+ }
+
+ fflush(pcfile);
+
+ if (pclist_bad_operand)
+ CError_FATAL(252);
+}
+
+static void pclistonoff(int flag) {
+ if (flag)
+ fprintf(pcfile, "On\n");
+ else
+ fprintf(pcfile, "Off\n");
+}
+
+void pcinitlisting() {
+ // unknown args, etc
+}
+
+void pccleanuplisting(void) {
+#ifdef CW_ENABLE_PCODE_DEBUG
+ // this code is not based on the original as we don't have it
+ if (pcfile) {
+ fclose(pcfile);
+ pcfile = NULL;
+ }
+#endif
+}
+
+void pclistblocks(char *name1, char *name2) {
+#ifdef CW_ENABLE_PCODE_DEBUG
+ // this code is not based on the original as we don't have it
+ PCodeBlock *block;
+ if (copts.debuglisting) {
+ if (!pcfile)
+ pcfile = fopen("pcdump.txt", "a");
+
+ fprintf(pcfile, "\n%s\n%s\n", name1, name2);
+ for (block = pcbasicblocks; block; block = block->nextBlock)
+ pclistblock(block, NULL, 0);
+ }
+#endif
+}
+
+void pclistdataflow() {
+ // unknown args
+}
+
+void pclistinterferences(char *class_format, int regcount) {
+}
+
+void pclistspill() {
+ // unknown args
+}
+
+void pclistcopypropitem() {
+ // unknown args
+}
+
+void pclistcoalesce() {
+ // unknown args
+}
+
+void pclistusedefs() {
+ // unknown args
+}
+
+void pclistpropinfo() {
+ // unknown args
+}
+
+static void listloop() {
+ // unknown args
+}
+
+static void listloops() {
+ // unknown args
+}
+
+void pclistloops() {
+ // unknown args
+}
+
+static void listswitchtables() {
+ // unknown args
+}
+
+void pclistswitchtables() {
+ // unknown args
+}
+
+void pclistdominators() {
+ // unknown args
+}
+
+void pclistbackedge() {
+ // unknown args
+}
+
+static char *GetInterferenceFlags(IGNode *node) {
+ char *buf;
+ Boolean first;
+
+ first = 1;
+ buf = oalloc(512);
+ buf[0] = 0;
+
+ if (node->flags & fSpilled) {
+ strcat(buf, "fSpilled");
+ first = 0;
+ }
+
+ if (node->flags & fPushed) {
+ if (!first)
+ strcat(buf, "|");
+ strcat(buf, "fPushed");
+ first = 0;
+ }
+
+ if (node->flags & fCoalesced) {
+ if (!first)
+ strcat(buf, "|");
+ strcat(buf, "fCoalesced");
+ first = 0;
+ }
+
+ if (node->flags & fCoalescedInto) {
+ if (!first)
+ strcat(buf, "|");
+ strcat(buf, "fCoalescedInto");
+ first = 0;
+ }
+
+ if (node->flags & fPairHigh) {
+ if (!first)
+ strcat(buf, "|");
+ strcat(buf, "fPairHigh");
+ first = 0;
+ }
+
+ if (node->flags & fPairLow) {
+ if (!first)
+ strcat(buf, "|");
+ strcat(buf, "fPairLow");
+ first = 0;
+ }
+
+ if (!*buf)
+ strcat(buf, "no_flags");
+
+ return buf;
+}
+
+void pclistinterferencegraphnode() {
+ // unknown args
+}
+
+void pclistinterferencegraph() {
+ // unknown args
+}
+
+void pclistblock_scheduler() {
+ // unknown args
+}
+
+void pclistblocks_start_scheduler(char *str1, char *str2) {
+}
+
+void pclistblocks_end_scheduler(void) {
+ if (pclist_bad_operand)
+ CError_FATAL(1318);
+}
+
+static void printheapsize() {
+ // unknown args
+}
+
+void pctotalheap() {
+ // unknown args
+}
+
+void pctotalmemory() {
+ // unknown args
+}
+
+void pcmessage(char *probably_a_string, ...) {
+}
+
+int formatalias(Alias *alias, char *buf, int bufSize) {
+ char *name;
+ char *typestr;
+ int len;
+ int len2;
+
+ if (bufSize < 16)
+ return sprintf(buf, "...");
+
+ switch (alias->type) {
+ case AliasType0:
+ case AliasType1:
+ name = CMangler_GetLinkName(alias->object)->name;
+ if (!strlen(name) || name[0] < 0)
+ CError_FATAL(1458);
+
+ if (strlen(name) + 16 > bufSize)
+ return sprintf(buf, "...");
+
+ switch (alias->object->datatype) {
+ case DNONLAZYPTR:
+ typestr = "{NL}";
+ break;
+ case DDATA:
+ typestr = "{RW}";
+ break;
+ case DLOCAL:
+ typestr = "{SP}";
+ break;
+ default:
+ typestr = "";
+ }
+
+ len = sprintf(buf, "%0.*s%s", bufSize - 20, name, typestr, alias->size);
+ buf += len;
+ if (alias->type == AliasType0)
+ return len;
+
+ if (alias->offset == 0)
+ len2 = sprintf(buf, ":%d", alias->size);
+ else if (alias->offset > 0)
+ len2 = sprintf(buf, "+%d:%d", alias->offset, alias->size);
+ else
+ len2 = sprintf(buf, "-%d:%d", -alias->offset, alias->size);
+
+ return len + len2;
+
+ case AliasType2:
+ len = 0;
+
+ len2 = sprintf(buf, "{");
+ buf += len2;
+ len += len2;
+
+ len2 = sprintf(buf, "*");
+ buf += len2;
+ len += len2;
+
+ len2 = sprintf(buf, "}");
+ buf += len2;
+ len += len2;
+ return len;
+
+ default:
+ CError_FATAL(1543);
+ return 0;
+ }
+}
+
+int dumpalias(Alias *alias, int len, Boolean flag1, Boolean flag2) {
+ char *name;
+ char *typestr;
+ AliasMember *member;
+ Boolean notFirst;
+
+ if (!flag2 && alias == worst_case) {
+ fprintf(pcfile, " ALIAS = {worst_case}");
+ if (flag1)
+ fprintf(pcfile, "\n");
+ return 0;
+ }
+
+ if (flag1) {
+ if (alias == worst_case)
+ fprintf(pcfile, "ALIAS worst_case = ");
+ else
+ fprintf(pcfile, " ALIAS = ");
+ }
+
+ switch (alias->type) {
+ case AliasType0:
+ case AliasType1:
+ name = CMangler_GetLinkName(alias->object)->name;
+ if (!strlen(name) || name[0] < 0)
+ CError_FATAL(1581);
+
+ switch (alias->object->datatype) {
+ case DNONLAZYPTR:
+ typestr = "{NL}";
+ break;
+ case DDATA:
+ typestr = "{RW}";
+ break;
+ case DLOCAL:
+ typestr = "{SP}";
+ break;
+ default:
+ typestr = "";
+ }
+
+ len += fprintf(pcfile, "%0.80s%s", name, typestr);
+
+ if (alias->type == AliasType0) {
+ if (flag1)
+ fprintf(pcfile, "\n");
+ return len;
+ }
+
+ if (alias->offset == 0)
+ len += fprintf(pcfile, ":%d", alias->size);
+ else if (alias->offset > 0)
+ len += fprintf(pcfile, "+%d:%d", alias->offset, alias->size);
+ else
+ len += fprintf(pcfile, "-%d:%d", -alias->offset, alias->size);
+
+ if (flag1)
+ fprintf(pcfile, "\n");
+
+ return len;
+
+ case AliasType2:
+ len += fprintf(pcfile, "{");
+ notFirst = 0;
+ for (member = alias->parents; member; member = member->nextParent) {
+ if (member->child->type == AliasType0) {
+ if (notFirst)
+ len += fprintf(pcfile, ",");
+ if (len > 60) {
+ fprintf(pcfile, "\n ");
+ len = 0;
+ }
+ len = dumpalias(member->child, len, 0, 0);
+ notFirst = 1;
+ }
+ }
+ for (member = alias->parents; member; member = member->nextParent) {
+ if (member->child->type != AliasType0) {
+ if (notFirst)
+ len += fprintf(pcfile, ",");
+ if (len > 60) {
+ fprintf(pcfile, "\n ");
+ len = 0;
+ }
+ len = dumpalias(member->child, len, 0, 0);
+ notFirst = 1;
+ }
+ }
+
+ len += fprintf(pcfile, "}");
+ if (flag1)
+ fprintf(pcfile, "\n");
+ return len;
+
+ default:
+ CError_FATAL(1661);
+ return 0;
+ }
+}
+
+void pcformatset() {
+ // unknown args
+}
+
+int GetLineEndOffset(char *str, int lineNum, int len) {
+ int offset;
+ char *work;
+
+ offset = GetLineOffset(str, lineNum, len);
+ if (offset < 0)
+ return offset;
+
+ work = str + offset;
+ while (*work) {
+ if (*work == '\n')
+ return work - str - 1;
+ work++;
+ }
+ return -1;
+}
+
+int GetLineOffset(char *str, int lineNum, int len) {
+ char *work = str;
+ char *end;
+
+ if (lineNum < 0)
+ return -1;
+
+ end = str + len;
+ while (work < end) {
+ if (*work == '\n' && --lineNum <= 0)
+ return work - str;
+ work++;
+ }
+
+ return 0;
+}
+
+void DumpSourceCode() {
+ // unknown args
+}
+
+int DumpIR_SrcBreak() {
+ // unknown args
+ return 0;
+}
+
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeUtilities.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeUtilities.c
new file mode 100644
index 0000000..b1f8ffb
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeUtilities.c
@@ -0,0 +1,345 @@
+#include "compiler/PCodeUtilities.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/CParser.h"
+#include "compiler/CodeGen.h"
+#include "compiler/Exceptions.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+#include "compiler/Registers.h"
+#include "compiler/enode.h"
+#include "compiler/objects.h"
+
+void pcsetrecordbit(PCode *pc) {
+ int reg;
+ PCodeArg *arg;
+ short argCount;
+ int argIdx;
+
+ pc->flags &= ~(fIsMove | fCommutative | fIsCSE);
+ if ((pc->flags & fOpTypeMask) == fOpTypeFPR) {
+ reg = 1;
+ } else if ((pc->flags & fOpTypeMask) == fOpTypeVR) {
+ reg = 6;
+ } else {
+ reg = 0;
+ }
+
+ if (pc->op == PC_ANDI || pc->op == PC_ANDIS) {
+ pc->flags |= fRecordBit;
+ } else if (pc->op == PC_ADDI || pc->op == PC_ADDIC) {
+ pc->flags |= fSetsCarry;
+ pc->flags |= fRecordBit;
+ change_num_operands(pc, 5);
+ pc->op = PC_ADDICR;
+
+ CError_ASSERT(76, pc->args[3].kind == PCOp_PLACEHOLDEROPERAND);
+ pc->args[3].kind = PCOp_REGISTER;
+ pc->args[3].arg = RegClass_SPR;
+ pc->args[3].data.reg.reg = 0;
+ pc->args[3].data.reg.effect = EffectWrite;
+ CError_ASSERT(80, pc->args[4].kind == PCOp_PLACEHOLDEROPERAND);
+ pc->args[4].kind = PCOp_REGISTER;
+ pc->args[4].arg = RegClass_CRFIELD;
+ pc->args[4].data.reg.reg = reg;
+ pc->args[4].data.reg.effect = EffectWrite;
+ } else {
+ arg = pc->args;
+ argIdx = argCount = pc->argCount;
+ while (arg->kind != PCOp_PLACEHOLDEROPERAND && argIdx) {
+ if (arg->kind == PCOp_REGISTER && arg->arg == RegClass_CRFIELD && arg->data.reg.reg == reg) {
+ arg->data.reg.effect |= EffectWrite;
+ pc->flags |= fRecordBit;
+ return;
+ }
+ arg++;
+ argIdx--;
+ }
+
+ if (argIdx <= 0) {
+ arg = &pc->args[argCount];
+ pc->argCount++;
+ }
+
+ CError_ASSERT(105, arg->kind == PCOp_PLACEHOLDEROPERAND);
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_CRFIELD;
+ arg->data.reg.reg = reg;
+ arg->data.reg.effect = EffectWrite;
+ if (pc->op != PC_ADDICR)
+ pc->flags |= fRecordBit;
+ }
+}
+
+void pcsetsideeffects(PCode *pc) {
+ pc->flags &= ~(fIsMove | fCommutative | fIsCSE);
+ pc->flags |= fSideEffects;
+}
+
+void pcsetlinkbit(PCode *pc) {
+ PCodeArg *arg;
+ int argIdx;
+
+ switch (pc->op) {
+ case PC_B:
+ pc->op = PC_BL;
+ break;
+ case PC_BCTR:
+ pc->op = PC_BCTRL;
+ break;
+ case PC_BLR:
+ pc->op = PC_BLRL;
+ break;
+ }
+
+ arg = pc->args;
+ argIdx = pc->argCount;
+ while (arg->kind != PCOp_PLACEHOLDEROPERAND && argIdx) {
+ if (arg->kind == PCOp_REGISTER && arg->arg == RegClass_SPR && arg->data.reg.reg == 1) {
+ arg->data.reg.effect |= EffectWrite;
+ pc->flags |= fLink;
+ return;
+ }
+ arg++;
+ argIdx--;
+ }
+
+ CError_ASSERT(169, arg->kind == PCOp_PLACEHOLDEROPERAND);
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_SPR;
+ arg->data.reg.reg = 1;
+ arg->data.reg.effect = EffectWrite;
+
+ if (opcodeinfo[pc->op].flags & fIsCall) {
+ pc->flags &= ~fIsBranch;
+ pc->flags |= fIsCall;
+ }
+ pc->flags |= fLink;
+}
+
+void branch_label(PCodeLabel *label) {
+ if (pclastblock->pcodeCount) {
+ pcbranch(pclastblock, label);
+ makepcblock();
+ }
+ pclabel(pclastblock, label);
+}
+
+void branch_conditional(short a, short compareop, short c, PCodeLabel *label) {
+ PCodeBlock *tmpblock;
+ PCodeLabel *tmplabel;
+ int r28;
+
+ tmpblock = pclastblock;
+ tmplabel = makepclabel();
+
+ switch (compareop) {
+ case ENOTEQU:
+ c = !c;
+ case EEQU:
+ r28 = 2;
+ break;
+ case EGREATEREQU:
+ c = !c;
+ case ELESS:
+ r28 = 0;
+ break;
+ case ELESSEQU:
+ c = !c;
+ case EGREATER:
+ r28 = 1;
+ break;
+ }
+
+ emitpcode(c ? PC_BT : PC_BF, a, r28, label);
+ pcbranch(pclastblock, label);
+ pcbranch(pclastblock, tmplabel);
+ makepcblock();
+ pclabel(pclastblock, tmplabel);
+}
+
+void branch_always(PCodeLabel *label) {
+ emitpcode(PC_B, label);
+ pcbranch(pclastblock, label);
+ makepcblock();
+}
+
+void branch_decrement_always(Opcode opcode, PCodeLabel *label) {
+ PCodeLabel *tmplabel = makepclabel();
+ emitpcode(opcode, label);
+ pcbranch(pclastblock, label);
+ pcbranch(pclastblock, tmplabel);
+ makepcblock();
+ pclabel(pclastblock, tmplabel);
+}
+
+void branch_indirect(Object *obj) {
+ emitpcode(PC_BCTR, obj, 0);
+ makepcblock();
+}
+
+int branch_count_volatiles(void) {
+ int count = 0;
+ int i;
+ RegClass rclass;
+
+ for (rclass = 0; rclass < RegClassMax; rclass++) {
+ for (i = 0; i < n_scratch_registers[rclass]; i++) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+PCodeArg *branch_record_volatiles(PCodeArg *arglist, UInt32 *masks) {
+ int i;
+ RegClass rclass;
+
+ for (rclass = RegClassMax - 1; rclass >= 0; rclass--) {
+ for (i = 0; i < n_scratch_registers[rclass]; i++) {
+ arglist->kind = PCOp_REGISTER;
+ arglist->arg = rclass;
+ arglist->data.reg.reg = scratch_registers[rclass][i];
+ arglist->data.reg.effect = EffectWrite;
+ if (masks[rclass] & (1 << scratch_registers[rclass][i]))
+ arglist->data.reg.effect |= EffectRead;
+ arglist++;
+ }
+ }
+
+ return arglist;
+}
+
+void branch_subroutine(Object *obj, short add_nop, UInt32 *masks) {
+ int count;
+ PCode *pc;
+ PCodeArg *arg;
+
+ count = branch_count_volatiles();
+ if (copts.exceptions && current_statement)
+ count += countexceptionactionregisters(current_statement->dobjstack);
+
+ pc = makepcode(PC_BL, count, obj, 0);
+ arg = branch_record_volatiles(pc->args + 1, masks);
+ if (copts.exceptions && current_statement)
+ noteexceptionactionregisters(current_statement->dobjstack, arg);
+ appendpcode(pclastblock, pc);
+
+ if (add_nop)
+ emitpcode(PC_NOP);
+
+ branch_label(makepclabel());
+ if (copts.exceptions && current_statement)
+ recordexceptionactions(pc, current_statement->dobjstack);
+}
+
+void branch_subroutine_ctr(UInt32 *masks) {
+ int count;
+ PCode *pc;
+ PCodeArg *arg;
+
+ count = branch_count_volatiles();
+ if (copts.exceptions && current_statement)
+ count += countexceptionactionregisters(current_statement->dobjstack);
+
+ pc = makepcode(PC_BCTRL, count);
+ arg = branch_record_volatiles(pc->args + 1, masks);
+ if (copts.exceptions && current_statement)
+ noteexceptionactionregisters(current_statement->dobjstack, arg);
+ appendpcode(pclastblock, pc);
+
+ branch_label(makepclabel());
+ if (copts.exceptions && current_statement)
+ recordexceptionactions(pc, current_statement->dobjstack);
+}
+
+void add_immediate(short dest_reg, short base_reg, Object *obj, SInt16 offset) {
+ short tmp_reg = base_reg;
+
+ if (obj && offset && obj->datatype != DLOCAL) {
+ tmp_reg = used_virtual_registers[RegClass_GPR]++;
+ add_immediate_lo(tmp_reg, base_reg, obj, 0, 1);
+ obj = NULL;
+ }
+
+ if (!obj && !offset)
+ emitpcode(PC_MR, dest_reg, tmp_reg);
+ else
+ emitpcode(PC_ADDI, dest_reg, tmp_reg, obj, offset);
+}
+
+PCode *add_immediate_lo(short dest_reg, short base_reg, Object *obj, SInt16 offset, char add_to_block) {
+ PCode *pc;
+
+ CError_ASSERT(577, obj);
+
+ pc = makepcode(PC_ADDI, dest_reg, base_reg, obj, offset);
+ if (add_to_block)
+ appendpcode(pclastblock, pc);
+ return pc;
+}
+
+PCode *op_absolute_ha(short dest_reg, short base_reg, Object *obj, short offset, char add_to_block) {
+ PCode *pc;
+ int tmp_reg;
+
+ if (obj->datatype == DLOCAL) {
+ pc = makepcode(PC_ADDIS, dest_reg, base_reg, obj, offset);
+ } else if (copts.codegen_pic) {
+ tmp_reg = base_reg;
+ CError_ASSERT(601, tmp_reg);
+ pc = makepcode(PC_ADDIS, dest_reg, tmp_reg, obj, offset);
+ } else {
+ CError_ASSERT(606, base_reg == 0);
+ pc = makepcode(PC_LIS, dest_reg, obj, offset);
+ }
+
+ if (add_to_block)
+ appendpcode(pclastblock, pc);
+ return pc;
+}
+
+void load_store_register(Opcode opcode, short dest_reg, short base_reg, Object *obj, SInt32 offset) {
+ short addi_tmp;
+ short offset_reg1;
+ short offset_reg2;
+
+ offset_reg1 = base_reg;
+ if (obj && offset && obj->datatype != DLOCAL) {
+ offset_reg1 = used_virtual_registers[RegClass_GPR]++;
+ add_immediate_lo(offset_reg1, base_reg, obj, 0, 1);
+ obj = NULL;
+ }
+
+ if (offset != (short)offset) {
+ if (opcode == PC_LWZ && dest_reg == 12)
+ offset_reg2 = 12;
+ else if (opcode == PC_LWZ && dest_reg == 11)
+ offset_reg2 = 11;
+ else
+ offset_reg2 = used_virtual_registers[RegClass_GPR]++;
+
+ emitpcode(PC_ADDIS, offset_reg2, offset_reg1, 0, (short) ((offset >> 16) + ((offset & 0x8000) >> 15)));
+ offset = (short) offset;
+ offset_reg1 = offset_reg2;
+ }
+
+ if (opcode == PC_STVX || opcode == PC_LVX) {
+ offset_reg2 = 0;
+ if (obj) {
+ addi_tmp = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_ADDI, addi_tmp, offset_reg1, obj, offset);
+ offset_reg1 = addi_tmp;
+ } else if (offset) {
+ offset_reg2 = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_LI, offset_reg2, offset);
+ }
+ if (!offset_reg2)
+ emitpcode(opcode, dest_reg, 0, offset_reg1);
+ else
+ emitpcode(opcode, dest_reg, offset_reg1, offset_reg2);
+ } else {
+ emitpcode(opcode, dest_reg, offset_reg1, obj, offset);
+ }
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Peephole.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Peephole.c
new file mode 100644
index 0000000..151e448
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Peephole.c
@@ -0,0 +1,2753 @@
+#include "compiler/Peephole.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/InstrSelection.h"
+#include "compiler/PCode.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+#include "compiler/Scheduler.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/Alias.h"
+#include "compiler/CParser.h"
+
+typedef int (*PeepholeFunc)(PCode *instr, UInt32 *masks);
+
+typedef struct Pattern {
+ struct Pattern *next;
+ PeepholeFunc func;
+} Pattern;
+
+typedef struct LiveRegs {
+ UInt32 x0;
+ UInt32 x4;
+ UInt32 x8;
+ UInt32 xC;
+} LiveRegs;
+
+static LiveRegs *liveregs[RegClassMax];
+static Pattern *peepholepatterns[OPCODE_MAX];
+static PCode **defininginstruction;
+
+static void computeregisterusedefs(void) {
+ PCodeBlock *block;
+ PCode *instr;
+ PCodeArg *op;
+ int i;
+ RegClass rclass;
+ LiveRegs *lr;
+ UInt32 array1[RegClassMax];
+ UInt32 array2[RegClassMax];
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ for (rclass = 0; rclass < RegClassMax; rclass++) {
+ array1[rclass] = 0;
+ array2[rclass] = 0;
+ }
+
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ for (op = instr->args, i = instr->argCount; i--; op++) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ (op->data.reg.effect & EffectRead) &&
+ !((1 << op->data.reg.reg) & array2[op->arg])
+ )
+ array1[op->arg] |= 1 << op->data.reg.reg;
+ }
+
+ for (op = instr->args, i = instr->argCount; i--; op++) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ (op->data.reg.effect & EffectWrite) &&
+ !((1 << op->data.reg.reg) & array1[op->arg])
+ )
+ array2[op->arg] |= 1 << op->data.reg.reg;
+ }
+ }
+
+ for (rclass = 0; rclass < RegClassMax; rclass++) {
+ lr = liveregs[rclass] + block->blockIndex;
+ lr->x0 = array1[rclass];
+ lr->x4 = array2[rclass];
+ if (rclass == RegClass_GPR) {
+ lr->x8 = 1 << 1;
+ lr->xC = 1 << 1;
+ } else {
+ lr->x8 = 0;
+ lr->xC = 0;
+ }
+ }
+ }
+}
+
+static void computeliveness(LiveRegs *lrarray, UInt32 x) {
+ PCodeBlock *block;
+ LiveRegs *lr;
+ PCLink *link;
+ UInt32 newC;
+ UInt32 new8;
+ int i;
+ int flag;
+
+ flag = 1;
+ while (flag) {
+ flag = 0;
+ i = pcblockcount;
+ while (i) {
+ if ((block = depthfirstordering[--i])) {
+ lr = lrarray + block->blockIndex;
+ newC = x;
+ for (link = block->successors; link; link = link->nextLink)
+ newC |= lrarray[link->block->blockIndex].x8;
+ lr->xC = newC;
+
+ new8 = lr->x0 | (lr->xC & ~lr->x4);
+ if (new8 != lr->x8) {
+ lr->x8 = new8;
+ flag = 1;
+ }
+ }
+ }
+ }
+}
+
+static void computeliveregisters(Object *func) {
+ Type *returntype;
+ RegClass rclass;
+
+ returntype = TYPE_FUNC(func->type)->functype;
+
+ for (rclass = 0; rclass < RegClassMax; rclass++)
+ liveregs[rclass] = lalloc(sizeof(LiveRegs) * pcblockcount);
+
+ computedepthfirstordering();
+ computeregisterusedefs();
+
+ if (TYPE_FITS_IN_REGISTER(returntype)) {
+ liveregs[RegClass_GPR][epilogue->blockIndex].x0 |= 1 << 3;
+ if (TYPE_IS_8BYTES(returntype))
+ liveregs[RegClass_GPR][epilogue->blockIndex].x0 |= 1 << 4;
+ } else if (IS_TYPE_FLOAT(returntype)) {
+ liveregs[RegClass_FPR][epilogue->blockIndex].x0 |= 1 << 1;
+ } else if (IS_TYPE_VECTOR(returntype)) {
+ liveregs[RegClass_VR][epilogue->blockIndex].x0 |= 1 << 2;
+ }
+
+ for (rclass = 0; rclass < RegClassMax; rclass++) {
+ if (rclass == RegClass_GPR)
+ computeliveness(liveregs[rclass], 2);
+ else
+ computeliveness(liveregs[rclass], 0);
+ }
+}
+
+static void computeinstructionpredecessors(PCodeBlock *block) {
+ PCode *nop;
+ RegClass rclass;
+ SInt32 i;
+ SInt32 defID;
+ SInt32 totalOps;
+ PCode *instr;
+ PCodeArg *op;
+ PCode *array[RegClassMax][32];
+
+ nop = makepcode(PC_NOP);
+ for (rclass = 0; rclass < RegClassMax; rclass++) {
+ for (i = 0; i < 32; i++) {
+ array[rclass][i] = nop;
+ }
+ }
+
+ totalOps = 0;
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode)
+ totalOps += instr->argCount;
+
+ if (totalOps) {
+ defininginstruction = oalloc(sizeof(PCode *) * totalOps);
+ for (i = 0; i < totalOps; i++)
+ defininginstruction[i] = nop;
+
+ defID = 0;
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ instr->defID = defID;
+
+ for (i = 0, op = instr->args; i < instr->argCount; i++, op++) {
+ if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectRead))
+ defininginstruction[defID + i] = array[op->arg][op->data.reg.reg];
+ }
+
+ for (i = 0, op = instr->args; i < instr->argCount; i++, op++) {
+ if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectWrite))
+ array[op->arg][op->data.reg.reg] = instr;
+ }
+
+ defID += instr->argCount;
+ }
+ }
+}
+
+static int dead(PCode *instr, UInt32 *masks) {
+ int i;
+ PCodeArg *op;
+
+ if (instr->block->flags & (fIsProlog | fIsEpilogue))
+ return 0;
+ if (instr->flags & (fIsBranch | fIsWrite | fIsCall | fIsVolatile | fSideEffects))
+ return 0;
+ if (!instr->block->predecessors)
+ return 1;
+
+ for (op = instr->args, i = instr->argCount; i--; op++) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ (op->data.reg.effect & EffectWrite) &&
+ ((1 << op->data.reg.reg) & masks[op->arg])
+ )
+ return 0;
+ }
+
+ return 1;
+}
+
+static int definedbetween(PCode *start, PCode *end, PCodeArg *checkOp) {
+ PCode *instr;
+ PCodeArg *op;
+ int i;
+
+ for (instr = start->prevPCode; instr != end; instr = instr->prevPCode) {
+ for (op = instr->args, i = instr->argCount; i--; op++) {
+ if (PC_OP_IS_WRITE_REGISTER(op, checkOp->arg, checkOp->data.reg.reg))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int usedbetween(PCode *start, PCode *end, PCodeArg *checkOp) {
+ PCode *instr;
+ PCodeArg *op;
+ int i;
+
+ for (instr = start->prevPCode; instr != end; instr = instr->prevPCode) {
+ for (op = instr->args, i = instr->argCount; i--; op++) {
+ if (PC_OP_IS_READ_REGISTER(op, checkOp->arg, checkOp->data.reg.reg))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int isSPRlive(PCode *instr, int reg) {
+ PCode *scan;
+ PCodeArg *op;
+ int i;
+
+ for (scan = instr->nextPCode; scan; scan = scan->nextPCode) {
+ for (op = scan->args, i = scan->argCount; i--; op++) {
+ if (PC_OP_IS_READ_REGISTER(op, RegClass_SPR, reg))
+ return 1;
+
+ if (PC_OP_IS_WRITE_REGISTER(op, RegClass_SPR, reg))
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static SInt32 extractedbits(PCode *instr) {
+ SInt32 a = instr->args[2].data.imm.value;
+ SInt32 b = instr->args[3].data.imm.value;
+ SInt32 c = instr->args[4].data.imm.value;
+ SInt32 val;
+
+ if (b <= c)
+ val = ((b > 31) ? 0 : (0xFFFFFFFFu >> b)) & ~(((c + 1) > 31) ? 0 : (0xFFFFFFFFu >> (c + 1)));
+ else
+ val = ((b > 31) ? 0 : (0xFFFFFFFFu >> b)) | ~(((c + 1) > 31) ? 0 : (0xFFFFFFFFu >> (c + 1)));
+
+ return ((UInt32) val >> a) | (val << (32 - a));
+}
+
+static int canmergemasks(SInt32 b1, SInt32 c1, SInt32 a, SInt32 b2, SInt32 c2, short *first, short *last) {
+ SInt32 val1;
+ SInt32 val2;
+
+ if (b1 <= c1)
+ val1 = ((b1 > 31) ? 0 : (0xFFFFFFFFu >> b1)) & ~(((c1 + 1) > 31) ? 0 : (0xFFFFFFFFu >> (c1 + 1)));
+ else
+ val1 = ((b1 > 31) ? 0 : (0xFFFFFFFFu >> b1)) | ~(((c1 + 1) > 31) ? 0 : (0xFFFFFFFFu >> (c1 + 1)));
+
+ if (b2 <= c2)
+ val2 = ((b2 > 31) ? 0 : (0xFFFFFFFFu >> b2)) & ~(((c2 + 1) > 31) ? 0 : (0xFFFFFFFFu >> (c2 + 1)));
+ else
+ val2 = ((b2 > 31) ? 0 : (0xFFFFFFFFu >> b2)) | ~(((c2 + 1) > 31) ? 0 : (0xFFFFFFFFu >> (c2 + 1)));
+
+ return ismaskconstant(val2 & ((val1 << a) | ((UInt32) val1 >> (32 - a))), first, last);
+}
+
+static int canuseupdatetest(PCodeBlock *block, PCode *instr, int count1, int count2, int count3, int count4, int count5) {
+ int i;
+ PCLink *link;
+
+ while (instr) {
+ if (++count1 > 17)
+ return 1;
+
+ switch (instr->op) {
+ case PC_DIVW:
+ case PC_DIVWU:
+ case PC_MULHW:
+ case PC_MULHWU:
+ case PC_MULLI:
+ case PC_MULLW:
+ return count3 == 0;
+ case PC_MTXER:
+ case PC_MTCTR:
+ case PC_MTLR:
+ case PC_MTCRF:
+ case PC_MTMSR:
+ case PC_MTSPR:
+ case PC_MFMSR:
+ case PC_MFSPR:
+ case PC_MFXER:
+ case PC_MFCTR:
+ case PC_MFLR:
+ case PC_MFCR:
+ case PC_ECIWX:
+ case PC_ECOWX:
+ case PC_DCBI:
+ case PC_ICBI:
+ case PC_MCRFS:
+ case PC_MCRXR:
+ case PC_MFTB:
+ case PC_MFSR:
+ case PC_MTSR:
+ case PC_MFSRIN:
+ case PC_MTSRIN:
+ case PC_MTFSB0:
+ case PC_MTFSB1:
+ case PC_MTFSFI:
+ case PC_SC:
+ case PC_TLBIA:
+ case PC_TLBIE:
+ case PC_TLBLD:
+ case PC_TLBLI:
+ case PC_TLBSYNC:
+ case PC_TW:
+ case PC_TRAP:
+ case PC_TWI:
+ case PC_MFROM:
+ case PC_DSA:
+ case PC_ESA:
+ return 1;
+ case PC_CRAND:
+ case PC_CRANDC:
+ case PC_CREQV:
+ case PC_CRNAND:
+ case PC_CRNOR:
+ case PC_CROR:
+ case PC_CRORC:
+ case PC_CRXOR:
+ case PC_MCRF:
+ if (++count5 > 1)
+ return 1;
+ }
+
+ if (instr->flags & (fIsRead | fIsWrite)) {
+ if (++count4 > 1)
+ return 1;
+ } else if (instr->flags & fIsBranch) {
+ if (++count2 > 2)
+ return 1;
+
+ for (i = 0; i < instr->argCount; i++) {
+ if (PC_OP_IS_ANY_REGISTER(&instr->args[i], RegClass_CRFIELD)) {
+ ++count3;
+ break;
+ }
+ }
+ }
+
+ instr = instr->nextPCode;
+ }
+
+ if (block && block->successors) {
+ for (link = block->successors; link; link = link->nextLink) {
+ if (link->block && !canuseupdatetest(link->block, link->block->firstPCode, count1, count2, count3, count4, count5))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int canuseupdate(PCode *instr) {
+ return canuseupdatetest(instr->block, instr->nextPCode, 0, 0, 0, 0, 0);
+}
+
+static int MR_Rx_Rx(PCode *instr, UInt32 *masks) {
+ if (
+ instr->args[0].data.reg.reg == instr->args[1].data.reg.reg &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit)
+ )
+ {
+ deletepcode(instr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int FMR_Fx_Fx(PCode *instr, UInt32 *masks) {
+ if (
+ instr->args[0].data.reg.reg == instr->args[1].data.reg.reg &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit)
+ )
+ {
+ deletepcode(instr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int VMR_Vx_Vx(PCode *instr, UInt32 *masks) {
+ if (
+ instr->args[0].data.reg.reg == instr->args[1].data.reg.reg &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit)
+ )
+ {
+ deletepcode(instr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int MR_MR(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ defInstr->op == PC_MR &&
+ instr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg &&
+ !definedbetween(instr, defInstr, &instr->args[0]) &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit)
+ )
+ {
+ deletepcode(instr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int FMR_FMR(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ defInstr->op == PC_FMR &&
+ instr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit) &&
+ !definedbetween(instr, defInstr, &instr->args[0])
+ )
+ {
+ deletepcode(instr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int VMR_VMR(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ defInstr->op == PC_VMR &&
+ instr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit) &&
+ !definedbetween(instr, defInstr, &instr->args[0])
+ )
+ {
+ deletepcode(instr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int VMR_VMRP(PCode *instr, UInt32 *masks) {
+ PCode *prev = instr->prevPCode;
+ PCode *next = instr->nextPCode;
+ int prevFlag = 0;
+ int prevPermute = 0;
+ int nextFlag = 0;
+ int nextPermute = 0;
+
+ if (prev) {
+ prevFlag = (prev->flags & fOpTypeMask) == fOpTypeVR;
+ prevPermute = uses_vpermute_unit(prev);
+ }
+ if (next) {
+ nextFlag = (next->flags & fOpTypeMask) == fOpTypeVR;
+ nextPermute = uses_vpermute_unit(next);
+ }
+
+ if (prev) {
+ if (next) {
+ if (prevFlag && !prevPermute) {
+ if (nextFlag) {
+ if (!nextPermute) {
+ change_opcode(instr, PC_VMRP);
+ return 1;
+ }
+ } else {
+ change_opcode(instr, PC_VMRP);
+ return 1;
+ }
+ }
+ } else {
+ if (prevFlag && !prevPermute) {
+ change_opcode(instr, PC_VMRP);
+ return 1;
+ }
+ }
+ } else {
+ if (next && nextFlag && !nextPermute) {
+ change_opcode(instr, PC_VMRP);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int MR_CMPI(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+ PCodeArg op;
+
+ if (
+ instr->args[0].data.reg.reg == 0 &&
+ instr->args[2].data.imm.value == 0 &&
+ (PCODE_FLAG_SET_F(defInstr) & (fSideEffects | fCanSetRecordBit | fOpTypeGPR)) == (fCanSetRecordBit | fOpTypeGPR) &&
+ !usedbetween(instr, defInstr, &instr->args[0]) &&
+ !definedbetween(instr, defInstr, &instr->args[0])
+ )
+ {
+ if (defInstr->op == PC_ADDI) {
+ op.kind = PCOp_REGISTER;
+ op.arg = RegClass_SPR;
+ op.data.reg.reg = 0;
+ op.data.reg.effect = EffectRead | EffectWrite;
+ if (usedbetween(instr, defInstr, &op))
+ return 0;
+ }
+
+ pcsetrecordbit(defInstr);
+ deletepcode(instr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int EXTSB_RLWINM(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ defInstr->op == PC_EXTSB &&
+ (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) &&
+ !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) &&
+ !definedbetween(instr, defInstr, &defInstr->args[1]) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0]) &&
+ (extractedbits(instr) & 0xFFFFFF00) == 0
+ )
+ {
+ instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg;
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+ deletepcode(defInstr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int EXTSH_RLWINM(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ defInstr->op == PC_EXTSH &&
+ (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) &&
+ !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) &&
+ !definedbetween(instr, defInstr, &defInstr->args[1]) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0]) &&
+ (extractedbits(instr) & 0xFFFF0000) == 0
+ )
+ {
+ instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg;
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+ deletepcode(defInstr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int LBZ_RLWINM(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ (defInstr->op == PC_LBZ || defInstr->op == PC_LBZX) &&
+ instr->args[2].data.imm.value == 0 &&
+ instr->args[3].data.imm.value <= 24 &&
+ instr->args[4].data.imm.value == 31 &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit) &&
+ (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0]) &&
+ !definedbetween(instr, defInstr, &instr->args[0]) &&
+ !usedbetween(instr, defInstr, &instr->args[0])
+ )
+ {
+ defInstr->args[0].data.reg.reg = instr->args[0].data.reg.reg;
+ deletepcode(instr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int LHZ_RLWINM(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ (defInstr->op == PC_LHZ || defInstr->op == PC_LHZX) &&
+ instr->args[2].data.imm.value == 0 &&
+ instr->args[3].data.imm.value <= 16 &&
+ instr->args[4].data.imm.value == 31 &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit) &&
+ (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0]) &&
+ !definedbetween(instr, defInstr, &instr->args[0]) &&
+ !usedbetween(instr, defInstr, &instr->args[0])
+ )
+ {
+ defInstr->args[0].data.reg.reg = instr->args[0].data.reg.reg;
+ deletepcode(instr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int LHA_EXTSH(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ defInstr->op == PC_LHA &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit) &&
+ (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0]) &&
+ !definedbetween(instr, defInstr, &instr->args[0]) &&
+ !usedbetween(instr, defInstr, &instr->args[0])
+ )
+ {
+ defInstr->args[0].data.reg.reg = instr->args[0].data.reg.reg;
+ deletepcode(instr);
+ return 1;
+ }
+
+ if (
+ defInstr->op == PC_EXTSB &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit)
+ )
+ {
+ if (defInstr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg) {
+ if (
+ !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg)) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0])
+ )
+ {
+ change_opcode(instr, PC_EXTSB);
+ deletepcode(defInstr);
+ return 1;
+ }
+ } else {
+ if (!definedbetween(instr, defInstr, &defInstr->args[1])) {
+ change_opcode(instr, PC_EXTSB);
+ instr->args[1] = defInstr->args[1];
+ } else {
+ change_opcode(instr, PC_MR);
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int ADDI_L_S(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+ SInt32 addleft;
+ SInt32 addright;
+
+ if (defInstr->op == PC_ADDI && instr->args[2].kind == PCOp_IMMEDIATE) {
+ if (!PC_OP_IS_REGISTER(&instr->args[0], RegClass_GPR, instr->args[1].data.reg.reg)) {
+ if (
+ instr->args[2].data.imm.value == 0 &&
+ defInstr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg &&
+ !usedbetween(instr, defInstr, &defInstr->args[0]) &&
+ (!(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg)) || canuseupdate(instr))
+ )
+ {
+ if (!(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) {
+ instr->args[2] = defInstr->args[2];
+ } else {
+ instr->op++;
+ instr->args[1].data.reg.effect |= EffectWrite;
+ instr->args[2] = defInstr->args[2];
+ }
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+ deletepcode(defInstr);
+ return 1;
+ }
+
+ addleft = 0x1FFFF;
+ addright = instr->args[2].data.imm.value;
+ if (defInstr->args[2].kind == PCOp_IMMEDIATE) {
+ addleft = defInstr->args[2].data.imm.value;
+ } else if (defInstr->args[2].kind == PCOp_MEMORY) {
+ if (defInstr->args[2].data.mem.obj->datatype == DLOCAL)
+ addleft = defInstr->args[2].data.mem.offset + defInstr->args[2].data.mem.obj->u.var.uid;
+ else if (addright == 0)
+ addleft = 0;
+ else
+ return 0;
+ }
+
+ if (!FITS_IN_SHORT(addleft + addright))
+ return 0;
+
+ if (
+ !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg)) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0]) &&
+ !definedbetween(instr, defInstr, &defInstr->args[1])
+ )
+ {
+ instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg;
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+
+ if (defInstr->args[2].kind == PCOp_MEMORY) {
+ instr->args[2] = defInstr->args[2];
+ instr->args[2].data.mem.offset += addright;
+ if (instr->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000)) {
+ instr->alias = make_alias(
+ instr->args[2].data.mem.obj,
+ instr->args[2].data.mem.offset,
+ nbytes_loaded_or_stored_by(instr)
+ );
+ }
+ } else {
+ instr->args[2].data.imm.value = addleft + addright;
+ }
+
+ deletepcode(defInstr);
+ return 1;
+ }
+
+ if (
+ instr->args[1].data.reg.reg != defInstr->args[1].data.reg.reg &&
+ !definedbetween(instr, defInstr, &defInstr->args[1])
+ )
+ {
+ if (defInstr->args[2].kind == PCOp_MEMORY && defInstr->args[2].data.mem.obj->datatype != DLOCAL)
+ return 0;
+
+ instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg;
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+
+ if (defInstr->args[2].kind == PCOp_MEMORY) {
+ instr->args[2] = defInstr->args[2];
+ instr->args[2].data.mem.offset += addright;
+ if (instr->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000)) {
+ instr->alias = make_alias(
+ instr->args[2].data.mem.obj,
+ instr->args[2].data.mem.offset,
+ nbytes_loaded_or_stored_by(instr)
+ );
+ }
+ } else {
+ instr->args[2].data.imm.value = addleft + addright;
+ }
+
+ return 1;
+ }
+ }
+ } else {
+ if (
+ defInstr->op == PC_MR &&
+ PC_OP_IS_ANY_REGISTER(&defInstr->args[1], RegClass_GPR) &&
+ defInstr->args[1].data.reg.reg != 0 &&
+ !definedbetween(instr, defInstr, &defInstr->args[1])
+ )
+ {
+ instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg;
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+ }
+ }
+
+ return 0;
+}
+
+static int ADDI_LU_SU(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ instr->args[2].kind == PCOp_IMMEDIATE &&
+ defInstr->args[2].kind == PCOp_IMMEDIATE &&
+ defInstr->op == PC_ADDI &&
+ defInstr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg &&
+ !(instr->args[0].arg == instr->args[1].arg && instr->args[0].data.reg.reg == instr->args[1].data.reg.reg) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0]) &&
+ FITS_IN_SHORT(instr->args[2].data.imm.value + defInstr->args[2].data.imm.value)
+ )
+ {
+ if ((instr->args[2].data.imm.value + defInstr->args[2].data.imm.value) == 0) {
+ instr->op--;
+ instr->args[1].data.reg.effect &= ~EffectWrite;
+ instr->args[2].data.imm.value = 0;
+ } else {
+ instr->args[2].data.imm.value += defInstr->args[2].data.imm.value;
+ }
+
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+ deletepcode(defInstr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int L_S_ADDI(PCode *instr, UInt32 *masks) {
+ PCode *scan;
+ PCodeArg *op;
+ int i;
+ short reg;
+
+ if (instr->args[2].kind != PCOp_IMMEDIATE)
+ return 0;
+
+ reg = instr->args[1].data.reg.reg;
+ if (!canuseupdate(instr))
+ return 0;
+
+ for (scan = instr->nextPCode; scan; scan = scan->nextPCode) {
+ for (op = scan->args, i = scan->argCount; i--; op++) {
+ if (PC_OP_IS_READ_REGISTER(op, RegClass_GPR, reg))
+ return 0;
+
+ if (PC_OP_IS_WRITE_REGISTER(op, RegClass_GPR, reg)) {
+ if (scan->op != PC_ADDI)
+ return 0;
+ if (scan->args[2].kind != PCOp_IMMEDIATE)
+ return 0;
+
+ if (
+ instr->args[2].data.imm.value == scan->args[2].data.imm.value &&
+ scan->args[0].data.reg.reg == scan->args[1].data.reg.reg &&
+ !(instr->args[0].arg == instr->args[1].arg && instr->args[0].data.reg.reg == instr->args[1].data.reg.reg)
+ )
+ {
+ if (!(masks[RegClass_GPR] & (1 << scan->args[0].data.reg.reg))) {
+ instr->args[2] = scan->args[2];
+ } else {
+ instr->op++;
+ instr->args[1].data.reg.effect |= EffectWrite;
+ instr->args[2] = scan->args[2];
+ }
+
+ change_opcode(scan, PC_NOP);
+ change_num_operands(scan, 0);
+ deletepcode(scan);
+ return 1;
+ }
+
+ return 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int LI_CMP_BC(PCode *instr, UInt32 *masks) {
+ PCode *defInstr;
+ PCode *defInstr2;
+ PCLink *link;
+ PCLink **ptr;
+
+ if (instr->args[1].data.imm.value == 2) {
+ defInstr = defininginstruction[instr->defID];
+ if ((defInstr->op == PC_CMPLI || defInstr->op == PC_CMPI) && defInstr->args[0].data.reg.reg == 0) {
+ defInstr2 = defininginstruction[defInstr->defID + 1];
+ if (
+ defInstr2->op == PC_LI &&
+ defInstr2->args[1].kind == PCOp_IMMEDIATE &&
+ (instr->op == PC_BT) == (defInstr2->args[1].data.imm.value == defInstr->args[2].data.imm.value)
+ )
+ {
+ change_opcode(instr, PC_B);
+ instr->args[0] = instr->args[2];
+ change_num_operands(instr, 1);
+
+ defininginstruction[instr->defID] = defininginstruction[instr->defID + 1];
+
+ for (ptr = &instr->block->successors; (link = *ptr); ptr = &link->nextLink) {
+ if (link->block == instr->block->nextBlock) {
+ *ptr = link->nextLink;
+ break;
+ }
+ }
+
+ for (ptr = &instr->block->nextBlock->predecessors; (link = *ptr); ptr = &link->nextLink) {
+ if (link->block == instr->block) {
+ *ptr = link->nextLink;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int RLWINM_CMPLI_BC(PCode *instr, UInt32 *masks) {
+ PCode *defInstr;
+ PCode *defInstr2;
+
+ if (instr->args[1].data.imm.value == 2) {
+ defInstr = defininginstruction[instr->defID];
+ if (defInstr->op == PC_CMPLI && defInstr->args[0].data.reg.reg == 0 && defInstr->args[2].data.imm.value == 0) {
+ defInstr2 = defininginstruction[defInstr->defID + 1];
+ if (
+ (PCODE_FLAG_SET_F(defInstr2) & (fSideEffects | fCanSetRecordBit | fOpTypeGPR)) == (fCanSetRecordBit | fOpTypeGPR) &&
+ !usedbetween(defInstr, defInstr2, &defInstr->args[0]) &&
+ !definedbetween(defInstr, defInstr2, &defInstr->args[0])
+ )
+ {
+ pcsetrecordbit(defInstr2);
+ defininginstruction[instr->defID] = defininginstruction[defInstr->defID + 1];
+ deletepcode(defInstr);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int LBZ_EXTSB_CMPI_BC(PCode *instr, UInt32 *masks) {
+ PCode *defInstr;
+ PCode *defInstr2;
+
+ if (instr->args[1].data.imm.value == 2) {
+ defInstr = defininginstruction[instr->defID];
+ if (
+ (
+ (defInstr->op == PC_CMPI || defInstr->op == PC_CMPLI) &&
+ defInstr->args[2].data.imm.value >= 0 &&
+ defInstr->args[2].data.imm.value <= 127
+ )
+ ||
+ (
+ (defInstr->op == PC_EXTSB || defInstr->op == PC_EXTSH) &&
+ (PCODE_FLAG_SET_F(defInstr) & fRecordBit)
+ )
+ )
+ {
+ defInstr2 = defininginstruction[defInstr->defID + 1];
+ if (
+ defInstr2->op == PC_EXTSB &&
+ defininginstruction[defInstr2->defID + 1]->op == PC_LBZ &&
+ !(masks[RegClass_GPR] & (1 << defInstr2->args[0].data.reg.reg)) &&
+ !usedbetween(instr, defInstr, &defInstr2->args[0]) &&
+ !usedbetween(defInstr, defInstr2, &defInstr2->args[0]) &&
+ !definedbetween(defInstr, defInstr2, &defInstr2->args[1])
+ )
+ {
+ defInstr->args[1].data.reg.reg = defInstr2->args[1].data.reg.reg;
+ defininginstruction[defInstr->defID + 1] = defininginstruction[defInstr2->defID + 1];
+ deletepcode(defInstr2);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int FRSP_STFS(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID];
+
+ if (
+ defInstr->op == PC_FRSP &&
+ !(masks[RegClass_FPR] & (1 << defInstr->args[0].data.reg.reg)) &&
+ !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) &&
+ !definedbetween(instr, defInstr, &defInstr->args[1]) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0])
+ )
+ {
+ instr->args[0].data.reg.reg = defInstr->args[1].data.reg.reg;
+ defininginstruction[instr->defID] = defininginstruction[defInstr->defID + 1];
+ deletepcode(defInstr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int NOT_AND(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 2];
+
+ if (
+ defInstr->op == PC_NOT &&
+ (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) &&
+ !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) &&
+ !definedbetween(instr, defInstr, &defInstr->args[1]) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0])
+ )
+ {
+ instr->args[2].data.reg.reg = defInstr->args[1].data.reg.reg;
+ defininginstruction[instr->defID + 2] = defininginstruction[defInstr->defID + 1];
+ change_opcode(instr, PC_ANDC);
+ deletepcode(defInstr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int LI_MR(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ defInstr->op == PC_LI &&
+ (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0])
+ )
+ {
+ change_opcode(instr, PC_LI);
+ instr->args[1] = defInstr->args[1];
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+ deletepcode(defInstr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int VSPLTIS_VMR(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+ short opcode = defInstr->op;
+
+ if (
+ (opcode == PC_VSPLTISB || opcode == PC_VSPLTISH || opcode == PC_VSPLTISW) &&
+ (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_VR] & (1 << defInstr->args[0].data.reg.reg))) &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0])
+ )
+ {
+ change_opcode(instr, opcode);
+ instr->args[1] = defInstr->args[1];
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+ deletepcode(defInstr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int L_MR(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ (defInstr->flags & fIsRead) &&
+ !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg)) &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0]) &&
+ !usedbetween(instr, defInstr, &instr->args[0]) &&
+ !definedbetween(instr, defInstr, &instr->args[0])
+ )
+ {
+ defInstr->args[0].data.reg.reg = instr->args[0].data.reg.reg;
+ deletepcode(instr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int L_FMR(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ (defInstr->flags & fIsRead) &&
+ !(masks[RegClass_FPR] & (1 << defInstr->args[0].data.reg.reg)) &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0]) &&
+ !usedbetween(instr, defInstr, &instr->args[0]) &&
+ !definedbetween(instr, defInstr, &instr->args[0])
+ )
+ {
+ defInstr->args[0].data.reg.reg = instr->args[0].data.reg.reg;
+ deletepcode(instr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int L_S(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID];
+ SInt32 isIndexed;
+ SInt32 isFloat;
+ SInt32 isVector;
+ PCode *scan;
+ SInt32 loadSize;
+ SInt32 defInstrOffset;
+ SInt32 scanOffset;
+ SInt32 storeSize;
+
+ if (PCODE_FLAG_SET_F(instr) & (fIsVolatile | fSideEffects | fUpdatesPtr))
+ return 0;
+ if (PCODE_FLAG_SET_F(defInstr) & (fIsVolatile | fSideEffects | fUpdatesPtr))
+ return 0;
+
+ if (
+ (defInstr->flags & fIsRead) &&
+ PC_OP_IS_REGISTER(&defInstr->args[1], RegClass_GPR, instr->args[1].data.reg.reg) &&
+ defInstr->args[2].kind == instr->args[2].kind &&
+ !definedbetween(instr, defInstr, &instr->args[1])
+ )
+ {
+ if (instr->args[2].kind == PCOp_IMMEDIATE) {
+ if (instr->args[2].data.imm.value != defInstr->args[2].data.imm.value)
+ return 0;
+ } else if (instr->args[2].kind == PCOp_MEMORY) {
+ if (instr->args[2].data.mem.offset != defInstr->args[2].data.mem.offset ||
+ instr->args[2].data.mem.obj != defInstr->args[2].data.mem.obj)
+ return 0;
+ } else if (instr->args[2].kind == PCOp_REGISTER && instr->args[2].arg == RegClass_GPR) {
+ if (instr->args[2].data.reg.reg != defInstr->args[2].data.reg.reg ||
+ definedbetween(instr, defInstr, &instr->args[2]))
+ return 0;
+ } else {
+ return 0;
+ }
+
+ isIndexed = 0;
+ isFloat = 0;
+ isVector = 0;
+ switch (defInstr->op) {
+ case PC_LBZX:
+ isIndexed = 1;
+ case PC_LBZ:
+ loadSize = 1;
+ break;
+ case PC_LHZX:
+ case PC_LHAX:
+ isIndexed = 1;
+ case PC_LHZ:
+ case PC_LHA:
+ loadSize = 2;
+ break;
+ case PC_LWZX:
+ isIndexed = 1;
+ case PC_LWZ:
+ loadSize = 4;
+ break;
+ case PC_LFSX:
+ isIndexed = 1;
+ case PC_LFS:
+ isFloat = 1;
+ loadSize = 4;
+ break;
+ case PC_LFDX:
+ isIndexed = 1;
+ case PC_LFD:
+ isFloat = 1;
+ loadSize = 8;
+ break;
+ case PC_LVX:
+ case PC_LVXL:
+ isIndexed = 1;
+ isVector = 1;
+ loadSize = 16;
+ break;
+ default:
+ return 0;
+ }
+
+ switch (instr->op) {
+ case PC_STBX:
+ if (!isIndexed) return 0;
+ case PC_STB:
+ if (isFloat) return 0;
+ if (loadSize != 1) return 0;
+ break;
+ case PC_STHX:
+ if (!isIndexed) return 0;
+ case PC_STH:
+ if (isFloat) return 0;
+ if (loadSize != 2) return 0;
+ break;
+ case PC_STWX:
+ if (!isIndexed) return 0;
+ case PC_STW:
+ if (isFloat) return 0;
+ if (loadSize != 4) return 0;
+ break;
+ case PC_STFSX:
+ if (!isIndexed) return 0;
+ case PC_STFS:
+ if (!isFloat) return 0;
+ if (loadSize != 4) return 0;
+ break;
+ case PC_STFDX:
+ if (!isIndexed) return 0;
+ case PC_STFD:
+ if (!isFloat) return 0;
+ if (loadSize != 8) return 0;
+ break;
+ case PC_STVX:
+ case PC_STVXL:
+ if (!isIndexed) return 0;
+ if (!isVector) return 0;
+ if (loadSize != 16) return 0;
+ break;
+ default:
+ return 0;
+ }
+
+ for (scan = instr->prevPCode; scan && scan != defInstr; scan = scan->prevPCode) {
+ if (scan->flags & fIsWrite) {
+ if (scan->args[1].data.reg.reg != instr->args[1].data.reg.reg)
+ return 0;
+ if (scan->args[2].kind != defInstr->args[2].kind)
+ return 0;
+
+ if (scan->args[2].kind == PCOp_MEMORY) {
+ if (instr->args[2].data.mem.obj == scan->args[2].data.mem.obj) {
+ if (instr->args[2].data.mem.offset == defInstr->args[2].data.mem.offset)
+ return 0;
+ defInstrOffset = defInstr->args[2].data.mem.offset;
+ scanOffset = scan->args[2].data.mem.offset;
+ }
+ } else if (scan->args[2].kind == PCOp_IMMEDIATE) {
+ if (instr->args[1].data.reg.reg != scan->args[1].data.reg.reg)
+ return 0;
+ if (instr->args[2].data.imm.value == scan->args[2].data.imm.value)
+ return 0;
+ defInstrOffset = defInstr->args[2].data.imm.value;
+ scanOffset = scan->args[2].data.imm.value;
+ } else {
+ return 0;
+ }
+
+ switch (scan->op) {
+ case PC_STB:
+ case PC_STBX:
+ storeSize = 1;
+ break;
+ case PC_STH:
+ case PC_STHX:
+ storeSize = 2;
+ break;
+ case PC_STW:
+ case PC_STWX:
+ case PC_STFS:
+ case PC_STFSX:
+ storeSize = 4;
+ break;
+ case PC_STFD:
+ case PC_STFDX:
+ storeSize = 8;
+ break;
+ case PC_STVX:
+ case PC_STVXL:
+ storeSize = 16;
+ break;
+ default:
+ return 0;
+ }
+
+ if (defInstrOffset > scanOffset) {
+ if ((scanOffset + storeSize) > defInstrOffset)
+ return 0;
+ } else {
+ if ((defInstrOffset + loadSize) > scanOffset)
+ return 0;
+ }
+ }
+ }
+
+ deletepcode(instr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int RLWINM_RLWINM(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+ short start;
+ short end;
+
+ if (
+ defInstr->op == PC_RLWINM &&
+ !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) &&
+ !definedbetween(instr, defInstr, &defInstr->args[1]) &&
+ !(
+ defInstr->args[0].data.reg.reg == defInstr->args[1].data.reg.reg &&
+ (
+ (defInstr->args[0].data.reg.reg != instr->args[0].data.reg.reg && (masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) ||
+ usedbetween(instr, defInstr, &defInstr->args[0])
+ )
+ ) &&
+ canmergemasks(
+ defInstr->args[3].data.imm.value,
+ defInstr->args[4].data.imm.value,
+ instr->args[2].data.imm.value,
+ instr->args[3].data.imm.value,
+ instr->args[4].data.imm.value,
+ &start, &end)
+ )
+ {
+ if (instr->op == PC_RLWIMI) {
+ if (instr->args[0].data.reg.reg == defInstr->args[0].data.reg.reg)
+ return 0;
+ if (start != instr->args[3].data.imm.value || end != instr->args[4].data.imm.value)
+ return 0;
+ }
+
+ instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg;
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+
+ instr->args[2].data.imm.value = (instr->args[2].data.imm.value + defInstr->args[2].data.imm.value) & 31;
+ instr->args[3].data.imm.value = start;
+ instr->args[4].data.imm.value = end;
+
+ if (
+ (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0])
+ )
+ deletepcode(defInstr);
+
+ return 1;
+ }
+
+ if (
+ defInstr->op == PC_MR &&
+ instr->op == PC_RLWINM &&
+ !definedbetween(instr, defInstr, &defInstr->args[1])
+ )
+ {
+ instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg;
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+
+ if (
+ (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) &&
+ !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0])
+ )
+ deletepcode(defInstr);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int MULLI_MULLI(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ defInstr->op == PC_MULLI &&
+ (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) &&
+ !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) &&
+ !definedbetween(instr, defInstr, &defInstr->args[1]) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0]) &&
+ FITS_IN_SHORT(instr->args[2].data.imm.value * defInstr->args[2].data.imm.value)
+ )
+ {
+ instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg;
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+
+ instr->args[2].data.imm.value *= defInstr->args[2].data.imm.value;
+ deletepcode(defInstr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int ADDI_ADDI(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ defInstr->op == PC_ADDI &&
+ (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) &&
+ !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) &&
+ !definedbetween(instr, defInstr, &defInstr->args[1]) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0]) &&
+ instr->args[2].kind == PCOp_IMMEDIATE &&
+ defInstr->args[2].kind == PCOp_IMMEDIATE &&
+ FITS_IN_SHORT(instr->args[2].data.imm.value + defInstr->args[2].data.imm.value)
+ )
+ {
+ instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg;
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+
+ instr->args[2].data.imm.value += defInstr->args[2].data.imm.value;
+ deletepcode(defInstr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int SRAWI_SRAWI(PCode *instr, UInt32 *masks) {
+ PCode *defInstr = defininginstruction[instr->defID + 1];
+
+ if (
+ defInstr->op == PC_SRAWI &&
+ (defInstr->args[0].data.reg.reg == instr->args[0].data.reg.reg || !(masks[RegClass_GPR] & (1 << defInstr->args[0].data.reg.reg))) &&
+ !(PCODE_FLAG_SET_F(defInstr) & fRecordBit) &&
+ !definedbetween(instr, defInstr, &defInstr->args[1]) &&
+ !usedbetween(instr, defInstr, &defInstr->args[0]) &&
+ instr->args[2].kind == PCOp_IMMEDIATE &&
+ defInstr->args[2].kind == PCOp_IMMEDIATE &&
+ (instr->args[2].data.imm.value + defInstr->args[2].data.imm.value) < 32 &&
+ (instr->args[2].data.imm.value + defInstr->args[2].data.imm.value) > 0
+ )
+ {
+ instr->args[1].data.reg.reg = defInstr->args[1].data.reg.reg;
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr->defID + 1];
+
+ instr->args[2].data.imm.value += defInstr->args[2].data.imm.value;
+ deletepcode(defInstr);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int MR_ADDI(PCode *instr, UInt32 *masks) {
+ PCode *prev = instr->prevPCode;
+ PCode *next = instr->nextPCode;
+ int prevFlag = 0;
+ int nextFlag = 0;
+
+ if (copts.processor == CPU_PPC603e) {
+ if (prev)
+ prevFlag = (prev->flags & fOpTypeMask) == fOpTypeGPR;
+ if (next)
+ nextFlag = (next->flags & fOpTypeMask) == fOpTypeGPR;
+
+ if (
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit) &&
+ instr->argCount >= 2 &&
+ instr->args[1].data.reg.reg != 0 &&
+ (prevFlag || nextFlag)
+ )
+ {
+ change_opcode(instr, PC_ADDI);
+ instr->args[2].kind = PCOp_IMMEDIATE;
+ instr->args[2].data.imm.value = 0;
+ instr->args[2].data.imm.obj = NULL;
+ change_num_operands(instr, 3);
+ }
+ }
+
+ return 0;
+}
+
+static int rotatedefinedusedtest(UInt32 *masks, PCode *instr, PCode *a, PCode *b, PCode *subfic) {
+ PCode *scan;
+ PCodeArg *op;
+ int i;
+ int reg1;
+ int reg2;
+
+ if (
+ (masks[RegClass_GPR] & (1 << subfic->args[0].data.reg.reg)) &&
+ subfic->args[0].data.reg.reg != instr->args[0].data.reg.reg &&
+ subfic->args[0].data.reg.reg != a->args[2].data.reg.reg
+ )
+ return 1;
+
+ for (scan = instr->block->firstPCode; scan != instr->block->lastPCode; scan = scan->nextPCode) {
+ if (scan == a) break;
+ if (scan == b) break;
+ if (scan == subfic) break;
+ }
+
+ reg1 = a->args[1].data.reg.reg;
+ reg2 = subfic->args[1].data.reg.reg;
+ while (scan != instr) {
+ for (op = instr->args, i = instr->argCount; i--; op++) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ (
+ (
+ (op->data.reg.reg == reg1 || op->data.reg.reg == reg2) &&
+ (op->data.reg.effect & EffectWrite)
+ )
+ ||
+ (
+ op->data.reg.reg == subfic->args[0].data.reg.reg && (op->data.reg.effect & EffectRead)
+ )
+ ) &&
+ scan != a &&
+ scan != b &&
+ scan != subfic
+ )
+ return 1;
+ }
+
+ scan = scan->nextPCode;
+ }
+
+ return 0;
+}
+
+static int SRW_SUBFIC_RLW_OR(PCode *instr, UInt32 *masks) {
+ PCode *subfic;
+ PCode *defInstr1 = defininginstruction[instr->defID + 1];
+ PCode *defInstr2 = defininginstruction[instr->defID + 2];
+
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ return 0;
+
+ if (
+ (masks[RegClass_GPR] & (1 << instr->args[1].data.reg.reg)) &&
+ instr->args[1].data.reg.reg != instr->args[0].data.reg.reg
+ )
+ return 0;
+
+ if (
+ (masks[RegClass_GPR] & (1 << instr->args[2].data.reg.reg)) &&
+ instr->args[1].data.reg.reg != instr->args[0].data.reg.reg
+ )
+ return 0;
+
+ if (defInstr1->op != PC_SRW && defInstr1->op != PC_SLW)
+ return 0;
+ if (defInstr2->op != PC_SRW && defInstr2->op != PC_SLW)
+ return 0;
+
+ if (usedbetween(instr, defInstr1, &defInstr1->args[0]))
+ return 0;
+ if (usedbetween(instr, defInstr2, &defInstr2->args[0]))
+ return 0;
+
+ if (
+ defInstr1->op == PC_SRW && defInstr2->op == PC_SLW &&
+ defInstr1->args[1].data.reg.reg == defInstr2->args[1].data.reg.reg
+ )
+ {
+ subfic = defininginstruction[defInstr1->defID + 2];
+ if (
+ subfic->op == PC_SUBFIC &&
+ subfic->args[1].data.reg.reg == defInstr2->args[2].data.reg.reg &&
+ subfic->args[2].data.imm.value == 32
+ )
+ {
+ if (rotatedefinedusedtest(masks, instr, defInstr2, defInstr1, subfic))
+ return 0;
+
+ change_opcode(instr, PC_RLWNM);
+
+ instr->args[1] = defInstr1->args[1];
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr1->defID + 1];
+
+ instr->args[2] = defInstr2->args[2];
+ defininginstruction[instr->defID + 2] = defininginstruction[defInstr2->defID + 2];
+
+ instr->args[3].kind = PCOp_IMMEDIATE;
+ instr->args[3].data.imm.value = 0;
+ instr->args[3].data.imm.obj = NULL;
+
+ instr->args[4].kind = PCOp_IMMEDIATE;
+ instr->args[4].data.imm.value = 31;
+ instr->args[4].data.imm.obj = NULL;
+
+ deletepcode(defInstr1);
+ deletepcode(defInstr2);
+ deletepcode(subfic);
+ return 1;
+ }
+
+ subfic = defininginstruction[defInstr2->defID + 2];
+ if (
+ subfic->op == PC_SUBFIC &&
+ subfic->args[1].data.reg.reg == defInstr1->args[2].data.reg.reg &&
+ subfic->args[2].data.imm.value == 32
+ )
+ {
+ if (rotatedefinedusedtest(masks, instr, defInstr2, defInstr1, subfic))
+ return 0;
+
+ change_opcode(instr, PC_RLWNM);
+
+ instr->args[1] = defInstr1->args[1];
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr1->defID + 1];
+
+ instr->args[2] = defInstr2->args[2];
+ defininginstruction[instr->defID + 2] = defininginstruction[defInstr2->defID + 2];
+
+ instr->args[3].kind = PCOp_IMMEDIATE;
+ instr->args[3].data.imm.value = 0;
+ instr->args[3].data.imm.obj = NULL;
+
+ instr->args[4].kind = PCOp_IMMEDIATE;
+ instr->args[4].data.imm.value = 31;
+ instr->args[4].data.imm.obj = NULL;
+
+ deletepcode(defInstr1);
+ deletepcode(defInstr2);
+ return 1;
+ }
+ } else if (
+ defInstr1->op == PC_SLW && defInstr2->op == PC_SRW &&
+ defInstr1->args[1].data.reg.reg == defInstr2->args[1].data.reg.reg
+ )
+ {
+ subfic = defininginstruction[defInstr1->defID + 2];
+ if (
+ subfic->op == PC_SUBFIC &&
+ subfic->args[1].data.reg.reg == defInstr2->args[2].data.reg.reg &&
+ subfic->args[2].data.imm.value == 32
+ )
+ {
+ if (rotatedefinedusedtest(masks, instr, defInstr1, defInstr2, subfic))
+ return 0;
+
+ change_opcode(instr, PC_RLWNM);
+
+ instr->args[1] = defInstr1->args[1];
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr1->defID + 1];
+
+ instr->args[2] = defInstr1->args[2];
+ defininginstruction[instr->defID + 2] = defininginstruction[defInstr1->defID + 2];
+
+ instr->args[3].kind = PCOp_IMMEDIATE;
+ instr->args[3].data.imm.value = 0;
+ instr->args[3].data.imm.obj = NULL;
+
+ instr->args[4].kind = PCOp_IMMEDIATE;
+ instr->args[4].data.imm.value = 31;
+ instr->args[4].data.imm.obj = NULL;
+
+ deletepcode(defInstr1);
+ deletepcode(defInstr2);
+ return 1;
+ }
+
+ subfic = defininginstruction[defInstr2->defID + 2];
+ if (
+ subfic->op == PC_SUBFIC &&
+ subfic->args[1].data.reg.reg == defInstr1->args[2].data.reg.reg &&
+ subfic->args[2].data.imm.value == 32
+ )
+ {
+ if (rotatedefinedusedtest(masks, instr, defInstr1, defInstr2, subfic))
+ return 0;
+
+ change_opcode(instr, PC_RLWNM);
+
+ instr->args[1] = defInstr1->args[1];
+ defininginstruction[instr->defID + 1] = defininginstruction[defInstr1->defID + 1];
+
+ instr->args[2] = defInstr1->args[2];
+ defininginstruction[instr->defID + 2] = defininginstruction[defInstr1->defID + 2];
+
+ instr->args[3].kind = PCOp_IMMEDIATE;
+ instr->args[3].data.imm.value = 0;
+ instr->args[3].data.imm.obj = NULL;
+
+ instr->args[4].kind = PCOp_IMMEDIATE;
+ instr->args[4].data.imm.value = 31;
+ instr->args[4].data.imm.obj = NULL;
+
+ deletepcode(defInstr1);
+ deletepcode(defInstr2);
+ deletepcode(subfic);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int RLWINM_RLWIMI_STW(PCode *instr, UInt32 *masks) {
+ PCode *newInstr;
+ Boolean isZeroOffset;
+ int flags;
+ PCode *scan;
+ int i;
+ PCode *array[4];
+
+ flags = 0;
+ isZeroOffset = 0;
+ if (instr->op == PC_STW && instr->args[2].kind == PCOp_IMMEDIATE && instr->args[2].data.imm.value == 0)
+ isZeroOffset = 1;
+
+ scan = instr;
+ for (i = 0; i < 4; i++) {
+ if (scan->op == PC_RLWINM)
+ array[i] = defininginstruction[scan->defID + 1];
+ else
+ array[i] = defininginstruction[scan->defID];
+
+ scan = array[i];
+ if (array[0]->args[1].data.reg.reg != scan->args[1].data.reg.reg)
+ return 0;
+
+ if (i < 3) {
+ if (scan->op != PC_RLWIMI)
+ return 0;
+ } else {
+ if (scan->op != PC_RLWINM)
+ return 0;
+ }
+
+ if (scan->args[2].data.imm.value == 8) {
+ if (scan->args[3].data.imm.value == 24 && scan->args[4].data.imm.value == 31) {
+ if (flags & 1)
+ return 0;
+ flags |= 1;
+ } else if (scan->args[3].data.imm.value == 8 && scan->args[4].data.imm.value == 15) {
+ if (flags & 4)
+ return 0;
+ flags |= 4;
+ } else {
+ return 0;
+ }
+ } else if (scan->args[2].data.imm.value == 24) {
+ if (scan->args[3].data.imm.value == 0 && scan->args[4].data.imm.value == 7) {
+ if (flags & 8)
+ return 0;
+ flags |= 8;
+ } else if (scan->args[3].data.imm.value == 16 && scan->args[4].data.imm.value == 23) {
+ if (flags & 2)
+ return 0;
+ flags |= 2;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ if (definedbetween(instr, array[3], &array[0]->args[1]))
+ return 0;
+
+ if (instr->op == PC_STWX) {
+ change_opcode(instr, PC_STWBRX);
+ instr->args[0] = array[0]->args[1];
+ defininginstruction[instr->defID] = defininginstruction[array[3]->defID + 1];
+ return 1;
+ }
+
+ if (instr->op == PC_STW) {
+ if (!isZeroOffset) {
+ if (masks[RegClass_GPR] & (1 << array[0]->args[0].data.reg.reg))
+ return 0;
+
+ if (usedbetween(array[2], array[3], &array[0]->args[0]))
+ return 0;
+ if (usedbetween(array[1], array[2], &array[0]->args[0]))
+ return 0;
+ if (usedbetween(array[0], array[1], &array[0]->args[0]))
+ return 0;
+ if (usedbetween(instr, array[0], &array[0]->args[0]))
+ return 0;
+ }
+
+ defininginstruction[instr->defID] = defininginstruction[array[3]->defID + 1];
+
+ if (!isZeroOffset) {
+ newInstr = makepcode(PC_STWBRX, array[3]->args[1].data.reg.reg, 0, instr->args[0].data.reg.reg);
+ newInstr->alias = instr->alias;
+ change_opcode(instr, PC_ADDI);
+ insertpcodeafter(instr, newInstr);
+
+ masks[RegClass_GPR] |= 1 << newInstr->args[0].data.reg.reg;
+ masks[RegClass_GPR] |= 1 << newInstr->args[2].data.reg.reg;
+ instr->args[0].data.reg.effect &= ~EffectRead;
+ instr->args[0].data.reg.effect |= EffectWrite;
+ defininginstruction[instr->defID] = instr;
+
+ deletepcode(array[0]);
+ deletepcode(array[1]);
+ deletepcode(array[2]);
+ deletepcode(array[3]);
+ } else {
+ change_opcode(instr, PC_STWBRX);
+ instr->args[0] = array[0]->args[1];
+ instr->args[2] = instr->args[1];
+ defininginstruction[instr->defID + 2] = defininginstruction[instr->defID + 1];
+
+ instr->args[1].kind = PCOp_REGISTER;
+ instr->args[1].arg = RegClass_GPR;
+ instr->args[1].data.reg.reg = 0;
+ instr->args[1].data.reg.effect = 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int RLWINM_RLWIMI_STH(PCode *instr, UInt32 *masks) {
+ PCode *newInstr;
+ Boolean isZeroOffset;
+ int flags;
+ PCode *scan;
+ int i;
+ PCode *array[2];
+
+ flags = 0;
+ isZeroOffset = 0;
+ if (instr->op == PC_STH && instr->args[2].kind == PCOp_IMMEDIATE && instr->args[2].data.imm.value == 0)
+ isZeroOffset = 1;
+
+ scan = instr;
+ for (i = 0; i < 2; i++) {
+ if (scan->op == PC_RLWINM)
+ array[i] = defininginstruction[scan->defID + 1];
+ else
+ array[i] = defininginstruction[scan->defID];
+
+ scan = array[i];
+ if (array[0]->args[1].data.reg.reg != scan->args[1].data.reg.reg)
+ return 0;
+
+ if (i < 1) {
+ if (scan->op != PC_RLWIMI)
+ return 0;
+ } else {
+ if (scan->op != PC_RLWINM)
+ return 0;
+ }
+
+ if (scan->args[2].data.imm.value == 8) {
+ if (scan->args[3].data.imm.value == 16 && scan->args[4].data.imm.value == 23) {
+ if (flags & 2)
+ return 0;
+ flags |= 2;
+ } else {
+ return 0;
+ }
+ } else if (scan->args[2].data.imm.value == 24) {
+ if (scan->args[3].data.imm.value == 24 && scan->args[4].data.imm.value == 31) {
+ if (flags & 1)
+ return 0;
+ flags |= 1;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ if (definedbetween(instr, array[1], &array[0]->args[1]))
+ return 0;
+
+ if (instr->op == PC_STHX) {
+ change_opcode(instr, PC_STHBRX);
+ instr->args[0] = array[0]->args[1];
+ defininginstruction[instr->defID] = defininginstruction[array[1]->defID + 1];
+ return 1;
+ }
+
+ if (instr->op == PC_STH) {
+ if (!isZeroOffset) {
+ if (masks[RegClass_GPR] & (1 << array[0]->args[0].data.reg.reg))
+ return 0;
+
+ if (usedbetween(array[0], array[1], &array[0]->args[0]))
+ return 0;
+ if (usedbetween(instr, array[0], &array[0]->args[0]))
+ return 0;
+ }
+
+ defininginstruction[instr->defID] = defininginstruction[array[1]->defID + 1];
+
+ if (!isZeroOffset) {
+ newInstr = makepcode(PC_STHBRX, array[1]->args[1].data.reg.reg, 0, instr->args[0].data.reg.reg);
+ newInstr->alias = instr->alias;
+ change_opcode(instr, PC_ADDI);
+
+ instr->args[0].data.reg.effect &= ~EffectRead;
+ instr->args[0].data.reg.effect |= EffectWrite;
+ defininginstruction[instr->defID] = instr;
+
+ insertpcodeafter(instr, newInstr);
+
+ masks[RegClass_GPR] |= 1 << newInstr->args[0].data.reg.reg;
+ masks[RegClass_GPR] |= 1 << newInstr->args[2].data.reg.reg;
+
+ deletepcode(array[0]);
+ deletepcode(array[1]);
+ } else {
+ change_opcode(instr, PC_STHBRX);
+ instr->args[0] = array[0]->args[1];
+ instr->args[2] = instr->args[1];
+ defininginstruction[instr->defID + 2] = defininginstruction[instr->defID + 1];
+
+ instr->args[1].kind = PCOp_REGISTER;
+ instr->args[1].arg = RegClass_GPR;
+ instr->args[1].data.reg.reg = 0;
+ instr->args[1].data.reg.effect = 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static void peepholeoptimizeblock(PCodeBlock *block) {
+ RegClass rclass;
+ PCode *instr;
+ PCodeArg *op;
+ int i;
+ Pattern *pattern;
+ UInt32 masks[RegClassMax];
+
+ for (rclass = 0; rclass < RegClassMax; rclass++)
+ masks[rclass] = liveregs[rclass][block->blockIndex].xC;
+
+ for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
+ if (dead(instr, masks)) {
+ deletepcode(instr);
+ } else {
+ pattern = peepholepatterns[instr->op];
+
+ while (pattern) {
+ if (pattern->func(instr, masks)) {
+ if (!instr->block)
+ break;
+ pattern = peepholepatterns[instr->op];
+ } else {
+ pattern = pattern->next;
+ }
+ }
+
+ if (instr->block) {
+ for (op = instr->args, i = instr->argCount; i--; op++) {
+ if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectWrite))
+ masks[op->arg] &= ~(1 << op->data.reg.reg);
+ }
+
+ for (op = instr->args, i = instr->argCount; i--; op++) {
+ if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectRead))
+ masks[op->arg] |= 1 << op->data.reg.reg;
+ }
+ }
+ }
+ }
+}
+
+static SInt32 computepossiblemask(PCode *instr, short reg) {
+ SInt32 mask;
+ SInt32 val;
+ PCodeArg *op;
+ int i;
+
+ mask = 0xFFFFFFFF;
+ while (instr) {
+ for (op = instr->args, i = instr->argCount; i--; op++) {
+ if (PC_OP_IS_WRITE_REGISTER(op, RegClass_GPR, reg)) {
+ switch (instr->op) {
+ case PC_LBZ:
+ case PC_LBZU:
+ case PC_LBZX:
+ case PC_LBZUX:
+ mask = 0xFF;
+ break;
+
+ case PC_LHZ:
+ case PC_LHZU:
+ case PC_LHZX:
+ case PC_LHZUX:
+ mask = 0xFFFF;
+ break;
+
+ case PC_LI:
+ mask = instr->args[1].data.imm.value;
+ break;
+
+ case PC_SRAWI:
+ mask = computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg) >> instr->args[2].data.imm.value;
+ break;
+
+ case PC_RLWINM:
+ val = computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg);
+ mask = (val << instr->args[2].data.imm.value) | ((UInt32) val >> (32 - instr->args[2].data.imm.value));
+
+ if (instr->args[3].data.imm.value <= instr->args[4].data.imm.value)
+ val = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) & ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1)));
+ else
+ val = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) | ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1)));
+
+ mask &= val;
+ break;
+
+ case PC_RLWIMI:
+ val = computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg);
+ mask = (val << instr->args[2].data.imm.value) | ((UInt32) val >> (32 - instr->args[2].data.imm.value));
+
+ if (instr->args[3].data.imm.value <= instr->args[4].data.imm.value)
+ val = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) & ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1)));
+ else
+ val = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) | ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1)));
+
+ mask &= val;
+ mask |= computepossiblemask(instr->prevPCode, instr->args[0].data.reg.reg);
+ break;
+
+ case PC_OR:
+ mask = computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg) |
+ computepossiblemask(instr->prevPCode, instr->args[2].data.reg.reg);
+ break;
+
+ case PC_ORI:
+ mask = instr->args[2].data.imm.value |
+ computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg);
+ break;
+
+ case PC_AND:
+ mask = computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg) &
+ computepossiblemask(instr->prevPCode, instr->args[2].data.reg.reg);
+ break;
+
+ case PC_ANDI:
+ mask = instr->args[2].data.imm.value &
+ computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg);
+ break;
+
+ case PC_MR:
+ mask = computepossiblemask(instr->prevPCode, instr->args[1].data.reg.reg);
+ break;
+ }
+
+ return mask;
+ }
+ }
+ instr = instr->prevPCode;
+ }
+
+ return mask;
+}
+
+static UInt32 fillmaskholes(UInt32 mask) {
+ UInt32 oneBit;
+ UInt32 allBits;
+ UInt32 result;
+
+ oneBit = 1;
+ allBits = 0xFFFFFFFF;
+ result = 0;
+
+ if ((mask & 1) && (mask & 0x80000000)) {
+ result = 0xFFFFFFFF;
+ while ((mask & oneBit) == 1) {
+ oneBit <<= 1;
+ }
+
+ while ((mask & oneBit) == 0) {
+ result &= ~oneBit;
+ oneBit <<= 1;
+ }
+
+ return result;
+ } else {
+ while ((mask & oneBit) == 0 && (mask & allBits) != 0) {
+ oneBit <<= 1;
+ allBits <<= 1;
+ }
+ while ((mask & allBits) != 0) {
+ result |= oneBit;
+ oneBit <<= 1;
+ allBits <<= 1;
+ }
+ return result;
+ }
+}
+
+static int canuseinsert(PCode *instr1, PCode *instr2, short reg) {
+ if (computepossiblemask(instr2, reg) & fillmaskholes(computepossiblemask(instr1, instr1->args[0].data.reg.reg)))
+ return 0;
+ return 1;
+}
+
+static PCode *find_def_backwords(PCode *instr, short reg) {
+ int i;
+
+ while (instr) {
+ for (i = 0; i < instr->argCount; i++) {
+ if (PC_OP_IS_WRITE_REGISTER(&instr->args[i], RegClass_GPR, reg))
+ return instr;
+ }
+ instr = instr->prevPCode;
+ }
+
+ return NULL;
+}
+
+static void adjustforward(PCodeBlock *block) {
+ PCode *instr;
+ PCode *scan;
+ PCode *tmp;
+ PCodeArg *op;
+ int i;
+ short opcode;
+ short reg0;
+ short reg1;
+ SInt32 valA;
+ SInt32 valB;
+
+ instr = block->firstPCode;
+ while (instr) {
+ if (instr->op == PC_RLWINM) {
+ SInt32 val2;
+ SInt32 val3;
+ SInt32 val4;
+ short start;
+ short end;
+
+ short flag1 = 0;
+ short flag2 = 0;
+ reg0 = instr->args[0].data.reg.reg;
+ reg1 = instr->args[1].data.reg.reg;
+ val2 = instr->args[2].data.imm.value;
+ val3 = instr->args[3].data.imm.value;
+ val4 = instr->args[4].data.imm.value;
+
+ for (scan = instr->nextPCode; scan; scan = scan->nextPCode) {
+ opcode = scan->op;
+ if (opcode == PC_RLWINM && scan->args[1].data.reg.reg == reg0) {
+ if (
+ scan->args[3].data.imm.value == val3 &&
+ scan->args[4].data.imm.value == val4 &&
+ scan->args[2].data.imm.value == 0
+ )
+ {
+ if (PCODE_FLAG_SET_F(scan) & fRecordBit) {
+ if (!flag1) {
+ pcsetrecordbit(instr);
+ change_opcode(scan, PC_MR);
+ scan->flags &= ~fRecordBit;
+ scan->flags |= fIsMove;
+ change_num_operands(scan, 2);
+ } else {
+ change_opcode(scan, PC_MR);
+ scan->args[2] = scan->args[5];
+ change_num_operands(scan, 3);
+ }
+ } else {
+ change_opcode(scan, PC_MR);
+ change_num_operands(scan, 2);
+ }
+ }
+ else if (
+ reg0 != reg1 &&
+ !flag2 &&
+ canmergemasks(
+ val3,
+ val4,
+ scan->args[2].data.imm.value,
+ scan->args[3].data.imm.value,
+ scan->args[4].data.imm.value,
+ &start, &end)
+ )
+ {
+ scan->args[1].data.reg.reg = reg1;
+ scan->args[2].data.imm.value = (scan->args[2].data.imm.value + instr->args[2].data.imm.value) & 31;
+ scan->args[3].data.imm.value = start;
+ scan->args[4].data.imm.value = end;
+ }
+ }
+ else if (
+ opcode == PC_SRAWI &&
+ scan->args[1].data.reg.reg == reg0 &&
+ reg0 != reg1 &&
+ instr->args[2].data.imm.value == 0 &&
+ !(computepossiblemask(instr, reg0) & 0x80000000) &&
+ !flag2 &&
+ canmergemasks(val3, val4, 32 - scan->args[2].data.imm.value, scan->args[2].data.imm.value, 31, &start, &end) &&
+ !isSPRlive(scan, 0)
+ )
+ {
+ insertpcodeafter(scan, makepcode(
+ PC_RLWINM, scan->args[0].data.reg.reg, reg1,
+ 32 - scan->args[2].data.imm.value, start, end
+ ));
+ if (PCODE_FLAG_SET_F(scan) & fRecordBit)
+ pcsetrecordbit(scan->nextPCode);
+ deletepcode(scan);
+ }
+ else if (
+ opcode == PC_OR &&
+ !flag2 &&
+ reg0 != reg1 &&
+ !(PCODE_FLAG_SET_F(scan) & fRecordBit) &&
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit) &&
+ scan->args[0].data.reg.reg != instr->args[1].data.reg.reg
+ )
+ {
+ if (scan->args[1].data.reg.reg == reg0 && canuseinsert(instr, scan, scan->args[2].data.reg.reg)) {
+ op = &scan->args[2];
+ tmp = find_def_backwords(scan->prevPCode, scan->args[2].data.reg.reg);
+ if (tmp->op == PC_RLWINM && tmp->args[2].data.imm.value == 0) {
+ if (instr->args[3].data.imm.value <= instr->args[4].data.imm.value)
+ valA = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) & ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1)));
+ else
+ valA = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) | ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1)));
+
+ if (tmp->args[3].data.imm.value <= tmp->args[4].data.imm.value)
+ valB = ((tmp->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> tmp->args[3].data.imm.value)) & ~(((tmp->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (tmp->args[4].data.imm.value + 1)));
+ else
+ valB = ((tmp->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> tmp->args[3].data.imm.value)) | ~(((tmp->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (tmp->args[4].data.imm.value + 1)));
+
+ if (valA == ~valB)
+ op = &tmp->args[1];
+ }
+
+ change_opcode(scan, PC_MR);
+ scan->args[1] = *op;
+ change_num_operands(scan, 2);
+
+ tmp = copypcode(instr);
+ change_opcode(tmp, PC_RLWIMI);
+ tmp->args[0] = scan->args[0];
+ tmp->args[0].data.reg.effect |= EffectRead;
+
+ if (ismaskconstant(fillmaskholes(computepossiblemask(instr, instr->args[0].data.reg.reg)), &start, &end)) {
+ tmp->args[3].data.imm.value = start;
+ tmp->args[4].data.imm.value = end;
+ }
+
+ insertpcodeafter(scan, tmp);
+ break;
+ }
+
+ if (
+ scan->args[2].data.reg.reg == reg0 &&
+ canuseinsert(instr, scan, scan->args[1].data.reg.reg)
+ )
+ {
+ op = &scan->args[1];
+ tmp = find_def_backwords(scan->prevPCode, scan->args[1].data.reg.reg);
+ if (tmp->op == PC_RLWINM && tmp->args[2].data.imm.value == 0) {
+ if (instr->args[3].data.imm.value <= instr->args[4].data.imm.value)
+ valA = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) & ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1)));
+ else
+ valA = ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> instr->args[3].data.imm.value)) | ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (instr->args[4].data.imm.value + 1)));
+
+ if (tmp->args[3].data.imm.value <= tmp->args[4].data.imm.value)
+ valB = ((tmp->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> tmp->args[3].data.imm.value)) & ~(((tmp->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (tmp->args[4].data.imm.value + 1)));
+ else
+ valB = ((tmp->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFu >> tmp->args[3].data.imm.value)) | ~(((tmp->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFu >> (tmp->args[4].data.imm.value + 1)));
+
+ if (valA == ~valB)
+ op = &tmp->args[1];
+ }
+
+ change_opcode(scan, PC_MR);
+ scan->args[1] = *op;
+ change_num_operands(scan, 2);
+
+ tmp = copypcode(instr);
+ change_opcode(tmp, PC_RLWIMI);
+ tmp->args[0] = scan->args[0];
+ tmp->args[0].data.reg.effect |= EffectRead;
+
+ if (ismaskconstant(fillmaskholes(computepossiblemask(instr, instr->args[0].data.reg.reg)), &start, &end)) {
+ tmp->args[3].data.imm.value = start;
+ tmp->args[4].data.imm.value = end;
+ }
+
+ insertpcodeafter(scan, tmp);
+ break;
+ }
+ }
+ else if (
+ !flag2 &&
+ reg0 != reg1 &&
+ val4 == 31 &&
+ instr->args[2].data.imm.value == 0 &&
+ (
+ ((opcode == PC_STB || opcode == PC_STBX) && val3 <= 24) ||
+ ((opcode == PC_STH || opcode == PC_STHX) && val3 <= 16)
+ ) &&
+ scan->args[0].data.reg.reg == reg0
+ )
+ {
+ scan->args[0].data.reg.reg = reg1;
+ }
+ else if (
+ opcode == PC_EXTSH &&
+ scan->args[1].data.reg.reg == reg0 &&
+ val2 == 0 &&
+ val3 > 16 &&
+ val3 < val4
+ )
+ {
+ change_opcode(scan, PC_MR);
+ if ((PCODE_FLAG_SET_F(scan) & fRecordBit) && !flag1) {
+ pcsetrecordbit(instr);
+ scan->flags &= ~fRecordBit;
+ scan->flags |= fIsMove;
+ change_num_operands(scan, 2);
+ }
+ }
+ else if (
+ opcode == PC_EXTSB &&
+ scan->args[1].data.reg.reg == reg0 &&
+ val2 == 0 &&
+ val3 > 24 &&
+ val3 < val4
+ )
+ {
+ change_opcode(scan, PC_MR);
+ if ((PCODE_FLAG_SET_F(scan) & fRecordBit) && !flag1) {
+ pcsetrecordbit(instr);
+ scan->flags &= ~fRecordBit;
+ scan->flags |= fIsMove;
+ change_num_operands(scan, 2);
+ }
+ }
+
+ for (op = scan->args, i = scan->argCount; i--; op++) {
+ if (PC_OP_IS_WRITE_REGISTER(op, RegClass_GPR, reg0)) {
+ scan = block->lastPCode;
+ break;
+ }
+
+ if (PC_OP_IS_WRITE_REGISTER(op, RegClass_GPR, reg1))
+ flag2 = 1;
+
+ if (PC_OP_IS_REGISTER(op, RegClass_CRFIELD, 0))
+ flag1 = 1;
+ }
+ }
+
+ } else if (
+ instr->op == PC_EXTSB &&
+ (reg0 = instr->args[0].data.reg.reg) != (reg1 = instr->args[1].data.reg.reg)
+ )
+ {
+ short flag = 0;
+ for (scan = instr->nextPCode; scan; scan = scan->nextPCode) {
+ if (
+ (scan->op >= PC_STB && scan->op <= PC_STBUX) &&
+ scan->args[0].data.reg.reg == reg0
+ )
+ {
+ scan->args[0].data.reg.reg = reg1;
+ }
+ else if (
+ (scan->op == PC_EXTSH || scan->op == PC_EXTSB) &&
+ scan->args[1].data.reg.reg == reg0
+ )
+ {
+ change_opcode(scan, PC_MR);
+ if ((PCODE_FLAG_SET_F(scan) & fRecordBit) && !flag) {
+ pcsetrecordbit(instr);
+ scan->flags &= ~fRecordBit;
+ scan->flags |= fIsMove;
+ change_num_operands(scan, 2);
+ }
+ }
+
+ for (op = scan->args, i = scan->argCount; i--; op++) {
+ if (
+ PC_OP_IS_WRITE_ANY_REGISTER(op, RegClass_GPR) &&
+ (op->data.reg.reg == reg0 || op->data.reg.reg == reg1)
+ )
+ {
+ scan = block->lastPCode;
+ break;
+ }
+
+ if (PC_OP_IS_REGISTER(op, RegClass_CRFIELD, 0))
+ flag = 1;
+ }
+ }
+ } else if (
+ instr->op == PC_EXTSH &&
+ (reg0 = instr->args[0].data.reg.reg) != (reg1 = instr->args[1].data.reg.reg)
+ )
+ {
+ short flag = 0;
+ for (scan = instr->nextPCode; scan; scan = scan->nextPCode) {
+ if (
+ ((scan->op >= PC_STB && scan->op <= PC_STBUX) || (scan->op >= PC_STH && scan->op <= PC_STHUX)) &&
+ scan->args[0].data.reg.reg == reg0
+ )
+ {
+ scan->args[0].data.reg.reg = reg1;
+ }
+ else if (scan->op == PC_EXTSH && scan->args[1].data.reg.reg == reg0)
+ {
+ change_opcode(scan, PC_MR);
+ if ((PCODE_FLAG_SET_F(scan) & fRecordBit) && !flag) {
+ pcsetrecordbit(instr);
+ scan->flags &= ~fRecordBit;
+ scan->flags |= fIsMove;
+ change_num_operands(scan, 2);
+ }
+ }
+
+ for (op = scan->args, i = scan->argCount; i--; op++) {
+ if (
+ PC_OP_IS_WRITE_ANY_REGISTER(op, RegClass_GPR) &&
+ (op->data.reg.reg == reg0 || op->data.reg.reg == reg1)
+ )
+ {
+ scan = block->lastPCode;
+ break;
+ }
+
+ if (PC_OP_IS_REGISTER(op, RegClass_CRFIELD, 0))
+ flag = 1;
+ }
+ }
+ } else if (
+ instr->op == PC_ADDI &&
+ (reg0 = instr->args[0].data.reg.reg) == (reg1 = instr->args[1].data.reg.reg) &&
+ instr->args[2].kind == PCOp_IMMEDIATE
+ )
+ {
+ Boolean flag1 = 0;
+ Boolean flag2 = 0;
+ SInt32 val2 = instr->args[2].data.imm.value;
+
+ for (scan = instr->nextPCode; scan; scan = scan->nextPCode) {
+ if ((scan->flags & fIsWrite) && scan->args[0].data.reg.reg == reg0)
+ break;
+
+ if (
+ (scan->flags & (fIsRead | fIsWrite)) &&
+ scan->args[1].data.reg.reg == reg0 &&
+ scan->args[2].kind == PCOp_IMMEDIATE &&
+ FITS_IN_SHORT(val2 + scan->args[2].data.imm.value)
+ )
+ {
+ scan->args[2].data.imm.value += val2;
+ tmp = instr->prevPCode;
+ if (
+ (scan->flags & fIsRead) &&
+ scan->args[0].data.reg.reg == reg0 &&
+ scan->args[0].kind == PCOp_REGISTER &&
+ scan->args[0].arg == RegClass_GPR
+ )
+ {
+ deletepcode(instr);
+ } else {
+ deletepcode(instr);
+ insertpcodeafter(scan, instr);
+ }
+ instr = tmp;
+ break;
+ }
+
+ if (
+ scan->op == PC_ADDI &&
+ scan->args[1].data.reg.reg == reg0 &&
+ scan->args[2].kind == PCOp_IMMEDIATE &&
+ FITS_IN_SHORT(val2 + scan->args[2].data.imm.value)
+ )
+ {
+ scan->args[2].data.imm.value += val2;
+ tmp = instr->prevPCode;
+ if (scan->args[0].data.reg.reg == reg0) {
+ deletepcode(instr);
+ } else {
+ deletepcode(instr);
+ insertpcodeafter(scan, instr);
+ }
+ instr = tmp;
+ break;
+ }
+
+ if (scan->flags & (fIsBranch | fIsCall)) {
+ if (flag1 && scan->prevPCode != instr) {
+ tmp = instr->prevPCode;
+ deletepcode(instr);
+ insertpcodebefore(scan, instr);
+ instr = tmp;
+ }
+ break;
+ }
+
+ for (op = scan->args, i = scan->argCount; i--; op++) {
+ if (PC_OP_IS_R_OR_W_REGISTER(op, RegClass_GPR, reg0)) {
+ if (flag1 && scan->prevPCode != instr) {
+ tmp = instr->prevPCode;
+ deletepcode(instr);
+ insertpcodebefore(scan, instr);
+ instr = tmp;
+ }
+ flag2 = 1;
+ break;
+ }
+ }
+
+ if (flag2)
+ break;
+
+ if (scan->op != PC_ADDI)
+ flag1 = 1;
+
+ if (flag1 && !scan->nextPCode) {
+ tmp = instr->prevPCode;
+ deletepcode(instr);
+ appendpcode(block, instr);
+ instr = tmp;
+ break;
+ }
+ }
+ }
+
+ if (instr)
+ instr = instr->nextPCode;
+ else
+ instr = block->firstPCode;
+ }
+}
+
+static void installpattern(Opcode opcode, PeepholeFunc func) {
+ Pattern *pattern = lalloc(sizeof(Pattern));
+ pattern->func = func;
+ pattern->next = peepholepatterns[opcode];
+ peepholepatterns[opcode] = pattern;
+}
+
+static void installpeepholepatterns(void) {
+ int i;
+
+ for (i = 0; i < OPCODE_MAX; i++)
+ peepholepatterns[i] = NULL;
+
+ installpattern(PC_AND, NOT_AND);
+ installpattern(PC_MR, LI_MR);
+ installpattern(PC_MR, L_MR);
+ installpattern(PC_FMR, L_FMR);
+ installpattern(PC_MR, MR_MR);
+ installpattern(PC_MR, MR_Rx_Rx);
+ installpattern(PC_FMR, FMR_FMR);
+ installpattern(PC_FMR, FMR_Fx_Fx);
+ installpattern(PC_VMR, VMR_VMRP);
+ installpattern(PC_VMR, VMR_VMR);
+ installpattern(PC_VMR, VMR_Vx_Vx);
+ installpattern(PC_VMR, VSPLTIS_VMR);
+ installpattern(PC_CMPI, MR_CMPI);
+ installpattern(PC_RLWIMI, RLWINM_RLWINM);
+ installpattern(PC_RLWINM, RLWINM_RLWINM);
+ installpattern(PC_RLWINM, EXTSB_RLWINM);
+ installpattern(PC_RLWINM, EXTSH_RLWINM);
+ installpattern(PC_RLWINM, LBZ_RLWINM);
+ installpattern(PC_RLWINM, LHZ_RLWINM);
+ installpattern(PC_EXTSH, LHA_EXTSH);
+ installpattern(PC_STW, RLWINM_RLWIMI_STW);
+ installpattern(PC_STWX, RLWINM_RLWIMI_STW);
+ installpattern(PC_STH, RLWINM_RLWIMI_STH);
+ installpattern(PC_STHX, RLWINM_RLWIMI_STH);
+ installpattern(PC_LBZ, ADDI_L_S);
+ installpattern(PC_LHZ, ADDI_L_S);
+ installpattern(PC_LHA, ADDI_L_S);
+ installpattern(PC_LWZ, ADDI_L_S);
+ installpattern(PC_STB, ADDI_L_S);
+ installpattern(PC_STH, ADDI_L_S);
+ installpattern(PC_STW, ADDI_L_S);
+ installpattern(PC_LFS, ADDI_L_S);
+ installpattern(PC_LFD, ADDI_L_S);
+ installpattern(PC_STFS, ADDI_L_S);
+ installpattern(PC_STFD, ADDI_L_S);
+ installpattern(PC_LBZU, ADDI_LU_SU);
+ installpattern(PC_LHZU, ADDI_LU_SU);
+ installpattern(PC_LHAU, ADDI_LU_SU);
+ installpattern(PC_LWZU, ADDI_LU_SU);
+ installpattern(PC_STBU, ADDI_LU_SU);
+ installpattern(PC_STHU, ADDI_LU_SU);
+ installpattern(PC_STWU, ADDI_LU_SU);
+ installpattern(PC_LFSU, ADDI_LU_SU);
+ installpattern(PC_LFDU, ADDI_LU_SU);
+ installpattern(PC_STFSU, ADDI_LU_SU);
+ installpattern(PC_STFDU, ADDI_LU_SU);
+ installpattern(PC_LBZ, L_S_ADDI);
+ installpattern(PC_LHZ, L_S_ADDI);
+ installpattern(PC_LHA, L_S_ADDI);
+ installpattern(PC_LWZ, L_S_ADDI);
+ installpattern(PC_STB, L_S_ADDI);
+ installpattern(PC_STH, L_S_ADDI);
+ installpattern(PC_STW, L_S_ADDI);
+ installpattern(PC_LFS, L_S_ADDI);
+ installpattern(PC_LFD, L_S_ADDI);
+ installpattern(PC_STFS, L_S_ADDI);
+ installpattern(PC_STFD, L_S_ADDI);
+ installpattern(PC_STB, L_S);
+ installpattern(PC_STH, L_S);
+ installpattern(PC_STW, L_S);
+ installpattern(PC_STFS, L_S);
+ installpattern(PC_STFD, L_S);
+ installpattern(PC_STBX, L_S);
+ installpattern(PC_STHX, L_S);
+ installpattern(PC_STWX, L_S);
+ installpattern(PC_STFSX, L_S);
+ installpattern(PC_STFDX, L_S);
+ installpattern(PC_BT, LBZ_EXTSB_CMPI_BC);
+ installpattern(PC_BF, LBZ_EXTSB_CMPI_BC);
+ installpattern(PC_BT, RLWINM_CMPLI_BC);
+ installpattern(PC_BF, RLWINM_CMPLI_BC);
+ installpattern(PC_BT, LI_CMP_BC);
+ installpattern(PC_BF, LI_CMP_BC);
+ installpattern(PC_RLWINM, RLWINM_RLWINM);
+ installpattern(PC_MULLI, MULLI_MULLI);
+ installpattern(PC_ADDI, ADDI_ADDI);
+ installpattern(PC_SRAWI, SRAWI_SRAWI);
+ installpattern(PC_MR, MR_ADDI);
+ installpattern(PC_OR, SRW_SUBFIC_RLW_OR);
+}
+
+void peepholeoptimizeforward(Object *func) {
+ PCodeBlock *block;
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ if (block->pcodeCount >= 2)
+ adjustforward(block);
+ }
+}
+
+void peepholemergeblocks(Object *func, Boolean flag) {
+ PCodeBlock *block;
+ PCodeBlock *next;
+ Boolean flag2;
+ PCode *instr;
+ PCode *nextinstr;
+ PCLink *link;
+ PCLink *link2;
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ flag2 = 0;
+ next = block->nextBlock;
+
+ if (!flag) {
+ flag2 = next && (next->flags & fIsEpilogue);
+ if (block->flags & fIsProlog)
+ continue;
+ }
+
+ if (block->pcodeCount > 0) {
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ if (instr->flags & (fIsCall | fSideEffects))
+ break;
+ }
+
+ if (instr)
+ continue;
+
+ instr = block->lastPCode;
+ if (instr && instr->op == PC_B) {
+ if (instr->args[0].kind == PCOp_LABEL && instr->args[0].data.label.label->block == next)
+ deletepcode(instr);
+ else
+ continue;
+ }
+
+ instr = block->lastPCode;
+ if (instr && (instr->flags & fIsBranch) && instr->op != PC_B)
+ continue;
+
+ while (
+ block->successors->block == next &&
+ block->successors->nextLink == NULL &&
+ next->predecessors->block == block &&
+ next->predecessors->nextLink == NULL &&
+ !flag2 &&
+ !(next->flags & fPCBlockFlag8000) &&
+ (block->pcodeCount + next->pcodeCount) <= 100
+ )
+ {
+ if (next->pcodeCount > 0) {
+ for (instr = next->firstPCode; instr; instr = nextinstr) {
+ nextinstr = instr->nextPCode;
+ if (instr->flags & (fIsCall | fSideEffects))
+ break;
+
+ deletepcode(instr);
+ if (instr->op != PC_B) {
+ appendpcode(block, instr);
+ } else if (instr->args[0].kind == PCOp_LABEL) {
+ if (instr->args[0].data.label.label->block != next->nextBlock)
+ appendpcode(block, instr);
+ } else {
+ appendpcode(block, instr);
+ }
+ }
+ }
+
+ if (next->pcodeCount != 0)
+ break;
+ if (next == epilogue)
+ break;
+
+ block->successors = next->successors;
+
+ for (link = block->successors; link; link = link->nextLink) {
+ for (link2 = link->block->predecessors; link2; link2 = link2->nextLink) {
+ if (link2->block == next) {
+ link2->block = block;
+ break;
+ }
+ }
+ }
+
+ block->nextBlock = next->nextBlock;
+ if (block->nextBlock)
+ block->nextBlock->prevBlock = block;
+
+ next->flags |= fDeleted;
+ next = block->nextBlock;
+
+ if (!flag)
+ flag2 = next && (next->flags & fIsEpilogue);
+ }
+ }
+ }
+}
+
+void peepholeoptimizepcode(Object *func) {
+ PCodeBlock *block;
+
+ installpeepholepatterns();
+ computeliveregisters(func);
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ if (block->pcodeCount >= 1) {
+ computeinstructionpredecessors(block);
+ peepholeoptimizeblock(block);
+ freeoheap();
+ }
+ }
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c
new file mode 100644
index 0000000..6fa4524
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c
@@ -0,0 +1,1252 @@
+#include "compiler/StackFrame.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+#define ALIGN(thing, alignment) ( ~((alignment) - 1) & ((thing) + (alignment) - 1) )
+#define ALIGN_REMAINDER(thing, alignment) ( ALIGN(thing, alignment) - (thing) )
+
+Boolean requires_frame;
+Boolean makes_call;
+Boolean uses_globals;
+Boolean dynamic_stack;
+Boolean large_stack;
+static SInt32 out_param_alignment;
+static SInt32 in_parameter_size;
+static SInt32 in_param_alignment;
+static SInt32 frame_alignment;
+static SInt32 alloca_alignment;
+static SInt32 linkage_area_size;
+static SInt32 parameter_area_size;
+static SInt32 parameter_area_size_estimate;
+static SInt32 local_data_size;
+static SInt32 local_data_limit;
+static SInt32 large_data_near_size;
+static SInt32 large_data_far_size;
+static ObjectList *local_objects[ObjClassMax];
+static ObjectList *local_objects_tail[ObjClassMax];
+static SInt32 non_volatile_save_offset[RegClassMax];
+static SInt32 VRSAVE_save_offset;
+static SInt32 LR_save_offset;
+static SInt32 nonvolatile_save_size;
+static UInt32 vrsave_mask;
+static SInt32 frame_size;
+static SInt32 frame_size_estimate;
+static SInt32 genuine_frame_size;
+static Object *dummylocal;
+static Boolean dynamic_align_stack;
+static Boolean has_varargs;
+static Boolean compressing_data_area;
+static PCode *setup_caller_sp;
+static PCode *align_instr1;
+static PCode *align_instr2;
+static short vrsave_register;
+static PCode *loadvrsave;
+static PCode *storevrsave;
+Object *dummyvaparam;
+void *dummyprofiler;
+
+// forward declarations
+static void insert_local_object(UInt8 oclass, Object *obj);
+static void compress_data_area(void);
+static UInt32 align_bits(UInt32 value, UInt8 bitcount);
+static Boolean use_helper_function(char rclass);
+static Boolean need_link_register(void);
+static void call_helper_function(char *name, char rclass, short effect);
+static void save_nonvolatile_FPRs(int reg, SInt32 offset);
+static void save_nonvolatile_VRs(int reg, SInt32 offset);
+static void restore_nonvolatile_FPRs(int reg, SInt32 offset);
+static void restore_nonvolatile_VRs(int reg, SInt32 offset);
+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 isConstantSize, int reg1, int reg2, SInt32 size);
+
+void init_stack_globals(Object *funcobj) {
+ RegClass rclass;
+ ObjClass oclass;
+
+ requires_frame = 0;
+ makes_call = 0;
+ uses_globals = 0;
+ dynamic_stack = 0;
+ large_stack = 0;
+ vrsave_register = -1;
+ dynamic_align_stack = 0;
+ compressing_data_area = 0;
+ align_instr1 = NULL;
+ align_instr2 = NULL;
+ setup_caller_sp = NULL;
+ dummyvaparam = NULL;
+ loadvrsave = NULL;
+ storevrsave = NULL;
+ local_data_size = 0;
+ local_data_limit = 0x2000;
+ large_data_near_size = 0;
+ large_data_far_size = 0;
+ frame_size_estimate = 0;
+ in_parameter_size = 0;
+ parameter_area_size = 0;
+ parameter_area_size_estimate = 0;
+ frame_alignment = 8;
+ out_param_alignment = 8;
+ in_param_alignment = 8;
+ alloca_alignment = 0;
+ has_varargs = 0;
+ linkage_area_size = 0;
+ frame_size = 0;
+ genuine_frame_size = 0;
+ nonvolatile_save_size = -1;
+ VRSAVE_save_offset = -1;
+ LR_save_offset = -1;
+
+ for (rclass = 0; rclass < RegClassMax; rclass++)
+ non_volatile_save_offset[rclass] = -1;
+
+ dummyprofiler = NULL;
+ dummyvaparam = NULL;
+ dummylocal = NULL;
+
+ for (oclass = 0; oclass < ObjClassMax; oclass++) {
+ local_objects[oclass] = NULL;
+ local_objects_tail[oclass] = NULL;
+ }
+}
+
+void init_frame_sizes(Boolean has_varargs) {
+ ObjectList *scan;
+ Object *obj;
+ SInt32 r30;
+ SInt32 align;
+ SInt32 mask;
+
+ r30 = in_parameter_size + parameter_area_size_estimate;
+ frame_size_estimate = r30 + 2484;
+ for (scan = locals; scan; scan = scan->next) {
+ obj = scan->object;
+ {
+ align = CMach_AllocationAlignment(obj->type, obj->qual) - 1;
+ mask = ~align;
+ }
+ frame_size_estimate = (frame_size_estimate + align) & mask;
+ frame_size_estimate += obj->type->size;
+ }
+
+ if (frame_size_estimate > 0x8000) {
+ dynamic_stack = 1;
+ large_stack = 1;
+ requires_frame = 1;
+ }
+
+ local_data_limit = 0x8000 - (r30 + 2484);
+
+ if (dynamic_stack) {
+ requires_frame = 1;
+ dummylocal = galloc(sizeof(Object));
+ memclrw(dummylocal, sizeof(Object));
+ dummylocal->type = (Type *) &stvoid;
+ dummylocal->otype = OT_OBJECT;
+ dummylocal->name = GetHashNameNode("<dummy>");
+ dummylocal->datatype = DLOCAL;
+ dummylocal->u.var.info = CodeGen_GetNewVarInfo();
+ dummylocal->u.var.info->flags |= VarInfoFlag80;
+ dummylocal->u.var.info->noregister = 1;
+ }
+
+ if (dynamic_stack) {
+ retain_register(NULL, RegClass_GPR, 31);
+ _FP_ = 31;
+ } else {
+ _FP_ = 1;
+ }
+}
+
+void assign_local_memory(Object *obj) {
+ // some misassigned registers x.x
+ short align;
+ VarInfo *vi;
+
+ align = CMach_AllocationAlignment(obj->type, obj->qual);
+ if (!compressing_data_area && (obj->u.var.info->flags & VarInfoFlag80))
+ return;
+
+ update_frame_align(align);
+ if (local_data_size + (ALIGN_REMAINDER(local_data_size, align) + ALIGN(obj->type->size, align)) < local_data_limit) {
+ local_data_size = ALIGN(local_data_size, align);
+ vi = Registers_GetVarInfo(obj);
+ vi->flags &= ~VarInfoFlag2;
+ vi->flags |= VarInfoFlag80;
+ obj->u.var.uid = local_data_size;
+ local_data_size += ALIGN(obj->type->size, align);
+ insert_local_object(ObjClass0, obj);
+ return;
+ }
+ if (compressing_data_area || obj->type->size <= 32) {
+ large_data_near_size = ALIGN(large_data_near_size, align);
+ vi = Registers_GetVarInfo(obj);
+ vi->flags &= ~VarInfoFlag2;
+ vi->flags |= VarInfoFlag80;
+ obj->u.var.uid = 0x8000 + large_data_near_size;
+ large_data_near_size += ALIGN(obj->type->size, align);
+ insert_local_object(ObjClass1, obj);
+ } else {
+ large_data_far_size = ALIGN(large_data_far_size, align);
+ vi = Registers_GetVarInfo(obj);
+ vi->flags &= ~VarInfoFlag2;
+ vi->flags |= VarInfoFlag80;
+ obj->u.var.uid = 0x10000 + large_data_far_size;
+ large_data_far_size += ALIGN(obj->type->size, align);
+ insert_local_object(ObjClass2, obj);
+ }
+}
+
+void assign_locals_to_memory(ObjectList *first) {
+ ObjectList *list;
+ Object *obj;
+ SInt32 i;
+
+ for (i = 1; i < 1024; i <<= 1) {
+ for (list = first; list; list = list->next) {
+ obj = list->object;
+ if (Registers_GetVarInfo(obj)->used) {
+ if ((Registers_GetVarInfo(obj) ? Registers_GetVarInfo(obj)->reg : 0) == 0) {
+ if (obj->type->size <= i)
+ assign_local_memory(obj);
+ }
+ }
+ }
+ }
+
+ for (list = first; list; list = list->next) {
+ obj = list->object;
+ if (Registers_GetVarInfo(obj)->used) {
+ if ((Registers_GetVarInfo(obj) ? Registers_GetVarInfo(obj)->reg : 0) == 0) {
+ assign_local_memory(list->object);
+ }
+ }
+
+ if (obj->type && IS_TYPE_ARRAY(obj->type) && IS_TYPE_VECTOR(TYPE_POINTER(obj->type)->target))
+ has_altivec_arrays = 1;
+ }
+}
+
+void compute_frame_sizes(void) {
+ SInt32 altivec_size;
+ SInt32 altivec_offset;
+
+ CError_ASSERT(897, alloca_alignment == 0 || alloca_alignment == frame_alignment);
+
+ update_asm_nonvolatile_registers();
+ LR_save_offset = 8;
+ non_volatile_save_offset[RegClass_FPR] = -(used_nonvolatile_registers[RegClass_FPR] * 8);
+ non_volatile_save_offset[RegClass_GPR] = -(((15 - non_volatile_save_offset[RegClass_FPR]) & ~15) + used_nonvolatile_registers[RegClass_GPR] * 4);
+ nonvolatile_save_size = -non_volatile_save_offset[RegClass_GPR];
+ non_volatile_save_offset[RegClass_CRFIELD] = 4;
+ VRSAVE_save_offset = -1;
+ non_volatile_save_offset[RegClass_VR] = -1;
+
+ if (copts.altivec_model) {
+ if (vrsave_mask) {
+ VRSAVE_save_offset = non_volatile_save_offset[RegClass_GPR] - 4;
+ nonvolatile_save_size = nonvolatile_save_size + 4;
+ }
+ altivec_size = used_nonvolatile_registers[RegClass_VR] * 16;
+ if (altivec_size > 0)
+ nonvolatile_save_size = ALIGN(nonvolatile_save_size + altivec_size, frame_alignment);
+ }
+
+ if (parameter_area_size)
+ requires_frame = 1;
+
+ compress_data_area();
+ local_data_size = ALIGN(local_data_size, frame_alignment);
+ nonvolatile_save_size = ALIGN(nonvolatile_save_size, frame_alignment);
+ if (!requires_frame && (local_data_size + nonvolatile_save_size) <= 224) {
+ CError_ASSERT(1005, !dynamic_align_stack);
+ linkage_area_size = 0;
+ frame_size = 0;
+ genuine_frame_size = local_data_size + nonvolatile_save_size;
+ } else {
+ requires_frame = 1;
+ if (parameter_area_size < 32)
+ parameter_area_size = 32;
+ parameter_area_size = ALIGN(parameter_area_size + 24, frame_alignment) - 24;
+ if (large_stack) {
+ CError_ASSERT(1019, !large_data_far_size);
+ large_data_near_size += parameter_area_size;
+ parameter_area_size = 0;
+ }
+ linkage_area_size = 24;
+ frame_size = nonvolatile_save_size + (altivec_offset = parameter_area_size + 24 + local_data_size);
+ if (copts.altivec_model && used_nonvolatile_registers[RegClass_VR])
+ non_volatile_save_offset[RegClass_VR] = altivec_offset;
+ frame_size += ALIGN_REMAINDER(frame_size, 16);
+ frame_size = ALIGN(frame_size, frame_alignment);
+ genuine_frame_size = frame_size;
+ }
+ if (!large_stack && frame_size > 0x7FFF)
+ CError_ErrorTerm(CErrorStr210);
+}
+
+static void allocate_new_frame(int reg1, int reg2) {
+ if (dynamic_align_stack) {
+ CError_ASSERT(1116, reg1 != _CALLER_SP_);
+ emitpcode(PC_RLWINM, reg1, 1, 0, align_bits(frame_alignment, 1), 31);
+ if (frame_size > 0x7FFF) {
+ CError_FATAL(1122);
+ return;
+ }
+
+ if (frame_size)
+ emitpcode(PC_SUBFIC, reg1, reg1, -frame_size);
+ else
+ emitpcode(PC_SUBFIC, reg1, reg1, -genuine_frame_size);
+
+ if (reg2)
+ emitpcode(PC_MR, reg2, 1);
+
+ emitpcode(PC_STWUX, 1, 1, reg1);
+ } else {
+ if (frame_size > 0x7FFF)
+ CError_FATAL(1153);
+ else
+ emitpcode(PC_STWU, 1, 1, 0, -frame_size);
+
+ if (reg2)
+ emitpcode(PC_MR, reg2, 1);
+ }
+}
+
+void generate_prologue(PCodeBlock *block, Boolean has_varargs) {
+ PCodeBlock *save_block;
+ Boolean needs_lr;
+ Statement *save_statement;
+ Statement stmt;
+ UInt32 vrsave_low;
+ UInt32 vrsave_high;
+
+ save_block = pclastblock;
+ needs_lr = need_link_register();
+ save_statement = current_statement;
+ stmt.sourceoffset = functionbodyoffset;
+ current_statement = &stmt;
+ pclastblock = block;
+
+ if (setup_caller_sp && setup_caller_sp->block) {
+ if (
+ setup_caller_sp->op == PC_MR &&
+ setup_caller_sp->args[1].kind == PCOp_REGISTER &&
+ setup_caller_sp->args[1].arg == RegClass_GPR &&
+ setup_caller_sp->args[1].data.reg.reg == _FP_
+ )
+ CError_FATAL(1197);
+
+ _CALLER_SP_ = setup_caller_sp->args[0].data.reg.reg;
+ deletepcode(setup_caller_sp);
+ setup_caller_sp = NULL;
+ } else if (_CALLER_SP_ != _FP_) {
+ _CALLER_SP_ = -1;
+ }
+
+ if (align_instr1 && align_instr1->block) {
+ deletepcode(align_instr1);
+ align_instr1 = NULL;
+ }
+
+ if (align_instr2 && align_instr2->block) {
+ deletepcode(align_instr2);
+ align_instr2 = NULL;
+ }
+
+ if (loadvrsave && loadvrsave->block) {
+ deletepcode(loadvrsave);
+ loadvrsave = NULL;
+ }
+
+ if (storevrsave && storevrsave->block) {
+ deletepcode(storevrsave);
+ storevrsave = NULL;
+ }
+
+ if (needs_lr)
+ emitpcode(PC_MFLR, 0);
+
+ if (used_nonvolatile_registers[RegClass_CRFIELD]) {
+ emitpcode(PC_MFCR, 12);
+ emitpcode(PC_STW, 12, 1, 0, non_volatile_save_offset[RegClass_CRFIELD]);
+ }
+
+ if (used_nonvolatile_registers[RegClass_FPR])
+ save_nonvolatile_FPRs(1, 0);
+ if (used_nonvolatile_registers[RegClass_GPR])
+ save_nonvolatile_GPRs(1, 0);
+ if (needs_lr)
+ emitpcode(PC_STW, 0, 1, 0, 8);
+
+ if (frame_size) {
+ if (vrsave_mask) {
+ emitpcode(PC_MFSPR, 0, 256);
+ emitpcode(PC_STW, 0, 1, 0, VRSAVE_save_offset);
+ vrsave_register = 0;
+ }
+ allocate_new_frame(12, (_CALLER_SP_ > 0 && _CALLER_SP_ != _FP_) ? _CALLER_SP_ : 0);
+ } else {
+ CError_ASSERT(1326, !dynamic_align_stack);
+ if (vrsave_mask)
+ emitpcode(PC_MFSPR, vrsave_register, 256);
+ }
+
+ if (vrsave_mask) {
+ vrsave_high = vrsave_mask >> 16;
+ vrsave_low = vrsave_mask & 0xFFFF;
+ if (vrsave_mask == 0xFFFFFFFF) {
+ emitpcode(PC_LI, 0, -1);
+ } else {
+ if (vrsave_high)
+ emitpcode(PC_ORIS, 0, vrsave_register, vrsave_high);
+ if (vrsave_low)
+ emitpcode(PC_ORI, 0, 0, vrsave_low);
+ }
+ emitpcode(PC_MTSPR, 256, 0);
+ }
+
+ if (used_nonvolatile_registers[RegClass_VR])
+ save_nonvolatile_VRs(1, 0);
+
+ if (dynamic_stack)
+ emitpcode(PC_MR, 31, 1);
+
+ if (large_stack)
+ do_allocate_dynamic_stack_space(1, 11, 0, large_data_near_size);
+
+ block->flags |= fIsProlog;
+ pclastblock = save_block;
+ current_statement = save_statement;
+}
+
+void generate_epilogue(PCodeBlock *block, Boolean add_blr) {
+ PCodeBlock *save_block;
+ Boolean needs_lr;
+ Statement *save_statement;
+ Statement stmt;
+
+ save_block = pclastblock;
+ needs_lr = need_link_register();
+ save_statement = current_statement;
+ if (!save_statement) {
+ stmt.sourceoffset = current_linenumber;
+ current_statement = &stmt;
+ }
+ pclastblock = block;
+
+ if (used_nonvolatile_registers[RegClass_VR])
+ restore_nonvolatile_VRs(_FP_, 0);
+
+ if (dynamic_align_stack) {
+ load_store_register(PC_LWZ, 1, 1, NULL, 0);
+ setpcodeflags(fSideEffects);
+ if (needs_lr)
+ load_store_register(PC_LWZ, 0, 1, 0, 8);
+ } else {
+ if (needs_lr)
+ load_store_register(PC_LWZ, 0, _FP_, 0, frame_size + 8);
+ if (frame_size > 0) {
+ if (dynamic_stack) {
+ load_store_register(PC_LWZ, 1, 1, 0, 0);
+ setpcodeflags(fSideEffects);
+ } else {
+ emitpcode(PC_ADDI, 1, 1, 0, frame_size);
+ setpcodeflags(fSideEffects);
+ }
+ }
+ }
+
+ if (used_nonvolatile_registers[RegClass_CRFIELD]) {
+ load_store_register(PC_LWZ, 12, 1, NULL, non_volatile_save_offset[RegClass_CRFIELD]);
+ emitpcode(PC_MTCRF, 255, 12);
+ }
+
+ if (vrsave_mask) {
+ if (!requires_frame) {
+ emitpcode(PC_MTSPR, 256, vrsave_register);
+ } else {
+ emitpcode(PC_LWZ, 11, 1, 0, VRSAVE_save_offset);
+ emitpcode(PC_MTSPR, 256, 11);
+ }
+ }
+
+ if (used_nonvolatile_registers[RegClass_FPR])
+ restore_nonvolatile_FPRs(1, 0);
+ if (needs_lr && !use_helper_function(RegClass_GPR))
+ emitpcode(PC_MTLR, 0);
+
+ if (used_nonvolatile_registers[RegClass_GPR])
+ restore_nonvolatile_GPRs(1, 0);
+ if (needs_lr && use_helper_function(RegClass_GPR))
+ emitpcode(PC_MTLR, 0);
+
+ if (add_blr) {
+ emitpcode(PC_BLR);
+ setpcodeflags(fIsVolatile);
+ }
+
+ block->flags |= fIsEpilogue;
+ pclastblock = save_block;
+ current_statement = save_statement;
+}
+
+static void load_base_offset(int dest_reg, int base_reg, SInt32 offset) {
+ if (offset)
+ emitpcode(PC_ADDI, dest_reg, base_reg, 0, offset);
+ else
+ emitpcode(PC_MR, dest_reg, base_reg);
+}
+
+static void save_nonvolatile_FPRs(int reg, SInt32 offset) {
+ short i;
+ SInt32 o;
+
+ o = offset + non_volatile_save_offset[RegClass_FPR];
+
+ if (!use_helper_function(RegClass_FPR)) {
+ for (i = 1; i <= used_nonvolatile_registers[RegClass_FPR]; i++) {
+ emitpcode(PC_STFD, 32 - i, reg, NULL, o + (used_nonvolatile_registers[RegClass_FPR] - i) * 8);
+ setpcodeflags(fIsVolatile);
+ }
+ } else {
+ load_base_offset(11, reg, o + used_nonvolatile_registers[RegClass_FPR] * 8);
+ call_helper_function("__save_fpr_%d", RegClass_FPR, EffectRead);
+ }
+}
+
+static void save_nonvolatile_VRs(int reg, SInt32 offset) {
+ short i;
+ SInt32 o;
+
+ o = offset + non_volatile_save_offset[RegClass_VR];
+
+ if (!use_helper_function(RegClass_VR)) {
+ for (i = 1; i <= used_nonvolatile_registers[RegClass_VR]; i++) {
+ emitpcode(PC_LI, 0, o + (used_nonvolatile_registers[RegClass_VR] - i) * 16);
+ emitpcode(PC_STVX, 32 - i, reg, 0);
+ setpcodeflags(fIsVolatile);
+ }
+ } else {
+ load_base_offset(0, reg, o + used_nonvolatile_registers[RegClass_VR] * 16);
+ call_helper_function("__savev%d", RegClass_VR, EffectRead);
+ }
+}
+
+static void restore_nonvolatile_FPRs(int reg, SInt32 offset) {
+ short i;
+ SInt32 o;
+
+ o = offset + non_volatile_save_offset[RegClass_FPR];
+
+ if (!use_helper_function(RegClass_FPR)) {
+ for (i = 1; i <= used_nonvolatile_registers[RegClass_FPR]; i++) {
+ load_store_register(PC_LFD, 32 - i, reg, NULL, o + (used_nonvolatile_registers[RegClass_FPR] - i) * 8);
+ setpcodeflags(fIsVolatile);
+ }
+ } else {
+ load_base_offset(11, reg, o + used_nonvolatile_registers[RegClass_FPR] * 8);
+ call_helper_function("__restore_fpr_%d", RegClass_FPR, EffectWrite);
+ }
+}
+
+static void restore_nonvolatile_VRs(int reg, SInt32 offset) {
+ short i;
+ SInt32 o;
+
+ o = offset + non_volatile_save_offset[RegClass_VR];
+
+ if (!use_helper_function(RegClass_VR)) {
+ for (i = 1; i <= used_nonvolatile_registers[RegClass_VR]; i++) {
+ emitpcode(PC_LI, 0, o + (used_nonvolatile_registers[RegClass_VR] - i) * 16);
+ setpcodeflags(fIsVolatile);
+ emitpcode(PC_LVX, 32 - i, reg, 0);
+ setpcodeflags(fIsVolatile);
+ }
+ } else {
+ load_base_offset(0, reg, o + used_nonvolatile_registers[RegClass_VR] * 16);
+ call_helper_function("__restv%d", RegClass_VR, EffectWrite);
+ }
+}
+
+static void save_nonvolatile_GPRs(int reg, SInt32 offset) {
+ int i;
+ SInt32 o;
+
+ o = offset + non_volatile_save_offset[RegClass_GPR];
+
+ if (!use_helper_function(RegClass_GPR)) {
+ if (copts.use_lmw_stmw && ((used_nonvolatile_registers[RegClass_GPR] > 4) || (copts.optimizesize && (used_nonvolatile_registers[RegClass_GPR] > 1)))) {
+ emitpcode(PC_STMW, used_nonvolatile_registers[RegClass_GPR] - 1, 32 - used_nonvolatile_registers[RegClass_GPR], reg, 0, o);
+ } else {
+ for (i = 1; i <= used_nonvolatile_registers[RegClass_GPR]; i++) {
+ emitpcode(PC_STW, 32 - i, reg, 0, o + (used_nonvolatile_registers[RegClass_GPR] - i) * 4);
+ }
+ }
+ } else {
+ load_base_offset(11, reg, o + used_nonvolatile_registers[RegClass_GPR] * 4);
+ call_helper_function("__savegpr_%d", RegClass_GPR, EffectRead);
+ }
+}
+
+static void restore_nonvolatile_GPRs(int reg, SInt32 offset) {
+ int i;
+ SInt32 o;
+
+ o = offset + non_volatile_save_offset[RegClass_GPR];
+
+ if (!use_helper_function(RegClass_GPR)) {
+ if (copts.use_lmw_stmw && ((used_nonvolatile_registers[RegClass_GPR] > 4) || (copts.optimizesize && (used_nonvolatile_registers[RegClass_GPR] > 1)))) {
+ emitpcode(PC_LMW, used_nonvolatile_registers[RegClass_GPR] - 1, 32 - used_nonvolatile_registers[RegClass_GPR], reg, 0, o);
+ setpcodeflags(fIsVolatile);
+ } else {
+ for (i = 1; i <= used_nonvolatile_registers[RegClass_GPR]; i++) {
+ emitpcode(PC_LWZ, 32 - i, reg, 0, o + (used_nonvolatile_registers[RegClass_GPR] - i) * 4);
+ setpcodeflags(fIsVolatile);
+ }
+ }
+ } else {
+ load_base_offset(11, reg, o + used_nonvolatile_registers[RegClass_GPR] * 4);
+ call_helper_function("__restgpr_%d", RegClass_GPR, EffectWrite);
+ }
+}
+
+static void do_allocate_dynamic_stack_space(Boolean isConstantSize, int reg1, int reg2, SInt32 size) {
+ load_store_register(PC_LWZ, reg2, 1, NULL, 0);
+ if (isConstantSize) {
+ size = ALIGN(size, frame_alignment);
+ if (size < 0x8000) {
+ emitpcode(PC_STWU, reg2, 1, 0, -size);
+ } else {
+ emitpcode(PC_LIS, reg1, 0, (short) HIGH_PART(-size));
+ if (-size)
+ emitpcode(PC_ADDI, reg1, reg1, 0, LOW_PART(-size));
+ emitpcode(PC_STWUX, reg2, 1, reg1);
+ setpcodeflags(fIsVolatile | fSideEffects);
+ }
+ } else {
+ emitpcode(PC_STWUX, reg2, 1, reg1);
+ setpcodeflags(fIsVolatile | fSideEffects);
+ }
+}
+
+void allocate_dynamic_stack_space(Boolean isConstantSize, int reg1, int reg2, SInt32 size) {
+ if (copts.altivec_model)
+ update_frame_align(16);
+ do_allocate_dynamic_stack_space(isConstantSize, reg1, reg2, size);
+ add_immediate(reg1, 1, dummylocal, 0);
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct Traceback {
+ UInt8 x0;
+ UInt8 x1;
+ UInt8 x2;
+ UInt8 x3;
+ UInt8 x4;
+ UInt8 x5;
+
+ UInt8 x6_0 : 2;
+ UInt8 x6_1 : 1; // set to 1
+ UInt8 x6_2 : 5;
+
+ UInt8 x7_0 : 1;
+ UInt8 x7_1 : 1; // set to 1
+ UInt8 has_dynamic_stack : 1; // set to 1 if dynamic_stack
+ UInt8 x7_3 : 3;
+ UInt8 uses_CRs : 1; // set to 1 if CRs used
+ UInt8 needs_link_register : 1; // set to 1 if link register used
+
+ UInt8 has_frame_size : 1; // set to 1 if frame_size is nonzero
+ UInt8 x8_1 : 1; // set to 0
+ UInt8 used_FPRs : 6; // stores non-volatile FPRs used
+
+ UInt8 x9_0 : 1; // set to 0
+ UInt8 x9_1 : 1; // set to 1 if VRs or vrsave used
+ UInt8 used_GPRs : 6; // stores non-volatile GPRs used
+
+ UInt8 xA;
+ UInt8 xB;
+
+ SInt32 funcsize;
+ SInt16 namelen;
+ char name[0];
+} Traceback;
+
+typedef struct TracebackExtra {
+ UInt8 used_VRs : 6;
+ UInt8 has_vrsave_mask : 1;
+ UInt8 is_varargs : 1;
+ UInt8 vec_arg_count : 7;
+ UInt8 has_vrsave_mask_or_used_VRs : 1;
+} TracebackExtra;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+char *generate_traceback(SInt32 funcsize, char *funcname, SInt32 *tbsize, Object *func) {
+ char *work;
+ short namelen;
+ Traceback *buf;
+ SInt32 bufsize;
+
+ namelen = strlen(funcname);
+ bufsize = ALIGN(sizeof(Traceback) + namelen + (dynamic_stack ? 1 : 0) + ((used_nonvolatile_registers[RegClass_VR] || vrsave_mask) ? sizeof(TracebackExtra) : 0), 4);
+ buf = lalloc(bufsize);
+ memclrw(buf, bufsize);
+
+ buf->x4 = 0;
+ buf->x5 = copts.cplusplus ? 9 : 0;
+ buf->x6_1 = 1;
+ buf->x7_1 = 1;
+ if (dynamic_stack)
+ buf->has_dynamic_stack = 1;
+ if (used_nonvolatile_registers[RegClass_CRFIELD])
+ buf->uses_CRs = 1;
+ if (need_link_register())
+ buf->needs_link_register = 1;
+ if (frame_size)
+ buf->has_frame_size = 1;
+ buf->used_FPRs = used_nonvolatile_registers[RegClass_FPR];
+ buf->used_GPRs = used_nonvolatile_registers[RegClass_GPR];
+ buf->x8_1 = 0;
+ buf->x9_0 = 0;
+ buf->x9_1 = (used_nonvolatile_registers[RegClass_VR] || vrsave_mask) != 0;
+ buf->funcsize = funcsize;
+ buf->namelen = namelen;
+
+ work = buf->name;
+ strcpy(work, funcname);
+ work += namelen;
+ if (dynamic_stack) {
+ *(work++) = 31;
+ }
+
+ if (vrsave_mask || used_nonvolatile_registers[RegClass_VR]) {
+ TracebackExtra *extra;
+ Boolean is_varargs;
+ int vec_count;
+ FuncArg *args, *scan;
+ Type *type;
+
+ extra = (TracebackExtra *) work;
+ vec_count = 0;
+ args = TYPE_FUNC(func->type)->args;
+ scan = args;
+ while (scan && scan != &elipsis)
+ scan = scan->next;
+ is_varargs = scan == &elipsis;
+ while (args) {
+ if ((type = args->type) && IS_TYPE_VECTOR(type))
+ vec_count++;
+ args = args->next;
+ }
+ extra->used_VRs = used_nonvolatile_registers[RegClass_VR];
+ extra->has_vrsave_mask = vrsave_mask != 0;
+ extra->is_varargs = is_varargs;
+ extra->vec_arg_count = vec_count;
+ extra->has_vrsave_mask_or_used_VRs = vrsave_mask || used_nonvolatile_registers[RegClass_VR];
+ }
+
+ *tbsize = bufsize;
+ return (char *) buf;
+}
+
+static SInt32 localsbase(void) {
+ SInt32 size = parameter_area_size;
+ if (frame_size || dynamic_align_stack)
+ size += linkage_area_size;
+ else
+ size -= genuine_frame_size;
+ return size;
+}
+
+static SInt32 parametersbase(int flag) {
+ if (flag)
+ return 24;
+
+ return frame_size ? (genuine_frame_size + 24) : 24;
+}
+
+void check_dynamic_aligned_frame(void) {
+ PCode *pc;
+
+ if (used_nonvolatile_registers[RegClass_VR]) {
+ update_frame_align(16);
+ requires_frame = 1;
+ }
+
+ if (frame_alignment > in_param_alignment) {
+ dynamic_align_stack = 1;
+ requires_frame = 1;
+ CError_ASSERT(2091, !has_varargs || _CALLER_SP_ != -1);
+ CError_ASSERT(2096, _CALLER_SP_ != _FP_);
+ if (setup_caller_sp && setup_caller_sp->block) {
+ align_instr1 = makepcode(PC_RLWINM, 12, 1, 0, 5, 31);
+ insertpcodebefore(setup_caller_sp, align_instr1);
+ align_instr2 = makepcode(PC_STWUX, 1, 1, 12);
+ insertpcodeafter(setup_caller_sp, align_instr2);
+ }
+ } else {
+ dynamic_align_stack = 0;
+ if (setup_caller_sp && setup_caller_sp->block) {
+ pc = makepcode(PC_MR, _CALLER_SP_, _FP_);
+ insertpcodebefore(setup_caller_sp, pc);
+ deletepcode(setup_caller_sp);
+ setup_caller_sp = pc;
+ }
+ _CALLER_SP_ = _FP_;
+ }
+
+ vrsave_mask = 0;
+ if (copts.altivec_model) {
+ vrsave_mask = colored_vrs_as_vrsave(pcbasicblocks);
+ if (!requires_frame && vrsave_mask) {
+ vrsave_register = 11;
+ loadvrsave = makepcode(PC_LWZ, 11, 1, 0, -4);
+ appendpcode(prologue, loadvrsave);
+ storevrsave = makepcode(PC_STW, 11, 1, 0, -4);
+ appendpcode(epilogue, storevrsave);
+ }
+ }
+}
+
+void move_varargs_to_memory(void) {
+ short reg;
+
+ has_varargs = 1;
+ dummyvaparam = galloc(sizeof(Object));
+ memclrw(dummyvaparam, sizeof(Object));
+
+ dummyvaparam->type = TYPE(&stvoid);
+ dummyvaparam->otype = OT_OBJECT;
+ dummyvaparam->name = GetHashNameNode("<vaparam>");
+ dummyvaparam->datatype = DLOCAL;
+ dummyvaparam->u.var.info = CodeGen_GetNewVarInfo();
+ dummyvaparam->u.var.uid = 0;
+ dummyvaparam->u.var.info->noregister = 1;
+ Registers_GetVarInfo(dummyvaparam)->flags = (Registers_GetVarInfo(dummyvaparam)->flags & ~VarInfoFlag1) | VarInfoFlag1;
+
+ for (reg = last_argument_register[RegClass_GPR] + 1; (int)reg <= 10; reg++) {
+ emitpcode(PC_STW, reg, local_base_register(dummyvaparam), dummyvaparam, (reg - 3) * 4);
+ setpcodeflags(fIsPtrOp | fIsArgInit);
+ }
+}
+
+void assign_arguments_to_memory(Object *func, UInt8 mysteryFlag, Boolean hasVarargs) {
+ // almost matches except for the not/andc issue
+ SInt32 pos;
+ ObjectList *list;
+ Object *obj;
+ Type *type;
+ short reg;
+ SInt32 chk;
+ Boolean flag;
+
+ pos = 0;
+ reg = 2;
+
+ for (list = arguments; list; list = list->next) {
+ obj = list->object;
+ type = obj->type;
+ if (!IS_TYPE_VECTOR(type)) {
+ obj->datatype = DLOCAL;
+ obj->u.var.info = CodeGen_GetNewVarInfo();
+ if (IS_TYPE_ARRAY(type) || IS_TYPE_NONVECTOR_STRUCT(type) || IS_TYPE_CLASS(type) ||
+ IS_TYPE_12BYTES_MEMBERPOINTER(type)) {
+ chk = CMach_ArgumentAlignment(type);
+ if (chk > 4) {
+ pos = ALIGN(pos, chk);
+ update_in_param_align(chk);
+ }
+ }
+ obj->u.var.uid = pos;
+ Registers_GetVarInfo(obj)->flags = (Registers_GetVarInfo(obj)->flags & ~VarInfoFlag1) | VarInfoFlag1;
+ if (!copts.littleendian && (IS_TYPE_INT(obj->type) || IS_TYPE_ENUM(obj->type)) && obj->type->size < 4)
+ obj->u.var.uid += 4 - obj->type->size;
+ pos += type->size;
+ pos = ALIGN(pos, 4);
+ } else {
+ obj->u.var.info = CodeGen_GetNewVarInfo();
+ obj->u.var.uid = 0;
+ obj->datatype = DLOCAL;
+ flag = 1;
+ if (reg <= 13)
+ flag = hasVarargs;
+ if (flag) {
+ pos = ALIGN(pos + 24, 16) - 24;
+ obj->u.var.uid = pos;
+ pos += 16;
+ update_in_param_align(16);
+ Registers_GetVarInfo(obj)->flags = (Registers_GetVarInfo(obj)->flags & ~VarInfoFlag1) | VarInfoFlag1;
+ } else {
+ assign_local_memory(obj);
+ Registers_GetVarInfo(obj)->flags = Registers_GetVarInfo(obj)->flags & ~VarInfoFlag1;
+ }
+ reg++;
+ }
+ }
+
+ in_parameter_size = (in_parameter_size < pos) ? pos : in_parameter_size;
+ CError_ASSERT(2408, !dummyvaparam);
+}
+
+SInt32 set_out_param_displ(SInt32 a, Type *type, Boolean flag, SInt32 *outvar, SInt32 b) {
+ // does not match due to errant andc
+ SInt32 argAlign;
+
+ if (!flag && !b) {
+ *outvar = 0;
+ return a;
+ }
+
+ if (IS_TYPE_VECTOR(type)) {
+ update_out_param_align(16);
+ a = ALIGN(a + 16 + 24, 16) - 24;
+ } else if (IS_TYPE_ARRAY(type) || IS_TYPE_NONVECTOR_STRUCT(type) || IS_TYPE_CLASS(type) || IS_TYPE_12BYTES_MEMBERPOINTER(type)) {
+ argAlign = CMach_ArgumentAlignment(type);
+ if (argAlign > 4) {
+ a = ALIGN(a + 24, argAlign) - 24;
+ update_in_param_align(argAlign);
+ }
+ }
+
+ *outvar = a;
+ a = ALIGN(a + b, 4);
+ return a;
+}
+
+SInt32 out_param_displ_to_offset(SInt32 displ) {
+ return displ + 24;
+}
+
+Boolean needs_frame(void) {
+ return (frame_size > 224) || requires_frame;
+}
+
+void update_out_param_size(SInt32 size) {
+ if (size < 32)
+ size = 32;
+ if (parameter_area_size < size)
+ parameter_area_size = size;
+}
+
+void estimate_out_param_size(SInt32 size) {
+ if (parameter_area_size_estimate < size)
+ parameter_area_size_estimate = size;
+}
+
+void update_out_param_align(SInt32 align) {
+ if (out_param_alignment < align)
+ out_param_alignment = align;
+ update_frame_align(align);
+}
+
+void update_in_param_align(SInt32 align) {
+ if (in_param_alignment < align)
+ in_param_alignment = align;
+}
+
+void update_frame_align(SInt32 align) {
+ if (frame_alignment < align)
+ frame_alignment = align;
+}
+
+SInt32 local_offset_32(Object *obj) {
+ short align;
+ SInt32 offset;
+
+ if (obj->u.var.info->flags & VarInfoFlag1)
+ align = CMach_ArgumentAlignment(obj->type);
+ else
+ align = CMach_AllocationAlignment(obj->type, obj->qual);
+
+ offset = obj->u.var.uid;
+ if (offset > 0x7FFF)
+ offset = 0x8000 - offset - ALIGN(obj->type->size, align);
+
+ if (obj->u.var.info->flags & VarInfoFlag1)
+ return offset + parametersbase(local_base_register(obj) != _FP_);
+ else
+ return offset + localsbase();
+}
+
+SInt32 local_offset_lo(Object *obj, SInt32 offset) {
+ SInt32 combo = offset + local_offset_32(obj);
+ return LOW_PART(combo);
+ //return (SInt16) (offset + local_offset_32(obj));
+}
+
+SInt32 local_offset_ha(Object *obj, SInt32 offset) {
+ SInt32 combo = offset + local_offset_32(obj);
+ return HIGH_PART(combo);
+ //return (SInt16) ((combo >> 16) + ((combo & 0x8000) >> 15));
+}
+
+SInt32 local_offset_16(Object *obj) {
+ SInt32 offset32 = local_offset_32(obj);
+ SInt16 offset16 = (SInt16) offset32;
+ CError_ASSERT(2662, offset32 == offset16);
+ return offset16;
+}
+
+Boolean local_is_16bit_offset(Object *obj) {
+ SInt32 offset32 = local_offset_32(obj);
+ SInt16 offset16 = (SInt16) offset32;
+ return offset32 == offset16;
+}
+
+int local_base_register(Object *obj) {
+ PCode *pc;
+
+ if (obj->u.var.info->flags & VarInfoFlag1) {
+ if (coloring && _CALLER_SP_ == -1) {
+ _CALLER_SP_ = used_virtual_registers[RegClass_GPR]++;
+ pc = makepcode(PC_LWZ, _CALLER_SP_, 1, 0, 0);
+ setup_caller_sp = pc;
+ appendpcode(prologue, pc);
+ }
+ return _CALLER_SP_;
+ } else {
+ return _FP_;
+ }
+}
+
+static UInt32 align_bits(UInt32 value, UInt8 bitcount) {
+ UInt32 base = bitcount != 0;
+ switch (value) {
+ case 0x0002: return base + 30;
+ case 0x0004: return base + 29;
+ case 0x0008: return base + 28;
+ case 0x0010: return base + 27;
+ case 0x0020: return base + 26;
+ case 0x0040: return base + 25;
+ case 0x0080: return base + 24;
+ case 0x0100: return base + 23;
+ case 0x0200: return base + 22;
+ case 0x0400: return base + 21;
+ case 0x0800: return base + 20;
+ case 0x1000: return base + 19;
+ case 0x2000: return base + 18;
+ default:
+ CError_FATAL(2754);
+ return base + 27;
+ }
+}
+
+Boolean is_large_frame(void) {
+ CError_ASSERT(2769, frame_size != -1);
+ return large_stack;
+}
+
+void no_frame_for_asm(void) {
+ frame_size = 0;
+}
+
+Boolean can_add_displ_to_local(Object *obj, SInt32 displ) {
+ if (obj->datatype != DLOCAL)
+ return 0;
+
+ if (local_offset_32(obj) == (short) local_offset_32(obj))
+ if ((displ + local_offset_32(obj)) == (short) (displ + local_offset_32(obj)))
+ return 1;
+
+ return 0;
+}
+
+SInt32 get_alloca_alignment(void) {
+ SInt32 align = frame_alignment;
+ if (copts.altivec_model)
+ align = ALIGN(align, 16);
+
+ if (!alloca_alignment)
+ alloca_alignment = align;
+ else
+ CError_ASSERT(2825, alloca_alignment == align);
+
+ return align_bits(align, 0);
+}
+
+static Boolean use_helper_function(char rclass) {
+ if (copts.no_register_save_helpers)
+ return 0;
+
+ switch (rclass) {
+ case RegClass_GPR:
+ if (copts.use_lmw_stmw)
+ return 0;
+ return (used_nonvolatile_registers[RegClass_GPR] > 4) || (copts.optimizesize && used_nonvolatile_registers[RegClass_GPR] > 2);
+ case RegClass_FPR:
+ return (used_nonvolatile_registers[RegClass_FPR] > 3) || (copts.optimizesize && used_nonvolatile_registers[RegClass_FPR] > 2);
+ case RegClass_VR:
+ return (used_nonvolatile_registers[RegClass_VR] > 3) || (copts.optimizesize && used_nonvolatile_registers[RegClass_VR] > 2);
+ default:
+ CError_FATAL(2862);
+ return 0;
+ }
+}
+
+static Boolean need_link_register(void) {
+ if (copts.codegen_pic && uses_globals)
+ return 1;
+
+ if (makes_call)
+ return 1;
+
+ return use_helper_function(RegClass_FPR) || use_helper_function(RegClass_GPR) || use_helper_function(RegClass_VR);
+}
+
+static void call_helper_function(char *name, char rclass, short effect) {
+ char str[32];
+ Object *func;
+ NameSpace *save_scope;
+ PCode *pc;
+ int extra_args;
+ PCodeArg *arg;
+ short i;
+
+ extra_args = 1;
+ if (rclass == RegClass_VR)
+ extra_args = 2;
+
+ sprintf(str, name, 32 - used_nonvolatile_registers[rclass]);
+
+ save_scope = cscope_current;
+ cscope_current = cscope_root;
+ func = CParser_NewRTFunc(&stvoid, NULL, 2, 0);
+ cscope_current = save_scope;
+
+ func->name = GetHashNameNodeExport(str);
+
+ pc = makepcode(PC_BL, extra_args + used_nonvolatile_registers[rclass], func, 0);
+ for (i = 1, arg = &pc->args[1]; i <= used_nonvolatile_registers[rclass]; i++, arg++) {
+ arg->kind = PCOp_REGISTER;
+ arg->arg = rclass;
+ arg->data.reg.reg = n_real_registers[rclass] - i;
+ arg->data.reg.effect = effect;
+ }
+
+ if (rclass == RegClass_VR) {
+ arg[1].kind = PCOp_REGISTER;
+ arg[1].arg = RegClass_GPR;
+ arg[1].data.reg.reg = 12;
+ arg[1].data.reg.effect = EffectWrite;
+ arg[2].kind = PCOp_REGISTER;
+ arg[2].arg = RegClass_GPR;
+ arg[2].data.reg.reg = 0;
+ arg[2].data.reg.effect = EffectRead;
+ } else {
+ arg[1].kind = PCOp_REGISTER;
+ arg[1].arg = RegClass_GPR;
+ arg[1].data.reg.reg = 11;
+ arg[1].data.reg.effect = EffectRead;
+ }
+
+ appendpcode(pclastblock, pc);
+ setpcodeflags(fSideEffects);
+}
+
+static SInt32 nearest_power_of_two(SInt32 n) {
+ SInt32 power = 1;
+ do {
+ power <<= 1;
+ } while (power && power < n);
+
+ CError_ASSERT(2933, power != 0);
+ return power;
+}
+
+static void compress_data_area(void) {
+ // doesn't quite match
+ SInt32 r0;
+ SInt32 r7;
+ ObjectList *list;
+ Object *obj;
+ PCodeBlock *block;
+ PCode *pc;
+ int i;
+
+ compressing_data_area = 1;
+
+ if (large_stack) {
+ r0 = 0;
+ } else {
+ r0 = parameter_area_size;
+ if (r0 < 32)
+ r0 = 32;
+ }
+ r7 = ALIGN(r0 + 24, frame_alignment) - 24;
+ local_data_limit = 0x8000 - ALIGN(24 + in_parameter_size + nonvolatile_save_size + r7, frame_alignment);
+
+ if (local_objects_tail[ObjClass0]) {
+ if (local_objects[ObjClass1]) {
+ local_objects_tail[ObjClass0]->next = local_objects[ObjClass1];
+ local_objects_tail[ObjClass0] = local_objects_tail[ObjClass1];
+ }
+ if (local_objects[ObjClass2]) {
+ local_objects_tail[ObjClass0]->next = local_objects[ObjClass2];
+ local_objects_tail[ObjClass0] = local_objects_tail[ObjClass2];
+ }
+ } else if (local_objects_tail[ObjClass1]) {
+ local_objects[ObjClass0] = local_objects[ObjClass1];
+ local_objects_tail[ObjClass0] = local_objects_tail[ObjClass1];
+ if (local_objects[ObjClass2]) {
+ local_objects_tail[ObjClass0]->next = local_objects[ObjClass2];
+ local_objects_tail[ObjClass0] = local_objects_tail[ObjClass2];
+ }
+ } else {
+ local_objects[ObjClass0] = local_objects[ObjClass2];
+ local_objects_tail[ObjClass0] = local_objects_tail[ObjClass2];
+ }
+
+ for (list = local_objects[ObjClass0]; list; list = list->next)
+ Registers_GetVarInfo(list->object)->used = 0;
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ for (pc = block->firstPCode; pc; pc = pc->nextPCode) {
+ for (i = 0; i < pc->argCount; i++) {
+ if (pc->args[i].kind == PCOp_MEMORY && pc->args[i].data.mem.obj && pc->args[i].data.mem.obj->datatype == DLOCAL)
+ Registers_GetVarInfo(pc->args[i].data.mem.obj)->used = 1;
+ }
+ }
+ }
+
+ local_data_size = 0;
+ large_data_near_size = 0;
+ large_data_far_size = 0;
+
+ for (list = local_objects[ObjClass0]; list; list = list->next) {
+ obj = list->object;
+ if (Registers_GetVarInfo(obj)->used)
+ assign_local_memory(obj);
+ }
+}
+
+static void insert_local_object(UInt8 oclass, Object *obj) {
+ ObjectList *list;
+
+ if (!compressing_data_area) {
+ list = lalloc(sizeof(ObjectList));
+ memclrw(list, sizeof(ObjectList));
+ list->object = obj;
+ if (!local_objects[oclass])
+ local_objects[oclass] = list;
+ if (local_objects_tail[oclass])
+ local_objects_tail[oclass]->next = list;
+ local_objects_tail[oclass] = list;
+ }
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c
new file mode 100644
index 0000000..7c28b88
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c
@@ -0,0 +1,792 @@
+#include "compiler/StructMoves.h"
+#include "compiler/CError.h"
+#include "compiler/CParser.h"
+#include "compiler/CodeGen.h"
+#include "compiler/Operands.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/Registers.h"
+
+void make_addressable(Operand *opnd, SInt32 offset, int unusedArg) {
+ int reg;
+
+ if (opnd->optype == OpndType_IndirectSymbol)
+ coerce_to_addressable(opnd);
+
+ if (opnd->optype != OpndType_IndirectGPR_ImmOffset || (opnd->immOffset + offset) > 0x7FFF) {
+ reg = used_virtual_registers[RegClass_GPR]++;
+ load_address(reg, opnd);
+ opnd->optype = OpndType_IndirectGPR_ImmOffset;
+ opnd->reg = reg;
+ opnd->object = NULL;
+ opnd->immOffset = 0;
+ }
+}
+
+static void load_displaced_address(Operand *opnd, SInt32 offset) {
+ int reg;
+
+ reg = used_virtual_registers[RegClass_GPR]++;
+ if (opnd->optype == OpndType_IndirectSymbol)
+ coerce_to_addressable(opnd);
+
+ if (opnd->optype == OpndType_IndirectGPR_ImmOffset) {
+ offset += opnd->immOffset;
+ if (!FITS_IN_SHORT(offset)) {
+ add_immediate(reg, opnd->reg, opnd->object, opnd->immOffset);
+ emitpcode(PC_ADDI, reg, reg, 0, offset - opnd->immOffset);
+ } else {
+ add_immediate(reg, opnd->reg, opnd->object, offset);
+ }
+ } else if (opnd->optype == OpndType_IndirectGPR_Indexed) {
+ emitpcode(PC_ADD, reg, opnd->reg, opnd->regOffset);
+ emitpcode(PC_ADDI, reg, reg, 0, offset);
+ } else {
+ CError_FATAL(80);
+ }
+
+ opnd->optype = OpndType_IndirectGPR_ImmOffset;
+ opnd->reg = reg;
+ opnd->object = NULL;
+ opnd->immOffset = 0;
+}
+
+static void move_block_via_load_store(Operand *dst, Operand *src, SInt32 len, SInt32 align) {
+ SInt32 step;
+ SInt32 pos;
+ int floatReg;
+ int reg;
+
+ if (src->optype == OpndType_IndirectSymbol)
+ coerce_to_addressable(src);
+ if (dst->optype == OpndType_IndirectSymbol)
+ coerce_to_addressable(dst);
+
+ if (len == 8) {
+ floatReg = used_virtual_registers[RegClass_FPR]++;
+ if (src->optype == OpndType_IndirectGPR_ImmOffset) {
+ load_store_register(PC_LFD, floatReg, src->reg, src->object, src->immOffset);
+ setpcodeflags(src->flags);
+ } else if (src->optype == OpndType_IndirectGPR_Indexed) {
+ emitpcode(PC_LFDX, floatReg, src->reg, src->regOffset);
+ setpcodeflags(src->flags);
+ } else {
+ CError_FATAL(145);
+ }
+
+ if (dst->optype == OpndType_IndirectGPR_ImmOffset) {
+ load_store_register(PC_STFD, floatReg, dst->reg, dst->object, dst->immOffset);
+ setpcodeflags(dst->flags);
+ } else if (dst->optype == OpndType_IndirectGPR_Indexed) {
+ emitpcode(PC_STFDX, floatReg, dst->reg, dst->regOffset);
+ setpcodeflags(dst->flags);
+ } else {
+ CError_FATAL(157);
+ }
+
+ return;
+ }
+
+ if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
+ SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align;
+ step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2;
+ } else {
+ step = ((UInt32) len > 4) ? 4 : ((UInt32) len <= 2) ? len : 2;
+ }
+
+ if (step != len) {
+ if (dst->optype == OpndType_IndirectGPR_Indexed)
+ make_addressable(dst, len, 0);
+ if (src->optype == OpndType_IndirectGPR_Indexed)
+ make_addressable(src, len, 0);
+ }
+
+ for (pos = 0; len != 0; len -= step, pos += step) {
+ reg = used_virtual_registers[RegClass_GPR]++;
+ if (src->optype == OpndType_IndirectGPR_ImmOffset) {
+ load_store_register(
+ (step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
+ reg,
+ src->reg,
+ src->object,
+ src->immOffset + pos
+ );
+ setpcodeflags(src->flags);
+ } else if (src->optype == OpndType_IndirectGPR_Indexed) {
+ emitpcode(
+ (step == 1) ? PC_LBZX : (step == 2) ? PC_LHZX : PC_LWZX,
+ reg,
+ src->reg,
+ src->regOffset
+ );
+ setpcodeflags(src->flags);
+ } else {
+ CError_FATAL(183);
+ }
+
+ if (dst->optype == OpndType_IndirectGPR_ImmOffset) {
+ load_store_register(
+ (step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
+ reg,
+ dst->reg,
+ dst->object,
+ dst->immOffset + pos
+ );
+ setpcodeflags(dst->flags);
+ } else if (dst->optype == OpndType_IndirectGPR_Indexed) {
+ emitpcode(
+ (step == 1) ? PC_STBX : (step == 2) ? PC_STHX : PC_STWX,
+ reg,
+ dst->reg,
+ dst->regOffset
+ );
+ setpcodeflags(dst->flags);
+ } else {
+ CError_FATAL(195);
+ }
+ }
+}
+
+static void move_block_via_load_store_sequence(Operand *dst, Operand *src, SInt32 len, SInt32 align) {
+ SInt32 pos;
+ int i;
+ SInt32 step;
+
+ pos = 0;
+ make_addressable(dst, len, 0);
+ make_addressable(src, len, 0);
+
+ if ((align % 8) == 0) {
+ while (len >= 16) {
+ int reg1 = used_virtual_registers[RegClass_FPR]++;
+ int reg2 = used_virtual_registers[RegClass_FPR]++;
+ load_store_register(PC_LFD, reg1, src->reg, src->object, src->immOffset + pos);
+ setpcodeflags(src->flags);
+ load_store_register(PC_LFD, reg2, src->reg, src->object, src->immOffset + pos + 8);
+ setpcodeflags(src->flags);
+
+ load_store_register(PC_STFD, reg1, dst->reg, dst->object, dst->immOffset + pos);
+ setpcodeflags(dst->flags);
+ load_store_register(PC_STFD, reg2, dst->reg, dst->object, dst->immOffset + pos + 8);
+ setpcodeflags(dst->flags);
+
+ pos += 16;
+ len -= 16;
+ }
+ }
+
+ while (len >= 8) {
+ if ((align % 8) == 0) {
+ int reg = used_virtual_registers[RegClass_FPR]++;
+
+ load_store_register(PC_LFD, reg, src->reg, src->object, src->immOffset + pos);
+ setpcodeflags(src->flags);
+
+ load_store_register(PC_STFD, reg, dst->reg, dst->object, dst->immOffset + pos);
+ setpcodeflags(dst->flags);
+
+ pos += 8;
+ len -= 8;
+ } else {
+ if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
+ SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align;
+ step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp > 2) ? 2 : 1;
+ } else {
+ step = 4;
+ }
+
+ for (i = 0; i < 8; i += (step * 2)) {
+ int reg1 = used_virtual_registers[RegClass_GPR]++;
+ int reg2 = used_virtual_registers[RegClass_GPR]++;
+
+ load_store_register(
+ (step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
+ reg1,
+ src->reg,
+ src->object,
+ src->immOffset + pos
+ );
+ setpcodeflags(src->flags);
+
+ load_store_register(
+ (step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
+ reg2,
+ src->reg,
+ src->object,
+ src->immOffset + pos + step
+ );
+ setpcodeflags(src->flags);
+
+ load_store_register(
+ (step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
+ reg1,
+ dst->reg,
+ dst->object,
+ dst->immOffset + pos
+ );
+ setpcodeflags(dst->flags);
+
+ load_store_register(
+ (step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
+ reg2,
+ dst->reg,
+ dst->object,
+ dst->immOffset + pos + step
+ );
+ setpcodeflags(dst->flags);
+
+ pos += (step * 2);
+ len -= (step * 2);
+ }
+ }
+ }
+
+ while (len) {
+ int reg;
+
+ if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
+ SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align;
+ step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2;
+ } else {
+ step = ((UInt32) len > 4) ? 4 : ((UInt32) len <= 2) ? len : 2;
+ }
+
+ reg = used_virtual_registers[RegClass_GPR]++;
+
+ load_store_register(
+ (step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
+ reg,
+ src->reg,
+ src->object,
+ src->immOffset + pos
+ );
+ setpcodeflags(src->flags);
+
+ load_store_register(
+ (step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
+ reg,
+ dst->reg,
+ dst->object,
+ dst->immOffset + pos
+ );
+ setpcodeflags(dst->flags);
+
+ len -= step;
+ pos += step;
+ }
+}
+
+static void move_block_via_inline_loop(Operand *dst, Operand *src, SInt32 len, SInt32 align) {
+ PCodeLabel *label; // r25
+ SInt32 pos; // r25
+ SInt32 step; // r24
+ int reg1; // r22
+ int reg2; // r23
+ SInt32 remainder; // r23
+
+ label = makepclabel();
+
+ if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
+ SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align;
+ step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2;
+ } else {
+ step = 4;
+ }
+
+ load_displaced_address(dst, -step);
+ load_displaced_address(src, -step);
+
+ CError_ASSERT(377, (len / step) != 0);
+
+ reg1 = used_virtual_registers[RegClass_GPR]++;
+ load_immediate(reg1, len / (step * 2));
+ emitpcode(PC_MTCTR, reg1);
+ branch_label(label);
+
+ reg1 = used_virtual_registers[RegClass_GPR]++;
+ reg2 = used_virtual_registers[RegClass_GPR]++;
+
+ load_store_register(
+ (step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
+ reg1,
+ src->reg,
+ NULL,
+ step
+ );
+ setpcodeflags(src->flags);
+
+ load_store_register(
+ (step == 1) ? PC_LBZU : (step == 2) ? PC_LHZU : PC_LWZU,
+ reg2,
+ src->reg,
+ NULL,
+ step * 2
+ );
+ setpcodeflags(src->flags);
+
+ load_store_register(
+ (step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
+ reg1,
+ dst->reg,
+ NULL,
+ step
+ );
+ setpcodeflags(dst->flags);
+
+ load_store_register(
+ (step == 1) ? PC_STBU : (step == 2) ? PC_STHU : PC_STWU,
+ reg2,
+ dst->reg,
+ NULL,
+ step * 2
+ );
+ setpcodeflags(dst->flags);
+
+ branch_decrement_always(PC_BDNZ, label);
+
+ for (remainder = len & 7, pos = step; remainder != 0; remainder -= step, pos += step) {
+ int reg;
+
+ if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
+ SInt32 tmp = (align == 0) ? 1 : (align > remainder) ? remainder : align;
+ step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2;
+ } else {
+ step = ((UInt32) remainder > 4) ? 4 : ((UInt32) remainder <= 2) ? remainder : 2;
+ }
+
+ reg = used_virtual_registers[RegClass_GPR]++;
+
+ load_store_register(
+ (step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
+ reg,
+ src->reg,
+ NULL,
+ pos
+ );
+ setpcodeflags(src->flags);
+
+ load_store_register(
+ (step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
+ reg,
+ dst->reg,
+ NULL,
+ pos
+ );
+ setpcodeflags(dst->flags);
+ }
+}
+
+void move_block(Operand *dst, Operand *src, SInt32 len, SInt32 align) {
+ Operand myDst;
+
+ myDst = *dst;
+
+ CError_ASSERT(447, myDst.optype >= OpndType_IndirectGPR_ImmOffset);
+ CError_ASSERT(449, src->optype >= OpndType_IndirectGPR_ImmOffset);
+
+ if (len == 1 || len == 2 || len == 4)
+ move_block_via_load_store(&myDst, src, len, align);
+ else if (len == 8 && align == 8)
+ move_block_via_load_store(&myDst, src, len, align);
+ else if (len <= 16 || (copts.optimizesize == 0 && len <= 64))
+ move_block_via_load_store_sequence(&myDst, src, len, align);
+ else
+ move_block_via_inline_loop(&myDst, src, len, align);
+}
+
+static void load_word_of_small_struct(short dstReg, short srcReg, Operand *opnd, SInt32 offset, SInt32 len, SInt32 align) {
+ short tmpReg;
+ short extra = 0;
+
+ switch (len) {
+ case 1:
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset);
+ setpcodeflags(opnd->flags);
+ emitpcode(PC_RLWINM, dstReg, tmpReg, 24, 0, 7);
+ setpcodeflags(opnd->flags);
+ break;
+ case 2:
+ case 3:
+ if (align > 1) {
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ load_store_register(PC_LHZ, tmpReg, srcReg, opnd->object, offset);
+ extra += 2;
+ setpcodeflags(opnd->flags);
+ emitpcode(PC_RLWINM, dstReg, tmpReg, 16, 0, 15);
+ setpcodeflags(opnd->flags);
+ } else {
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset);
+ setpcodeflags(opnd->flags);
+ emitpcode(PC_RLWINM, dstReg, tmpReg, 24, 0, 7);
+ setpcodeflags(opnd->flags);
+
+ load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 1);
+ extra += 2;
+ setpcodeflags(opnd->flags);
+ emitpcode(PC_RLWIMI, dstReg, tmpReg, 16, 8, 15);
+ setpcodeflags(opnd->flags);
+ }
+ if (len == 3) {
+ load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + extra);
+ setpcodeflags(opnd->flags);
+ emitpcode(PC_RLWIMI, dstReg, tmpReg, 8, 16, 23);
+ setpcodeflags(opnd->flags);
+ }
+ break;
+ case 4:
+ if (align > 2) {
+ load_store_register(PC_LWZ, dstReg, srcReg, opnd->object, offset);
+ setpcodeflags(opnd->flags);
+ } else if (align > 1) {
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ load_store_register(PC_LHZ, tmpReg, srcReg, opnd->object, offset);
+ setpcodeflags(opnd->flags);
+ emitpcode(PC_RLWINM, dstReg, tmpReg, 16, 0, 15);
+ setpcodeflags(opnd->flags);
+
+ load_store_register(PC_LHZ, tmpReg, srcReg, opnd->object, offset + 2);
+ setpcodeflags(opnd->flags);
+ emitpcode(PC_RLWIMI, dstReg, tmpReg, 0, 16, 31);
+ setpcodeflags(opnd->flags);
+ } else {
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset);
+ setpcodeflags(opnd->flags);
+ emitpcode(PC_RLWINM, dstReg, tmpReg, 24, 0, 7);
+ setpcodeflags(opnd->flags);
+
+ load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 1);
+ setpcodeflags(opnd->flags);
+ emitpcode(PC_RLWIMI, dstReg, tmpReg, 16, 8, 15);
+ setpcodeflags(opnd->flags);
+
+ load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 2);
+ setpcodeflags(opnd->flags);
+ emitpcode(PC_RLWIMI, dstReg, tmpReg, 8, 16, 23);
+ setpcodeflags(opnd->flags);
+
+ load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 3);
+ setpcodeflags(opnd->flags);
+ emitpcode(PC_RLWIMI, dstReg, tmpReg, 0, 24, 31);
+ setpcodeflags(opnd->flags);
+ }
+ break;
+ }
+}
+
+void load_small_block_into_reg(short dstReg, Operand *srcOpnd, Type *type, SInt32 align) {
+ short finalReg;
+ short tmpReg;
+ SInt32 absAddress;
+
+ coerce_to_addressable(srcOpnd);
+
+ if (srcOpnd->optype == OpndType_IndirectGPR_Indexed) {
+ CError_FATAL(557);
+
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ load_address(tmpReg, srcOpnd);
+ srcOpnd->optype = OpndType_IndirectGPR_ImmOffset;
+ srcOpnd->reg = tmpReg;
+ srcOpnd->object = NULL;
+ srcOpnd->immOffset = 0;
+ }
+
+ if (copts.misaligned_mem_access)
+ align = 4;
+
+ switch (srcOpnd->optype) {
+ case OpndType_GPRPair:
+ return;
+ case OpndType_GPR:
+ return;
+ case OpndType_GPR_ImmOffset:
+ finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++;
+ add_immediate(finalReg, srcOpnd->reg, srcOpnd->object, srcOpnd->immOffset);
+ break;
+ case OpndType_GPR_Indexed:
+ finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_ADD, finalReg, srcOpnd->reg, srcOpnd->regOffset);
+ break;
+ case OpndType_Absolute:
+ finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++;
+ absAddress = srcOpnd->immediate;
+ if (FITS_IN_SHORT(absAddress)) {
+ emitpcode(PC_LI, finalReg, absAddress);
+ } else {
+ tmpReg = finalReg;
+ if (copts.optimizationlevel > 1 && absAddress)
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_LIS, tmpReg, 0, HIGH_PART(absAddress));
+ if (absAddress)
+ emitpcode(PC_ADDI, finalReg, tmpReg, 0, LOW_PART(absAddress));
+ }
+ break;
+ case OpndType_IndirectGPR_ImmOffset:
+ finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++;
+ load_word_of_small_struct(finalReg, srcOpnd->reg, srcOpnd, srcOpnd->immOffset, type->size, align);
+ break;
+ default:
+ CError_FATAL(606);
+ }
+
+ srcOpnd->optype = OpndType_GPR;
+ srcOpnd->reg = finalReg;
+}
+
+void load_small_block_into_reg_pair(short dstRegLo, short dstRegHi, Operand *srcOpnd, Type *type, SInt32 align) {
+ short finalRegLo;
+ short finalRegHi;
+ short tmpRegLo;
+ short tmpRegHi;
+ short tmpReg;
+ SInt32 absAddress;
+
+ finalRegHi = -1;
+ coerce_to_addressable(srcOpnd);
+
+ if (srcOpnd->optype == OpndType_IndirectGPR_Indexed) {
+ CError_FATAL(624);
+
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ load_address(tmpReg, srcOpnd);
+ srcOpnd->optype = OpndType_IndirectGPR_ImmOffset;
+ srcOpnd->reg = tmpReg;
+ srcOpnd->object = NULL;
+ srcOpnd->immOffset = 0;
+ }
+
+ if (copts.misaligned_mem_access)
+ align = 4;
+
+ switch (srcOpnd->optype) {
+ case OpndType_GPRPair:
+ if (dstRegLo != 0 && dstRegHi == 0)
+ dstRegHi = used_virtual_registers[RegClass_GPR]++;
+ if (dstRegHi != 0 && dstRegLo == 0)
+ dstRegLo = used_virtual_registers[RegClass_GPR]++;
+
+ if (srcOpnd->reg != dstRegLo || srcOpnd->regHi != dstRegHi) {
+ tmpRegLo = dstRegLo ? dstRegLo : srcOpnd->reg;
+ tmpRegHi = dstRegHi ? dstRegHi : srcOpnd->regHi;
+
+ if (tmpRegLo != srcOpnd->reg) {
+ if (tmpRegLo == srcOpnd->regHi) {
+ CError_ASSERT(657, tmpRegLo != tmpRegHi);
+ emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi);
+ emitpcode(PC_MR, tmpRegLo, srcOpnd->reg);
+ } else {
+ emitpcode(PC_MR, tmpRegLo, srcOpnd->reg);
+ if (srcOpnd->regHi != tmpRegHi)
+ emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi);
+ }
+ } else if (tmpRegHi != srcOpnd->regHi) {
+ if (tmpRegHi == srcOpnd->reg) {
+ CError_ASSERT(671, tmpRegLo != tmpRegHi);
+ emitpcode(PC_MR, tmpRegLo, srcOpnd->reg);
+ emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi);
+ } else {
+ emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi);
+ if (srcOpnd->reg != tmpRegLo)
+ emitpcode(PC_MR, tmpRegLo, srcOpnd->reg);
+ }
+ }
+ }
+
+ finalRegLo = srcOpnd->reg;
+ finalRegHi = srcOpnd->regHi;
+ break;
+ case OpndType_GPR:
+ CError_FATAL(688);
+ break;
+ case OpndType_GPR_ImmOffset:
+ CError_FATAL(691);
+ break;
+ case OpndType_GPR_Indexed:
+ CError_FATAL(694);
+ break;
+ case OpndType_Absolute:
+ finalRegLo = dstRegLo ? dstRegLo : used_virtual_registers[RegClass_GPR]++;
+ absAddress = srcOpnd->immediate;
+ if (FITS_IN_SHORT(absAddress)) {
+ emitpcode(PC_LI, finalRegLo, absAddress);
+ } else {
+ tmpReg = finalRegLo;
+ if (copts.optimizationlevel > 1 && absAddress)
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_LIS, tmpReg, 0, HIGH_PART(absAddress));
+ if (absAddress)
+ emitpcode(PC_ADDI, finalRegLo, tmpReg, 0, LOW_PART(absAddress));
+ }
+
+ finalRegHi = dstRegHi ? dstRegHi : used_virtual_registers[RegClass_GPR]++;
+ if (is_unsigned(type) || absAddress >= 0)
+ load_immediate(finalRegHi, 0);
+ else
+ load_immediate(finalRegHi, -1);
+
+ break;
+ case OpndType_IndirectGPR_ImmOffset:
+ finalRegLo = dstRegLo ? dstRegLo : used_virtual_registers[RegClass_GPR]++;
+ finalRegHi = dstRegHi ? dstRegHi : used_virtual_registers[RegClass_GPR]++;
+ if (srcOpnd->reg == finalRegHi) {
+ if (srcOpnd->reg == finalRegLo) {
+ CError_FATAL(726);
+ } else {
+ load_word_of_small_struct(
+ finalRegLo, srcOpnd->reg, srcOpnd,
+ srcOpnd->immOffset + low_offset, type->size - 4, align);
+ load_word_of_small_struct(
+ finalRegHi, srcOpnd->reg, srcOpnd,
+ srcOpnd->immOffset + high_offset, 4, align);
+ }
+ } else {
+ load_word_of_small_struct(
+ finalRegHi, srcOpnd->reg, srcOpnd,
+ srcOpnd->immOffset + high_offset, 4, align);
+ load_word_of_small_struct(
+ finalRegLo, srcOpnd->reg, srcOpnd,
+ srcOpnd->immOffset + low_offset, type->size - 4, align);
+ }
+ break;
+ default:
+ CError_FATAL(737);
+ }
+
+ if (finalRegHi == -1) {
+ CError_FATAL(741);
+ } else {
+ srcOpnd->optype = OpndType_GPRPair;
+ srcOpnd->reg = finalRegLo;
+ srcOpnd->regHi = finalRegHi;
+ }
+}
+
+static void store_word_of_small_struct(short srcReg, short dstReg, Operand *opnd, SInt32 offset, SInt32 len, SInt32 align) {
+ short tmpReg;
+ short extra = 0;
+
+ switch (len) {
+ case 1:
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_RLWINM, tmpReg, srcReg, 8, 24, 31);
+ setpcodeflags(opnd->flags);
+ load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset);
+ setpcodeflags(opnd->flags);
+ break;
+ case 2:
+ case 3:
+ if (align > 1) {
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 16, 31);
+ setpcodeflags(opnd->flags);
+ load_store_register(PC_STH, tmpReg, dstReg, opnd->object, offset);
+ extra += 2;
+ setpcodeflags(opnd->flags);
+ } else {
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_RLWINM, tmpReg, srcReg, 8, 24, 31);
+ setpcodeflags(opnd->flags);
+ load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset);
+ setpcodeflags(opnd->flags);
+
+ emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 24, 31);
+ setpcodeflags(opnd->flags);
+ load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + 1);
+ extra += 2;
+ setpcodeflags(opnd->flags);
+ }
+ if (len == 3) {
+ emitpcode(PC_RLWINM, tmpReg, srcReg, 24, 24, 31);
+ setpcodeflags(opnd->flags);
+ load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + extra);
+ setpcodeflags(opnd->flags);
+ }
+ break;
+ case 4:
+ if (align > 2) {
+ load_store_register(PC_STW, srcReg, dstReg, opnd->object, offset);
+ setpcodeflags(opnd->flags);
+ } else if (align > 1) {
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 16, 31);
+ setpcodeflags(opnd->flags);
+ load_store_register(PC_STH, tmpReg, dstReg, opnd->object, offset);
+ setpcodeflags(opnd->flags);
+
+ load_store_register(PC_STH, srcReg, dstReg, opnd->object, offset + 2);
+ setpcodeflags(opnd->flags);
+ } else {
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ emitpcode(PC_RLWINM, tmpReg, srcReg, 8, 24, 31);
+ setpcodeflags(opnd->flags);
+ load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset);
+ setpcodeflags(opnd->flags);
+
+ emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 24, 31);
+ setpcodeflags(opnd->flags);
+ load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + 1);
+ setpcodeflags(opnd->flags);
+
+ emitpcode(PC_RLWINM, tmpReg, srcReg, 24, 24, 31);
+ setpcodeflags(opnd->flags);
+ load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + 2);
+ setpcodeflags(opnd->flags);
+
+ load_store_register(PC_STB, srcReg, dstReg, opnd->object, offset + 3);
+ setpcodeflags(opnd->flags);
+ }
+ break;
+ }
+}
+
+void store_small_block_from_reg(short srcReg, Operand *dstOpnd, Type *type, SInt32 align) {
+ short tmpReg;
+
+ coerce_to_addressable(dstOpnd);
+
+ if (dstOpnd->optype == OpndType_IndirectGPR_Indexed) {
+ CError_FATAL(839);
+
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ load_address(tmpReg, dstOpnd);
+ dstOpnd->optype = OpndType_IndirectGPR_ImmOffset;
+ dstOpnd->reg = tmpReg;
+ dstOpnd->object = NULL;
+ dstOpnd->immOffset = 0;
+ }
+
+ if (copts.misaligned_mem_access)
+ align = 4;
+
+ store_word_of_small_struct(srcReg, dstOpnd->reg, dstOpnd, dstOpnd->immOffset, type->size, align);
+}
+
+void store_small_block_from_reg_pair(short srcRegLo, short srcRegHi, Operand *dstOpnd, Type *type, SInt32 align) {
+ short tmpReg;
+
+ coerce_to_addressable(dstOpnd);
+
+ if (dstOpnd->optype == OpndType_IndirectGPR_Indexed) {
+ CError_FATAL(860);
+
+ tmpReg = used_virtual_registers[RegClass_GPR]++;
+ load_address(tmpReg, dstOpnd);
+ dstOpnd->optype = OpndType_IndirectGPR_ImmOffset;
+ dstOpnd->reg = tmpReg;
+ dstOpnd->object = NULL;
+ dstOpnd->immOffset = 0;
+ }
+
+ if (copts.misaligned_mem_access)
+ align = 4;
+
+ store_word_of_small_struct(
+ srcRegLo, dstOpnd->reg, dstOpnd,
+ dstOpnd->immOffset + low_offset, type->size - 4, align);
+ store_word_of_small_struct(
+ srcRegHi, dstOpnd->reg, dstOpnd,
+ dstOpnd->immOffset + high_offset, 4, align);
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Switch.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Switch.c
new file mode 100644
index 0000000..4bbd82e
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Switch.c
@@ -0,0 +1,518 @@
+#include "compiler/Switch.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInt64.h"
+#include "compiler/CParser.h"
+#include "compiler/InstrSelection.h"
+#include "compiler/ObjGenMachO.h"
+#include "compiler/Operands.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/TOC.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/objects.h"
+
+ObjectList *switchtables;
+static SwitchCase **caselabels;
+static CaseRange *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 int compare_cases(const void *a, const void *b) {
+ const SwitchCase **casea = (const SwitchCase **) a;
+ const SwitchCase **caseb = (const SwitchCase **) b;
+
+ if (CInt64_Less((*casea)->min, (*caseb)->min))
+ return -1;
+ if (CInt64_Greater((*casea)->min, (*caseb)->min))
+ return 1;
+ return 0;
+}
+
+static void build_case_ranges(Type *type, SwitchCase *cases, CLabel *label) {
+ SwitchCase **caseptr;
+ SInt32 i;
+ SwitchCase *curcase;
+ CaseRange *currange;
+
+ if (type->size == 8) {
+ min.lo = 0;
+ min.hi = 0x80000000;
+ max.lo = 0xFFFFFFFF;
+ max.hi = 0x7FFFFFFF;
+ } else if (type->size == 4) {
+ CInt64_SetLong(&min, 0x80000000);
+ CInt64_SetLong(&max, 0x7FFFFFFF);
+ } else if (is_unsigned(type)) {
+ min.hi = 0;
+ min.lo = 0;
+ max.hi = 0;
+ max.lo = 0xFFFF;
+ } else {
+ CInt64_SetLong(&min, -0x8000);
+ CInt64_SetLong(&max, 0x7FFF);
+ }
+
+ caselabels = lalloc(sizeof(SwitchCase *) * ncases);
+ caseptr = caselabels;
+ while (cases) {
+ *caseptr = cases;
+ cases = cases->next;
+ ++caseptr;
+ }
+
+ caseranges = lalloc(((ncases * 2) + 2) * sizeof(CaseRange));
+ if (type->size < 8) {
+ for (i = 0; i < ncases; i++)
+ CInt64_SetLong(&caselabels[i]->min, caselabels[i]->min.lo);
+ }
+
+ qsort(caselabels, ncases, sizeof(SwitchCase *), &compare_cases);
+
+ currange = caseranges;
+ currange->min = min;
+ currange->range = CInt64_Sub(max, min);
+ currange->label = label->pclabel;
+
+ for (i = 0; i < ncases; i++) {
+ curcase = caselabels[i];
+ if (CInt64_GreaterEqual(curcase->min, min) && CInt64_LessEqual(curcase->min, max)) {
+ if (CInt64_Equal(currange->min, min))
+ first = curcase->min;
+ range = CInt64_Sub(curcase->min, first);
+
+ if (CInt64_Greater(curcase->min, currange->min)) {
+ currange->range = CInt64_Sub(CInt64_Sub(curcase->min, currange->min), cint64_one);
+ (++currange)->min = curcase->min;
+ } else if (CInt64_Greater(currange->min, min) && curcase->label->pclabel == currange[-1].label) {
+ currange[-1].range = CInt64_Add(currange[-1].range, cint64_one);
+ if (CInt64_Equal(currange->range, cint64_zero)) {
+ currange--;
+ } else {
+ currange->min = CInt64_Add(currange->min, cint64_one);
+ currange->range = CInt64_Sub(currange->range, cint64_one);
+ }
+ continue;
+ }
+
+ currange->range = cint64_zero;
+ currange->label = curcase->label->pclabel;
+
+ if (CInt64_Less(curcase->min, max)) {
+ currange++;
+ currange->min = CInt64_Add(curcase->min, cint64_one);
+ currange->range = CInt64_Sub(max, currange->min);
+ currange->label = label->pclabel;
+ }
+ }
+ }
+
+ nranges_minus1 = currange - caseranges;
+}
+
+static void treecompare(SInt32 start, SInt32 end) {
+ SInt32 r30;
+ SInt32 r29;
+ CaseRange *currange;
+ int count;
+
+ count = end - start;
+ CError_ASSERT(175, selector_type->size <= 4);
+
+ r29 = start + (count >> 1) + 1;
+ currange = caseranges + r29;
+
+ if (CInt64_Equal(currange[-1].range, cint64_zero) && (!(count & 1) || (CInt64_NotEqual(currange->range, cint64_zero) && count > 1))) {
+ currange--;
+ r29--;
+ }
+
+ r30 = r29 - 1;
+
+ if (selector_type->size < 4 && is_unsigned(selector_type)) {
+ emitpcode(PC_CMPLI, 0, selector_gpr, CInt64_GetULong(&currange->min));
+ } else if (FITS_IN_SHORT((SInt32) CInt64_GetULong(&currange->min))) {
+ emitpcode(PC_CMPI, 0, selector_gpr, CInt64_GetULong(&currange->min));
+ } else {
+ SInt32 value = CInt64_GetULong(&currange->min);
+ int reg = ALLOC_GPR();
+ load_immediate(reg, value);
+ emitpcode(PC_CMP, 0, selector_gpr, reg);
+ }
+
+ if (CInt64_Equal(currange->range, cint64_zero) && r29 < end) {
+ branch_conditional(0, EEQU, 1, currange->label);
+ r29++;
+ }
+
+ if (r29 == end) {
+ if (start == r30) {
+ if (caseranges[start].label == caseranges[end].label) {
+ branch_always(caseranges[start].label);
+ } else {
+ branch_conditional(0, EGREATEREQU, 1, caseranges[end].label);
+ branch_always(caseranges[start].label);
+ }
+ } else {
+ branch_conditional(0, EGREATEREQU, 1, caseranges[end].label);
+ treecompare(start, r30);
+ }
+ } else {
+ if (start == r30) {
+ branch_conditional(0, ELESS, 1, caseranges[start].label);
+ treecompare(r29, end);
+ } else {
+ PCodeLabel *label = makepclabel();
+ branch_conditional(0, EGREATEREQU, 1, label);
+ treecompare(start, r30);
+ branch_label(label);
+ treecompare(r29, end);
+ }
+ }
+}
+
+static void I8_treecompare(SInt32 start, SInt32 end) {
+ SInt32 r30;
+ SInt32 r29;
+ CaseRange *currange;
+ int count;
+
+ count = end - start;
+
+ r29 = start + (count >> 1) + 1;
+ currange = caseranges + r29;
+
+ if (CInt64_Equal(currange[-1].range, cint64_zero) && (!(count & 1) || (CInt64_NotEqual(currange->range, cint64_zero) && count > 1))) {
+ currange--;
+ r29--;
+ }
+
+ r30 = r29 - 1;
+
+ if (CInt64_Equal(currange->range, cint64_zero) && r29 < end) {
+ short a = ALLOC_GPR();
+ short b = ALLOC_GPR();
+ load_immediate(a, currange->min.lo);
+ load_immediate(b, currange->min.hi);
+ emitpcode(PC_XOR, a, selector_gpr, a);
+ emitpcode(PC_XOR, b, selector_gprHi, b);
+ emitpcode(PC_OR, b, a, b);
+ emitpcode(PC_CMPI, 0, b, 0);
+ branch_conditional(0, EEQU, 1, currange->label);
+ r29++;
+ }
+
+ if (r29 == end) {
+ if (start == r30) {
+ if (caseranges[start].label == caseranges[end].label) {
+ branch_always(caseranges[start].label);
+ } else {
+ short a = ALLOC_GPR();
+ short b = ALLOC_GPR();
+ short c = ALLOC_GPR();
+ short d = ALLOC_GPR();
+ load_immediate(a, currange->min.lo);
+ load_immediate(b, currange->min.hi);
+ if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) {
+ emitpcode(PC_XORIS, c, selector_gprHi, 0x8000);
+ emitpcode(PC_XORIS, d, b, 0x8000);
+ } else {
+ c = selector_gprHi;
+ d = b;
+ }
+ emitpcode(PC_SUBFC, a, a, selector_gpr);
+ emitpcode(PC_SUBFE, b, d, c);
+ emitpcode(PC_SUBFE, b, a, a);
+ emitpcode(PC_NEG, b, b);
+ emitpcode(PC_CMPI, 0, b, 0);
+ branch_conditional(0, EEQU, 1, caseranges[end].label);
+ branch_always(caseranges[start].label);
+ }
+ } else {
+ short a = ALLOC_GPR();
+ short b = ALLOC_GPR();
+ short c = ALLOC_GPR();
+ short d = ALLOC_GPR();
+ load_immediate(a, currange->min.lo);
+ load_immediate(b, currange->min.hi);
+ if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) {
+ emitpcode(PC_XORIS, c, selector_gprHi, 0x8000);
+ emitpcode(PC_XORIS, d, b, 0x8000);
+ } else {
+ c = selector_gprHi;
+ d = b;
+ }
+ emitpcode(PC_SUBFC, a, a, selector_gpr);
+ emitpcode(PC_SUBFE, b, d, c);
+ emitpcode(PC_SUBFE, b, a, a);
+ emitpcode(PC_NEG, b, b);
+ emitpcode(PC_CMPI, 0, b, 0);
+ branch_conditional(0, EEQU, 1, caseranges[end].label);
+ I8_treecompare(start, r30);
+ }
+ } else {
+ if (start == r30) {
+ short a = ALLOC_GPR();
+ short b = ALLOC_GPR();
+ short c = ALLOC_GPR();
+ short d = ALLOC_GPR();
+ load_immediate(a, currange->min.lo);
+ load_immediate(b, currange->min.hi);
+ if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) {
+ emitpcode(PC_XORIS, c, selector_gprHi, 0x8000);
+ emitpcode(PC_XORIS, d, b, 0x8000);
+ } else {
+ c = selector_gprHi;
+ d = b;
+ }
+ emitpcode(PC_SUBFC, a, selector_gpr, a);
+ emitpcode(PC_SUBFE, b, c, d);
+ emitpcode(PC_SUBFE, b, a, a);
+ emitpcode(PC_NEG, b, b);
+ emitpcode(PC_CMPI, 0, b, 0);
+ branch_conditional(0, ENOTEQU, 1, caseranges[end].label);
+ I8_treecompare(r29, end);
+ } else {
+ PCodeLabel *label;
+ short a = ALLOC_GPR();
+ short b = ALLOC_GPR();
+ short c = ALLOC_GPR();
+ short d = ALLOC_GPR();
+ load_immediate(a, currange->min.lo);
+ load_immediate(b, currange->min.hi);
+ if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) {
+ emitpcode(PC_XORIS, c, selector_gprHi, 0x8000);
+ emitpcode(PC_XORIS, d, b, 0x8000);
+ } else {
+ c = selector_gprHi;
+ d = b;
+ }
+ emitpcode(PC_SUBFC, a, a, selector_gpr);
+ emitpcode(PC_SUBFE, b, d, c);
+ emitpcode(PC_SUBFE, b, a, a);
+ emitpcode(PC_NEG, b, b);
+ emitpcode(PC_CMPI, 0, b, 0);
+ label = makepclabel();
+ branch_conditional(0, EEQU, 1, label);
+ I8_treecompare(start, r30);
+ branch_label(label);
+ I8_treecompare(r29, end);
+ }
+ }
+}
+
+static void generate_tree(ENode *expr) {
+ Operand op;
+
+ memclrw(&op, sizeof(Operand));
+ if (TYPE_IS_8BYTES(expr->rtype)) {
+ GEN_NODE(expr, &op);
+ coerce_to_register_pair(&op, expr->rtype, 0, 0);
+ selector_type = expr->rtype;
+ selector_gpr = op.reg;
+ selector_gprHi = op.regHi;
+ I8_treecompare(0, nranges_minus1);
+ } else {
+ GEN_NODE(expr, &op);
+ if (expr->rtype->size < 4)
+ extend32(&op, expr->rtype, 0);
+ ENSURE_GPR(&op, expr->rtype, 0);
+ selector_type = expr->rtype;
+ selector_gpr = op.reg;
+ treecompare(0, nranges_minus1);
+ }
+}
+
+static Object *create_switch_table(void) {
+ Object *obj;
+ ObjectList *list;
+ UInt32 *outptr;
+ CaseRange *currange;
+ SInt32 size;
+ CInt64 value;
+
+ obj = galloc(sizeof(Object));
+ list = galloc(sizeof(ObjectList));
+ memclrw(obj, sizeof(Object));
+ memclrw(list, sizeof(ObjectList));
+
+ obj->otype = OT_OBJECT;
+ obj->access = ACCESSPUBLIC;
+ obj->datatype = DDATA;
+ obj->name = CParser_GetUniqueName();
+ obj->toc = NULL;
+ obj->sclass = TK_STATIC;
+ obj->qual = Q_CONST;
+ obj->flags |= OBJECT_FLAGS_2 | OBJECT_DEFINED;
+ obj->u.data.linkname = obj->name;
+ obj->type = NULL;
+ createIndirect(obj, 0, 0);
+ obj->type = TYPE(&void_ptr);
+
+ size = CInt64_GetULong(&range) + 1;
+ obj->u.data.u.switchtable.size = size;
+ obj->u.data.u.switchtable.data = lalloc(4 * size);
+
+ currange = caseranges;
+ outptr = (UInt32 *) obj->u.data.u.switchtable.data;
+ value = cint64_zero;
+ while (CInt64_LessEqual(value, range)) {
+ while (CInt64_Greater(CInt64_Add(first, value), CInt64_Add(currange->min, currange->range)))
+ currange++;
+ *outptr = CTool_CreateIndexFromPointer(currange->label);
+ value = CInt64_Add(value, cint64_one);
+ outptr++;
+ }
+
+ list->object = obj;
+ list->next = switchtables;
+ switchtables = list;
+ return list->object;
+}
+
+static void generate_table(ENode *expr, SwitchInfo *info) {
+ Object *table;
+ SwitchCase *curcase;
+ short reg;
+ short reg2;
+ short reg3;
+ Operand op1;
+ Operand op2;
+
+ CInt64 val3 = {0, 3};
+ memclrw(&op1, sizeof(Operand));
+ memclrw(&op2, sizeof(Operand));
+
+ if (CInt64_Greater(first, cint64_zero) && CInt64_Less(first, val3)) {
+ range = CInt64_Add(range, first);
+ first = cint64_zero;
+ }
+
+ table = create_switch_table();
+ CError_ASSERT(553, !TYPE_IS_8BYTES(expr->rtype));
+
+ GEN_NODE(expr, &op1);
+ if (expr->rtype->size < 4)
+ extend32(&op1, expr->rtype, 0);
+ ENSURE_GPR(&op1, expr->rtype, 0);
+
+ reg = op1.reg;
+ if (CInt64_NotEqual(first, cint64_zero)) {
+ SInt32 value;
+ reg = ALLOC_GPR();
+ value = -CInt64_GetULong(&first);
+ if (!FITS_IN_SHORT(value)) {
+ emitpcode(PC_ADDIS, reg, op1.reg, 0, HIGH_PART(value));
+ if (value)
+ emitpcode(PC_ADDI, reg, reg, 0, LOW_PART(value));
+ } else {
+ emitpcode(PC_ADDI, reg, op1.reg, 0, value);
+ }
+ }
+
+ if (!FITS_IN_SHORT(CInt64_GetULong(&range))) {
+ short tmp = ALLOC_GPR();
+ load_immediate(tmp, CInt64_GetULong(&range));
+ emitpcode(PC_CMPL, 0, reg, tmp);
+ } else {
+ emitpcode(PC_CMPLI, 0, reg, CInt64_GetULong(&range));
+ }
+
+ branch_conditional(0, EGREATER, 1, defaultlabel);
+ if (table->toc) {
+ op2.optype = OpndType_Symbol;
+ op2.object = table->toc;
+ indirect(&op2, NULL);
+ } else {
+ op2.optype = OpndType_Symbol;
+ op2.object = table;
+ }
+
+ if (op2.optype != OpndType_GPR) {
+ Coerce_to_register(&op2, TYPE(&void_ptr), reg2 = ALLOC_GPR());
+ }
+
+ if (op2.optype != OpndType_GPR) {
+ CError_FATAL(599);
+ } else {
+ if (op2.reg != reg2)
+ emitpcode(PC_MR, reg2, op2.reg);
+ }
+
+ if (CInt64_Equal(first, cint64_zero)) {
+ reg = ALLOC_GPR();
+ emitpcode(PC_RLWINM, reg, op1.reg, 2, 0, 29);
+ } else {
+ emitpcode(PC_RLWINM, reg, reg, 2, 0, 29);
+ }
+
+ reg3 = reg2;
+ emitpcode(PC_LWZX, reg3, reg3, reg);
+ for (curcase = info->cases; curcase; curcase = curcase->next)
+ pcbranch(pclastblock, curcase->label->pclabel);
+ pcbranch(pclastblock, info->defaultlabel->pclabel);
+ emitpcode(PC_MTCTR, reg3);
+ branch_indirect(table);
+}
+
+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++;
+ }
+
+ CError_ASSERT(656, ncases >= 0 && ncases <= 0x3333332U);
+
+ 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 / 2) + 4))
+ generate_tree(expr);
+ else
+ generate_table(expr, info);
+}
+
+void dumpswitchtables(Object *funcobj) {
+ Object *table;
+ ObjectList *list;
+ SInt32 size;
+ UInt32 *array;
+
+ for (list = switchtables; list; list = list->next) {
+ table = list->object;
+ CError_ASSERT(694, table->otype == OT_OBJECT && table->access == ACCESSPUBLIC && table->datatype == DDATA);
+
+ size = table->u.data.u.switchtable.size;
+ array = (UInt32 *) table->u.data.u.switchtable.data;
+ while (size--) {
+ *array = CTool_EndianConvertWord32(((PCodeLabel *) CTool_ResolveIndexToPointer(*array))->block->codeOffset);
+ array++;
+ }
+
+ ObjGen_DeclareSwitchTable(table, funcobj);
+ }
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/TOC.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/TOC.c
new file mode 100644
index 0000000..7af09e3
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/TOC.c
@@ -0,0 +1,2272 @@
+#include "cos.h"
+#include "compiler/TOC.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CInit.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/CompilerTools.h"
+#include "compiler/Exceptions.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/InlineAsmPPC.h"
+#include "compiler/InstrSelection.h"
+#include "compiler/Intrinsics.h"
+#include "compiler/ObjGenMachO.h"
+#include "compiler/Operands.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+#include "compiler/PPCError.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/StackFrame.h"
+#include "compiler/enode.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+ObjectList *toclist;
+ObjectList *exceptionlist;
+void *descriptorlist;
+PoolEntry *floatconstpool;
+PoolEntry *doubleconstpool;
+ObjectList *floatconstlist;
+PoolEntry *vectorconstpool;
+ObjectList *vectorconstlist;
+Object toc0;
+Boolean no_descriptors;
+Object pic_base;
+VarInfo pic_base_varinfo;
+short pic_base_reg;
+CodeLabelList *codelabellist;
+
+UInt8 lvslBytes[16][16] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11,
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13,
+ 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+ 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
+ 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E
+};
+
+UInt8 lvsrBytes[16][16] = {
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E,
+ 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
+ 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
+ 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13,
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10
+};
+
+// forward decls
+static void estimate_func_param_size(ENode *node);
+
+static int disables_optimizer(ENode *node) {
+ ENode *funcref = node->data.funccall.funcref;
+ if (ENODE_IS(funcref, EOBJREF)) {
+ if (!strcmp(CMangler_GetLinkName(funcref->data.objref)->name, "___setjmp"))
+ return 1;
+ if (!strcmp(CMangler_GetLinkName(funcref->data.objref)->name, "___vec_setjmp"))
+ return 1;
+ }
+ return 0;
+}
+
+void setupaddressing(void) {
+ floatconstlist = NULL;
+ descriptorlist = NULL;
+ toclist = NULL;
+ exceptionlist = NULL;
+ vectorconstlist = NULL;
+ vectorconstpool = NULL;
+ floatconstpool = NULL;
+ doubleconstpool = NULL;
+
+ no_descriptors = 1;
+ memclrw(&toc0, sizeof(toc0));
+
+ pic_base_reg = 0;
+ memclrw(&pic_base, sizeof(pic_base));
+ memclrw(&pic_base_varinfo, sizeof(pic_base_varinfo));
+ pic_base.otype = OT_OBJECT;
+ pic_base.type = (Type *) &void_ptr;
+ pic_base.datatype = DNONLAZYPTR;
+ pic_base.u.toc.info = &pic_base_varinfo;
+}
+
+void createNonLazyPointer(Object *obj) {
+ Object *toc;
+ ObjectList *list;
+
+ toc = galloc(sizeof(Object));
+ obj->toc = toc;
+ memclrw(toc, sizeof(Object));
+
+ toc->otype = OT_OBJECT;
+ toc->name = CParser_GetUniqueName();
+ toc->toc = NULL;
+ toc->section = SECT_NONLAZY_PTRS;
+ toc->u.toc.info = CodeGen_GetNewVarInfo();
+ toc->sclass = TK_STATIC;
+ toc->qual = Q_CONST;
+ toc->datatype = DNONLAZYPTR;
+ toc->flags |= OBJECT_FLAGS_2;
+ toc->type = CDecl_NewPointerType(obj->type);
+ toc->u.toc.over_load = obj;
+ toc->u.toc.linkname = CMangler_GetLinkName(obj);
+
+ list = galloc(sizeof(ObjectList));
+ memclrw(list, sizeof(ObjectList));
+ list->object = toc;
+ list->next = toclist;
+ toclist = list;
+}
+
+void referenceIndirectPointer(Object *obj) {
+ VarInfo *vi = obj->toc->u.toc.info;
+ vi->used = 1;
+ vi->usage += copts.optimizesize ? 1 : curstmtvalue;
+}
+
+Object *createIndirect(Object *obj, Boolean flag1, Boolean flag2) {
+ CError_ASSERT(622, !copts.no_common || (obj->section != SECT_COMMON_VARS) || (obj->qual & Q_20000));
+
+ if (CParser_HasInternalLinkage(obj))
+ return NULL;
+ if (ObjGen_IsExported(obj))
+ return NULL;
+
+ if (!copts.no_common && obj->datatype == DDATA && obj->section == SECT_DEFAULT && (obj->qual & Q_1000000))
+ obj->section = SECT_COMMON_VARS;
+
+ if (copts.codegen_dynamic && (!copts.no_common || !(obj->qual & Q_1000000))) {
+ if (!obj->toc)
+ createNonLazyPointer(obj);
+ else if (flag1)
+ obj->toc->u.toc.info = CodeGen_GetNewVarInfo();
+
+ if (flag2)
+ referenceIndirectPointer(obj);
+
+ return obj->toc;
+ } else {
+ return NULL;
+ }
+}
+
+Object *createfloatconstant(Type *type, Float *data) {
+ ObjectList *list;
+ Object *obj;
+ UInt32 *check;
+
+ for (list = floatconstlist; list; list = list->next) {
+ obj = list->object;
+ check = (UInt32 *) obj->u.data.u.floatconst;
+ if (obj->type == type && check[0] == ((UInt32 *) data)[0] && check[1] == ((UInt32 *) data)[1])
+ return obj;
+ }
+
+ obj = galloc(sizeof(Object));
+ memclrw(obj, sizeof(Object));
+ obj->otype = OT_OBJECT;
+ obj->type = type;
+ obj->name = CParser_GetUniqueName();
+ obj->toc = NULL;
+ obj->u.data.info = NULL;
+ obj->u.data.linkname = obj->name;
+ obj->sclass = TK_STATIC;
+ obj->qual = Q_CONST | Q_INLINE_DATA;
+ obj->datatype = DDATA;
+ if (type->size == 8)
+ obj->section = SECT_8BYTE_LITERALS;
+ else if (type->size == 4)
+ obj->section = SECT_4BYTE_LITERALS;
+ else
+ CError_FATAL(807);
+
+ obj->flags |= OBJECT_FLAGS_2;
+
+ obj->u.data.u.floatconst = galloc(sizeof(Float));
+ *obj->u.data.u.floatconst = *data;
+
+ list = galloc(sizeof(ObjectList));
+ memclrw(list, sizeof(ObjectList));
+ list->object = obj;
+ list->next = floatconstlist;
+ floatconstlist = list;
+
+ ObjGen_DeclareFloatConst(obj);
+ return obj;
+}
+
+Object *createvectorconstant(Type *type, MWVector128 *data) {
+ ObjectList *list;
+ Object *obj;
+ MWVector128 *check;
+
+ for (list = vectorconstlist; list; list = list->next) {
+ obj = list->object;
+ check = obj->u.data.u.vector128const;
+ if (check->ul[0] == data->ul[0] && check->ul[1] == data->ul[1] && check->ul[2] == data->ul[2] && check->ul[3] == data->ul[3])
+ return obj;
+ }
+
+ obj = galloc(sizeof(Object));
+ memclrw(obj, sizeof(Object));
+ obj->otype = OT_OBJECT;
+ obj->type = type;
+ obj->name = CParser_GetUniqueName();
+ obj->toc = NULL;
+ obj->u.data.info = NULL;
+ obj->u.data.linkname = obj->name;
+ obj->sclass = TK_STATIC;
+ obj->qual = Q_CONST | Q_INLINE_DATA;
+ obj->datatype = DDATA;
+ if (type->size == 16)
+ obj->section = SECT_16BYTE_LITERALS;
+ else
+ CError_FATAL(900);
+
+ obj->flags |= OBJECT_FLAGS_2;
+
+ obj->u.data.u.vector128const = galloc(sizeof(MWVector128));
+ *obj->u.data.u.vector128const = *data;
+
+ list = galloc(sizeof(ObjectList));
+ memclrw(list, sizeof(ObjectList));
+ list->object = obj;
+ list->next = vectorconstlist;
+ vectorconstlist = list;
+
+ ObjGen_DeclareVectorConst(obj);
+ return obj;
+}
+
+void DeclarePooledConstants(void) {
+ PoolEntry *entry;
+ char *buffer;
+ SInt32 fsize;
+ SInt32 dsize;
+ SInt32 vsize;
+
+ fsize = 0;
+ for (entry = floatconstpool; entry; entry = entry->next)
+ fsize += 4;
+
+ if (fsize) {
+ floatconstpool->object->type = CDecl_NewArrayType(TYPE(&stfloat), fsize);
+ buffer = galloc(fsize);
+ for (entry = floatconstpool; entry; entry = entry->next)
+ memcpy(buffer + entry->offset, entry->buffer, 4);
+ CInit_DeclareReadOnlyData(floatconstpool->object, buffer, NULL, fsize);
+ }
+
+ dsize = 0;
+ for (entry = doubleconstpool; entry; entry = entry->next)
+ dsize += 8;
+
+ if (dsize) {
+ doubleconstpool->object->type = CDecl_NewArrayType(TYPE(&stdouble), dsize);
+ buffer = galloc(dsize);
+ for (entry = doubleconstpool; entry; entry = entry->next)
+ memcpy(buffer + entry->offset, entry->buffer, 8);
+ CInit_DeclareReadOnlyData(doubleconstpool->object, buffer, NULL, dsize);
+ }
+
+ vsize = 0;
+ for (entry = vectorconstpool; entry; entry = entry->next)
+ vsize += 16;
+
+ if (vsize) {
+ vectorconstpool->object->type = CDecl_NewArrayType(TYPE(&stvectorsignedlong), vsize);
+ buffer = galloc(vsize);
+ for (entry = vectorconstpool; entry; entry = entry->next)
+ memcpy(buffer + entry->offset, entry->buffer, 16);
+ CInit_DeclareReadOnlyData(vectorconstpool->object, buffer, NULL, vsize);
+ }
+}
+
+static Object *CreatePooledFloatConst(Type *type, Float *data, SInt32 *pOffset) {
+ if (type->size == 8u) {
+ PoolEntry *entry;
+ void *buffer;
+ Object *object;
+ SInt32 offset;
+
+ buffer = galloc(8u);
+ CMach_InitFloatMem(type, *data, buffer);
+ if (cparamblkptr->precompile == 1)
+ CError_Error(CErrorStr180);
+
+ for (entry = doubleconstpool; entry; entry = entry->next) {
+ if (!memcmp(entry->buffer, buffer, 8u))
+ break;
+ }
+
+ if (!entry) {
+ if (doubleconstpool) {
+ object = doubleconstpool->object;
+ offset = doubleconstpool->offset + 8u;
+ doubleconstpool->object->type->size += 8u;
+ } else {
+ DeclInfo di;
+ memclrw(&di, sizeof(di));
+ di.thetype = CDecl_NewArrayType(TYPE(&stdouble), 8u);
+ di.name = GetHashNameNodeExport("@doubleBase0");
+ di.qual = Q_CONST;
+ di.storageclass = TK_STATIC;
+ di.is_extern_c = 1;
+ di.section = SECT_CONST;
+ object = CParser_NewGlobalDataObject(&di);
+ object->nspace = cscope_root;
+ offset = 0;
+ }
+
+ entry = galloc(sizeof(PoolEntry));
+ entry->next = doubleconstpool;
+ doubleconstpool = entry;
+ entry->object = object;
+ entry->offset = offset;
+ entry->buffer = galloc(8u);
+ memcpy(entry->buffer, buffer, 8u);
+ }
+
+ *pOffset = entry->offset;
+ return entry->object;
+ }
+
+ if (type->size == 4u) {
+ PoolEntry *entry;
+ void *buffer;
+ Object *object;
+ SInt32 offset;
+
+ buffer = galloc(4u);
+ CMach_InitFloatMem(type, *data, buffer);
+ if (cparamblkptr->precompile == 1)
+ CError_Error(CErrorStr180);
+
+ for (entry = floatconstpool; entry; entry = entry->next) {
+ if (!memcmp(entry->buffer, buffer, 4u))
+ break;
+ }
+
+ if (!entry) {
+ if (floatconstpool) {
+ object = floatconstpool->object;
+ offset = floatconstpool->offset + 4u;
+ object->type->size += 4u;
+ } else {
+ DeclInfo di;
+ memclrw(&di, sizeof(di));
+ di.thetype = CDecl_NewArrayType(TYPE(&stfloat), 4u);
+ di.name = GetHashNameNodeExport("@floatBase0");
+ di.qual = Q_CONST;
+ di.storageclass = TK_STATIC;
+ di.is_extern_c = 1;
+ di.section = SECT_CONST;
+ object = CParser_NewGlobalDataObject(&di);
+ object->nspace = cscope_root;
+ offset = 0;
+ }
+
+ entry = galloc(sizeof(PoolEntry));
+ entry->next = floatconstpool;
+ floatconstpool = entry;
+ entry->object = object;
+ entry->offset = offset;
+ entry->buffer = galloc(4u);
+ memcpy(entry->buffer, buffer, 4u);
+ }
+
+ *pOffset = entry->offset;
+ return entry->object;
+ }
+
+ CError_FATAL(1183);
+ return NULL;
+}
+
+Object *CreateFloatConst(Type *type, Float *data, SInt32 *pOffset) {
+ *pOffset = 0;
+ return createfloatconstant(type, data);
+}
+
+static void RewriteFloatConst(ENode *expr) {
+ Object *obj;
+ SInt32 n;
+ ENode *subexpr;
+
+ obj = CreateFloatConst(expr->rtype, &expr->data.floatval, &n);
+ if (n) {
+ subexpr = makediadicnode(create_objectrefnode(obj), intconstnode(TYPE(&stunsignedlong), n), EADD);
+ } else {
+ subexpr = create_objectrefnode(obj);
+ }
+
+ expr->type = EINDIRECT;
+ expr->cost = 1;
+ expr->flags |= Q_CONST;
+ expr->data.monadic = subexpr;
+}
+
+static void RewriteVectorConst(ENode *expr) {
+ PoolEntry *entry;
+ Object *object;
+ SInt32 offset;
+ ENode *inner;
+ UInt8 data[16];
+
+ CMach_InitVectorMem(expr->rtype, expr->data.vector128val, data, 1);
+
+ if (cparamblkptr->precompile == 1)
+ CError_Error(CErrorStr180);
+
+ for (entry = vectorconstpool; entry; entry = entry->next) {
+ if (!memcmp(entry->buffer, data, 16))
+ break;
+ }
+
+ if (!entry) {
+ if (vectorconstpool) {
+ object = vectorconstpool->object;
+ offset = vectorconstpool->offset + 16;
+ vectorconstpool->object->type->size += 16;
+ } else {
+ DeclInfo di;
+ memclrw(&di, sizeof(di));
+ di.thetype = CDecl_NewArrayType(TYPE(&stvectorsignedlong), 16);
+ di.name = GetHashNameNodeExport("@vectorBase0");
+ di.qual = Q_CONST;
+ di.storageclass = TK_STATIC;
+ di.is_extern_c = 1;
+ di.section = SECT_CONST;
+ object = CParser_NewGlobalDataObject(&di);
+ object->nspace = cscope_root;
+ offset = 0;
+ }
+
+ entry = galloc(sizeof(PoolEntry));
+ entry->next = vectorconstpool;
+ vectorconstpool = entry;
+ entry->object = object;
+ entry->offset = offset;
+ entry->buffer = galloc(16);
+ memcpy(entry->buffer, data, 16);
+ }
+
+ if (entry->offset) {
+ inner = makediadicnode(
+ create_objectrefnode(entry->object),
+ intconstnode(TYPE(&stunsignedlong), entry->offset),
+ EADD);
+ } else {
+ inner = create_objectrefnode(entry->object);
+ }
+
+ expr->type = EINDIRECT;
+ expr->cost = 1;
+ expr->flags |= ENODE_FLAG_CONST;
+ expr->data.monadic = inner;
+}
+
+static Object *createcodelabel(CLabel *label) {
+ CodeLabelList *list;
+ Object *obj;
+
+ for (list = codelabellist; list; list = list->next) {
+ if (list->label == label)
+ return list->object;
+ }
+
+ obj = galloc(sizeof(Object));
+ memclrw(obj, sizeof(Object));
+ obj->otype = OT_OBJECT;
+ obj->type = (Type *) &void_ptr;
+ obj->name = label->uniquename;
+ obj->toc = NULL;
+ obj->u.data.info = NULL; // not sure if this is the right union!
+ obj->sclass = TK_STATIC;
+ obj->qual = Q_CONST;
+ obj->datatype = DDATA;
+ obj->flags |= OBJECT_FLAGS_2 | OBJECT_DEFINED;
+
+ list = galloc(sizeof(CodeLabelList));
+ memclrw(list, sizeof(CodeLabelList));
+ list->object = obj;
+ list->label = label;
+ list->next = codelabellist;
+ codelabellist = list;
+
+ return obj;
+}
+
+void dumpcodelabels(Object *func) {
+ CodeLabelList *list;
+
+ for (list = codelabellist; list; list = list->next)
+ ObjGen_DeclareCodeLabel(list->object, list->label->pclabel->block->codeOffset, func);
+}
+
+static void referenceexception(Object *obj) {
+ ObjectList *list;
+
+ if (obj && obj->otype == OT_OBJECT && obj->datatype == DLOCAL) {
+ for (list = exceptionlist; list; list = list->next) {
+ if (list->object == obj)
+ return;
+ }
+
+ list = lalloc(sizeof(ObjectList));
+ memclrw(list, sizeof(ObjectList));
+ list->object = obj;
+ list->next = exceptionlist;
+ exceptionlist = list;
+ }
+}
+
+static ENodeType invert_relop(ENodeType nodetype) {
+ switch (nodetype) {
+ case ELESS: return EGREATEREQU;
+ case EGREATER: return ELESSEQU;
+ case ELESSEQU: return EGREATER;
+ case EGREATEREQU: return ELESS;
+ case EEQU: return ENOTEQU;
+ case ENOTEQU: return EEQU;
+ default: return nodetype;
+ }
+}
+
+static ENode *COND_to_COMPARE(ENode *cond, ENode *expr1, ENode *expr2) {
+ SInt32 val1;
+ SInt32 val2;
+ SInt32 condval;
+ ENodeType invop;
+
+ while (expr1->type == ETYPCON && TYPE_FITS_IN_REGISTER(expr1->rtype))
+ expr1 = expr1->data.monadic;
+ while (expr2->type == ETYPCON && TYPE_FITS_IN_REGISTER(expr2->rtype))
+ expr2 = expr2->data.monadic;
+
+ if (expr1->type != EINTCONST || !TYPE_FITS_IN_REGISTER(expr1->rtype) || !CInt64_IsInRange(expr1->data.intval, 4))
+ return NULL;
+ if (expr2->type != EINTCONST || !TYPE_FITS_IN_REGISTER(expr2->rtype) || !CInt64_IsInRange(expr2->data.intval, 4))
+ return NULL;
+
+ val1 = expr1->data.intval.lo;
+ val2 = expr2->data.intval.lo;
+ condval = 0;
+ switch (val1) {
+ case 1:
+ if (val2 != 0)
+ return NULL;
+ break;
+ case 0:
+ condval = 1;
+ if (val2 != 1)
+ return NULL;
+ break;
+ default:
+ return NULL;
+ }
+
+ while (cond->type == ELOGNOT) {
+ condval = (condval + 1) & 1;
+ cond = cond->data.monadic;
+ }
+
+ if (condval) {
+ invop = invert_relop(cond->type);
+ if (invop == cond->type)
+ return NULL;
+ cond->type = invop;
+ }
+
+ return cond;
+}
+
+static ENode *comparewithzero(ENode *expr) {
+ ENode *expr1;
+ ENode *expr2;
+ ENode *tmp;
+
+ expr1 = lalloc(sizeof(ENode));
+ memclrw(expr1, sizeof(ENode));
+ expr2 = lalloc(sizeof(ENode));
+ memclrw(expr2, sizeof(ENode));
+
+ while (expr->type == EFORCELOAD || expr->type == ETYPCON || expr->type == ECOMMA) {
+ if (!TYPE_FITS_IN_REGISTER(expr->rtype))
+ break;
+ if (expr->type == ECOMMA) {
+ expr->data.diadic.right = comparewithzero(expr->data.diadic.right);
+ return expr;
+ }
+ expr = expr->data.monadic;
+ }
+
+ if (expr->type == ECOND && TYPE_FITS_IN_REGISTER(expr->rtype)) {
+ tmp = COND_to_COMPARE(expr->data.cond.cond, expr->data.cond.expr1, expr->data.cond.expr2);
+ if (tmp)
+ expr = tmp;
+ }
+
+ if (expr->type >= ELESS && expr->type <= ENOTEQU)
+ return expr;
+
+ if (IS_TYPE_FLOAT(expr->rtype)) {
+ static Float float0 = {0.0};
+
+ expr2->type = EFLOATCONST;
+ expr2->cost = 0;
+ expr2->rtype = (expr->rtype->size == 4) ? (Type *) &stfloat : (Type *) &stdouble;
+ expr2->data.floatval = float0;
+ } else {
+ expr2->type = EINTCONST;
+ expr2->cost = 0;
+ if (TYPE_IS_8BYTES(expr->rtype))
+ expr2->rtype = (Type *) &stsignedlonglong;
+ else
+ expr2->rtype = (Type *) &stsignedint;
+ expr2->data.intval.lo = 0;
+ expr2->data.intval.hi = 0;
+ }
+
+ expr1->type = ENOTEQU;
+ expr1->cost = expr->cost;
+ expr1->rtype = (Type *) &stsignedint;
+ expr1->data.diadic.left = expr;
+ expr1->data.diadic.right = expr2;
+ return expr1;
+}
+
+static void rewritefunctioncallreturningstruct(ENode *expr) {
+ ENode *ret_expr;
+ ENode *copy;
+
+ ret_expr = expr->data.funccall.args->node;
+
+ copy = lalloc(sizeof(ENode));
+ memclrw(copy, sizeof(ENode));
+
+ *copy = *expr;
+ expr->type = ECOMMA;
+ expr->data.diadic.left = copy;
+ expr->data.diadic.right = ret_expr;
+}
+
+static void rewritestrcpy(ENode *expr) {
+ ENode *int_expr;
+ ENodeList *list;
+
+ int_expr = lalloc(sizeof(ENode));
+ memclrw(int_expr, sizeof(ENode));
+ int_expr->type = EINTCONST;
+ int_expr->cost = 0;
+ int_expr->flags = 0;
+ int_expr->rtype = (Type *) &stunsignedlong;
+ CInt64_SetLong(&int_expr->data.intval, expr->data.funccall.args->next->node->data.string.size);
+
+ list = lalloc(sizeof(ENodeList));
+ memclrw(list, sizeof(ENodeList));
+ list->next = NULL;
+ list->node = int_expr;
+ expr->data.funccall.args->next->next = list;
+ expr->data.funccall.funcref->data.objref = __memcpy_object;
+}
+
+static SInt32 magnitude(Type *type) {
+ if (IS_TYPE_FLOAT(type))
+ return type->size * 4;
+ else if (is_unsigned(type))
+ return (type->size * 2) + 1;
+ else
+ return type->size * 2;
+}
+
+static Type *promote_type(Type *type) {
+ if (IS_TYPE_ENUM(type))
+ type = TYPE_ENUM(type)->enumtype;
+ if (TYPE_INTEGRAL(type)->integral > stsignedint.integral)
+ return type;
+ else
+ return (Type *) &stsignedint;
+}
+
+static Type *common_type(Type *type1, Type *type2) {
+ Type *tmp;
+
+ if (IS_TYPE_FLOAT(type1) || IS_TYPE_FLOAT(type2)) {
+ if (TYPE_INTEGRAL(type1)->integral > TYPE_INTEGRAL(type2)->integral)
+ return type1;
+ else
+ return type2;
+ }
+
+ type1 = promote_type(type1);
+ type2 = promote_type(type2);
+ if (type1 != type2) {
+ if (TYPE_INTEGRAL(type1)->integral < TYPE_INTEGRAL(type2)->integral) {
+ tmp = type1;
+ type1 = type2;
+ type2 = tmp;
+ }
+
+ if (type1->size == type2->size && !is_unsigned(type1) && is_unsigned(type2)) {
+ if (type1 == (Type *) &stsignedlong) {
+ type1 = (Type *) &stunsignedlong;
+ } else {
+ CError_ASSERT(1789, type1 == (Type *) &stsignedlonglong);
+ type1 = (Type *) &stunsignedlonglong;
+ }
+ }
+ }
+
+ return type1;
+}
+
+static void rewrite_opassign(ENode *expr, ENodeType exprtype) {
+ ENode *left_sub;
+ ENode *right;
+ Type *left_type;
+ Type *right_type;
+ ENode *new_expr;
+ ENode *tmp;
+ Type *commontype;
+ Type *promo_left;
+ Type *promo_right;
+
+ left_sub = expr->data.diadic.left->data.monadic;
+ right = expr->data.diadic.right;
+ left_type = expr->data.diadic.left->rtype;
+ right_type = expr->data.diadic.right->rtype;
+
+ new_expr = lalloc(sizeof(ENode));
+ memclrw(new_expr, sizeof(ENode));
+ new_expr->type = exprtype;
+ new_expr->rtype = left_type;
+ new_expr->data.diadic.left = expr->data.diadic.left;
+ new_expr->data.diadic.right = right;
+
+ expr->type = EASS;
+ expr->data.diadic.left = left_sub;
+ expr->data.diadic.right = new_expr;
+
+ if (left_sub->type != EOBJREF) {
+ ENode *define;
+ ENode *reuse;
+
+ define = lalloc(sizeof(ENode));
+ memclrw(define, sizeof(ENode));
+ define->type = EDEFINE;
+ define->rtype = left_type;
+
+ reuse = lalloc(sizeof(ENode));
+ memclrw(reuse, sizeof(ENode));
+ reuse->type = EREUSE;
+ reuse->rtype = left_type;
+ reuse->data.monadic = define;
+
+ if (left_sub->type != EBITFIELD) {
+ define->data.monadic = expr->data.diadic.left;
+ expr->data.diadic.left = define;
+ new_expr->data.diadic.left->data.diadic.left = reuse;
+ } else {
+ ENode *copy;
+ define->data.monadic = left_sub->data.diadic.left;
+ left_sub->data.diadic.left = define;
+
+ copy = lalloc(sizeof(ENode));
+ *copy = *left_sub;
+ copy->data.diadic.left = reuse;
+ new_expr->data.diadic.left->data.diadic.left = copy;
+ }
+ }
+
+ switch (exprtype) {
+ case EADD:
+ case ESUB:
+ if (IS_TYPE_POINTER(left_type))
+ break;
+ if (right->type == EINTCONST && TYPE_FITS_IN_REGISTER(left_type))
+ break;
+ case EAND:
+ case EXOR:
+ case EOR:
+ if (left_type == right_type)
+ break;
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ commontype = common_type(left_type, right_type);
+ if (left_type != commontype) {
+ tmp = lalloc(sizeof(ENode));
+ memclrw(tmp, sizeof(ENode));
+ tmp->type = ETYPCON;
+ tmp->rtype = left_type;
+ tmp->data.monadic = expr->data.diadic.right;
+ expr->data.diadic.right = tmp;
+
+ tmp = lalloc(sizeof(ENode));
+ memclrw(tmp, sizeof(ENode));
+ tmp->type = ETYPCON;
+ tmp->rtype = commontype;
+ tmp->data.monadic = new_expr->data.diadic.left;
+ new_expr->data.diadic.left = tmp;
+ }
+ if (right_type != commontype) {
+ tmp = lalloc(sizeof(ENode));
+ memclrw(tmp, sizeof(ENode));
+ tmp->type = ETYPCON;
+ tmp->rtype = commontype;
+ tmp->data.monadic = new_expr->data.diadic.right;
+ new_expr->data.diadic.right = tmp;
+ }
+ new_expr->rtype = commontype;
+ break;
+
+ case ESHL:
+ case ESHR:
+ promo_left = promote_type(left_type);
+ promo_right = promote_type(right_type);
+ if (left_type != promo_left) {
+ tmp = lalloc(sizeof(ENode));
+ memclrw(tmp, sizeof(ENode));
+ tmp->type = ETYPCON;
+ tmp->rtype = left_type;
+ tmp->data.monadic = expr->data.diadic.right;
+ expr->data.diadic.right = tmp;
+
+ tmp = lalloc(sizeof(ENode));
+ memclrw(tmp, sizeof(ENode));
+ tmp->type = ETYPCON;
+ tmp->rtype = promo_left;
+ tmp->data.monadic = new_expr->data.diadic.left;
+ new_expr->data.diadic.left = tmp;
+ }
+ if (right_type != promo_right) {
+ if (new_expr->data.diadic.right->type == EINTCONST && promo_right == (Type *) &stsignedint) {
+ new_expr->data.diadic.right->rtype = (Type *) &stsignedint;
+ } else {
+ tmp = lalloc(sizeof(ENode));
+ memclrw(tmp, sizeof(ENode));
+ tmp->type = ETYPCON;
+ tmp->rtype = promo_right;
+ tmp->data.monadic = new_expr->data.diadic.right;
+ new_expr->data.diadic.right = tmp;
+ }
+ }
+ new_expr->rtype = promo_left;
+ break;
+ }
+}
+
+static void rewrite_preincdec(ENode *expr) {
+ ENode *subexpr; // r31
+ Type *type; // r28
+ ENode *new_expr; // r29
+
+ subexpr = expr->data.monadic;
+ type = expr->rtype;
+
+ new_expr = lalloc(sizeof(ENode));
+ memclrw(new_expr, sizeof(ENode));
+
+ if (IS_TYPE_FLOAT(type)) {
+ new_expr->type = EFLOATCONST;
+ new_expr->cost = 0;
+ new_expr->rtype = type;
+ new_expr->data.floatval = one_point_zero;
+ } else if (IS_TYPE_POINTER(type)) {
+ new_expr->type = EINTCONST;
+ new_expr->cost = 0;
+ new_expr->rtype = (Type *) &stunsignedlong;
+ new_expr->data.intval.hi = 0;
+ new_expr->data.intval.lo = TYPE_POINTER(type)->target->size;
+ } else {
+ new_expr->type = EINTCONST;
+ new_expr->cost = 0;
+ new_expr->rtype = type;
+ new_expr->data.intval.hi = 0;
+ new_expr->data.intval.lo = 1;
+ }
+
+ expr->type = (expr->type == EPREDEC) ? ESUBASS : EADDASS;
+ expr->data.diadic.left = subexpr;
+ expr->data.diadic.right = new_expr;
+}
+
+// Don't know what this would be called in the original, but weh
+typedef union signed_vec {
+ SInt8 sc[16];
+ SInt16 ss[8];
+ SInt32 sl[4];
+} signed_vec;
+
+Boolean canoptimizevectorconst(MWVector128 *vecp, Type *type, COVCResult *result) {
+ // this function is very broken
+ signed_vec vec;
+ union { SInt32 lg; SInt8 ch[4]; } conv32;
+ union { SInt16 sh; SInt8 ch[2]; } conv16;
+ char flag;
+ SInt8 first8;
+ SInt16 first16;
+ SInt32 first32;
+ int i;
+ char ci;
+ UInt32 l0, l1, l2, l3;
+
+ if (IS_TYPE_VECTOR(type)) {
+ vec = *((signed_vec *) vecp);
+
+ first8 = vec.sc[0];
+ flag = 1;
+ i = 1;
+ while (flag && i < 16)
+ flag = first8 == vec.sc[i++];
+ /*flag = 1;
+ for (i = 1; flag && i < 16; i++) {
+ flag = first8 == vec.sc[i];
+ }*/
+
+ if (flag && first8 < 16 && first8 > -17) {
+ if (result) {
+ result->op1 = PC_VSPLTISB;
+ result->op2 = -1;
+ result->arg = first8;
+ }
+ return 1;
+ }
+
+ first16 = vec.ss[0];
+ flag = 1;
+ for (i = 1; flag && i < 8; i++) {
+ flag = vec.ss[i] == first16;
+ }
+
+ conv16.sh = first16;
+ if (flag && conv16.ch[0] == 0 && conv16.ch[1] < 16 && conv16.ch[1] >= 0) {
+ if (result) {
+ result->op1 = PC_VSPLTISH;
+ result->op2 = -1;
+ result->arg = conv16.ch[1];
+ }
+ return 1;
+ }
+
+ if (flag && conv16.ch[0] == -1 && (conv16.ch[1] & 0xF0) == 0xF0) {
+ if (result) {
+ result->op1 = PC_VSPLTISH;
+ result->op2 = -1;
+ result->arg = conv16.ch[1];
+ }
+ return 1;
+ }
+
+ first32 = vec.sl[0];
+ flag = 1;
+ for (i = 1; flag && i < 4; i++) {
+ flag = vec.sl[i] == first32;
+ }
+
+ conv32.lg = first32;
+ if (flag && conv32.ch[0] == 0 && conv32.ch[1] == 0 && conv32.ch[2] == 0 && conv32.ch[3] < 16 && conv32.ch[3] >= 0) {
+ if (result) {
+ result->op1 = PC_VSPLTISW;
+ result->op2 = -1;
+ result->arg = conv32.ch[3];
+ }
+ return 1;
+ }
+
+ if (flag && conv32.ch[0] == -1 && conv32.ch[1] == -1 && conv32.ch[2] == -1 && (conv32.ch[3] & 0xF0) == 0xF0) {
+ if (result) {
+ result->op1 = PC_VSPLTISW;
+ result->op2 = -1;
+ result->arg = conv32.ch[3];
+ }
+ return 1;
+ }
+
+ l0 = vec.sl[0];
+ l1 = vec.sl[1];
+ l2 = vec.sl[2];
+ l3 = vec.sl[3];
+ for (ci = 0; ci < 16; ci++) {
+ UInt32 *l;
+ UInt32 *r;
+
+ l = (UInt32 *) lvslBytes[(char) ci];
+ r = (UInt32 *) lvsrBytes[(char) ci];
+ if (l0 == l[0] && l1 == l[1] && l2 == l[2] && l3 == l[3]) {
+ if (result) {
+ result->op1 = -1;
+ result->op2 = PC_LVSL;
+ result->arg = ci;
+ }
+ return 1;
+ }
+ if (l0 == r[0] && l1 == r[1] && l2 == r[2] && l3 == r[3]) {
+ if (result) {
+ result->op1 = -1;
+ result->op2 = PC_LVSR;
+ result->arg = ci;
+ }
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static SInt32 countindirects(ENode *expr) {
+ SInt32 tmp1;
+ SInt32 tmp2;
+
+ switch (expr->type) {
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EVECTOR128CONST:
+ return 0;
+ case ECOND:
+ if (expr->data.cond.cond->hascall || expr->data.cond.expr1->hascall || expr->data.cond.expr2->hascall)
+ return 2;
+
+ if ((tmp1 = countindirects(expr->data.cond.cond)) >= 2)
+ return 2;
+ if ((tmp2 = countindirects(expr->data.cond.expr1)) >= 2)
+ return 2;
+ if (tmp2 > tmp1)
+ tmp1 = tmp2;
+ if ((tmp2 = countindirects(expr->data.cond.expr2)) >= 2)
+ return 2;
+ if (tmp2 > tmp1)
+ tmp1 = tmp2;
+ return tmp1;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ return 2;
+ case EMUL:
+ case EMULV:
+ case EDIV:
+ case EMODULO:
+ case EADDV:
+ case ESUBV:
+ case EADD:
+ case ESUB:
+ case ESHL:
+ case ESHR:
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ case ENOTEQU:
+ case EAND:
+ case EXOR:
+ case EOR:
+ case ELAND:
+ case ELOR:
+ case EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case ECOMMA:
+ case EPMODULO:
+ case EROTL:
+ case EROTR:
+ case EBCLR:
+ case EBTST:
+ case EBSET:
+ if ((tmp1 = countindirects(expr->data.diadic.left)) >= 2)
+ return 2;
+ if ((tmp2 = countindirects(expr->data.diadic.right)) >= 2)
+ return 2;
+ if (tmp2 > tmp1)
+ tmp1 = tmp2;
+ return tmp1;
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EINDIRECT:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case EFORCELOAD:
+ case ETYPCON:
+ case EBITFIELD:
+ if (expr->type == EINDIRECT)
+ return countindirects(expr->data.monadic) + 1;
+ else
+ return countindirects(expr->data.monadic);
+ default:
+ return 2;
+ }
+}
+
+static Boolean DetectCondSideAffect(ENode *expr) {
+ switch (expr->type) {
+ case EMUL:
+ case EMULV:
+ case EDIV:
+ case EMODULO:
+ case EADDV:
+ case ESUBV:
+ case EADD:
+ case ESUB:
+ case ESHL:
+ case ESHR:
+ case EAND:
+ case EXOR:
+ case EOR:
+ case ECOMMA:
+ case EPMODULO:
+ case EROTL:
+ case EROTR:
+ case EBCLR:
+ case EBTST:
+ case EBSET:
+ if (DetectCondSideAffect(expr->data.diadic.left))
+ return 1;
+ return DetectCondSideAffect(expr->data.diadic.right);
+ case EINDIRECT:
+ if (expr->data.monadic->type == EINDIRECT)
+ return 1;
+ if (expr->data.monadic->type == EOBJREF) {
+ if (expr->data.monadic->data.objref->datatype != DLOCAL && expr->data.monadic->data.objref->datatype != DDATA)
+ return 1;
+ if (IS_TYPE_POINTER(expr->data.monadic->data.objref->type))
+ return 1;
+ return Registers_GetVarInfo(expr->data.monadic->data.objref)->noregister != 0;
+ }
+ return 1;
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case EFORCELOAD:
+ case ETYPCON:
+ case EBITFIELD:
+ return DetectCondSideAffect(expr->data.monadic);
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EVECTOR128CONST:
+ return 0;
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ case ENOTEQU:
+ case ELAND:
+ case ELOR:
+ case EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case ECOND:
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ case EMFPOINTER:
+ case ENULLCHECK:
+ case EPRECOMP:
+ case EDEFINE:
+ case EREUSE:
+ case EASSBLK:
+ case ECONDASS:
+ return 1;
+ default:
+ CError_FATAL(2523);
+ return 1;
+ }
+}
+
+static UInt8 WeightandSumOps(ENode *expr) {
+ UInt32 score;
+
+ switch (expr->type) {
+ case ECOND:
+ case ECONDASS:
+ score = WeightandSumOps(expr->data.cond.cond);
+ score += WeightandSumOps(expr->data.cond.expr1);
+ score += WeightandSumOps(expr->data.cond.expr2);
+ break;
+ case EMUL:
+ case EMULV:
+ case EMULASS:
+ score = WeightandSumOps(expr->data.diadic.left) + 10;
+ score += WeightandSumOps(expr->data.diadic.right);
+ break;
+ case EDIV:
+ case EMODULO:
+ case EDIVASS:
+ case EMODASS:
+ score = WeightandSumOps(expr->data.diadic.left) + 20;
+ score += WeightandSumOps(expr->data.diadic.right);
+ break;
+ case EADDV:
+ case ESUBV:
+ case EADD:
+ case ESUB:
+ case ESHL:
+ case ESHR:
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ case ENOTEQU:
+ case EAND:
+ case EXOR:
+ case EOR:
+ case ELAND:
+ case ELOR:
+ case EASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case ECOMMA:
+ case EPMODULO:
+ case EROTL:
+ case EROTR:
+ case EBCLR:
+ case EBTST:
+ case EBSET:
+ score = WeightandSumOps(expr->data.diadic.left) + 1;
+ score += WeightandSumOps(expr->data.diadic.right);
+ break;
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ score = WeightandSumOps(expr->data.monadic) + 1;
+ break;
+ case EINDIRECT:
+ if (expr->data.monadic->type == EOBJREF && expr->data.monadic->data.objref->datatype == DLOCAL)
+ if (!Registers_GetVarInfo(expr->data.monadic->data.objref)->noregister)
+ return 0;
+ case EFORCELOAD:
+ case ETYPCON:
+ case EBITFIELD:
+ score = WeightandSumOps(expr->data.monadic);
+ break;
+ case EOBJREF:
+ score = 0;
+ break;
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EVECTOR128CONST:
+ score = 0;
+ break;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ score = 5;
+ break;
+ default:
+ score = 255;
+ }
+
+ if (score >= 255)
+ score = 255;
+ return (UInt8) score;
+}
+
+Boolean TOC_use_fsel(ENode *expr) {
+ ENode *left;
+ ENode *right;
+ Type *rtype;
+ int score1;
+ int score2;
+
+ left = expr->data.cond.expr1;
+ right = expr->data.cond.expr2;
+ rtype = expr->rtype;
+
+ if (!copts.peephole) return 0;
+ if (!copts.gen_fsel) return 0;
+ if (left->hascall) return 0;
+ if (right->hascall) return 0;
+ if (!IS_TYPE_FLOAT(rtype)) return 0;
+ if (!IS_TYPE_FLOAT(left->rtype)) return 0;
+ if (!IS_TYPE_FLOAT(right->rtype)) return 0;
+
+ if (expr->data.cond.cond->type < ELESS || expr->data.cond.cond->type > ENOTEQU)
+ return 0;
+ if (!IS_TYPE_FLOAT(expr->data.cond.cond->data.diadic.right->rtype))
+ return 0;
+ if (expr->data.cond.cond->type == ELOGNOT || expr->data.cond.cond->type == ELAND || expr->data.cond.cond->type == ELOR)
+ return 0;
+
+ if (expr->type == ECONDASS) {
+ if (left->type != EINDIRECT)
+ return 0;
+ if (left->data.monadic->type != EOBJREF)
+ return 0;
+ }
+
+ if (DetectCondSideAffect(left))
+ return 0;
+ if (DetectCondSideAffect(right))
+ return 0;
+
+ if (expr->type == ECONDASS)
+ score1 = 1;
+ else
+ score1 = WeightandSumOps(left);
+ score2 = WeightandSumOps(right);
+
+ if (score1 > copts.gen_fsel)
+ return 0;
+ else if (score2 > copts.gen_fsel)
+ return 0;
+ else
+ return 1;
+}
+
+Boolean TOC_use_isel(ENode *expr, Boolean flag) {
+ int opt;
+ ENode *left;
+ ENode *right;
+ Type *rtype;
+ Object *obj;
+ int score1;
+ int score2;
+
+ left = expr->data.cond.expr1;
+ right = expr->data.cond.expr2;
+ rtype = expr->rtype;
+ if (flag)
+ opt = 10;
+ else
+ opt = copts.gen_isel;
+
+ if (!opt) return 0;
+ if (!copts.peephole) return 0;
+ if (left->hascall) return 0;
+ if (right->hascall) return 0;
+ if (!TYPE_FITS_IN_REGISTER(rtype)) return 0;
+ if (!TYPE_FITS_IN_REGISTER(left->rtype)) return 0;
+ if (!TYPE_FITS_IN_REGISTER(right->rtype)) return 0;
+
+ if (expr->data.cond.cond->type < ELESS || expr->data.cond.cond->type > ENOTEQU)
+ return 0;
+ if (TYPE_IS_8BYTES(rtype))
+ return 0;
+
+ if (flag) {
+ if (!TYPE_FITS_IN_REGISTER(expr->data.cond.cond->data.diadic.right->rtype))
+ return 0;
+ if (TYPE_IS_8BYTES(expr->data.cond.cond->data.diadic.right->rtype))
+ return 0;
+ }
+
+ if (expr->type == ECONDASS) {
+ if (left->type != EINDIRECT)
+ return 0;
+ if (left->data.monadic->type != EOBJREF)
+ return 0;
+ if (flag) {
+ obj = left->data.monadic->data.objref;
+ if (obj->datatype != DLOCAL)
+ return 0;
+ if ((Registers_GetVarInfo(obj) ? Registers_GetVarInfo(obj)->reg : 0) == 0)
+ return 0;
+ if (obj->u.var.info->rclass != RegClass_GPR)
+ return 0;
+ }
+ }
+
+ if (DetectCondSideAffect(left))
+ return 0;
+ if (DetectCondSideAffect(right))
+ return 0;
+
+ if (expr->type == ECONDASS)
+ score1 = 1;
+ else
+ score1 = WeightandSumOps(left);
+ score2 = WeightandSumOps(right);
+
+ if (score1 > opt)
+ return 0;
+ else if (score2 > opt)
+ return 0;
+ else
+ return 1;
+}
+
+SInt32 GetSizeSkip(ENode *expr) {
+ if (expr->type == EASS)
+ expr = expr->data.diadic.right;
+ if (expr->type == ETYPCON && expr->data.monadic->rtype->size < expr->rtype->size)
+ return expr->data.monadic->rtype->size;
+ else
+ return expr->rtype->size;
+}
+
+void Optimize64bitMath(ENode *expr) {
+ ENode *left; // r23
+ ENode *right; // r28
+ SInt32 leftsize; // r24
+ SInt32 rightsize; // r25
+ SInt32 totalsize; // r22
+ int unsignedflag; // r4
+
+ CError_ASSERT(2886, TYPE_IS_8BYTES(expr->rtype));
+
+ left = expr->data.diadic.left;
+ right = expr->data.diadic.right;
+ leftsize = GetSizeSkip(left);
+ totalsize = (leftsize + (rightsize = GetSizeSkip(right)));
+ unsignedflag = is_unsigned(expr->rtype) != 0;
+
+ switch (totalsize) {
+ case 2:
+ case 3:
+ case 4:
+ if (unsignedflag) {
+ left->rtype = (Type *) &stunsignedint;
+ right->rtype = (Type *) &stunsignedint;
+ } else {
+ left->rtype = (Type *) &stsignedint;
+ right->rtype = (Type *) &stsignedint;
+ }
+ break;
+ case 5:
+ case 6:
+ case 8:
+ case 9:
+ case 10:
+ case 12:
+ if (expr->type != ESUB || leftsize >= rightsize) {
+ if (leftsize < 4) {
+ if (unsignedflag)
+ left->rtype = (Type *) &stunsignedint;
+ else
+ left->rtype = (Type *) &stsignedint;
+ } else {
+ if (left->type == ETYPCON && left->data.monadic->rtype != (Type *) &stfloat)
+ expr->data.diadic.left = left->data.monadic;
+ }
+ if (rightsize < 4) {
+ if (unsignedflag)
+ right->rtype = (Type *) &stunsignedint;
+ else
+ right->rtype = (Type *) &stsignedint;
+ } else {
+ if (right->type == ETYPCON && right->data.monadic->rtype != (Type *) &stfloat)
+ expr->data.diadic.right = right->data.monadic;
+ }
+ }
+ break;
+ case 16:
+ break;
+ default:
+ CError_FATAL(2975);
+ }
+}
+
+static Boolean OptimizeNestedAssginments(ENode **pexpr, Object *check) {
+ ENode *expr;
+ Boolean success1;
+ Boolean success2;
+
+ expr = *pexpr;
+ switch (expr->type) {
+ case EOBJREF:
+ return check != expr->data.objref;
+ case EMUL:
+ case EMULV:
+ case EDIV:
+ case EMODULO:
+ case EADDV:
+ case ESUBV:
+ case EADD:
+ case ESUB:
+ case ESHL:
+ case ESHR:
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ case ENOTEQU:
+ case EAND:
+ case EXOR:
+ case EOR:
+ case ELAND:
+ case ELOR:
+ case EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case ECOMMA:
+ case EPMODULO:
+ case EROTL:
+ case EROTR:
+ case EBCLR:
+ case EBTST:
+ case EBSET:
+ switch (expr->type) {
+ case EASS:
+ if (ENODE_IS(expr->data.diadic.left, EOBJREF) && expr->data.diadic.left->data.objref == check) {
+ *pexpr = expr->data.diadic.right;
+ return OptimizeNestedAssginments(pexpr, check);
+ }
+ break;
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ CError_FATAL(3033);
+ return 0;
+ }
+ if (OptimizeNestedAssginments(&expr->data.diadic.right, check))
+ return OptimizeNestedAssginments(&expr->data.diadic.left, check);
+ else
+ return 0;
+ break;
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EINDIRECT:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case EFORCELOAD:
+ case ETYPCON:
+ case EBITFIELD:
+ return OptimizeNestedAssginments(&expr->data.monadic, check);
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EVECTOR128CONST:
+ return 1;
+ case ECOND:
+ success2 = OptimizeNestedAssginments(&expr->data.cond.expr2, check);
+ success1 = OptimizeNestedAssginments(&expr->data.cond.expr1, check);
+ if (!success2 || !success1)
+ return 0;
+ return OptimizeNestedAssginments(&expr->data.cond.cond, check) == 0;
+ case ECONDASS:
+ if (!OptimizeNestedAssginments(&expr->data.cond.expr2, check))
+ return 0;
+ if (OptimizeNestedAssginments(&expr->data.cond.cond, check))
+ return OptimizeNestedAssginments(&expr->data.cond.expr1, check) == 0;
+ else
+ return 0;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ case EMFPOINTER:
+ case ENULLCHECK:
+ case EPRECOMP:
+ case EDEFINE:
+ case EREUSE:
+ case EASSBLK:
+ return 0;
+ default:
+ CError_FATAL(3083);
+ return 0;
+ }
+}
+
+static void expandTOCexpression(ENode *expr, Type *type, int ignored) {
+ Object *obj;
+ Object *tmpobj;
+ ENode *cond;
+ ENode *tmpexpr;
+ ENode *newexpr;
+ ENodeList *list;
+
+ expr->ignored = ignored;
+ switch (expr->type) {
+ case EINTCONST:
+ expr->hascall = 0;
+ break;
+ case EFLOATCONST:
+ uses_globals = 1;
+ RewriteFloatConst(expr);
+ expandTOCexpression(expr, NULL, 0);
+ break;
+ case EVECTOR128CONST:
+ if (!canoptimizevectorconst(&expr->data.vector128val, expr->rtype, NULL)) {
+ uses_globals = 1;
+ RewriteVectorConst(expr);
+ expandTOCexpression(expr, NULL, 0);
+ }
+ break;
+ case ESTRINGCONST:
+ uses_globals = 1;
+ CInit_RewriteString(expr, 1);
+ expandTOCexpression(expr, NULL, 0);
+ break;
+ case EOBJREF:
+ obj = expr->data.objref;
+ CError_ASSERT(3203, obj->datatype != DALIAS);
+ if (obj->datatype == DFUNC || obj->datatype == DVFUNC)
+ uses_globals = 1;
+ if (obj->datatype == DDATA) {
+ uses_globals = 1;
+ if (createIndirect(obj, 0, 1)) {
+ tmpexpr = lalloc(sizeof(ENode));
+ memclrw(tmpexpr, sizeof(ENode));
+ tmpexpr->type = EOBJREF;
+ tmpexpr->cost = 0;
+ tmpexpr->data.objref = obj->toc;
+ tmpexpr->rtype = CDecl_NewPointerType(expr->rtype);
+
+ expr->type = EINDIRECT;
+ expr->cost = 1;
+ expr->data.monadic = tmpexpr;
+ }
+ }
+ expr->hascall = 0;
+ break;
+ case ECONDASS:
+ expr->ignored = 0;
+ case ECOND:
+ if (!ENODE_IS_RANGE(expr->data.cond.cond, ELESS, ENOTEQU))
+ expr->data.cond.cond = comparewithzero(expr->data.cond.cond);
+ expandTOCexpression(expr->data.cond.expr1, NULL, ignored);
+ expandTOCexpression(expr->data.cond.expr2, NULL, ignored);
+ if (TOC_use_fsel(expr)) {
+ cond = expr->data.cond.cond;
+ if (ENODE_IS(cond->data.diadic.right, EFLOATCONST) && CMach_FloatIsZero(cond->data.diadic.right->data.floatval)) {
+ expandTOCexpression(cond->data.diadic.left, NULL, 0);
+ } else if (ENODE_IS(cond->data.diadic.left, EFLOATCONST) && CMach_FloatIsZero(cond->data.diadic.left->data.floatval)) {
+ expandTOCexpression(cond->data.diadic.right, NULL, 0);
+ } else {
+ expandTOCexpression(expr->data.cond.cond, NULL, 0);
+ }
+ } else {
+ expandTOCexpression(expr->data.cond.cond, NULL, 0);
+ }
+ expr->hascall = expr->data.cond.cond->hascall | expr->data.cond.expr1->hascall | expr->data.cond.expr2->hascall;
+ break;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ if (is_intrinsic_function_call(expr)) {
+ expr->hascall = 0;
+ if ((expr->data.funccall.funcref->data.objref->u.func.u.intrinsicid & 0xFFFFu) == Intrinsic_008) {
+ if (copts.altivec_model)
+ update_frame_align(16);
+ dynamic_stack = 1;
+ requires_frame = 1;
+ } else if ((expr->data.funccall.funcref->data.objref->u.func.u.intrinsicid & 0xFFFFu) == Intrinsic_035) {
+ if (expr->data.funccall.args->next->node->type == ESTRINGCONST) {
+ rewritestrcpy(expr);
+ } else {
+ requires_frame = 1;
+ makes_call = 1;
+ expr->hascall = 1;
+ }
+ } else if ((expr->data.funccall.funcref->data.objref->u.func.u.intrinsicid & 0xFFFFu) == Intrinsic_036) {
+ if (expr->data.funccall.args->next->next->node->type != EINTCONST) {
+ requires_frame = 1;
+ makes_call = 1;
+ expr->hascall = 1;
+ }
+ }
+ } else {
+ requires_frame = 1;
+ makes_call = 1;
+ expr->hascall = 1;
+ }
+
+ if (disables_optimizer(expr)) {
+ disable_optimizer |= 1;
+ if (copts.disable_registers)
+ disable_optimizer |= 2;
+ }
+
+ if (ENODE_IS(expr->data.funccall.funcref, EINDIRECT) && IS_TYPE_FUNC(expr->data.funccall.funcref->rtype))
+ *expr->data.funccall.funcref = *expr->data.funccall.funcref->data.monadic;
+
+ if (ENODE_IS(expr->data.funccall.funcref, EOBJREF)) {
+ expr->data.funccall.funcref->hascall = 0;
+ if (expr->data.funccall.funcref->data.objref->datatype == DVFUNC && (expr->data.funccall.funcref->flags & ENODE_FLAG_80)) {
+ tmpobj = galloc(sizeof(Object));
+ *tmpobj = *expr->data.funccall.funcref->data.objref;
+ tmpobj->datatype = DFUNC;
+ expr->data.funccall.funcref->data.objref = tmpobj;
+ }
+ } else {
+ expandTOCexpression(expr->data.funccall.funcref, NULL, 0);
+ }
+
+ for (list = expr->data.funccall.args; list; list = list->next)
+ expandTOCexpression(list->node, NULL, 0);
+
+ if (expr->hascall)
+ estimate_func_param_size(expr);
+
+ if (is_intrinsic_function_call(expr)) {
+ for (list = expr->data.funccall.args; list; list = list->next)
+ expr->hascall |= list->node->hascall;
+ }
+
+ if (CMach_PassResultInHiddenArg(TYPE_FUNC(expr->data.funccall.functype)->functype))
+ rewritefunctioncallreturningstruct(expr);
+
+ break;
+ case ECOMMA:
+ expandTOCexpression(expr->data.diadic.left, NULL, 1);
+ expandTOCexpression(expr->data.diadic.right, NULL, ignored);
+ expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall;
+ break;
+ case ELAND:
+ case ELOR:
+ if (!ENODE_IS(expr->data.diadic.left, ELOGNOT) && !ENODE_IS2(expr->data.diadic.left, ELAND, ELOR) && !ENODE_IS_RANGE(expr->data.diadic.left, ELESS, ENOTEQU))
+ expr->data.diadic.left = comparewithzero(expr->data.diadic.left);
+ if (!ENODE_IS(expr->data.diadic.right, ELOGNOT) && !ENODE_IS2(expr->data.diadic.right, ELAND, ELOR) && !ENODE_IS_RANGE(expr->data.diadic.right, ELESS, ENOTEQU))
+ expr->data.diadic.right = comparewithzero(expr->data.diadic.right);
+ expandTOCexpression(expr->data.diadic.left, NULL, 0);
+ expandTOCexpression(expr->data.diadic.right, NULL, 0);
+ expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall;
+ break;
+ case EDIVASS:
+ if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype))
+ uses_globals = 1;
+ rewrite_opassign(expr, EDIV);
+ goto opassign_common;
+ case EMULASS:
+ if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype))
+ uses_globals = 1;
+ rewrite_opassign(expr, EMUL);
+ goto opassign_common;
+ case EADDASS:
+ if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype))
+ uses_globals = 1;
+ rewrite_opassign(expr, EADD);
+ goto opassign_common;
+ case ESUBASS:
+ if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype))
+ uses_globals = 1;
+ rewrite_opassign(expr, ESUB);
+ goto opassign_common;
+ case EMODASS:
+ if (!IS_TYPE_FLOAT(expr->rtype) && IS_TYPE_FLOAT(expr->data.diadic.right->rtype))
+ uses_globals = 1;
+ rewrite_opassign(expr, EMODULO);
+ goto opassign_common;
+ case ESHLASS:
+ rewrite_opassign(expr, ESHL);
+ goto opassign_common;
+ case ESHRASS:
+ rewrite_opassign(expr, ESHR);
+ goto opassign_common;
+ case EANDASS:
+ rewrite_opassign(expr, EAND);
+ goto opassign_common;
+ case EXORASS:
+ rewrite_opassign(expr, EXOR);
+ goto opassign_common;
+ case EORASS:
+ rewrite_opassign(expr, EOR);
+ goto opassign_common;
+ case EASS:
+ if (ENODE_IS(expr->data.diadic.left, EINDIRECT))
+ expr->data.diadic.left = expr->data.diadic.left->data.monadic;
+ opassign_common:
+ expandTOCexpression(expr->data.diadic.left, NULL, 0);
+ expandTOCexpression(expr->data.diadic.right, NULL, 0);
+ expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall;
+ break;
+ case EEQU:
+ case ENOTEQU:
+ if (ENODE_IS(expr->data.diadic.right, EINTCONST) && expr->data.diadic.right->data.intval.lo == 0 && expr->data.diadic.right->data.intval.hi == 0) {
+ for (tmpexpr = expr->data.diadic.left; ENODE_IS2(tmpexpr, EFORCELOAD, ETYPCON); tmpexpr = tmpexpr->data.monadic) {
+ if (!TYPE_FITS_IN_REGISTER(tmpexpr->rtype))
+ break;
+ }
+ if (ENODE_IS(tmpexpr, ELOGNOT) && TYPE_FITS_IN_REGISTER(tmpexpr->data.monadic->rtype)) {
+ if (ENODE_IS(expr, EEQU))
+ expr->type = ENOTEQU;
+ else
+ expr->type = EEQU;
+ expr->data.diadic.left = tmpexpr->data.monadic;
+ expandTOCexpression(expr, NULL, 0);
+ break;
+ }
+ if (ENODE_IS(tmpexpr, EEQU)) {
+ if (ENODE_IS(expr, EEQU))
+ tmpexpr->type = ENOTEQU;
+ *expr = *tmpexpr;
+ expandTOCexpression(expr, NULL, 0);
+ break;
+ }
+ if (ENODE_IS(tmpexpr, ENOTEQU)) {
+ if (ENODE_IS(expr, EEQU))
+ tmpexpr->type = EEQU;
+ *expr = *tmpexpr;
+ expandTOCexpression(expr, NULL, 0);
+ break;
+ }
+ if (ENODE_IS(tmpexpr, ECOND)) {
+ newexpr = COND_to_COMPARE(tmpexpr->data.cond.cond, tmpexpr->data.cond.expr1, tmpexpr->data.cond.expr2);
+ if (newexpr) {
+ *tmpexpr = *newexpr;
+ expandTOCexpression(expr, NULL, 0);
+ break;
+ }
+ }
+ }
+ case EDIV:
+ if (ENODE_IS(expr, EDIV) && ENODE_IS(expr->data.diadic.right, EFLOATCONST) && CMach_FloatIsPowerOf2(expr->data.diadic.right->data.floatval)) {
+ expr->type = EMUL;
+ expr->data.diadic.right->data.floatval = CMach_FloatReciprocal(expr->data.diadic.right->data.floatval);
+ }
+ case EMODULO:
+ case ESHL:
+ case ESHR:
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ expandTOCexpression(expr->data.diadic.left, NULL, 0);
+ expandTOCexpression(expr->data.diadic.right, NULL, 0);
+ expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall;
+ if (TYPE_IS_8BYTES(expr->rtype)) {
+ if (ENODE_IS2(expr, ESHL, ESHR) && !ENODE_IS(expr->data.diadic.right, EINTCONST)) {
+ expr->hascall = 1;
+ requires_frame = 1;
+ makes_call = 1;
+ }
+ if (ENODE_IS2(expr, EDIV, EMODULO)) {
+ if (ENODE_IS(expr->data.diadic.right, EINTCONST)) {
+ if (I8_log2n(((SInt64) expr->data.diadic.right->data.intval.hi << 32) + expr->data.diadic.right->data.intval.lo) <= 0) {
+ expr->hascall = 1;
+ requires_frame = 1;
+ makes_call = 1;
+ }
+ } else {
+ expr->hascall = 1;
+ requires_frame = 1;
+ makes_call = 1;
+ }
+ }
+ }
+ break;
+ case ESUB:
+ if (ENODE_IS(expr->data.diadic.right, EINTCONST)) {
+ expr->type = EADD;
+ expr->data.diadic.right->data.intval = CInt64_Neg(expr->data.diadic.right->data.intval);
+ }
+ case EMUL:
+ case EADD:
+ case EAND:
+ case EXOR:
+ case EOR:
+ expandTOCexpression(expr->data.diadic.left, type, 0);
+ expandTOCexpression(expr->data.diadic.right, type, 0);
+ expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall;
+ if (ENODE_IS3(expr, EMUL, EADD, ESUB) && TYPE_IS_8BYTES(expr->rtype))
+ Optimize64bitMath(expr);
+ if (type) {
+ if (
+ ENODE_IS(expr->data.diadic.left, ETYPCON) &&
+ IS_TYPE_INT_OR_ENUM(expr->data.diadic.left->rtype) &&
+ IS_TYPE_INT_OR_ENUM(expr->data.diadic.left->data.monadic->rtype) &&
+ expr->data.diadic.left->data.monadic->rtype->size >= type->size &&
+ !TYPE_IS_8BYTES(expr->data.diadic.left->data.monadic->rtype)
+ )
+ expr->data.diadic.left = expr->data.diadic.left->data.monadic;
+
+ if (
+ ENODE_IS(expr->data.diadic.right, ETYPCON) &&
+ IS_TYPE_INT_OR_ENUM(expr->data.diadic.right->rtype) &&
+ IS_TYPE_INT_OR_ENUM(expr->data.diadic.right->data.monadic->rtype) &&
+ expr->data.diadic.right->data.monadic->rtype->size >= type->size &&
+ !TYPE_IS_8BYTES(expr->data.diadic.right->data.monadic->rtype)
+ )
+ expr->data.diadic.right = expr->data.diadic.right->data.monadic;
+
+ expr->rtype = type;
+ }
+ break;
+
+ case ETYPCON:
+ tmpexpr = expr->data.monadic;
+ if ((IS_TYPE_INT_OR_ENUM(expr->rtype) && expr->rtype->size < 4) && IS_TYPE_INT_OR_ENUM(tmpexpr->rtype) && !TYPE_IS_8BYTES(tmpexpr->rtype)) {
+ expandTOCexpression(tmpexpr, expr->rtype, 0);
+ } else {
+ expandTOCexpression(tmpexpr, NULL, expr->rtype->type == TYPEVOID);
+ }
+
+ expr->hascall = tmpexpr->hascall;
+ if (IS_TYPE_INT_OR_ENUM(tmpexpr->rtype) && IS_TYPE_FLOAT(expr->rtype))
+ uses_globals = 1;
+
+ if ((TYPE_IS_8BYTES(tmpexpr->rtype) && IS_TYPE_FLOAT(expr->rtype)) || (TYPE_IS_8BYTES(expr->rtype) && IS_TYPE_FLOAT(tmpexpr->rtype))) {
+ uses_globals = 1;
+ expr->hascall = 1;
+ requires_frame = 1;
+ makes_call = 1;
+ }
+
+ if (IS_TYPE_FLOAT(tmpexpr->rtype)) {
+ if (is_unsigned(expr->rtype) && expr->rtype->size == 4) {
+ expr->hascall = 1;
+ requires_frame = 1;
+ makes_call = 1;
+ } else {
+ uses_globals = 1;
+ }
+ }
+
+ if (IS_TYPE_VECTOR(expr->rtype) && !IS_TYPE_VECTOR(tmpexpr->rtype))
+ PPCError_Error(PPCErrorStr114);
+ break;
+
+ case EPOSTINC:
+ if (!expr->ignored) {
+ if (IS_TYPE_FLOAT(expr->data.monadic->rtype) && is_unsigned(expr->rtype))
+ uses_globals = 1;
+ expandTOCexpression(expr->data.monadic, NULL, 0);
+ expr->hascall = expr->data.monadic->hascall;
+ break;
+ }
+ expr->type = EPREINC;
+ case EPREINC:
+ rewrite_preincdec(expr);
+ rewrite_opassign(expr, EADD);
+ goto opassign_common;
+
+ case EPOSTDEC:
+ if (!expr->ignored) {
+ if (IS_TYPE_FLOAT(expr->data.monadic->rtype) && is_unsigned(expr->rtype))
+ uses_globals = 1;
+ expandTOCexpression(expr->data.monadic, NULL, 0);
+ expr->hascall = expr->data.monadic->hascall;
+ break;
+ }
+ expr->type = EPREDEC;
+ case EPREDEC:
+ rewrite_preincdec(expr);
+ rewrite_opassign(expr, ESUB);
+ goto opassign_common;
+
+ case ELOGNOT:
+ if (!ENODE_IS(expr->data.monadic, ELOGNOT) && !ENODE_IS2(expr->data.monadic, ELAND, ELOR) && !ENODE_IS_RANGE(expr->data.monadic, ELESS, ENOTEQU))
+ expr->data.monadic = comparewithzero(expr->data.monadic);
+ case EMONMIN:
+ case EBINNOT:
+ tmpexpr = expr->data.monadic;
+ expandTOCexpression(tmpexpr, type, 0);
+ expr->hascall = tmpexpr->hascall;
+ if (type && ENODE_IS(expr->data.monadic, ETYPCON)) {
+ if (IS_TYPE_INT_OR_ENUM(expr->data.monadic->rtype) && IS_TYPE_INT_OR_ENUM(expr->data.monadic->data.monadic->rtype)) {
+ if (expr->data.monadic->data.monadic->rtype->size >= type->size) {
+ expr->data.monadic = expr->data.monadic->data.monadic;
+ expr->rtype = type;
+ }
+ }
+ }
+ break;
+
+ case EINDIRECT:
+ case EFORCELOAD:
+ case EBITFIELD:
+ tmpexpr = expr->data.monadic;
+ expandTOCexpression(tmpexpr, NULL, 0);
+ expr->hascall = tmpexpr->hascall;
+ break;
+
+ case EDEFINE:
+ tmpexpr = expr->data.monadic;
+ expandTOCexpression(tmpexpr, NULL, 0);
+ expr->hascall = tmpexpr->hascall;
+ break;
+
+ case EREUSE:
+ expr->hascall = expr->data.monadic->hascall;
+ break;
+
+ case ENULLCHECK:
+ expandTOCexpression(expr->data.diadic.left, NULL, 0);
+ expandTOCexpression(expr->data.diadic.right, NULL, 0);
+ expr->hascall = expr->data.diadic.left->hascall | expr->data.diadic.right->hascall;
+ break;
+
+ case EPRECOMP:
+ expr->hascall = 0;
+ break;
+
+ case ELABEL:
+ obj = createcodelabel(expr->data.label);
+ newexpr = lalloc(sizeof(ENode));
+ memclrw(newexpr, sizeof(ENode));
+ newexpr->type = EOBJREF;
+ newexpr->cost = 0;
+ newexpr->data.objref = obj;
+ newexpr->rtype = CDecl_NewPointerType(obj->type);
+
+ expr->type = EINDIRECT;
+ expr->cost = 1;
+ expr->data.monadic = newexpr;
+ expr->hascall = 0;
+ break;
+ }
+}
+
+static void checkexceptionreferences(ExceptionAction *action) {
+ for (; action; action = action->prev) {
+ switch (action->type) {
+ case EAT_DESTROYLOCAL:
+ referenceexception(action->data.destroy_local.local);
+ break;
+ case EAT_DESTROYLOCALCOND:
+ referenceexception(action->data.destroy_local_cond.local);
+ referenceexception(action->data.destroy_local_cond.cond);
+ break;
+ case EAT_DESTROYLOCALOFFSET:
+ referenceexception(action->data.destroy_local_offset.local);
+ break;
+ case EAT_DESTROYLOCALPOINTER:
+ referenceexception(action->data.destroy_local_pointer.pointer);
+ break;
+ case EAT_DESTROYLOCALARRAY:
+ referenceexception(action->data.destroy_local_array.localarray);
+ break;
+ case EAT_DESTROYBASE:
+ referenceexception(action->data.destroy_member.objectptr); // wrong union?
+ break;
+ case EAT_DESTROYPARTIALARRAY:
+ referenceexception(action->data.destroy_partial_array.arraypointer);
+ referenceexception(action->data.destroy_partial_array.arraycounter);
+ referenceexception(action->data.destroy_partial_array.element_size);
+ break;
+ case EAT_DESTROYMEMBER:
+ referenceexception(action->data.destroy_member.objectptr);
+ break;
+ case EAT_DESTROYMEMBERCOND:
+ referenceexception(action->data.destroy_member_cond.objectptr);
+ referenceexception(action->data.destroy_member_cond.cond);
+ break;
+ case EAT_DESTROYMEMBERARRAY:
+ referenceexception(action->data.destroy_member_array.objectptr);
+ break;
+ case EAT_DELETEPOINTER:
+ case EAT_DELETELOCALPOINTER:
+ referenceexception(action->data.delete_pointer.pointerobject);
+ break;
+ case EAT_DELETEPOINTERCOND:
+ referenceexception(action->data.delete_pointer_cond.pointerobject);
+ referenceexception(action->data.delete_pointer_cond.cond);
+ break;
+ case EAT_CATCHBLOCK:
+ referenceexception(action->data.catch_block.catch_object);
+ referenceexception(action->data.catch_block.catch_info_object);
+ break;
+ case EAT_ACTIVECATCHBLOCK:
+ referenceexception(action->data.active_catch_block.catch_info_object);
+ break;
+ }
+ }
+}
+
+void expandTOCreferences(Statement **stmts) {
+ Statement *stmt;
+ IAOperand *op;
+ int i;
+ InlineAsm *ia;
+ VarInfo *vi;
+
+ codelabellist = NULL;
+ exceptionlist = NULL;
+
+ for (stmt = *stmts; stmt; stmt = stmt->next) {
+ curstmtvalue = stmt->value;
+ if (stmt->flags & StmtFlag_1) {
+ has_catch_blocks = 1;
+ dynamic_stack = 1;
+ requires_frame = 1;
+ }
+
+ switch (stmt->type) {
+ case ST_EXPRESSION:
+ expandTOCexpression(stmt->expr, NULL, 1);
+ if (stmt->expr->type == ETYPCON && IS_TYPE_VOID(stmt->expr->rtype))
+ stmt->expr = stmt->expr->data.monadic;
+ break;
+ case ST_GOTOEXPR:
+ expandTOCexpression(stmt->expr, NULL, 0);
+ break;
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ if (stmt->expr->type < ELESS || stmt->expr->type > ENOTEQU)
+ stmt->expr = comparewithzero(stmt->expr);
+ expandTOCexpression(stmt->expr, NULL, 0);
+ break;
+ case ST_RETURN:
+ if (!stmt->expr)
+ continue;
+ expandTOCexpression(
+ stmt->expr, NULL,
+ IS_TYPE_ARRAY(stmt->expr->rtype) || IS_TYPE_NONVECTOR_STRUCT(stmt->expr->rtype) || IS_TYPE_CLASS(stmt->expr->rtype) ||
+ IS_TYPE_12BYTES_MEMBERPOINTER(stmt->expr->rtype));
+ break;
+ case ST_SWITCH:
+ uses_globals = 1;
+ expandTOCexpression(stmt->expr, NULL, 0);
+ break;
+ case ST_ENDCATCHDTOR:
+ requires_frame = 1;
+ makes_call = 1;
+ break;
+ case ST_ASM:
+ if ((ia = (InlineAsm *) stmt->expr)) {
+ if (ia->flags & IAFlag1) {
+ if (ia->opcode == IADirective_FrFree)
+ requires_frame = 1;
+ } else {
+ for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+ if (op->type == IAOpnd_Reg) {
+ if (!op->u.reg.object) {
+ if (op->u.reg.num == INVALID_PIC_REG)
+ uses_globals = 1;
+ else if (op->u.reg.effect & EffectWrite)
+ asm_used_register(op->u.reg.rclass, op->u.reg.num);
+ } else if ((vi = Registers_GetVarInfo(op->u.reg.object))) {
+ vi->flags |= VarInfoFlag40;
+ }
+ } else if (op->type == IAOpnd_3) {
+ uses_globals = 1;
+ }
+ }
+
+ if (ia->flags & IAFlag2)
+ makes_call = 1;
+ }
+ }
+ break;
+ }
+
+ checkexceptionreferences(stmt->dobjstack);
+ }
+}
+
+void resetTOCvarinfo(void) {
+ ObjectList *list;
+
+ for (list = toclist; list; list = list->next)
+ list->object->u.toc.info = CodeGen_GetNewVarInfo();
+}
+
+Boolean needdescriptor(void) {
+ // completely unused, dunno what args this might take
+ return 0;
+}
+
+Object *createstaticinitobject(void) {
+ char buf[100];
+ char *p;
+ Str255 fname;
+ TypeFunc *tfunc;
+ Object *obj;
+
+ COS_FileGetFSSpecInfo(&cparamblkptr->sourcefile, NULL, NULL, fname);
+ sprintf(buf, "__sinit_%*.*s", -fname[0], fname[0], &fname[1]);
+ for (p = &buf[1]; *p; p++) {
+ if (*p == '.')
+ *p = '_';
+ }
+
+ tfunc = galloc(sizeof(TypeFunc));
+ memclrw(tfunc, sizeof(TypeFunc));
+ tfunc->type = TYPEFUNC;
+ tfunc->functype = &stvoid;
+ tfunc->args = NULL;
+ tfunc->flags = FUNC_DEFINED;
+
+ obj = galloc(sizeof(Object));
+ memclrw(obj, sizeof(Object));
+ obj->otype = OT_OBJECT;
+ obj->type = (Type *) tfunc;
+ obj->name = GetHashNameNodeExport(buf);
+ obj->sclass = TK_STATIC;
+ obj->datatype = DFUNC;
+
+ return obj;
+}
+
+static void estimate_func_param_size(ENode *node) {
+ SInt32 work;
+ ENodeList *list;
+ SInt32 align;
+
+ work = 0;
+ for (list = node->data.funccall.args; list; list = list->next) {
+ align = ~7 & (CMach_ArgumentAlignment(list->node->rtype) + 7);
+ work += ~(align - 1) & (list->node->rtype->size + align - 1);
+ }
+
+ estimate_out_param_size(work);
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/Alias.c b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/Alias.c
new file mode 100644
index 0000000..8223bf4
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/Alias.c
@@ -0,0 +1,747 @@
+#include "compiler/Alias.h"
+#include "compiler/CClass.h"
+#include "compiler/CError.h"
+#include "compiler/CParser.h"
+#include "compiler/CMachine.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CopyPropagation.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/UseDefChains.h"
+#include "compiler/ValueNumbering.h"
+#include "compiler/BitVectors.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+static Alias *aliases;
+static int n_aliases;
+static int n_gathered_aliases;
+static Alias *alias_hash[997];
+Alias *worst_case;
+Object worst_case_obj;
+
+static TypePointer worst_case_memory_type = {
+ TYPEARRAY,
+ 0xFFFFFF,
+ TYPE(&stchar)
+};
+
+static Boolean is_safe_const(Object *obj) {
+ Type *type;
+
+ type = obj->type;
+ while (IS_TYPE_ARRAY(type))
+ type = TPTR_TARGET(type);
+
+ if (TYPE_FITS_IN_REGISTER(type) || IS_TYPE_VECTOR(type) || IS_TYPE_FLOAT(type) || IS_TYPE_STRUCT(type))
+ return is_const_object(obj);
+
+ if (IS_TYPE_CLASS(type))
+ return is_const_object(obj) && CClass_IsPODClass(TYPE_CLASS(type));
+
+ return 0;
+}
+
+void initialize_aliases(void) {
+ int i;
+
+ memclrw(&worst_case_obj, sizeof(Object));
+ worst_case_obj.otype = OT_OBJECT;
+ worst_case_obj.type = TYPE(&worst_case_memory_type);
+ worst_case_obj.datatype = DDATA;
+ worst_case_obj.name = GetHashNameNodeExport("@worst_case@");
+
+ aliases = NULL;
+ n_aliases = 0;
+ n_gathered_aliases = 0;
+ for (i = 0; i < 997; i++)
+ alias_hash[i] = NULL;
+
+ worst_case = make_alias_set();
+ add_alias_member(worst_case, make_alias(&worst_case_obj, 0, 0));
+}
+
+static UInt32 hash_alias(Object *object, SInt32 offset, SInt32 size) {
+ return (UInt32) (object->name->hashval * offset * size) % 997;
+}
+
+static Alias *create_alias(AliasType type, Object *object, SInt32 offset, SInt32 size, Boolean addToHash) {
+ Alias *alias;
+ UInt32 hash;
+
+ alias = lalloc(sizeof(Alias));
+ memclrw(alias, sizeof(Alias));
+ alias->type = type;
+ alias->index = n_aliases++;
+ alias->next = aliases;
+ aliases = alias;
+ alias->object = object;
+ alias->offset = offset;
+ alias->size = size;
+
+ if (addToHash) {
+ hash = hash_alias(object, offset, size);
+ alias->hashNext = alias_hash[hash];
+ alias_hash[hash] = alias;
+ }
+
+ return alias;
+}
+
+static Alias *lookup_alias(Object *object, SInt32 offset, SInt32 size) {
+ Alias *scan;
+
+ for (scan = alias_hash[hash_alias(object, offset, size)]; scan; scan = scan->hashNext) {
+ if (scan->object == object && scan->offset == offset && scan->size == size)
+ return scan;
+ }
+
+ return NULL;
+}
+
+Alias *make_alias(Object *object, SInt32 offset, SInt32 size) {
+ Alias *alias;
+ Alias *alias2;
+
+ if (!offset && !size)
+ size = object->type->size;
+
+ alias = lookup_alias(object, offset, size);
+ if (!alias) {
+ if (offset > 0 || size != object->type->size) {
+ alias2 = make_alias(object, 0, object->type->size);
+ alias = create_alias(AliasType1, object, offset, size, 1);
+ add_alias_member(alias2, alias);
+ } else {
+ alias = create_alias(AliasType0, object, offset, size, 1);
+ }
+
+ switch (object->datatype) {
+ case DLOCAL:
+ case DNONLAZYPTR:
+ break;
+ default:
+ if (!is_safe_const(object))
+ add_alias_member(worst_case, make_alias(object, 0, 0));
+ }
+ }
+
+ if (offset > object->type->size)
+ return NULL;
+ else
+ return alias;
+}
+
+Alias *make_alias_set(void) {
+ return create_alias(AliasType2, NULL, 0, 0, 0);
+}
+
+void add_alias_member(Alias *parent, Alias *child) {
+ AliasMember *member;
+
+ if (child->type == AliasType2) {
+ for (member = child->parents; member; member = member->nextParent)
+ add_alias_member(parent, member->child);
+ } else {
+ if (parent == worst_case && child->type == AliasType1)
+ child = make_alias(child->object, 0, 0);
+
+ for (member = parent->parents; member; member = member->nextParent) {
+ if (member->child == child)
+ return;
+ }
+
+ member = lalloc(sizeof(AliasMember));
+ member->parent = parent;
+ member->child = child;
+ member->nextParent = parent->parents;
+ parent->parents = member;
+ member->nextChild = child->children;
+ child->children = member;
+ }
+}
+
+Alias *make_alias_set_from_IR(void) {
+ CError_FATAL(333);
+ return NULL;
+}
+
+static Boolean aliases_overlap(Alias *a, Alias *b) {
+ return (
+ a->offset == b->offset ||
+ (a->offset > b->offset && a->offset < (b->offset + b->size)) ||
+ (b->offset > a->offset && b->offset < (a->offset + a->size))
+ );
+}
+
+static int is_address_load(PCode *pcode) {
+ Object *obj;
+
+ switch (pcode->op) {
+ case PC_LWZ:
+ if (pcode->args[2].kind == PCOp_MEMORY && pcode->args[2].data.mem.obj->datatype == DNONLAZYPTR)
+ return 1;
+ break;
+ case PC_LBZU:
+ case PC_LBZUX:
+ case PC_LHZU:
+ case PC_LHZUX:
+ case PC_LHAU:
+ case PC_LHAUX:
+ case PC_LWZU:
+ case PC_LWZUX:
+ case PC_STBU:
+ case PC_STBUX:
+ case PC_STHU:
+ case PC_STHUX:
+ case PC_STWU:
+ case PC_STWUX:
+ return 1;
+ case PC_ADDI:
+ case PC_ADDIS:
+ if (pcode->args[0].data.reg.reg < n_real_registers[RegClass_GPR]) {
+ if (pcode->args[2].kind == PCOp_MEMORY) {
+ obj = pcode->args[2].data.mem.obj;
+ if (obj->datatype == DLOCAL && !is_safe_const(obj))
+ add_alias_member(worst_case, make_alias(obj, 0, 0));
+ return 0;
+ }
+ } else {
+ return 1;
+ }
+ break;
+ case PC_ADD:
+ return 1;
+ }
+
+ return 0;
+}
+
+static int addresspropagatestouse(int candidateID, int useID) {
+ PCode *candidate_pcode; // r30
+ PCode *use_pcode; // r29
+ int reg; // r28
+ short reg2;
+ Object *object; // r27
+ SInt32 offset; // r26
+ Alias *alias; // r25
+ Boolean flag24; // r24
+ SInt32 size; // r23
+ Alias *aliasSet; // r22
+ int i;
+ PCode *scan;
+ PCodeArg *op;
+
+ candidate_pcode = Candidates[candidateID].pcode;
+ use_pcode = Uses[useID].pcode;
+ flag24 = 0;
+ size = 1;
+ reg = candidate_pcode->args[0].data.reg.reg;
+
+ if (candidate_pcode->alias && (candidate_pcode->alias->type == AliasType0 || candidate_pcode->alias->type == AliasType1)) {
+ object = candidate_pcode->alias->object;
+ offset = candidate_pcode->alias->offset;
+ if (offset == 0 && candidate_pcode->alias->size == object->type->size)
+ flag24 = 1;
+ } else if (candidate_pcode->args[2].kind == PCOp_MEMORY) {
+ object = candidate_pcode->args[2].data.mem.obj;
+ if (candidate_pcode->op == PC_ADDIS)
+ offset = candidate_pcode->args[2].data.mem.offset << 16;
+ else
+ offset = candidate_pcode->args[2].data.mem.offset;
+ } else {
+ return 0;
+ }
+
+ CError_ASSERT(478, object->otype == OT_OBJECT);
+
+ if ((candidate_pcode->flags & (fIsRead | fIsWrite)) && (candidate_pcode->flags & fUpdatesPtr)) {
+ reg = candidate_pcode->args[1].data.reg.reg;
+ offset = 0;
+ flag24 = 1;
+ } else if (candidate_pcode->op == PC_LWZ) {
+ if (object->datatype != DNONLAZYPTR)
+ return 0;
+
+ object = object->u.var.realObj;
+ CError_ASSERT(495, object->otype == OT_OBJECT);
+ offset = 0;
+ } else if (candidate_pcode->op == PC_ADDI) {
+ if (!candidate_pcode->alias && object)
+ candidate_pcode->alias = make_alias(object, offset, 1);
+ } else if (candidate_pcode->op == PC_ADDIS) {
+ if (!candidate_pcode->alias && object)
+ candidate_pcode->alias = make_alias(object, offset, 1);
+ } else if (candidate_pcode->op == PC_ADD) {
+ offset = 0;
+ flag24 = 1;
+ } else {
+ CError_FATAL(509);
+ }
+
+ if (
+ !(use_pcode->flags & (fIsRead | fIsWrite)) &&
+ use_pcode->op != PC_ADDI &&
+ use_pcode->op != PC_ADD &&
+ use_pcode->op != PC_ADDIS
+ ) {
+ if (object->datatype == DLOCAL && !is_safe_const(object))
+ add_alias_member(worst_case, make_alias(object, 0, 0));
+ return 1;
+ }
+
+ if (
+ (use_pcode->flags & (fIsWrite | fPCodeFlag40000)) &&
+ use_pcode->args[0].kind == PCOp_REGISTER &&
+ use_pcode->args[0].arg == RegClass_GPR &&
+ use_pcode->args[0].data.reg.reg == reg &&
+ object->datatype == DLOCAL &&
+ !is_safe_const(object)
+ )
+ add_alias_member(worst_case, make_alias(object, 0, 0));
+
+ if (use_pcode->argCount < 3)
+ return 1;
+
+ CError_ASSERT(543, use_pcode->args[1].kind == PCOp_REGISTER);
+
+ if (candidate_pcode->block == use_pcode->block && precedes(candidate_pcode, use_pcode)) {
+ for (scan = candidate_pcode->nextPCode; scan && scan != use_pcode; scan = scan->nextPCode) {
+ for (op = scan->args, i = scan->argCount; i--; op++) {
+ if (op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ (op->data.reg.effect & EffectWrite) &&
+ op->data.reg.reg == reg)
+ return 1;
+ }
+ }
+ } else {
+ if (!bitvectorgetbit(candidateID, propinfo[use_pcode->block->blockIndex].vec8)) {
+ if (bitvectorgetbit(candidate_pcode->defID, usedefinfo[use_pcode->block->blockIndex].defvec8)) {
+ for (scan = use_pcode->block->firstPCode; scan && scan != use_pcode; scan = scan->nextPCode) {
+ for (op = scan->args, i = scan->argCount; i--; op++) {
+ if (op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ (op->data.reg.effect & EffectWrite) &&
+ op->data.reg.reg == reg)
+ return 1;
+ }
+ }
+ } else {
+ return 1;
+ }
+ }
+
+ for (scan = use_pcode->block->firstPCode; scan; scan = scan->nextPCode) {
+ if (scan == use_pcode)
+ break;
+ for (op = scan->args, i = scan->argCount; i--; op++) {
+ if (op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ (op->data.reg.effect & EffectWrite) &&
+ op->data.reg.reg == reg)
+ return 1;
+ }
+ }
+ }
+
+ CError_ASSERT(598, object != NULL);
+
+ if (use_pcode->op == PC_ADDI || use_pcode->op == PC_ADD || use_pcode->op == PC_ADDIS) {
+ if (use_pcode->args[0].data.reg.reg < n_real_registers[RegClass_GPR] && !is_safe_const(object))
+ add_alias_member(worst_case, make_alias(object, 0, 0));
+ }
+
+ if (use_pcode->flags & (fIsRead | fIsWrite))
+ size = nbytes_loaded_or_stored_by(use_pcode);
+
+ if (use_pcode->args[2].kind == PCOp_REGISTER) {
+ if (use_pcode->args[1].data.reg.reg == 0) {
+ if (use_pcode->args[2].data.reg.reg == reg)
+ alias = make_alias(object, offset, size);
+ } else {
+ if (use_pcode->args[1].data.reg.reg == reg)
+ reg2 = use_pcode->args[2].data.reg.reg;
+ else if (use_pcode->args[2].data.reg.reg == reg)
+ reg2 = use_pcode->args[1].data.reg.reg;
+ else
+ return 1;
+
+ for (scan = use_pcode->prevPCode; scan; scan = scan->prevPCode) {
+ if (scan->op == PC_LI && scan->args[0].data.reg.reg == reg2)
+ break;
+
+ for (i = 0; i < scan->argCount; i++) {
+ if (scan->args[i].kind == PCOp_REGISTER &&
+ scan->args[i].arg == RegClass_GPR &&
+ scan->args[i].data.reg.reg == reg2 &&
+ (scan->args[i].data.reg.effect & EffectWrite)) {
+ scan = NULL;
+ break;
+ }
+ }
+
+ if (!scan)
+ break;
+ }
+
+ if (scan) {
+ offset += scan->args[1].data.mem.offset;
+ alias = make_alias(object, offset, size);
+ } else {
+ alias = make_alias(object, 0, 0);
+ }
+ }
+ } else {
+ if (use_pcode->args[1].kind != PCOp_REGISTER ||
+ use_pcode->args[1].arg != RegClass_GPR ||
+ use_pcode->args[1].data.reg.reg != reg)
+ return 1;
+
+ if (use_pcode->args[1].data.reg.effect & EffectWrite) {
+ alias = make_alias(object, 0, 0);
+ } else if (use_pcode->args[2].kind == PCOp_IMMEDIATE) {
+ if (use_pcode->op == PC_ADDIS) {
+ offset += use_pcode->args[2].data.imm.value << 16;
+ alias = make_alias(object, offset, 1);
+ } else {
+ offset += use_pcode->args[2].data.imm.value;
+ alias = make_alias(object, offset, size);
+ }
+ } else {
+ return 1;
+ }
+ }
+
+ if (flag24)
+ alias = make_alias(object, 0, 0);
+
+ if (!alias)
+ return 1;
+
+ if (!use_pcode->alias) {
+ if (
+ use_pcode->op == PC_ADDI ||
+ use_pcode->op == PC_ADD ||
+ use_pcode->op == PC_ADDIS ||
+ ((candidate_pcode->flags & (fIsRead | fIsWrite)) && (candidate_pcode->flags & fUpdatesPtr))
+ )
+ recursive_propagation = 1;
+ }
+
+ if (use_pcode->alias) {
+ if (use_pcode->alias == worst_case) {
+ add_alias_member(worst_case, make_alias(object, 0, 0));
+ } else if (use_pcode->alias == alias) {
+ return 1;
+ } else if (use_pcode->alias->type == AliasType0 || use_pcode->alias->type == AliasType1) {
+ if (object == use_pcode->alias->object) {
+ use_pcode->alias = make_alias(object, 0, 0);
+ } else {
+ aliasSet = make_alias_set();
+ if (
+ use_pcode->op == PC_ADDI ||
+ use_pcode->op == PC_ADD ||
+ use_pcode->op == PC_ADDIS ||
+ ((use_pcode->flags & (fIsRead | fIsWrite)) && (use_pcode->flags & fUpdatesPtr))
+ ) {
+ if (alias->type == AliasType2)
+ add_alias_member(worst_case, alias);
+ else
+ add_alias_member(worst_case, make_alias(use_pcode->alias->object, 0, 0));
+ }
+ add_alias_member(aliasSet, use_pcode->alias);
+ add_alias_member(aliasSet, alias);
+ use_pcode->alias = aliasSet;
+ }
+ } else {
+ add_alias_member(use_pcode->alias, alias);
+ }
+ } else {
+ use_pcode->alias = alias;
+ }
+
+ propagated_instructions = 1;
+ return 1;
+}
+
+static void finishpropagatealiases(int id) {
+ propagated_instructions = 1;
+}
+
+static Propagation alias_prop = {
+ &is_address_load,
+ &addresspropagatestouse,
+ &finishpropagatealiases,
+ "ALIAS",
+ "ALIASES",
+ "A%" PRId32,
+ 1
+};
+
+static void propagatealiasinfo(Object *proc) {
+ propagateinstructions(proc, &alias_prop, (copts.optimizationlevel >= 4) ? 4 : 1, 1);
+}
+
+void gather_alias_info(void) {
+ UInt32 *myvec; // r31
+ Alias *alias; // r22
+ AliasMember *member;
+ AliasMember *member2;
+ PCodeBlock *block; // r21
+ PCode *pcode; // r20
+ PCodeArg *op; // r19
+ RegUseOrDef *list; // r18
+ int i; // r17
+ Alias *alias_choice; // r16
+ int aliases_idx; // r15 (helper in r23)
+ PCode *defpcode; // r14
+ Alias *alias_array[3];
+ UseOrDef *def;
+ int defID;
+
+ if (coloring) {
+ propagatealiasinfo(gFunction);
+ myvec = oalloc(4 * ((number_of_Defs + 31) >> 5));
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ bitvectorcopy(myvec, usedefinfo[block->blockIndex].defvec8, number_of_Defs);
+
+ for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
+ if (pcode->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000)) {
+ if (!pcode->alias) {
+ pcode->alias = worst_case;
+ } else {
+ if ((pcode->alias->type == AliasType0 || pcode->alias->type == AliasType1) &&
+ pcode->alias->size == nbytes_loaded_or_stored_by(pcode)) {
+ pcode->flags &= ~fIsPtrOp;
+ } else {
+ pcode->flags |= fIsPtrOp;
+ }
+
+ if (pcode->alias != worst_case) {
+ aliases_idx = 0;
+ alias_choice = NULL;
+ op = pcode->args;
+ for (i = 0; i < pcode->argCount; i++, op++) {
+ if (
+ (!(pcode->flags & (fIsWrite | fPCodeFlag40000)) || op != pcode->args) &&
+ op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ (op->data.reg.effect & EffectRead)
+ ) {
+ alias_array[aliases_idx] = NULL;
+ if (aliases_idx >= 2) {
+ alias_choice = worst_case;
+ break;
+ }
+ alias_array[aliases_idx] = pcode->alias;
+
+ for (list = reg_Defs[RegClass_GPR][op->data.reg.reg]; list; list = list->next) {
+ if (bitvectorgetbit(list->id, myvec)) {
+ defpcode = Defs[list->id].pcode;
+ if (!defpcode->alias || !is_address_load(defpcode) || defpcode->alias == worst_case) {
+ alias_array[aliases_idx] = worst_case;
+ break;
+ }
+ }
+ }
+
+ aliases_idx++;
+ }
+ }
+
+ if (!alias_choice) {
+ if (aliases_idx > 0) {
+ alias_choice = alias_array[0];
+ if (aliases_idx == 2) {
+ if (alias_array[0] != worst_case) {
+ if (alias_array[1] != worst_case)
+ alias_choice = worst_case;
+ } else if (alias_array[1] != worst_case) {
+ alias_choice = alias_array[1];
+ }
+ }
+ }
+
+ if (alias_choice == worst_case) {
+ pcode->flags |= fIsPtrOp;
+ if (pcode->alias->type == AliasType2)
+ add_alias_member(worst_case, pcode->alias);
+ else
+ add_alias_member(worst_case, make_alias(pcode->alias->object, 0, 0));
+ }
+
+ if (alias_choice)
+ pcode->alias = alias_choice;
+ }
+ }
+ }
+ } else {
+ if ((pcode->flags & fIsCall) && !pcode->alias)
+ pcode->alias = worst_case;
+ }
+
+ for (def = &Defs[defID = pcode->defID]; defID < number_of_Defs && def->pcode == pcode; defID++, def++) {
+ if (def->v.kind == PCOp_REGISTER && def->v.arg == RegClass_GPR) {
+ for (list = reg_Defs[RegClass_GPR][def->v.u.reg]; list; list = list->next)
+ bitvectorclearbit(list->id, myvec);
+ }
+ bitvectorsetbit(defID, myvec);
+ }
+ }
+ }
+
+ freeoheap();
+ } else {
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
+ if ((pcode->flags & (fIsRead | fIsWrite | fIsCall | fPCodeFlag20000 | fPCodeFlag40000)) && !pcode->alias)
+ pcode->alias = worst_case;
+ }
+ }
+ }
+
+ if (n_gathered_aliases != n_aliases) {
+ for (alias = aliases; alias; alias = alias->next) {
+ if (alias->type == AliasType2) {
+ alias->vec24 = lalloc(4 * ((n_aliases + 31) >> 5));
+ bitvectorinitialize(alias->vec24, n_aliases, 0);
+ for (member = alias->parents; member; member = member->nextParent) {
+ bitvectorsetbit(member->child->index, alias->vec24);
+ for (member2 = member->child->parents; member2; member2 = member2->nextParent)
+ bitvectorsetbit(member2->child->index, alias->vec24);
+ }
+ }
+ }
+ n_gathered_aliases = n_aliases;
+ }
+}
+
+static Boolean may_alias_alias(Alias *a, Alias *b) {
+ switch ((a->type * 3) + b->type) {
+ case (AliasType0 * 3) + AliasType0:
+ return a == b;
+ case (AliasType0 * 3) + AliasType1:
+ case (AliasType1 * 3) + AliasType0:
+ return a->object == b->object;
+ case (AliasType1 * 3) + AliasType1:
+ return (a->object == b->object) && aliases_overlap(a, b);
+ case (AliasType0 * 3) + AliasType2:
+ case (AliasType1 * 3) + AliasType2:
+ return bitvectorgetbit(a->index, b->vec24) != 0;
+ case (AliasType2 * 3) + AliasType0:
+ case (AliasType2 * 3) + AliasType1:
+ return bitvectorgetbit(b->index, a->vec24) != 0;
+ case (AliasType2 * 3) + AliasType2:
+ return (a == b) || !bitvectorintersectionisempty(a->vec24, b->vec24, n_aliases);
+ default:
+ CError_FATAL(1054);
+ return 1;
+ }
+}
+
+Boolean may_alias(PCode *a, PCode *b) {
+ return may_alias_alias(a->alias, b->alias);
+}
+
+Boolean uniquely_aliases(PCode *a, PCode *b) {
+ if (may_alias_alias(a->alias, b->alias)) {
+ if (
+ a->alias->type != AliasType2 &&
+ b->alias->type != AliasType2 &&
+ a->alias &&
+ b->alias &&
+ a->alias->size == nbytes_loaded_or_stored_by(a) &&
+ b->alias->size == nbytes_loaded_or_stored_by(b)
+ )
+ return 1;
+ }
+
+ return 0;
+}
+
+Boolean may_alias_worst_case(PCode *pcode) {
+ return may_alias_alias(pcode->alias, worst_case);
+}
+
+Boolean may_alias_object(PCode *pcode, Object *object) {
+ return may_alias_alias(pcode->alias, make_alias(object, 0, 0));
+}
+
+void initialize_alias_values(void) {
+ Alias *alias;
+
+ for (alias = aliases; alias; alias = alias->next) {
+ alias->valuenumber = nextvaluenumber++;
+ alias->valuepcode = NULL;
+ }
+}
+
+void update_alias_value(Alias *alias, PCode *pcode) {
+ AliasMember *member;
+ AliasMember *member2;
+ AliasMember *member3;
+
+ switch (alias->type) {
+ case AliasType0:
+ killmemory(alias, pcode);
+ for (member = alias->children; member; member = member->nextChild) {
+ CError_ASSERT(1152, member->parent->type == AliasType2);
+ killmemory(member->parent, NULL);
+ }
+ for (member = alias->parents; member; member = member->nextParent) {
+ CError_ASSERT(1157, member->child->type == AliasType1);
+ killmemory(member->child, NULL);
+ for (member2 = member->child->children; member2; member2 = member2->nextChild) {
+ if (member2->parent != alias) {
+ CError_ASSERT(1163, member2->parent->type == AliasType2);
+ killmemory(member2->parent, NULL);
+ }
+ }
+ }
+ break;
+
+ case AliasType1:
+ killmemory(alias, pcode);
+ for (member = alias->children; member; member = member->nextChild) {
+ killmemory(member->parent, NULL);
+ if (member->parent->type == AliasType0) {
+ for (member2 = member->parent->parents; member2; member2 = member2->nextParent) {
+ if (member2->child != alias && aliases_overlap(alias, member2->child)) {
+ killmemory(member2->child, NULL);
+ }
+ }
+ }
+ }
+ break;
+
+ case AliasType2:
+ killmemory(alias, NULL);
+ for (member = alias->parents; member; member = member->nextParent) {
+ killmemory(member->child, NULL);
+ for (member2 = member->child->children; member2; member2 = member2->nextChild) {
+ if (member2->parent != alias)
+ killmemory(member2->parent, NULL);
+ }
+ for (member3 = member->child->parents; member3; member3 = member3->nextParent) {
+ killmemory(member3->child, NULL);
+ for (member2 = member3->child->children; member2; member2 = member2->nextChild) {
+ if (member2->parent != member->child)
+ killmemory(member2->parent, NULL);
+ }
+ }
+ }
+ break;
+ }
+}
+
+void update_all_alias_values(void) {
+ Alias *alias;
+
+ for (alias = aliases; alias; alias = alias->next)
+ killmemory(alias, NULL);
+}
+
diff --git a/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/CodeMotion.c b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/CodeMotion.c
new file mode 100644
index 0000000..8ce2962
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/CodeMotion.c
@@ -0,0 +1,906 @@
+#include "compiler/CodeMotion.h"
+#include "compiler/Alias.h"
+#include "compiler/BitVectors.h"
+#include "compiler/LoopDetection.h"
+#include "compiler/LoopOptimization.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/PCode.h"
+#include "compiler/UseDefChains.h"
+#include "compiler/RegisterInfo.h"
+
+int movedloopinvariantcode;
+int unswitchedinvariantcode;
+
+static int isloopinvariant(PCode *pcode, Loop *loop, UInt32 *vec, int flag1, int flag2) {
+ PCodeArg *op;
+ RegUseOrDef *list;
+ int i;
+
+ if (pcode->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000)) {
+ if (pcode->alias) {
+ if (pcode->alias->type == AliasType2 || (pcode->flags & (fIsVolatile | fSideEffects)))
+ return 0;
+
+ if (pcode->flags & fIsRead) {
+ for (list = findobjectusedef(pcode->alias->object)->defs; list; list = list->next) {
+ if (
+ may_alias(pcode, Defs[list->id].pcode) &&
+ bitvectorgetbit(list->id, vec) &&
+ bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks)
+ )
+ return 0;
+ }
+ }
+
+ if (pcode->flags & fIsWrite) {
+ for (list = findobjectusedef(pcode->alias->object)->uses; list; list = list->next) {
+ if (
+ may_alias(pcode, Uses[list->id].pcode) &&
+ bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)
+ )
+ return 0;
+ }
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ if ((pcode->flags & fIsWrite) && !bitvectorgetbit(pcode->block->blockIndex, loop->vec2C))
+ return 0;
+
+ op = pcode->args;
+ i = pcode->argCount;
+ while (i--) {
+ switch (op->kind) {
+ case PCOp_MEMORY:
+ if ((pcode->flags & fIsRead) && ((pcode->flags == 0) & 0x40)) {
+ for (list = findobjectusedef(op->data.mem.obj)->defs; list; list = list->next) {
+ if (
+ may_alias(pcode, Defs[list->id].pcode) &&
+ bitvectorgetbit(list->id, vec) &&
+ bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks)
+ )
+ return 0;
+ }
+ }
+ if (pcode->flags & fIsWrite) {
+ for (list = findobjectusedef(op->data.mem.obj)->uses; list; list = list->next) {
+ if (
+ may_alias(pcode, Uses[list->id].pcode) &&
+ bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)
+ )
+ return 0;
+ }
+ }
+ break;
+ case PCOp_REGISTER:
+ if (op->data.reg.effect & (EffectRead | EffectWrite)) {
+ if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR) {
+ if (op->data.reg.reg == _FP_)
+ break;
+ if (op->data.reg.reg == _CALLER_SP_)
+ break;
+ if (op->data.reg.reg == 2)
+ break;
+ }
+ if (op->data.reg.reg < n_real_registers[op->arg]) {
+ if (op->arg == RegClass_CRFIELD) {
+ if (!flag2 || (op->data.reg.effect & EffectRead))
+ return 0;
+ } else if (op->arg == RegClass_SPR) {
+ if (!flag1)
+ return 0;
+ } else {
+ return 0;
+ }
+ } else if (op->data.reg.effect & EffectRead) {
+ if (flag1 && op->kind == PCOp_REGISTER && op->arg == RegClass_SPR)
+ break;
+ if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR) {
+ if (op->data.reg.reg == _FP_)
+ break;
+ if (op->data.reg.reg == _CALLER_SP_)
+ break;
+ if (op->data.reg.reg == 2)
+ break;
+ }
+
+ for (list = reg_Defs[op->arg][op->data.reg.reg]; list; list = list->next) {
+ if (
+ bitvectorgetbit(list->id, vec) &&
+ bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks)
+ )
+ return 0;
+ }
+ }
+ }
+ break;
+ }
+ op++;
+ }
+
+ return 1;
+}
+
+static int isuniquedefinition(PCode *pcode, Loop *loop) {
+ RegUseOrDef *list;
+ int defID;
+ UseOrDef *def;
+
+ defID = pcode->defID;
+ def = &Defs[defID];
+ if (defID >= number_of_Defs)
+ return 0;
+ if (def->pcode != pcode)
+ return 0;
+ if ((defID + 1) < number_of_Defs && def[1].pcode == pcode)
+ return 0;
+
+ if (def->v.kind == PCOp_REGISTER) {
+ for (list = reg_Defs[def->v.arg][def->v.u.reg]; list; list = list->next) {
+ if (
+ bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks) &&
+ list->id != defID
+ )
+ return 0;
+ }
+ } else if (def->v.kind == PCOp_MEMORY) {
+ for (list = findobjectusedef(def->v.u.object)->defs; list; list = list->next) {
+ if (
+ may_alias(pcode, Defs[list->id].pcode) &&
+ bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks) &&
+ list->id != defID
+ )
+ return 0;
+ }
+ } else {
+ CError_FATAL(292);
+ }
+
+ return 1;
+}
+
+static int uniquelyreachesuse(int defID, int useID) {
+ UseOrDef *def;
+ UseOrDef *use;
+ RegUseOrDef *list;
+ PCode *pcode;
+
+ def = &Defs[defID];
+ use = &Uses[useID];
+ if (def->v.kind == PCOp_REGISTER) {
+ for (list = reg_Defs[def->v.arg][def->v.u.reg]; list; list = list->next) {
+ if (
+ list->id != defID &&
+ bitvectorgetbit(list->id, usedefinfo[use->pcode->block->blockIndex].defvec8)
+ )
+ break;
+ }
+ } else if (def->v.kind == PCOp_MEMORY) {
+ for (list = findobjectusedef(def->v.u.object)->defs; list; list = list->next) {
+ if (
+ may_alias(def->pcode, Defs[list->id].pcode) &&
+ list->id != defID &&
+ bitvectorgetbit(list->id, usedefinfo[use->pcode->block->blockIndex].defvec8)
+ )
+ break;
+ }
+ }
+
+ if (!list)
+ return 1;
+
+ if (def->pcode->block == use->pcode->block) {
+ for (pcode = use->pcode->prevPCode; pcode; pcode = pcode->prevPCode) {
+ if (pcode == def->pcode)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int uniquelyreachesalluses(int defID, Loop *loop) {
+ UseOrDef *def;
+ RegUseOrDef *list;
+
+ def = &Defs[defID];
+
+ if (def->v.kind == PCOp_REGISTER) {
+ for (list = reg_Uses[def->v.arg][def->v.u.reg]; list; list = list->next) {
+ if (
+ bitvectorgetbit(list->id, usedefinfo[loop->preheader->blockIndex].usevec1C) ||
+ (bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks) && !uniquelyreachesuse(defID, list->id))
+ )
+ return 0;
+ }
+ } else if (def->v.kind == PCOp_MEMORY) {
+ for (list = findobjectusedef(def->v.u.object)->uses; list; list = list->next) {
+ if (may_alias(def->pcode, Uses[list->id].pcode)) {
+ if (
+ bitvectorgetbit(list->id, usedefinfo[loop->preheader->blockIndex].usevec1C) ||
+ (bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks) && !uniquelyreachesuse(defID, list->id))
+ )
+ return 0;
+ }
+ }
+ } else {
+ CError_FATAL(382);
+ }
+
+ return 1;
+}
+
+static int isliveonexit(TinyValue *v, Loop *loop) {
+ RegUseOrDef *list;
+ UInt32 *vec;
+
+ vec = usedefinfo[loop->preheader->blockIndex].usevec1C;
+
+ if (v->kind == PCOp_REGISTER) {
+ for (list = reg_Uses[v->arg][v->u.reg]; list; list = list->next) {
+ if (
+ bitvectorgetbit(list->id, vec) &&
+ !bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)
+ )
+ return 1;
+ }
+ } else if (v->kind == PCOp_MEMORY) {
+ for (list = findobjectusedef(v->u.object)->uses; list; list = list->next) {
+ if (
+ bitvectorgetbit(list->id, vec) &&
+ !bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)
+ )
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int dominatesallexits(PCode *pcode, Loop *loop) {
+ return bitvectorgetbit(pcode->block->blockIndex, loop->vec28) != 0;
+}
+
+static int maymove(PCode *pcode, Loop *loop) {
+ short reg;
+
+ if (!isuniquedefinition(pcode, loop))
+ return 0;
+ if (!uniquelyreachesalluses(pcode->defID, loop))
+ return 0;
+ if (!dominatesallexits(pcode, loop) && isliveonexit(&Defs[pcode->defID].v, loop))
+ return 0;
+
+ if (loop->bodySize > 25) {
+ switch (pcode->op) {
+ case PC_LI:
+ if (
+ pcode->nextPCode &&
+ pcode->nextPCode->op == PC_LVX &&
+ (pcode->nextPCode->flags & fIsConst)
+ ) {
+ reg = pcode->args[0].data.reg.reg;
+ if (pcode->nextPCode->args[1].data.reg.reg == reg ||
+ pcode->nextPCode->args[2].data.reg.reg == reg)
+ return 1;
+ }
+ case PC_VSPLTISB:
+ case PC_VSPLTISH:
+ case PC_VSPLTISW:
+ return 0;
+ default:
+ if (!bitvectorgetbit(pcode->block->blockIndex, loop->vec2C))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void moveinvariantcomputation(PCode *pcode, Loop *loop) {
+ ObjectUseDef *oud;
+ BlockList *blocklist;
+ RegUseOrDef *list;
+ UseOrDef *def;
+ int defID;
+
+ defID = pcode->defID;
+ def = &Defs[defID];
+ deletepcode(pcode);
+ insertpcodebefore(loop->preheader->lastPCode, pcode);
+ loop->bodySize--;
+ movedloopinvariantcode = 1;
+
+ if (def->v.kind == PCOp_REGISTER) {
+ for (blocklist = loop->blocks; blocklist; blocklist = blocklist->next) {
+ for (list = reg_Defs[def->v.arg][def->v.u.reg]; list; list = list->next)
+ bitvectorclearbit(list->id, usedefinfo[blocklist->block->blockIndex].defvec8);
+ bitvectorsetbit(defID, usedefinfo[blocklist->block->blockIndex].defvec8);
+ }
+ } else if (def->v.kind == PCOp_MEMORY) {
+ oud = findobjectusedef(def->v.u.object);
+ for (blocklist = loop->blocks; blocklist; blocklist = blocklist->next) {
+ for (list = oud->defs; list; list = list->next) {
+ if (uniquely_aliases(pcode, Defs[list->id].pcode))
+ bitvectorclearbit(list->id, usedefinfo[blocklist->block->blockIndex].defvec8);
+ }
+ bitvectorsetbit(defID, usedefinfo[blocklist->block->blockIndex].defvec8);
+ }
+ } else {
+ CError_FATAL(545);
+ }
+}
+
+static int srawi_addze_maymove(PCode *pcode, Loop *loop) {
+ RegUseOrDef *list;
+ UseOrDef *def;
+ int defID;
+ int nextDefID;
+
+ defID = pcode->defID;
+ nextDefID = pcode->nextPCode->defID;
+
+ def = &Defs[defID];
+ if (defID >= number_of_Defs)
+ return 0;
+ if (def->pcode != pcode)
+ return 0;
+ if ((defID + 1) < number_of_Defs && def[1].pcode == pcode)
+ return 0;
+
+ if (def->v.kind == PCOp_REGISTER && def->v.arg == RegClass_GPR) {
+ for (list = reg_Defs[RegClass_GPR][def->v.u.reg]; list; list = list->next) {
+ if (
+ bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks) &&
+ list->id != defID &&
+ list->id != nextDefID
+ )
+ return 0;
+ }
+ } else {
+ CError_FATAL(582);
+ }
+
+ if (!uniquelyreachesalluses(pcode->defID, loop))
+ return 0;
+ if (!dominatesallexits(pcode, loop) && isliveonexit(&Defs[pcode->defID].v, loop))
+ return 0;
+ if (!dominatesallexits(pcode->nextPCode, loop) && isliveonexit(&Defs[pcode->nextPCode->defID].v, loop))
+ return 0;
+
+ return 1;
+}
+
+static int srawi_addze_isloopinvariant(PCode *pcode, Loop *loop, UInt32 *vec) {
+ static PCode *oldNextInstr;
+ PCode *nextInstr;
+
+ nextInstr = pcode->nextPCode;
+ if (
+ pcode->op == PC_ADDZE &&
+ oldNextInstr == pcode
+ ) {
+ oldNextInstr = NULL;
+ return 1;
+ } else if (
+ pcode->op == PC_SRAWI &&
+ nextInstr &&
+ nextInstr->op == PC_ADDZE &&
+ pcode->args[0].data.reg.reg == nextInstr->args[0].data.reg.reg &&
+ nextInstr->args[0].data.reg.reg == nextInstr->args[1].data.reg.reg &&
+ !(pcode->flags & (fIsCall | fIsPtrOp | fIsVolatile | fSideEffects)) &&
+ !(nextInstr->flags & (fIsCall | fIsPtrOp | fIsVolatile | fSideEffects)) &&
+ isloopinvariant(pcode, loop, vec, 1, 0) &&
+ srawi_addze_maymove(pcode, loop)
+ ) {
+ oldNextInstr = nextInstr;
+ return 1;
+ } else {
+ oldNextInstr = NULL;
+ return 0;
+ }
+}
+
+static void removeblockfromloop(Loop *loop, PCodeBlock *block) {
+ BlockList *list;
+ BlockList **ptr;
+
+ bitvectorclearbit(block->blockIndex, loop->memberblocks);
+ bitvectorclearbit(block->blockIndex, loop->vec24);
+ bitvectorclearbit(block->blockIndex, loop->vec28);
+ bitvectorclearbit(block->blockIndex, loop->vec2C);
+ loop->bodySize -= block->pcodeCount;
+
+ ptr = &loop->blocks;
+ while ((list = *ptr)) {
+ if (list->block == block)
+ *ptr = list->next;
+ else
+ ptr = &list->next;
+ }
+}
+
+static void changesuccessor(PCodeBlock *block, PCodeBlock *from, PCodeBlock *to) {
+ PCLink **ptr;
+ PCLink *link;
+
+ for (link = block->successors; link; link = link->nextLink) {
+ if (link->block == from)
+ link->block = to;
+ }
+
+ ptr = &from->predecessors;
+ while ((link = *ptr)) {
+ if (link->block == block) {
+ *ptr = link->nextLink;
+ link->nextLink = to->predecessors;
+ to->predecessors = link;
+ } else {
+ ptr = &link->nextLink;
+ }
+ }
+}
+
+static void movesuccessor(PCodeBlock *to, PCodeBlock *from, PCodeBlock *block) {
+ PCLink **ptr;
+ PCLink *link;
+
+ for (link = block->predecessors; link; link = link->nextLink) {
+ if (link->block == from)
+ link->block = to;
+ }
+
+ ptr = &from->successors;
+ while ((link = *ptr)) {
+ if (link->block == block) {
+ *ptr = link->nextLink;
+ link->nextLink = to->successors;
+ to->successors = link;
+ } else {
+ ptr = &link->nextLink;
+ }
+ }
+}
+
+static void movecmptopreheader(Loop *loop, PCodeBlock *block, PCode *pc1, PCode *pc2, PCodeArg *op) {
+ PCodeBlock *preheader;
+ PCode *pc3;
+
+ preheader = loop->preheader;
+ if (PCODE_FLAG_SET_F(pc1) & fRecordBit) {
+ moveinvariantcomputation(pc1, loop);
+ } else {
+ deletepcode(pc1);
+ insertpcodebefore(loop->preheader->lastPCode, pc1);
+ loop->bodySize--;
+ movedloopinvariantcode = 1;
+ }
+ loop->preheader = NULL;
+
+ insertpreheaderblock(loop);
+
+ pc3 = preheader->lastPCode;
+ CError_ASSERT(775, pc3->op == PC_B);
+ deletepcode(pc3);
+ deletepcode(pc2);
+ appendpcode(preheader, pc2);
+ movesuccessor(preheader, block, op->data.label.label->block);
+}
+
+static PCodeBlock *appendheadercopy(Loop *loop, PCodeBlock *block1, PCodeBlock *block2, PCodeBlock *block3) {
+ PCodeBlock *newblock1;
+ PCodeBlock *newblock2;
+ PCLink *link;
+ PCode *scan;
+
+ newblock1 = lalloc(sizeof(PCodeBlock));
+ newblock2 = lalloc(sizeof(PCodeBlock));
+
+ newblock1->labels = NULL;
+ newblock1->predecessors = newblock1->successors = NULL;
+ newblock1->firstPCode = newblock1->lastPCode = NULL;
+ newblock1->pcodeCount = 0;
+ newblock1->loopWeight = loop->body->loopWeight;
+ newblock1->flags = 0;
+ newblock1->blockIndex = pcblockcount++;
+
+ newblock2->labels = NULL;
+ newblock2->predecessors = newblock2->successors = NULL;
+ newblock2->firstPCode = newblock2->lastPCode = NULL;
+ newblock2->pcodeCount = 0;
+ newblock2->loopWeight = loop->body->loopWeight;
+ newblock2->flags = 0;
+ newblock2->blockIndex = pcblockcount++;
+
+ newblock1->nextBlock = newblock2;
+ newblock2->prevBlock = newblock1;
+ newblock1->prevBlock = block1;
+ newblock2->nextBlock = block1->nextBlock;
+ block1->nextBlock = newblock1;
+ newblock2->nextBlock->prevBlock = newblock2;
+
+ pclabel(newblock1, makepclabel());
+ pclabel(newblock2, makepclabel());
+
+ changesuccessor(block1, block1->successors->block, newblock1);
+
+ link = lalloc(sizeof(PCLink));
+ link->block = newblock2;
+ link->nextLink = newblock1->successors;
+ newblock1->successors = link;
+
+ link = lalloc(sizeof(PCLink));
+ link->block = newblock1;
+ link->nextLink = newblock2->predecessors;
+ newblock2->predecessors = link;
+
+ appendpcode(newblock2, makepcode(PC_B, block2->nextBlock->labels));
+ pcbranch(newblock2, block2->nextBlock->labels);
+ pccomputepredecessors1(newblock2);
+
+ for (scan = block2->firstPCode; scan; scan = scan->nextPCode)
+ appendpcode(newblock1, copypcode(scan));
+
+ pcbranch(newblock1, block3->labels);
+
+ link = lalloc(sizeof(PCLink));
+ link->block = newblock1;
+ link->nextLink = block3->predecessors;
+ block3->predecessors = link;
+
+ addblocktoloop(loop, newblock1);
+ if (bitvectorgetbit(block2->blockIndex, loop->vec28))
+ bitvectorsetbit(newblock1->blockIndex, loop->vec28);
+ if (bitvectorgetbit(block2->blockIndex, loop->vec2C))
+ bitvectorsetbit(newblock1->blockIndex, loop->vec2C);
+
+ for (loop = loop->parent; loop; loop = loop->parent) {
+ addblocktoloop(loop, newblock1);
+ if (bitvectorgetbit(block2->blockIndex, loop->vec28))
+ bitvectorsetbit(newblock1->blockIndex, loop->vec28);
+ if (bitvectorgetbit(block2->blockIndex, loop->vec2C))
+ bitvectorsetbit(newblock1->blockIndex, loop->vec2C);
+
+ addblocktoloop(loop, newblock2);
+ if (bitvectorgetbit(block2->blockIndex, loop->vec28))
+ bitvectorsetbit(newblock2->blockIndex, loop->vec28);
+ if (bitvectorgetbit(block2->blockIndex, loop->vec2C))
+ bitvectorsetbit(newblock2->blockIndex, loop->vec2C);
+ }
+
+ return newblock1;
+}
+
+static BlockList *findswitchpath(Loop *loop, PCodeBlock *block) {
+ BlockList *head;
+ BlockList *tail;
+ BlockList *node;
+ PCodeBlock *scan;
+
+ head = NULL;
+ tail = NULL;
+
+ for (scan = block; scan && scan != loop->body; scan = scan->successors->block) {
+ if (!bitvectorgetbit(scan->blockIndex, loop->memberblocks))
+ return NULL;
+ if (scan->successors && scan->successors->nextLink)
+ return NULL;
+
+ node = oalloc(sizeof(BlockList));
+ node->block = scan;
+ node->next = NULL;
+ if (head) {
+ tail->next = node;
+ tail = node;
+ } else {
+ head = node;
+ tail = node;
+ }
+ }
+
+ return head;
+}
+
+static void simpleunswitchloop(Loop *loop) {
+ PCode *pc29;
+ PCodeArg *op27;
+ UInt32 *myvec;
+ PCodeBlock *block26;
+ PCode *pc25; // r25
+ BlockList *path2_24;
+ PCodeArg *op23;
+ PCode *pc23; // r23
+ BlockList *scanlist; // r23
+ BlockList *bestpath1; // r23
+ BlockList *bestpath2; // r22
+ PCodeBlock *headercopy; // r22
+ Loop *newloop; // r21
+ PCodeBlock *preheader21;
+ BlockList *path20;
+ PCode *scan20;
+ PCode *lastpcode;
+ int i;
+ BlockList *pathiter1;
+ BlockList *pathiter2;
+
+ if (!(lastpcode = loop->body->lastPCode))
+ return;
+ if (lastpcode->op != PC_BT && lastpcode->op != PC_BF)
+ return;
+ if (lastpcode->args[2].kind != PCOp_LABEL)
+ return;
+ if (!bitvectorgetbit(lastpcode->args[2].data.label.label->block->blockIndex, loop->memberblocks))
+ return;
+ if (loop->x57)
+ return;
+ if (loop->x4D)
+ return;
+ if (bitvectorgetbit(loop->body->nextBlock->blockIndex, loop->memberblocks))
+ return;
+
+ for (block26 = pcbasicblocks; block26; block26 = block26->nextBlock) {
+ if (bitvectorgetbit(block26->blockIndex, loop->memberblocks))
+ break;
+ }
+
+ if (!block26)
+ return;
+
+ myvec = oalloc(4 * ((number_of_Defs + 31) >> 5));
+ bitvectorcopy(myvec, usedefinfo[block26->blockIndex].defvec8, number_of_Defs);
+ for (pc25 = loop->preheader->nextBlock->firstPCode; pc25; pc25 = pc25->nextPCode) {
+ if (!(PCODE_FLAG_SET_F(pc25) & (fIsCall | fIsPtrOp | fIsVolatile | fSideEffects | fRecordBit))) {
+ if (isloopinvariant(pc25, loop, myvec, 0, 1))
+ break;
+ }
+ }
+
+ if (!pc25 || pc25->argCount < 1)
+ return;
+
+ if (
+ pc25->argCount < 1 ||
+ pc25->args[0].kind != PCOp_REGISTER ||
+ pc25->args[0].arg != RegClass_CRFIELD
+ )
+ return;
+
+ pc29 = pc25->block->lastPCode;
+ if (
+ !pc29 ||
+ !(pc29->flags & fIsBranch) ||
+ pc29->args[0].kind != PCOp_REGISTER ||
+ pc29->args[0].arg != RegClass_CRFIELD
+ )
+ return;
+
+ if (pc29->args[0].data.reg.reg != pc25->args[0].data.reg.reg)
+ return;
+
+ op27 = NULL;
+ for (i = 0; i < pc29->argCount; i++) {
+ if (pc29->args[i].kind == PCOp_LABEL)
+ op27 = &pc29->args[i];
+ }
+
+ if (op27) {
+ preheader21 = loop->preheader;
+
+ path20 = findswitchpath(loop, block26->nextBlock);
+ if (!path20)
+ return;
+
+ path2_24 = findswitchpath(loop, op27->data.label.label->block);
+ if (!path2_24)
+ return;
+
+ bestpath1 = NULL;
+ bestpath2 = NULL;
+ for (pathiter1 = path20; pathiter1; pathiter1 = pathiter1->next) {
+ for (pathiter2 = path2_24; pathiter2; pathiter2 = pathiter2->next) {
+ if (pathiter1->block == pathiter2->block) {
+ bestpath1 = pathiter1;
+ break;
+ }
+ }
+ if (bestpath1)
+ break;
+ bestpath2 = pathiter1;
+ }
+
+ CError_ASSERT(1192, bestpath2->block);
+
+ if (bestpath2->block->lastPCode && bestpath2->block->lastPCode->op == PC_B)
+ deletepcode(bestpath2->block->lastPCode);
+
+ while (bestpath1) {
+ for (scan20 = bestpath1->block->firstPCode; scan20; scan20 = scan20->nextPCode) {
+ if (scan20->op != PC_B)
+ appendpcode(bestpath2->block, copypcode(scan20));
+ }
+ bestpath1 = bestpath1->next;
+ }
+
+ headercopy = appendheadercopy(loop, bestpath2->block, loop->body, block26);
+ movecmptopreheader(loop, block26, pc25, pc29, op27);
+
+ if (block26->pcodeCount) {
+ if (path2_24->block->firstPCode) {
+ pc23 = path2_24->block->firstPCode;
+ for (scan20 = block26->firstPCode; scan20; scan20 = scan20->nextPCode) {
+ if (scan20->op != PC_B)
+ insertpcodebefore(pc23, copypcode(scan20));
+ }
+ } else {
+ for (scan20 = block26->firstPCode; scan20; scan20 = scan20->nextPCode) {
+ if (scan20->op != PC_B)
+ appendpcode(path2_24->block, copypcode(scan20));
+ }
+ }
+ }
+
+ op23 = NULL;
+ for (i = 0; i < loop->body->lastPCode->argCount; i++) {
+ if (loop->body->lastPCode->args[i].kind == PCOp_LABEL)
+ op23 = &loop->body->lastPCode->args[i];
+ }
+
+ CError_ASSERT(1250, op23 != NULL);
+
+ changesuccessor(loop->body, op23->data.label.label->block, path2_24->block);
+ op23->data.label.label = path2_24->block->labels;
+
+ op23 = NULL;
+ for (i = 0; i < preheader21->lastPCode->argCount; i++) {
+ if (preheader21->lastPCode->args[i].kind == PCOp_LABEL)
+ op23 = &preheader21->lastPCode->args[i];
+ }
+
+ CError_ASSERT(1267, op23 != NULL);
+
+ changesuccessor(preheader21, op23->data.label.label->block, loop->body);
+ op23->data.label.label = loop->body->labels;
+
+ op23 = NULL;
+ for (i = 0; i < loop->preheader->lastPCode->argCount; i++) {
+ if (loop->preheader->lastPCode->args[i].kind == PCOp_LABEL)
+ op23 = &loop->preheader->lastPCode->args[i];
+ }
+
+ CError_ASSERT(1284, op23 != NULL);
+
+ changesuccessor(loop->preheader, op23->data.label.label->block, headercopy);
+ op23->data.label.label = headercopy->labels;
+
+ newloop = lalloc(sizeof(Loop));
+ newloop->parent = loop->parent;
+ newloop->children = NULL;
+ newloop->nextSibling = loop->nextSibling;
+ loop->nextSibling = newloop;
+ newloop->body = loop->body;
+ newloop->preheader = NULL;
+ newloop->blocks = NULL;
+ newloop->basicInductionVars = NULL;
+ newloop->footer = NULL;
+ newloop->pc18 = NULL;
+ newloop->loopWeight = loop->loopWeight;
+
+ bitvectorinitialize(newloop->memberblocks = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
+ bitvectorinitialize(newloop->vec24 = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
+ bitvectorinitialize(newloop->vec28 = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
+ bitvectorinitialize(newloop->vec2C = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
+
+ removeblockfromloop(loop, newloop->body);
+ addblocktoloop(newloop, newloop->body);
+
+ bitvectorsetbit(newloop->body->blockIndex, newloop->vec24);
+ bitvectorsetbit(newloop->body->blockIndex, newloop->vec2C);
+ bitvectorsetbit(newloop->body->blockIndex, newloop->vec28);
+
+ for (scanlist = path2_24; scanlist; scanlist = scanlist->next) {
+ removeblockfromloop(loop, scanlist->block);
+ addblocktoloop(newloop, scanlist->block);
+ bitvectorsetbit(scanlist->block->blockIndex, newloop->vec2C);
+ }
+
+ newloop->preheader = NULL;
+ insertpreheaderblock(newloop);
+ analyzeloop(newloop);
+
+ loop->body = headercopy;
+
+ for (scanlist = loop->blocks; scanlist; scanlist = scanlist->next)
+ bitvectorsetbit(scanlist->block->blockIndex, loop->vec2C);
+
+ bitvectorsetbit(headercopy->blockIndex, loop->vec24);
+ analyzeloop(loop);
+
+ unswitchedinvariantcode = 1;
+ }
+}
+
+static void simpleunswitchloops(Loop *loop) {
+ while (loop) {
+ if (loop->children)
+ simpleunswitchloops(loop->children);
+ else if (!loop->x4F)
+ simpleunswitchloop(loop);
+ loop = loop->nextSibling;
+ }
+}
+
+static void moveinvariantsfromloop(Loop *loop) {
+ RegUseOrDef *list;
+ BlockList *blocklist;
+ PCode *instr;
+ PCode *nextInstr;
+ UInt32 *myvec;
+ UseOrDef *def;
+ int defID;
+ int flag;
+ PCodeBlock *block;
+
+ myvec = oalloc(4 * ((number_of_Defs + 31) >> 5));
+ do {
+ flag = 0;
+ for (blocklist = loop->blocks; blocklist; blocklist = blocklist->next) {
+ block = blocklist->block;
+ bitvectorcopy(myvec, usedefinfo[block->blockIndex].defvec8, number_of_Defs);
+ for (instr = block->firstPCode; instr; instr = nextInstr) {
+ nextInstr = instr->nextPCode;
+ if (!(instr->flags & fIsBranch) && instr->argCount) {
+ if (
+ !(instr->flags & (fIsCall | fIsPtrOp | fIsVolatile | fSideEffects)) &&
+ isloopinvariant(instr, loop, myvec, 0, 0) &&
+ maymove(instr, loop)
+ ) {
+ moveinvariantcomputation(instr, loop);
+ flag = 1;
+ } else if (srawi_addze_isloopinvariant(instr, loop, myvec)) {
+ moveinvariantcomputation(instr, loop);
+ flag = 1;
+ }
+
+ for (def = &Defs[defID = instr->defID]; defID < number_of_Defs && def->pcode == instr; def++, defID++) {
+ if (def->v.kind == PCOp_REGISTER) {
+ for (list = reg_Defs[def->v.arg][def->v.u.reg]; list; list = list->next)
+ bitvectorclearbit(list->id, myvec);
+ } else if (def->v.kind == PCOp_MEMORY) {
+ if (def->v.arg == PCOpMemory0) {
+ for (list = findobjectusedef(def->v.u.object)->defs; list; list = list->next) {
+ if (uniquely_aliases(instr, Defs[list->id].pcode))
+ bitvectorclearbit(list->id, myvec);
+ }
+ }
+ } else {
+ CError_FATAL(1434);
+ }
+
+ bitvectorsetbit(defID, myvec);
+ }
+ }
+ }
+ }
+ } while (flag);
+}
+
+static void moveinvariantsfromloops(Loop *loop) {
+ while (loop) {
+ if (loop->children)
+ moveinvariantsfromloops(loop->children);
+ moveinvariantsfromloop(loop);
+ loop = loop->nextSibling;
+ }
+}
+
+void moveloopinvariantcode(void) {
+ unswitchedinvariantcode = 0;
+ movedloopinvariantcode = 0;
+ if (loopsinflowgraph) {
+ moveinvariantsfromloops(loopsinflowgraph);
+ simpleunswitchloops(loopsinflowgraph);
+ }
+ freeoheap();
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/ConstantPropagation.c b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/ConstantPropagation.c
new file mode 100644
index 0000000..2b40453
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/ConstantPropagation.c
@@ -0,0 +1,643 @@
+#include "compiler/ConstantPropagation.h"
+#include "compiler/Alias.h"
+#include "compiler/BitVectors.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/StackFrame.h"
+#include "compiler/UseDefChains.h"
+#include "compiler/objects.h"
+
+int propagatedconstants;
+static int changed;
+static PCode **defininginstruction;
+static PCode **vrdefininginstruction;
+
+static void computedefininginstructions(PCodeBlock *block) {
+ RegUseOrDef *list;
+ PCode *instr;
+ int i;
+
+ for (i = 0; i < used_virtual_registers[RegClass_GPR]; i++) {
+ instr = NULL;
+ for (list = reg_Defs[RegClass_GPR][i]; list; list = list->next) {
+ if (bitvectorgetbit(list->id, usedefinfo[block->blockIndex].defvec8)) {
+ if (instr == NULL) {
+ instr = Defs[list->id].pcode;
+ } else {
+ instr = NULL;
+ break;
+ }
+ }
+ }
+ defininginstruction[i] = instr;
+ }
+
+ for (i = 0; i < used_virtual_registers[RegClass_VR]; i++) {
+ instr = NULL;
+ for (list = reg_Defs[RegClass_VR][i]; list; list = list->next) {
+ if (bitvectorgetbit(list->id, usedefinfo[block->blockIndex].defvec8)) {
+ if (instr == NULL) {
+ instr = Defs[list->id].pcode;
+ } else {
+ instr = NULL;
+ break;
+ }
+ }
+ }
+ vrdefininginstruction[i] = instr;
+ }
+}
+
+static PCode *isstackoperand(PCodeArg *op, SInt16 *resultValue, SInt16 addend) {
+ PCode *instr;
+
+ if ((instr = defininginstruction[op->data.reg.reg]) && instr->op == PC_ADDI) {
+ if (
+ instr->args[2].kind == PCOp_MEMORY &&
+ (instr->args[1].data.reg.reg == _FP_ || instr->args[1].data.reg.reg == _CALLER_SP_) &&
+ instr->args[2].data.mem.obj->datatype == DLOCAL
+ )
+ {
+ if (can_add_displ_to_local(instr->args[2].data.mem.obj, addend)) {
+ *resultValue = instr->args[2].data.mem.offset;
+ return instr;
+ } else {
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+}
+
+static int isconstantoperand(PCodeArg *op, SInt16 *resultValue) {
+ PCode *instr;
+
+ if (
+ (instr = defininginstruction[op->data.reg.reg]) &&
+ instr->op == PC_LI &&
+ instr->args[1].kind == PCOp_IMMEDIATE
+ )
+ {
+ *resultValue = instr->args[1].data.imm.value;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int isuint16constantoperand(PCodeArg *op, SInt16 *resultValue) {
+ PCode *instr;
+
+ if (
+ (instr = defininginstruction[op->data.reg.reg]) &&
+ instr->op == PC_LI &&
+ instr->args[1].kind == PCOp_IMMEDIATE &&
+ FITS_IN_USHORT(instr->args[1].data.imm.value)
+ )
+ {
+ *resultValue = instr->args[1].data.imm.value;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int isvectorconstantoperand(PCodeArg *op, SInt16 *resultValue, Opcode *resultNewOp) {
+ PCode *instr;
+
+ if (
+ (instr = vrdefininginstruction[op->data.reg.reg]) &&
+ (instr->op == PC_VSPLTISB || instr->op == PC_VSPLTISH || instr->op == PC_VSPLTISW) &&
+ instr->args[1].kind == PCOp_IMMEDIATE
+ )
+ {
+ *resultValue = instr->args[1].data.imm.value;
+ *resultNewOp = instr->op;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int isunsignedloadoperand(PCodeArg *op) {
+ PCode *instr;
+
+ if ((instr = defininginstruction[op->data.reg.reg])) {
+ if (instr->flags & fIsRead) {
+ if (instr->op >= PC_LHZ && instr->op <= PC_LHZUX)
+ return 2;
+ if (instr->op >= PC_LBZ && instr->op <= PC_LBZUX)
+ return 1;
+ } else if (instr->op == PC_RLWINM) {
+ int var3 = instr->args[3].data.imm.value;
+ int var4 = instr->args[4].data.imm.value;
+ if (var4 == 31) {
+ if (var3 == 24)
+ return 1;
+ if (var3 == 16)
+ return 2;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int ismaskedoperand(PCodeArg *op, UInt32 *resultMask) {
+ PCode *instr;
+ UInt32 mask;
+
+ if ((instr = defininginstruction[op->data.reg.reg]) && instr->op == PC_RLWINM) {
+ if (instr->args[3].data.imm.value <= instr->args[4].data.imm.value) {
+ mask =
+ ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFU >> instr->args[3].data.imm.value)) &
+ ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFU >> (instr->args[4].data.imm.value + 1)));
+ } else {
+ mask =
+ ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFU >> instr->args[3].data.imm.value)) |
+ ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFU >> (instr->args[4].data.imm.value + 1)));
+ }
+ *resultMask = mask;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int issignedloadoperand(PCodeArg *op) {
+ PCode *instr;
+
+ if ((instr = defininginstruction[op->data.reg.reg])) {
+ if (instr->flags & fIsRead) {
+ if (instr->op >= PC_LHA && instr->op <= PC_LHAUX)
+ return 2;
+ } else if (instr->op == PC_EXTSB) {
+ return 1;
+ } else if (instr->op == PC_EXTSH) {
+ return 2;
+ }
+ }
+
+ return 0;
+}
+
+static void propagateconstantstoblock(PCodeBlock *block) {
+ PCode *instr;
+ SInt16 immAddend;
+ SInt16 value1;
+ SInt16 valueU16;
+ Opcode newOpcode;
+ SInt16 value2;
+ UInt32 mask;
+ UInt32 mask2;
+ int loadSize;
+ PCodeArg *op;
+ int i;
+
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ switch (instr->op) {
+ case PC_MR:
+ if (isconstantoperand(&instr->args[1], &value1)) {
+ change_opcode(instr, PC_LI);
+ instr->args[1].kind = PCOp_IMMEDIATE;
+ instr->args[1].data.imm.value = value1;
+ instr->args[1].data.imm.obj = NULL;
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ break;
+ case PC_VMR:
+ if (isvectorconstantoperand(&instr->args[1], &value1, &newOpcode)) {
+ change_opcode(instr, newOpcode);
+ instr->args[1].kind = PCOp_IMMEDIATE;
+ instr->args[1].data.imm.value = value1;
+ instr->args[1].data.imm.obj = NULL;
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ break;
+ case PC_RLWINM:
+ if (
+ !(PCODE_FLAG_SET_F(instr) & fRecordBit) &&
+ instr->args[2].data.imm.value == 0 &&
+ instr->args[4].data.imm.value == 31
+ )
+ {
+ if (isconstantoperand(&instr->args[1], &value1)) {
+ if (
+ (instr->args[3].data.imm.value == 16 && value1 == (value1 & 0x7FFF)) ||
+ (instr->args[3].data.imm.value == 24 && value1 == (value1 & 0xFF))
+ )
+ {
+ change_opcode(instr, PC_LI);
+ instr->args[1].kind = PCOp_IMMEDIATE;
+ instr->args[1].data.imm.value = value1;
+ instr->args[1].data.imm.obj = NULL;
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ break;
+ }
+ }
+
+ loadSize = isunsignedloadoperand(&instr->args[1]);
+ if (
+ (loadSize == 2 && instr->args[3].data.imm.value <= 16) ||
+ (loadSize == 1 && instr->args[3].data.imm.value <= 24)
+ )
+ {
+ change_opcode(instr, PC_MR);
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ break;
+ }
+
+ if (ismaskedoperand(&instr->args[1], &mask)) {
+ if (instr->args[3].data.imm.value <= instr->args[4].data.imm.value) {
+ mask2 =
+ ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFU >> instr->args[3].data.imm.value)) &
+ ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFU >> (instr->args[4].data.imm.value + 1)));
+ } else {
+ mask2 =
+ ((instr->args[3].data.imm.value > 31) ? 0 : (0xFFFFFFFFU >> instr->args[3].data.imm.value)) |
+ ~(((instr->args[4].data.imm.value + 1) > 31) ? 0 : (0xFFFFFFFFU >> (instr->args[4].data.imm.value + 1)));
+ }
+ if (mask == (mask & mask2)) {
+ change_opcode(instr, PC_MR);
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ }
+ }
+ break;
+
+ case PC_EXTSH:
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ break;
+
+ if (isconstantoperand(&instr->args[1], &value1)) {
+ change_opcode(instr, PC_LI);
+ instr->args[1].kind = PCOp_IMMEDIATE;
+ instr->args[1].data.imm.value = value1;
+ instr->args[1].data.imm.obj = NULL;
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ break;
+ }
+
+ loadSize = issignedloadoperand(&instr->args[1]);
+ if (loadSize == 1 || loadSize == 2) {
+ change_opcode(instr, PC_MR);
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ break;
+
+ case PC_EXTSB:
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ break;
+
+ if (
+ isconstantoperand(&instr->args[1], &value1) &&
+ value1 >= -128 &&
+ value1 <= 127
+ )
+ {
+ change_opcode(instr, PC_LI);
+ instr->args[1].kind = PCOp_IMMEDIATE;
+ instr->args[1].data.imm.value = value1;
+ instr->args[1].data.imm.obj = NULL;
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ break;
+ }
+
+ loadSize = issignedloadoperand(&instr->args[1]);
+ if (loadSize == 1) {
+ change_opcode(instr, PC_MR);
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ break;
+
+ case PC_ADDI:
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ break;
+
+ immAddend = instr->args[2].data.imm.value;
+ if (
+ isconstantoperand(&instr->args[1], &value1) &&
+ FITS_IN_SHORT(immAddend + value1)
+ )
+ {
+ change_opcode(instr, PC_LI);
+ instr->args[1].kind = PCOp_IMMEDIATE;
+ instr->args[1].data.imm.value = immAddend + value1;
+ instr->args[1].data.imm.obj = NULL;
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ break;
+
+ case PC_ADD:
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ break;
+
+ if (isconstantoperand(&instr->args[2], &value1)) {
+ if (value1 == 0) {
+ change_opcode(instr, PC_MR);
+ change_num_operands(instr, 2);
+ } else {
+ change_opcode(instr, PC_ADDI);
+ instr->args[2].kind = PCOp_IMMEDIATE;
+ instr->args[2].data.imm.value = value1;
+ instr->args[2].data.imm.obj = NULL;
+ }
+ propagatedconstants = 1;
+ changed = 1;
+ immAddend = value1;
+ }
+
+ if (isconstantoperand(&instr->args[1], &value1)) {
+ if (instr->op == PC_ADDI || instr->op == PC_MR) {
+ if (FITS_IN_SHORT(immAddend + value1)) {
+ change_opcode(instr, PC_LI);
+ instr->args[1].kind = PCOp_IMMEDIATE;
+ instr->args[1].data.imm.value = immAddend + value1;
+ instr->args[1].data.imm.obj = NULL;
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ } else {
+ instr->args[1] = instr->args[2];
+ if (value1 == 0) {
+ change_opcode(instr, PC_MR);
+ change_num_operands(instr, 2);
+ } else {
+ change_opcode(instr, PC_ADDI);
+ instr->args[2].kind = PCOp_IMMEDIATE;
+ instr->args[2].data.imm.value = value1;
+ instr->args[2].data.imm.obj = NULL;
+ }
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ }
+
+ if (changed) {
+ if (instr->op == PC_MR) {
+ PCode *stackInstr;
+ if ((stackInstr = isstackoperand(&instr->args[1], &value1, 0))) {
+ change_opcode(instr, PC_ADDI);
+ instr->flags = stackInstr->flags;
+ instr->args[1] = stackInstr->args[1];
+ instr->args[2] = stackInstr->args[2];
+ change_num_operands(instr, 3);
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ } else if (instr->op == PC_ADDI && instr->args[2].kind == PCOp_IMMEDIATE) {
+ PCode *stackInstr;
+ SInt16 addend = instr->args[2].data.imm.value;
+ if ((stackInstr = isstackoperand(&instr->args[1], &value1, addend))) {
+ change_opcode(instr, PC_ADDI);
+ instr->flags = stackInstr->flags;
+ instr->args[1] = stackInstr->args[1];
+ instr->args[2] = stackInstr->args[2];
+ instr->args[2].data.imm.value = value1 + addend;
+ if (instr->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000))
+ instr->alias = make_alias(instr->args[2].data.imm.obj, instr->args[2].data.imm.value, 1);
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ }
+ }
+ break;
+
+ case PC_OR:
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ break;
+
+ value1 = 0;
+ immAddend = 0;
+ if (isconstantoperand(&instr->args[2], &value1)) {
+ if (isuint16constantoperand(&instr->args[2], &valueU16)) {
+ if (valueU16 != 0) {
+ change_opcode(instr, PC_ORI);
+ instr->args[2].kind = PCOp_IMMEDIATE;
+ instr->args[2].data.imm.value = valueU16;
+ instr->args[2].data.imm.obj = NULL;
+ propagatedconstants = 1;
+ changed = 1;
+ } else {
+ change_opcode(instr, PC_MR);
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ value1 = valueU16;
+ } else if (value1 == 0) {
+ change_opcode(instr, PC_MR);
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ immAddend = value1;
+ }
+
+ if (isconstantoperand(&instr->args[1], &value1)) {
+ if (instr->op == PC_ORI || instr->op == PC_MR) {
+ change_opcode(instr, PC_LI);
+ instr->args[1].kind = PCOp_IMMEDIATE;
+ instr->args[1].data.imm.value = immAddend | value1;
+ instr->args[1].data.imm.obj = NULL;
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ } else if (isuint16constantoperand(&instr->args[1], &valueU16)) {
+ if (valueU16 != 0) {
+ change_opcode(instr, PC_ORI);
+ instr->args[1] = instr->args[2];
+ instr->args[2].kind = PCOp_IMMEDIATE;
+ instr->args[2].data.imm.value = valueU16;
+ instr->args[2].data.imm.obj = NULL;
+ propagatedconstants = 1;
+ changed = 1;
+ } else {
+ change_opcode(instr, PC_MR);
+ instr->args[1] = instr->args[2];
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ } else if (value1 == 0) {
+ change_opcode(instr, PC_MR);
+ instr->args[1] = instr->args[2];
+ change_num_operands(instr, 2);
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ }
+ break;
+
+ case PC_SUBF:
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ break;
+
+ if (isconstantoperand(&instr->args[1], &value1) && FITS_IN_SHORT(-value1)) {
+ if (isconstantoperand(&instr->args[2], &value2) && FITS_IN_SHORT(value2 - value1)) {
+ change_opcode(instr, PC_LI);
+ instr->args[1].kind = PCOp_IMMEDIATE;
+ instr->args[1].data.imm.value = value2 - value1;
+ instr->args[1].data.imm.obj = NULL;
+ change_num_operands(instr, 2);
+ } else if (value1 == 0) {
+ change_opcode(instr, PC_MR);
+ instr->args[1] = instr->args[2];
+ change_num_operands(instr, 2);
+ } else {
+ change_opcode(instr, PC_ADDI);
+ instr->args[1] = instr->args[2];
+ instr->args[2].kind = PCOp_IMMEDIATE;
+ instr->args[2].data.imm.value = -value1;
+ instr->args[2].data.imm.obj = NULL;
+ }
+ propagatedconstants = 1;
+ changed = 1;
+ value2 = value1;
+ } else if (isconstantoperand(&instr->args[2], &value1) && FITS_IN_SHORT(-value1)) {
+ if (value1 == 0) {
+ change_opcode(instr, PC_NEG);
+ change_num_operands(instr, 2);
+ } else {
+ instr->flags = opcodeinfo[PC_SUBFIC].flags | (instr->flags & ~opcodeinfo[PC_SUBF].flags);
+ change_opcode(instr, PC_SUBFIC);
+ instr->args[2].kind = PCOp_IMMEDIATE;
+ instr->args[2].data.imm.value = value1;
+ instr->args[2].data.imm.obj = NULL;
+ instr->args[3].kind = PCOp_REGISTER;
+ instr->args[3].arg = RegClass_SPR;
+ instr->args[3].data.reg.reg = 0;
+ instr->args[3].data.reg.effect = EffectWrite;
+ change_num_operands(instr, 4);
+ }
+ propagatedconstants = 1;
+ changed = 1;
+ }
+
+ break;
+
+ case PC_LBZ:
+ case PC_LHZ:
+ case PC_LHA:
+ case PC_LWZ:
+ case PC_STB:
+ case PC_STH:
+ case PC_STW:
+ case PC_LFS:
+ case PC_LFD:
+ case PC_STFS:
+ case PC_STFD:
+ if (instr->args[2].kind == PCOp_IMMEDIATE) {
+ PCode *stackInstr;
+ SInt16 addend = instr->args[2].data.imm.value;
+
+ if ((stackInstr = isstackoperand(&instr->args[1], &value1, addend))) {
+ instr->args[1] = stackInstr->args[1];
+ instr->args[2] = stackInstr->args[2];
+ instr->args[2].data.imm.value = value1 + addend;
+ if (instr->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000))
+ instr->alias = make_alias(instr->args[2].data.imm.obj, instr->args[2].data.imm.value,
+ nbytes_loaded_or_stored_by(instr));
+ propagatedconstants = 1;
+ changed = 1;
+ }
+ }
+ break;
+
+ case PC_LBZX:
+ case PC_LHZX:
+ case PC_LHAX:
+ case PC_LWZX:
+ case PC_STBX:
+ case PC_STHX:
+ case PC_STWX:
+ case PC_LFSX:
+ case PC_LFDX:
+ case PC_STFSX:
+ case PC_STFDX:
+ if (isconstantoperand(&instr->args[2], &value1)) {
+ instr->op -= 2;
+ instr->args[2].kind = PCOp_IMMEDIATE;
+ instr->args[2].data.imm.value = value1;
+ instr->args[2].data.imm.obj = NULL;
+ propagatedconstants = 1;
+ changed = 1;
+ } else if (isconstantoperand(&instr->args[1], &value1)) {
+ instr->op -= 2;
+ instr->args[1] = instr->args[2];
+ instr->args[2].kind = PCOp_IMMEDIATE;
+ instr->args[2].data.imm.value = value1;
+ instr->args[2].data.imm.obj = NULL;
+ propagatedconstants = 1;
+ changed = 1;
+ }
+
+ break;
+ }
+
+ for (i = 0, op = instr->args; i < instr->argCount; i++, op++) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ (op->data.reg.effect & EffectWrite)
+ )
+ {
+ defininginstruction[op->data.reg.reg] = instr;
+ }
+ else if (
+ op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_VR &&
+ (op->data.reg.effect & EffectWrite)
+ )
+ {
+ vrdefininginstruction[op->data.reg.reg] = instr;
+ }
+ }
+ }
+}
+
+void propagateconstants(void) {
+ PCodeBlock *block;
+ int i;
+
+ propagatedconstants = 0;
+ computeusedefchains(0);
+ defininginstruction = galloc(sizeof(PCode *) * used_virtual_registers[RegClass_GPR]);
+ vrdefininginstruction = galloc(sizeof(PCode *) * used_virtual_registers[RegClass_VR]);
+
+ do {
+ changed = 0;
+ for (i = 0; i < pcblockcount; i++) {
+ if ((block = depthfirstordering[i])) {
+ computedefininginstructions(block);
+ propagateconstantstoblock(block);
+ }
+ }
+ } while (changed);
+
+ freeoheap();
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/LoopDetection.c b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/LoopDetection.c
new file mode 100644
index 0000000..6bb2d51
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/LoopDetection.c
@@ -0,0 +1,885 @@
+#include "compiler/LoopDetection.h"
+#include "compiler/CFunc.h"
+#include "compiler/PCode.h"
+#include "compiler/TOC.h"
+#include "compiler/UseDefChains.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/BitVectors.h"
+#include "compiler/enode.h"
+#include "compiler/objects.h"
+
+Loop *loopsinflowgraph;
+int loopdetection_nblocks;
+static UInt32 **dominators;
+static BlockList *loopheaders;
+static int nloopheaders;
+static PCodeBlock **loopstack;
+BitVector *LoopTemp;
+struct LoopList *LoopList_First;
+
+static void computedominators(void) {
+ int i;
+ PCodeBlock *block;
+ int blockCount;
+ int flag;
+ UInt32 *myvec;
+ PCLink *link;
+
+ blockCount = pcblockcount;
+ flag = 1;
+
+ dominators = oalloc(sizeof(UInt32 *) * pcblockcount);
+ for (i = 0; i < pcblockcount; i++)
+ dominators[i] = oalloc(4 * ((blockCount + 31) >> 5));
+
+ myvec = oalloc(4 * ((blockCount + 31) >> 5));
+
+ bitvectorinitialize(dominators[pcbasicblocks->blockIndex], blockCount, 0);
+ //dominators[pcbasicblocks->blockIndex][0] |= 1;
+ bitvectorsetbit(0, dominators[pcbasicblocks->blockIndex]);
+
+ for (block = pcbasicblocks->nextBlock; block; block = block->nextBlock)
+ bitvectorinitialize(dominators[block->blockIndex], blockCount, 0xFFFFFFFF);
+
+ computedepthfirstordering();
+
+ while (flag) {
+ flag = 0;
+ for (i = 0; i < pcblockcount; i++) {
+ block = depthfirstordering[i];
+ if (block && block->blockIndex != pcbasicblocks->blockIndex) {
+ bitvectorcopy(myvec, dominators[block->predecessors->block->blockIndex], blockCount);
+ for (link = block->predecessors->nextLink; link; link = link->nextLink)
+ bitvectorintersect(myvec, dominators[link->block->blockIndex], blockCount);
+ //myvec[block->blockIndex >> 5] |= 1 << (block->blockIndex & 31);
+ bitvectorsetbit(block->blockIndex, myvec);
+
+ if (bitvectorchanged(dominators[block->blockIndex], myvec, blockCount))
+ flag = 1;
+ }
+ }
+ }
+}
+
+static BlockList *findloopheaders(void) {
+ PCodeBlock *block;
+ PCLink *link;
+ BlockList *list;
+
+ loopheaders = NULL;
+ nloopheaders = 0;
+
+ for (block = pcbasicblocks->nextBlock; block; block = block->nextBlock) {
+ for (link = block->predecessors; link; link = link->nextLink) {
+ //if ((1 << (block->blockIndex & 31)) & dominators[link->block->blockIndex][block->blockIndex >> 5])
+ if (bitvectorgetbit(block->blockIndex, dominators[link->block->blockIndex]))
+ break;
+ }
+
+ if (link) {
+ list = oalloc(sizeof(BlockList));
+ list->block = block;
+ list->next = loopheaders;
+ loopheaders = list;
+ nloopheaders++;
+ }
+ }
+
+ return loopheaders;
+}
+
+void addblocktoloop(Loop *loop, PCodeBlock *block) {
+ BlockList *list = lalloc(sizeof(BlockList));
+
+ //loop->memberblocks[block->blockIndex >> 5] |= 1 << (block->blockIndex & 31);
+ bitvectorsetbit(block->blockIndex, loop->memberblocks);
+
+ list->block = block;
+ list->next = loop->blocks;
+ loop->blocks = list;
+}
+
+static void findnaturalloop(Loop *loop) {
+ BlockList *list;
+ BlockList *list2;
+ PCLink *link;
+ PCodeBlock *block;
+ int i;
+
+ i = 0;
+ addblocktoloop(loop, loop->body);
+ for (link = loop->body->predecessors; link; link = link->nextLink) {
+ if (bitvectorgetbit(loop->body->blockIndex, dominators[link->block->blockIndex]) && link->block != loop->body) {
+ addblocktoloop(loop, link->block);
+ loopstack[i++] = link->block;
+ }
+ }
+
+ while (i) {
+ link = loopstack[--i]->predecessors;
+ while (link) {
+ if (!bitvectorgetbit(link->block->blockIndex, loop->memberblocks)) {
+ addblocktoloop(loop, link->block);
+ loopstack[i++] = link->block;
+ }
+ link = link->nextLink;
+ }
+ }
+
+ for (list = loop->blocks; list; list = list->next) {
+ block = list->block;
+ for (link = block->successors; link; link = link->nextLink) {
+ if (!bitvectorgetbit(link->block->blockIndex, loop->memberblocks)) {
+ bitvectorsetbit(block->blockIndex, loop->vec24);
+ break;
+ }
+ }
+ }
+
+ for (list = loop->blocks; list; list = list->next) {
+ for (list2 = loop->blocks; list2; list2 = list2->next) {
+ if (bitvectorgetbit(list2->block->blockIndex, loop->vec24) &&
+ !bitvectorgetbit(list->block->blockIndex, dominators[list2->block->blockIndex]))
+ break;
+ }
+
+ if (!list2)
+ bitvectorsetbit(list->block->blockIndex, loop->vec28);
+ }
+
+ for (list = loop->blocks; list; list = list->next) {
+ for (link = loop->body->predecessors; link; link = link->nextLink) {
+ if (bitvectorgetbit(link->block->blockIndex, loop->memberblocks) &&
+ !bitvectorgetbit(list->block->blockIndex, dominators[link->block->blockIndex]))
+ break;
+ }
+
+ if (!link)
+ bitvectorsetbit(list->block->blockIndex, loop->vec2C);
+ }
+}
+
+static void addlooptolist(Loop *loop, Loop **list) {
+ Loop **scan;
+ Loop *scanloop;
+
+ scan = list;
+ while ((scanloop = *scan)) {
+ if (bitvectorgetbit(loop->body->blockIndex, scanloop->memberblocks)) {
+ loop->parent = scanloop;
+ addlooptolist(loop, &scanloop->children);
+ return;
+ }
+
+ if (bitvectorgetbit(scanloop->body->blockIndex, loop->memberblocks)) {
+ *scan = scanloop->nextSibling;
+ scanloop->parent = loop;
+ scanloop->nextSibling = loop->children;
+ loop->children = scanloop;
+ } else {
+ scan = &scanloop->nextSibling;
+ }
+ }
+
+ loop->nextSibling = *list;
+ *list = loop;
+}
+
+static void findnaturalloops(void) {
+ Loop *loop;
+ int size;
+
+ loopdetection_nblocks = pcblockcount + 5 * nloopheaders;
+ loopstack = oalloc(sizeof(PCodeBlock *) * pcblockcount);
+ while (loopheaders) {
+ loop = lalloc(sizeof(Loop));
+ loop->parent = loop->nextSibling = loop->children = NULL;
+ loop->body = loopheaders->block;
+ loop->preheader = NULL;
+ loop->blocks = NULL;
+ loop->basicInductionVars = NULL;
+ loop->footer = NULL;
+ loop->pc18 = NULL;
+ loop->loopWeight = loop->body->loopWeight;
+
+ bitvectorinitialize(loop->memberblocks = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
+ bitvectorinitialize(loop->vec24 = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
+ bitvectorinitialize(loop->vec28 = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
+ bitvectorinitialize(loop->vec2C = lalloc(4 * ((loopdetection_nblocks + 31) >> 5)), loopdetection_nblocks, 0);
+
+ findnaturalloop(loop);
+ addlooptolist(loop, &loopsinflowgraph);
+
+ loopheaders = loopheaders->next;
+ }
+}
+
+static PCodeBlock *makepreheaderblock(void) {
+ PCodeLabel *label;
+ PCodeBlock *block;
+
+ label = makepclabel();
+ block = lalloc(sizeof(PCodeBlock));
+ block->nextBlock = NULL;
+ block->prevBlock = NULL;
+ block->labels = NULL;
+ block->successors = NULL;
+ block->predecessors = NULL;
+ block->firstPCode = block->lastPCode = NULL;
+ block->pcodeCount = 0;
+ block->flags = 0;
+ block->blockIndex = pcblockcount++;
+ pclabel(block, label);
+ return block;
+}
+
+static void insertpreheaderbefore(PCodeBlock *a, PCodeBlock *b) {
+ a->nextBlock = b;
+ a->prevBlock = b->prevBlock;
+ b->prevBlock->nextBlock = a;
+ b->prevBlock = a;
+}
+
+void insertpreheaderblock(Loop *loop) {
+ PCodeBlock *preheader;
+ PCodeBlock *block29;
+ PCodeBlock *block28;
+ PCode *pcode27;
+ PCLink *link; // r26
+ PCLink **linkptr; // r25
+ PCodeLabel *newlabel; // r23
+ PCLink *innerlink;
+ PCodeBlock *block;
+ PCodeArg *arg;
+ int i;
+
+ preheader = loop->preheader = makepreheaderblock();
+ block29 = NULL;
+ block28 = loop->body;
+
+ if (!block28->labels)
+ pclabel(block28, makepclabel());
+
+ appendpcode(preheader, makepcode(PC_B, block28->labels));
+ preheader->loopWeight = loop->parent ? loop->parent->loopWeight : 1;
+
+ linkptr = &block28->predecessors;
+ while ((link = *linkptr)) {
+ if (bitvectorgetbit(link->block->blockIndex, loop->memberblocks)) {
+ linkptr = &link->nextLink;
+ } else {
+ if (link->block->pcodeCount) {
+ pcode27 = link->block->lastPCode;
+ if (pcode27->op == PC_B) {
+ CError_ASSERT(462, pcode27->args[0].kind == PCOp_LABEL);
+ if (pcode27->args[0].data.label.label->block == block28)
+ pcode27->args[0].data.label.label = preheader->labels;
+ } else if (pcode27->op == PC_BT || pcode27->op == PC_BF) {
+ CError_ASSERT(474, pcode27->args[2].kind == PCOp_LABEL);
+ if (pcode27->args[2].data.label.label->block == block28)
+ pcode27->args[2].data.label.label = preheader->labels;
+ } else if (pcode27->op == PC_BCTR) {
+ if (pcode27->argCount > 1 && pcode27->args[1].kind == PCOp_MEMORY) {
+ Object *obj = pcode27->args[1].data.mem.obj;
+ UInt32 *array = (UInt32 *) obj->u.data.u.switchtable.data;
+ int i;
+ for (i = 0; i < obj->u.data.u.switchtable.size; i++) {
+ if (((PCodeLabel *) CTool_ResolveIndexToPointer(array[i]))->block == block28)
+ array[i] = CTool_CreateIndexFromPointer(preheader->labels);
+ }
+ } else {
+ CodeLabelList *cll;
+ for (cll = codelabellist; cll; cll = cll->next) {
+ if (cll->label->pclabel->block == block28)
+ cll->label->pclabel = preheader->labels;
+ }
+ }
+ } else {
+ CError_ASSERT(505, link->block->nextBlock == block28);
+ }
+ }
+
+ for (innerlink = link->block->successors; innerlink; innerlink = innerlink->nextLink) {
+ if (innerlink->block == block28)
+ innerlink->block = preheader;
+ }
+
+ *linkptr = link->nextLink;;
+ link->nextLink = preheader->predecessors;
+ preheader->predecessors = link;
+ }
+ }
+
+ if (!bitvectorgetbit(block28->prevBlock->blockIndex, loop->memberblocks)) {
+ insertpreheaderbefore(preheader, block28);
+
+ if (
+ (!block28->nextBlock || !bitvectorgetbit(block28->nextBlock->blockIndex, loop->memberblocks)) &&
+ block28->lastPCode &&
+ (block28->lastPCode->flags & fIsBranch) &&
+ block28->lastPCode->op != PC_BDNZ
+ ) {
+ i = block28->lastPCode->argCount;
+ arg = block28->lastPCode->args;
+ while (i && arg->kind != PCOp_LABEL) {
+ arg++;
+ i--;
+ }
+
+ if (i && arg->kind == PCOp_LABEL && arg->data.label.label->block == block28) {
+ block29 = makepreheaderblock();
+ insertpreheaderbefore(block29, block28);
+ newlabel = makepclabel();
+ pclabel(block29, newlabel);
+ arg->data.label.label = newlabel;
+
+ link = lalloc(sizeof(PCLink));
+ link->block = block28;
+ link->nextLink = block29->predecessors;
+ block29->predecessors = link;
+
+ link = lalloc(sizeof(PCLink));
+ link->block = block28;
+ link->nextLink = block29->successors;
+ block29->successors = link;
+
+ for (link = block28->successors; link; link = link->nextLink) {
+ if (link->block == block28)
+ link->block = block29;
+ }
+ for (link = block28->predecessors; link; link = link->nextLink) {
+ if (link->block == block28)
+ link->block = block29;
+ }
+
+ bitvectorsetbit(block29->blockIndex, loop->vec2C);
+ addblocktoloop(loop, block29);
+ }
+ }
+ } else {
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ if (bitvectorgetbit(block->blockIndex, loop->memberblocks))
+ break;
+ }
+ insertpreheaderbefore(preheader, block);
+ }
+
+ link = lalloc(sizeof(PCLink));
+ link->block = preheader;
+ link->nextLink = block28->predecessors;
+ block28->predecessors = link;
+
+ link = lalloc(sizeof(PCLink));
+ link->block = block28;
+ link->nextLink = preheader->successors;
+ preheader->successors = link;
+
+ for (loop = loop->parent; loop; loop = loop->parent) {
+ addblocktoloop(loop, preheader);
+ if (bitvectorgetbit(block28->blockIndex, loop->vec28)) {
+ bitvectorsetbit(preheader->blockIndex, loop->vec28);
+ if (block29)
+ bitvectorsetbit(block29->blockIndex, loop->vec28);
+ }
+ if (bitvectorgetbit(block28->blockIndex, loop->vec2C)) {
+ bitvectorsetbit(preheader->blockIndex, loop->vec2C);
+ if (block29)
+ bitvectorsetbit(block29->blockIndex, loop->vec2C);
+ }
+ }
+}
+
+static void insertpreheaderblocks(Loop *loop) {
+ while (loop) {
+ if (loop->children)
+ insertpreheaderblocks(loop->children);
+ insertpreheaderblock(loop);
+ loop = loop->nextSibling;
+ }
+}
+
+void findloopsinflowgraph(void) {
+ loopsinflowgraph = NULL;
+ computedominators();
+ if (findloopheaders()) {
+ findnaturalloops();
+ insertpreheaderblocks(loopsinflowgraph);
+ }
+ freeoheap();
+}
+
+static int checklooplimits(SInt32 opcode, SInt32 condition, SInt32 c, SInt32 d, SInt32 addend, SInt32 *result) {
+ if (opcode == PC_BT) {
+ if (condition == 0) {
+ if (addend <= 0)
+ return 0;
+ if (c < d)
+ *result = (d - c + addend - 1) / addend;
+ else
+ *result = 0;
+ } else if (condition == 1) {
+ if (addend >= 0)
+ return 0;
+ if (c > d)
+ *result = (c - d - addend - 1) / -addend;
+ else
+ *result = 0;
+ } else {
+ return 0;
+ }
+ } else {
+ if (condition == 0) {
+ if (addend >= 0)
+ return 0;
+ if (c >= d)
+ *result = (c - d - addend) / -addend;
+ else
+ *result = 0;
+ } else if (condition == 1) {
+ if (addend <= 0)
+ return 0;
+ if (c <= d)
+ *result = (d - c + addend) / addend;
+ else
+ *result = 0;
+ } else if (c < d) {
+ if (addend <= 0)
+ return 0;
+ if ((d - c) % addend)
+ return 0;
+ *result = (d - c) / addend;
+ } else if (c > d) {
+ if (addend >= 0)
+ return 0;
+ if ((c - d) % -addend)
+ return 0;
+ *result = (c - d) / -addend;
+ } else {
+ *result = 0;
+ }
+ }
+
+ return 1;
+}
+
+static int checkunsignedlooplimits(SInt32 opcode, SInt32 condition, UInt32 c, UInt32 d, SInt32 addend, UInt32 *result) {
+ if (opcode == PC_BT) {
+ if (condition == 0) {
+ if (addend <= 0)
+ return 0;
+ if (c < d)
+ *result = (d - c + addend - 1) / addend;
+ else
+ *result = 0;
+ } else if (condition == 1) {
+ if (addend >= 0)
+ return 0;
+ if (c > d)
+ *result = (c - d - addend - 1) / -addend;
+ else
+ *result = 0;
+ } else {
+ return 0;
+ }
+ } else {
+ if (condition == 0) {
+ if (addend >= 0)
+ return 0;
+ if (c >= d)
+ *result = (c - d - addend) / -addend;
+ else
+ *result = 0;
+ } else if (condition == 1) {
+ if (addend <= 0)
+ return 0;
+ if (c <= d)
+ *result = (d - c + addend) / addend;
+ else
+ *result = 0;
+ } else if (c < d) {
+ if (addend <= 0)
+ return 0;
+ if ((d - c) % addend)
+ return 0;
+ *result = (d - c) / addend;
+ } else if (c > d) {
+ if (addend >= 0)
+ return 0;
+ if ((c - d) % -addend)
+ return 0;
+ *result = (c - d) / -addend;
+ } else {
+ *result = 0;
+ }
+ }
+
+ return (*result & 0x80000000) == 0;
+}
+
+static int checkunknownloop(int a, int b, int c, unsigned char *op) {
+ if (a == PC_BT) {
+ if (b == 0) {
+ if (c <= 0)
+ return 0;
+ *op = ELESS;
+ } else if (b == 1) {
+ if (c >= 0)
+ return 0;
+ *op = EGREATER;
+ } else {
+ return 0;
+ }
+ } else {
+ if (b == 0) {
+ if (c >= 0)
+ return 0;
+ *op = EGREATEREQU;
+ } else if (b == 1) {
+ if (c <= 0)
+ return 0;
+ *op = ELESSEQU;
+ } else if (c == 1) {
+ *op = ENOTEQU;
+ } else if (c == -1) {
+ *op = ENOTEQU;
+ } else {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void checkcountingloop(Loop *loop) {
+ RegUseOrDef *list;
+ PCode *lastpcode;
+ PCode *prevpcode;
+ PCode *pc8;
+ PCode *check;
+ short op12;
+ short reg11;
+ SInt16 reg4;
+ short reg11b;
+ Loop *child;
+
+ if (!(lastpcode = loop->body->lastPCode))
+ return;
+ if (lastpcode->op != PC_BT && lastpcode->op != PC_BF)
+ return;
+ if (lastpcode->args[2].kind != PCOp_LABEL)
+ return;
+
+ if (!bitvectorgetbit(lastpcode->args[2].data.label.label->block->blockIndex, loop->memberblocks))
+ return;
+ if (bitvectorgetbit(loop->body->nextBlock->blockIndex, loop->memberblocks))
+ return;
+
+ reg11 = lastpcode->args[0].data.reg.reg;
+ reg4 = lastpcode->args[1].data.imm.value;
+ prevpcode = lastpcode->prevPCode;
+ if (!prevpcode)
+ return;
+
+ op12 = prevpcode->op;
+ if (op12 == PC_ADDI && prevpcode->args[2].kind == PCOp_IMMEDIATE) {
+ pc8 = prevpcode;
+ prevpcode = prevpcode->prevPCode;
+ if (!prevpcode)
+ return;
+
+ op12 = prevpcode->op;
+ if (pc8->args[0].data.reg.reg != pc8->args[1].data.reg.reg)
+ return;
+ if (op12 != PC_CMP && op12 != PC_CMPL && op12 != PC_CMPI && op12 != PC_CMPLI)
+ return;
+ if (prevpcode->args[1].data.reg.reg != pc8->args[0].data.reg.reg)
+ return;
+ if ((loop->step = pc8->args[2].data.imm.value) == 0)
+ return;
+ }
+
+ if (op12 != PC_CMP && op12 != PC_CMPL && op12 != PC_CMPI && op12 != PC_CMPLI)
+ return;
+
+ if (prevpcode->args[0].data.reg.reg != reg11)
+ return;
+
+ reg11b = prevpcode->args[1].data.reg.reg;
+ if (reg11b < 32)
+ return;
+
+ if (loop->preheader->nextBlock != lastpcode->args[2].data.label.label->block)
+ return;
+
+ if (op12 == PC_CMPI) {
+ if (prevpcode->prevPCode)
+ return;
+ loop->upper = prevpcode->args[2].data.imm.value;
+ loop->upperType = LOOP_BOUND_CONSTANT;
+ } else if (op12 == PC_CMPLI) {
+ if (prevpcode->prevPCode)
+ return;
+ loop->upper = prevpcode->args[2].data.imm.value & 0xFFFF;
+ loop->upperType = LOOP_BOUND_CONSTANT;
+ } else if (op12 == PC_CMP || op12 == PC_CMPL) {
+ if (prevpcode->prevPCode) {
+ if (
+ prevpcode->prevPCode->op == PC_LI &&
+ prevpcode->prevPCode->args[1].kind == PCOp_IMMEDIATE &&
+ prevpcode->prevPCode->args[0].data.reg.reg == prevpcode->args[2].data.reg.reg &&
+ !prevpcode->prevPCode->prevPCode
+ ) {
+ loop->upper = prevpcode->prevPCode->args[1].data.imm.value;
+ loop->upperType = LOOP_BOUND_CONSTANT;
+ } else if (
+ prevpcode->prevPCode->op == PC_LIS &&
+ prevpcode->prevPCode->args[1].kind == PCOp_IMMEDIATE &&
+ prevpcode->prevPCode->args[0].data.reg.reg == prevpcode->args[2].data.reg.reg &&
+ !prevpcode->prevPCode->prevPCode
+ ) {
+ loop->upper = prevpcode->prevPCode->args[1].data.imm.value << 16;
+ loop->upperType = LOOP_BOUND_CONSTANT;
+ } else if (
+ prevpcode->prevPCode->op == PC_ADDI &&
+ prevpcode->prevPCode->args[2].kind == PCOp_IMMEDIATE &&
+ prevpcode->prevPCode->args[0].data.reg.reg == prevpcode->args[2].data.reg.reg &&
+ prevpcode->prevPCode->args[1].data.reg.reg == prevpcode->args[2].data.reg.reg &&
+ prevpcode->prevPCode->prevPCode &&
+ prevpcode->prevPCode->prevPCode->op == PC_LIS &&
+ prevpcode->prevPCode->prevPCode->args[1].kind == PCOp_IMMEDIATE &&
+ prevpcode->prevPCode->prevPCode->args[0].data.reg.reg == prevpcode->args[2].data.reg.reg &&
+ !prevpcode->prevPCode->prevPCode->prevPCode
+ ) {
+ loop->upper = prevpcode->prevPCode->args[2].data.imm.value +
+ (prevpcode->prevPCode->prevPCode->args[1].data.imm.value << 16);
+ loop->upperType = LOOP_BOUND_CONSTANT;
+ } else {
+ return;
+ }
+ } else {
+ pc8 = NULL;
+ for (list = reg_Defs[RegClass_GPR][prevpcode->args[2].data.reg.reg]; list; list = list->next) {
+ if (bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks))
+ return;
+ }
+ for (list = reg_Defs[RegClass_GPR][prevpcode->args[2].data.reg.reg]; list; list = list->next) {
+ if (bitvectorgetbit(list->id, usedefinfo[loop->preheader->blockIndex].defvec8)) {
+ if (!pc8) {
+ pc8 = Defs[list->id].pcode;
+ if (
+ pc8->op == PC_LI &&
+ pc8->args[1].kind == PCOp_IMMEDIATE
+ ) {
+ loop->upper = pc8->args[1].data.imm.value;
+ loop->upperType = LOOP_BOUND_CONSTANT;
+ } else if (
+ pc8->op == PC_LIS &&
+ pc8->args[1].kind == PCOp_IMMEDIATE
+ ) {
+ loop->upper = pc8->args[1].data.imm.value << 16;
+ loop->upperType = LOOP_BOUND_CONSTANT;
+ } else if (
+ pc8->op == PC_ADDI &&
+ pc8->args[2].kind == PCOp_IMMEDIATE &&
+ pc8->args[1].data.reg.reg == prevpcode->args[2].data.reg.reg &&
+ pc8->prevPCode &&
+ pc8->prevPCode->op == PC_LIS &&
+ pc8->prevPCode->args[1].kind == PCOp_IMMEDIATE &&
+ pc8->prevPCode->args[0].data.reg.reg == prevpcode->args[2].data.reg.reg
+ ) {
+ loop->upper = pc8->args[2].data.imm.value +
+ (pc8->prevPCode->args[1].data.imm.value << 16);
+ loop->upperType = LOOP_BOUND_CONSTANT;
+ } else {
+ loop->upperType = LOOP_BOUND_VARIABLE;
+ break;
+ }
+ } else {
+ loop->upperType = LOOP_BOUND_VARIABLE;
+ break;
+ }
+ }
+ }
+
+ if (loop->upperType == LOOP_BOUND_INDETERMINATE)
+ loop->upperType = LOOP_BOUND_VARIABLE;
+ }
+ }
+
+ pc8 = NULL;
+
+ for (list = reg_Defs[RegClass_GPR][reg11b]; list; list = list->next) {
+ check = Defs[list->id].pcode;
+ if (bitvectorgetbit(check->block->blockIndex, loop->memberblocks)) {
+ if (!pc8) {
+ pc8 = check;
+ if (check->op != PC_ADDI)
+ return;
+ if (check->args[1].data.reg.reg != reg11b)
+ return;
+ if (check->args[2].kind != PCOp_IMMEDIATE)
+ return;
+ if ((loop->step = check->args[2].data.imm.value) == 0)
+ return;
+ } else {
+ return;
+ }
+ }
+ }
+
+ if (!pc8)
+ return;
+
+ if (pc8->block != prevpcode->block && !bitvectorgetbit(prevpcode->block->blockIndex, loop->vec2C))
+ return;
+
+ if (loop->children) {
+ for (child = loop->children; child; child = child->nextSibling) {
+ if (bitvectorgetbit(pc8->block->blockIndex, child->memberblocks))
+ return;
+ }
+ }
+
+ loop->pc18 = pc8;
+
+ pc8 = NULL;
+
+ for (list = reg_Defs[RegClass_GPR][reg11b]; list; list = list->next) {
+ if (bitvectorgetbit(list->id, usedefinfo[loop->preheader->blockIndex].defvec8)) {
+ if (!pc8) {
+ pc8 = Defs[list->id].pcode;
+ if (
+ pc8->op == PC_LI &&
+ pc8->args[1].kind == PCOp_IMMEDIATE
+ ) {
+ loop->lower = pc8->args[1].data.imm.value;
+ loop->lowerType = LOOP_BOUND_CONSTANT;
+ } else if (
+ pc8->op == PC_LIS &&
+ pc8->args[1].kind == PCOp_IMMEDIATE
+ ) {
+ loop->lower = pc8->args[1].data.imm.value << 16;
+ loop->lowerType = LOOP_BOUND_CONSTANT;
+ } else if (
+ pc8->op == PC_ADDI &&
+ pc8->args[2].kind == PCOp_IMMEDIATE &&
+ pc8->args[1].data.reg.reg == reg11b &&
+ pc8->prevPCode &&
+ pc8->prevPCode->op == PC_LIS &&
+ pc8->prevPCode->args[1].kind == PCOp_IMMEDIATE &&
+ pc8->prevPCode->args[0].data.reg.reg == reg11b
+ ) {
+ loop->lower = pc8->args[2].data.imm.value +
+ (pc8->prevPCode->args[1].data.imm.value << 16);
+ loop->lowerType = LOOP_BOUND_CONSTANT;
+ } else {
+ loop->lowerType = LOOP_BOUND_VARIABLE;
+ break;
+ }
+ } else {
+ loop->lowerType = LOOP_BOUND_INDETERMINATE;
+ break;
+ }
+ }
+ }
+
+ if (loop->lowerType == LOOP_BOUND_INDETERMINATE)
+ loop->lowerType = LOOP_BOUND_VARIABLE;
+
+ if (loop->lowerType == LOOP_BOUND_CONSTANT && loop->upperType == LOOP_BOUND_CONSTANT) {
+ if (op12 == PC_CMP || op12 == PC_CMPI) {
+ if (!checklooplimits(lastpcode->op, reg4, loop->lower, loop->upper, loop->step, &loop->iterationCount))
+ return;
+ } else {
+ if (!checkunsignedlooplimits(lastpcode->op, reg4, loop->lower, loop->upper, loop->step, (UInt32 *) &loop->iterationCount))
+ return;
+ }
+ loop->isKnownCountingLoop = 1;
+ } else if (loop->lowerType != LOOP_BOUND_INDETERMINATE || loop->upperType != LOOP_BOUND_INDETERMINATE) {
+ if (!checkunknownloop(lastpcode->op, reg4, loop->step, &loop->unknownCondition))
+ return;
+ loop->isUnknownCountingLoop = 1;
+ }
+}
+
+void analyzeForCountableLoops(Loop *loop) {
+ if (!loop)
+ return;
+
+ while (loop) {
+ if (loop->children)
+ analyzeForCountableLoops(loop->children);
+ checkcountingloop(loop);
+ loop = loop->nextSibling;
+ }
+}
+
+void analyzeloop(Loop *loop) {
+ BlockList *list;
+ PCodeBlock *block;
+ PCode *pcode;
+
+ loop->bodySize = 0;
+ loop->x4D = 0;
+ loop->x4E = 0;
+ loop->x4F = 1;
+ loop->isKnownCountingLoop = 0;
+ loop->isUnknownCountingLoop = 0;
+ loop->lowerType = LOOP_BOUND_INDETERMINATE;
+ loop->upperType = LOOP_BOUND_INDETERMINATE;
+ loop->iterationCount = -1;
+ loop->x57 = 0;
+ loop->x52 = 0;
+
+ for (list = loop->blocks; list; list = list->next) {
+ block = list->block;
+ if (!loop->children)
+ block->flags |= fPCBlockFlag2000;
+ loop->bodySize += block->pcodeCount;
+
+ if (block != loop->body) {
+ if (!block->successors || !block->predecessors || block->successors->nextLink || block->predecessors->nextLink)
+ loop->x4F = 0;
+ }
+
+ if ((block->flags & fPCBlockFlag4000) == fPCBlockFlag4000)
+ loop->x52 = 1;
+
+ for (pcode = block->firstPCode; pcode; pcode = pcode->nextPCode) {
+ if (PCODE_FLAG_SET_T(pcode) & fLink)
+ loop->x4D = 1;
+
+ if (pcode->op == PC_BCTRL || pcode->op == PC_BCTR || pcode->op == PC_BCCTR || pcode->op == PC_MTCTR || pcode->op == PC_MFCTR) {
+ loop->x4E = 1;
+ } else if (pcode->flags & fIsRead) {
+ if (pcode->op == PC_LBZX || pcode->op == PC_LHZX || pcode->op == PC_LHAX || pcode->op == PC_LWZX || pcode->op == PC_LFSX || pcode->op == PC_LFDX)
+ loop->x53 = 1;
+ } else if (pcode->flags & fIsWrite) {
+ if (pcode->op == PC_STBX || pcode->op == PC_STHX || pcode->op == PC_STWX || pcode->op == PC_STFSX || pcode->op == PC_STFDX)
+ loop->x54 = 1;
+ } else {
+ if (pcode->op == PC_EIEIO || pcode->op == PC_SYNC || pcode->op == PC_ISYNC)
+ loop->x57 = 1;
+ }
+ }
+ }
+
+ if (!loop->children && !loop->x4D && loop->bodySize < 32) {
+ for (list = loop->blocks; list; list = list->next)
+ list->block->flags |= fPCBlockFlag2000;
+ }
+}
+
+static void analyzeloops(Loop *loop) {
+ while (loop) {
+ if (loop->children)
+ analyzeloops(loop->children);
+ analyzeloop(loop);
+ loop = loop->nextSibling;
+ }
+}
+
+void analyzeloopsinflowgraph(void) {
+ if (loopsinflowgraph)
+ analyzeloops(loopsinflowgraph);
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/LoopOptimization.c b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/LoopOptimization.c
new file mode 100644
index 0000000..b2aef1e
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/LoopOptimization.c
@@ -0,0 +1,1553 @@
+#include "compiler/LoopOptimization.h"
+#include "compiler/CFunc.h"
+#include "compiler/CParser.h"
+#include "compiler/BitVectors.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/LoopDetection.h"
+#include "compiler/PCode.h"
+#include "compiler/Registers.h"
+#include "compiler/UseDefChains.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+int optimizedloops;
+int optimizedloop_full_unroll;
+int optimizedloop_trans_regs;
+static UInt32 *liveonexit;
+static UInt32 *inductionvariables;
+static int last_virtual_GPR;
+
+static int ispowerof2(SInt32 value) {
+ int bit = getbit(value);
+ return (bit > 0 && bit < 31) ? bit : 0;
+}
+
+static void insertupdateinstructions(Loop *loop) {
+ // nothing
+}
+
+static void computeliveonexit(Loop *loop) {
+ UInt32 *usevec;
+ UInt32 *defvec;
+ BlockList *blocklist;
+ RegUseOrDef *list;
+ int gpr;
+
+ bitvectorinitialize(usevec = oalloc(4 * ((number_of_Uses + 31) >> 5)), number_of_Uses, 0);
+ for (blocklist = loop->blocks; blocklist; blocklist = blocklist->next) {
+ if (bitvectorgetbit(blocklist->block->blockIndex, loop->vec24))
+ bitvectorunion(usevec, usedefinfo[blocklist->block->blockIndex].usevec1C, number_of_Uses);
+ }
+
+ bitvectorinitialize(defvec = oalloc(4 * ((number_of_Defs + 31) >> 5)), number_of_Defs, 0);
+ if (loop->preheader)
+ bitvectorunion(defvec, usedefinfo[loop->preheader->blockIndex].defvec8, number_of_Defs);
+
+ bitvectorinitialize(liveonexit, last_virtual_GPR, 0);
+
+ for (gpr = 32; gpr < last_virtual_GPR; gpr++) {
+ for (list = reg_Defs[RegClass_GPR][gpr]; list; list = list->next) {
+ if (bitvectorgetbit(list->id, defvec)) {
+ if (!Defs[list->id].pcode->block || bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks)) {
+ bitvectorsetbit(gpr, liveonexit);
+ break;
+ }
+ }
+ }
+
+ for (list = reg_Uses[RegClass_GPR][gpr]; list; list = list->next) {
+ if (bitvectorgetbit(list->id, usevec)) {
+ if (!Uses[list->id].pcode->block || !bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)) {
+ bitvectorsetbit(gpr, liveonexit);
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void eliminateinductionvariables(Loop *loop) {
+ BlockList *blocklist;
+ PCode *instr;
+ PCode *nextInstr;
+ PCodeArg *op;
+ int i;
+
+ bitvectorinitialize(inductionvariables, last_virtual_GPR, 0xFFFFFFFF);
+
+ for (blocklist = loop->blocks; blocklist; blocklist = blocklist->next) {
+ for (instr = blocklist->block->firstPCode; instr; instr = instr->nextPCode) {
+ if (
+ instr->op != PC_ADDI ||
+ instr->args[0].data.reg.reg < 32 ||
+ instr->args[0].data.reg.reg >= last_virtual_GPR ||
+ instr->args[1].data.reg.reg != instr->args[0].data.reg.reg
+ ) {
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ op->data.reg.reg >= n_real_registers[RegClass_GPR] &&
+ op->data.reg.reg < last_virtual_GPR
+ )
+ bitvectorclearbit(op->data.reg.reg, inductionvariables);
+ op++;
+ }
+ }
+ }
+ }
+
+ if (loop->parent) {
+ for (instr = loop->preheader->firstPCode; instr; instr = nextInstr) {
+ nextInstr = instr->nextPCode;
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ op->data.reg.reg >= n_real_registers[RegClass_GPR] &&
+ op->data.reg.reg < last_virtual_GPR
+ )
+ bitvectorsetbit(op->data.reg.reg, liveonexit);
+ op++;
+ }
+ }
+ }
+
+ for (blocklist = loop->blocks; blocklist; blocklist = blocklist->next) {
+ for (instr = blocklist->block->firstPCode; instr; instr = nextInstr) {
+ nextInstr = instr->nextPCode;
+ if (
+ instr->op == PC_ADDI &&
+ instr->args[0].data.reg.reg >= 32 &&
+ instr->args[0].data.reg.reg < last_virtual_GPR &&
+ instr->args[1].data.reg.reg == instr->args[0].data.reg.reg &&
+ bitvectorgetbit(instr->args[0].data.reg.reg, inductionvariables) &&
+ !bitvectorgetbit(instr->args[0].data.reg.reg, liveonexit)
+ ) {
+ deletepcode(instr);
+ optimizedloops = 1;
+ }
+ }
+ }
+}
+
+static void skiplooptest(Loop *loop) {
+ PCodeBlock *preheader;
+ PCodeLabel *label;
+ PCLink **ptr;
+ PCLink *link;
+ PCode *lastInstr;
+ PCode *instr;
+
+ preheader = loop->preheader;
+ lastInstr = loop->body->lastPCode;
+ CError_ASSERT(340, lastInstr->args[2].kind == PCOp_LABEL);
+
+ label = lastInstr->args[2].data.label.label;
+ preheader->lastPCode->args[0].data.label.label = label;
+ preheader->successors->block = label->block;
+
+ ptr = &loop->body->predecessors;
+ while ((link = *ptr)) {
+ if (link->block == preheader) {
+ *ptr = link->nextLink;
+ break;
+ }
+ ptr = &link->nextLink;
+ }
+
+ link->nextLink = label->block->predecessors;
+ label->block->predecessors = link;
+
+ while (1) {
+ instr = loop->body->firstPCode;
+ CError_ASSERT(369, instr);
+
+ if (instr->op == PC_CMP || instr->op == PC_CMPI || instr->op == PC_CMPLI || instr->op == PC_CMPL)
+ break;
+
+ deletepcode(instr);
+ insertpcodebefore(loop->preheader->lastPCode, instr);
+ loop->bodySize--;
+ }
+
+ for (instr = instr->nextPCode; instr && !(instr->flags & fIsBranch); instr = instr->nextPCode)
+ insertpcodebefore(loop->preheader->lastPCode, copypcode(instr));
+}
+
+static void unrollloop(Loop *loop) {
+ PCodeBlock *newBlock;
+ int i;
+ int factor;
+ PCode *instr;
+ PCodeBlock *block;
+ PCode *firstInstr;
+ PCode *nextInstr;
+
+ for (factor = copts.unroll_factor_limit; factor > 1; factor--) {
+ if ((loop->iterationCount % factor) == 0 && (loop->bodySize - 2) * factor <= copts.unroll_instr_limit)
+ break;
+ }
+
+ if (factor == 1)
+ return;
+ if ((loop->iterationCount / factor) != 1 && loop->bodySize < 4)
+ return;
+
+ newBlock = oalloc(sizeof(PCodeBlock));
+ newBlock->firstPCode = newBlock->lastPCode = NULL;
+ for (i = 0; i < factor - 1; i++) {
+ firstInstr = loop->body->firstPCode;
+ CError_ASSERT(448, firstInstr);
+ if (firstInstr->op != PC_CMP && firstInstr->op != PC_CMPL && firstInstr->op != PC_CMPI && firstInstr->op != PC_CMPLI)
+ CError_FATAL(450);
+
+ for (instr = firstInstr->nextPCode; instr && !(instr->flags & fIsBranch); instr = instr->nextPCode)
+ appendpcode(newBlock, copypcode(instr));
+
+ for (block = loop->preheader->successors->block; block != loop->body; block = block->successors->block) {
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ if (instr->op != PC_B)
+ appendpcode(newBlock, copypcode(instr));
+ }
+ }
+ }
+
+ block = loop->body->predecessors->block;
+ for (instr = newBlock->firstPCode; instr; instr = nextInstr) {
+ nextInstr = instr->nextPCode;
+ appendpcode(block, instr);
+ }
+ loop->iterationCount /= factor;
+}
+
+void pccomputepredecessors1(PCodeBlock *block) {
+ PCLink *succ;
+ PCLink *pred;
+
+ for (succ = block->successors; succ; succ = succ->nextLink) {
+ if (!succ->block) {
+ CError_FATAL(496);
+ } else {
+ for (pred = succ->block->predecessors; pred; pred = pred->nextLink) {
+ if (pred->block == block)
+ break;
+ }
+
+ if (!pred) {
+ pred = lalloc(sizeof(PCLink));
+ pred->block = block;
+ pred->nextLink = succ->block->predecessors;
+ succ->block->predecessors = pred;
+ }
+ }
+ }
+}
+
+static PCodeBlock *insertnewpcblock(PCodeBlock *block, int loopWeight) {
+ PCodeBlock *newBlock;
+ PCodeBlock *nextBlock;
+ PCodeLabel *label;
+ PCLink *prev;
+ PCLink *link;
+
+ label = makepclabel();
+ newBlock = lalloc(sizeof(PCodeBlock));
+
+ nextBlock = block->nextBlock;
+ newBlock->nextBlock = nextBlock;
+ block->nextBlock = newBlock;
+
+ newBlock->prevBlock = block;
+ nextBlock->prevBlock = newBlock;
+
+ newBlock->labels = NULL;
+ newBlock->predecessors = newBlock->successors = NULL;
+ newBlock->firstPCode = newBlock->lastPCode = NULL;
+ newBlock->pcodeCount = 0;
+ newBlock->loopWeight = loopWeight;
+ newBlock->flags = 0;
+ newBlock->blockIndex = pcblockcount++;
+ pclabel(newBlock, label);
+
+ prev = NULL;
+ for (link = block->successors; link; link = link->nextLink) {
+ if (link->block == nextBlock) {
+ if (!prev)
+ block->successors = link->nextLink;
+ else
+ prev->nextLink = link->nextLink;
+ link->nextLink = NULL;
+ newBlock->successors = link;
+ break;
+ }
+ prev = link;
+ }
+
+ prev = NULL;
+ for (link = nextBlock->predecessors; link; link = link->nextLink) {
+ if (link->block == block) {
+ if (!prev)
+ nextBlock->predecessors = link->nextLink;
+ else
+ prev->nextLink = link->nextLink;
+ link->nextLink = NULL;
+ newBlock->predecessors = link;
+ break;
+ }
+ prev = link;
+ }
+
+ link = lalloc(sizeof(PCLink));
+ link->block = newBlock;
+ link->nextLink = block->successors;
+ block->successors = link;
+
+ link = lalloc(sizeof(PCLink));
+ link->block = newBlock;
+ link->nextLink = nextBlock->predecessors;
+ nextBlock->predecessors = link;
+
+ return newBlock;
+}
+
+static void unrollloopconditional(Loop *loop) {
+ PCodeBlock *lastBlock;
+ PCodeLabel *label24;
+ PCode *instr;
+ PCode *instrCopy;
+ int outputBlockCount;
+ int inputBlockCount;
+ PCodeBlock **blocks;
+ PCodeBlock **blocks2;
+ PCodeBlock **blocks3;
+ PCode *firstInstr;
+ int factor;
+ PCodeBlock *block;
+ PCLink *link;
+ PCLink *prev;
+ int i;
+ int j;
+ int k;
+ int instructionCount;
+
+ label24 = NULL;
+ outputBlockCount = 0;
+ instructionCount = 0;
+
+ for (factor = copts.unroll_factor_limit; factor > 1; factor--) {
+ if ((loop->iterationCount % factor) == 0 && (loop->bodySize - 2) * factor <= copts.unroll_instr_limit)
+ break;
+ }
+
+ if (factor == 1)
+ return;
+
+ inputBlockCount = 0;
+ for (block = loop->preheader->successors->block; block != loop->body; block = block->nextBlock) {
+ inputBlockCount++;
+ if (!bitvectorgetbit(block->blockIndex, loop->memberblocks))
+ instructionCount += block->pcodeCount;
+ }
+
+ if ((loop->bodySize - instructionCount - 2) < instructionCount || instructionCount > 8)
+ return;
+
+ blocks = oalloc(inputBlockCount * sizeof(PCodeBlock *));
+ blocks2 = oalloc(inputBlockCount * sizeof(PCodeBlock *));
+ blocks3 = oalloc(factor * (inputBlockCount * sizeof(PCodeBlock *)));
+ memclrw(blocks, inputBlockCount * sizeof(PCodeBlock *));
+ memclrw(blocks2, inputBlockCount * sizeof(PCodeBlock *));
+ memclrw(blocks3, factor * (inputBlockCount * sizeof(PCodeBlock *)));
+
+ block = loop->preheader->nextBlock;
+ for (i = 0; i < inputBlockCount; i++) {
+ blocks[i] = block;
+ block = block->nextBlock;
+ }
+
+ lastBlock = blocks[inputBlockCount - 1];
+ for (i = 0; i < factor - 1; i++) {
+ for (j = 0; j < inputBlockCount; j++) {
+ blocks2[j] = insertnewpcblock(lastBlock, loop->loopWeight);
+ blocks3[outputBlockCount++] = blocks2[j];
+ lastBlock = blocks2[j];
+ }
+ if (label24) {
+ pclabel(blocks2[0], label24);
+ label24 = NULL;
+ }
+
+ for (j = 0; j < inputBlockCount; j++) {
+ for (instr = blocks[j]->firstPCode; instr; instr = instr->nextPCode) {
+ if (instr->flags & fIsBranch) {
+ PCodeArg *op;
+ int opID;
+ instrCopy = copypcode(instr);
+ op = NULL;
+ for (opID = 0; opID < instr->argCount; opID++) {
+ if (instr->args[opID].kind == PCOp_LABEL) {
+ op = &instr->args[opID];
+ break;
+ }
+ }
+
+ if (op) {
+ if (op->data.label.label->block == loop->body) {
+ if (!label24)
+ label24 = makepclabel();
+ instrCopy->args[opID].data.label.label = label24;
+ } else {
+ for (k = 0; k < inputBlockCount; k++) {
+ if (op->data.label.label->block == blocks[k]) {
+ instrCopy->args[opID].data.label.label = blocks2[k]->labels;
+ break;
+ }
+ }
+ }
+ }
+
+ appendpcode(blocks2[j], instrCopy);
+ if (op)
+ pcbranch(blocks2[j], instrCopy->args[opID].data.label.label);
+ } else {
+ appendpcode(blocks2[j], copypcode(instr));
+ }
+ }
+ }
+
+ firstInstr = loop->body->firstPCode;
+ CError_ASSERT(762, firstInstr != NULL);
+ if (firstInstr->op != PC_CMP && firstInstr->op != PC_CMPL && firstInstr->op != PC_CMPI && firstInstr->op != PC_CMPLI)
+ CError_FATAL(764);
+
+ for (instr = firstInstr->nextPCode; instr && !(instr->flags & fIsBranch); instr = instr->nextPCode)
+ appendpcode(blocks2[inputBlockCount - 1], copypcode(instr));
+
+ for (j = 0; j < inputBlockCount; j++) {
+ for (link = blocks[j]->successors; link; link = link->nextLink) {
+ if (link->block == blocks[j]->nextBlock)
+ break;
+ }
+
+ if (!link) {
+ for (link = blocks2[j]->successors, prev = NULL; link; link = link->nextLink) {
+ if (link->block == blocks2[j]->nextBlock) {
+ if (prev)
+ prev->nextLink = link->nextLink;
+ else
+ blocks2[j]->successors = link->nextLink;
+ } else {
+ prev = link;
+ }
+ }
+
+ for (link = blocks2[j]->nextBlock->predecessors, prev = NULL; link; link = link->nextLink) {
+ if (link->block == blocks2[j]) {
+ if (prev)
+ prev->nextLink = link->nextLink;
+ else
+ blocks2[j]->nextBlock->predecessors = link->nextLink;
+ } else {
+ prev = link;
+ }
+ }
+ }
+ }
+ }
+
+ if (label24)
+ pclabel(loop->body, label24);
+
+ for (i = 0; i < inputBlockCount; i++) {
+ for (instr = blocks[i]->firstPCode; instr; instr = instr->nextPCode) {
+ if (instr->flags & fIsBranch) {
+ PCodeArg *op;
+ int opID;
+ op = NULL;
+ for (opID = 0; opID < instr->argCount; opID++) {
+ if (instr->args[opID].kind == PCOp_LABEL) {
+ op = &instr->args[opID];
+ break;
+ }
+ }
+
+ if (op && op->data.label.label->block == loop->body) {
+ instr->args[opID].data.label.label = blocks3[0]->labels;
+
+ for (link = blocks[i]->successors, prev = NULL; link; link = link->nextLink) {
+ if (link->block == loop->body) {
+ if (prev)
+ prev->nextLink = link->nextLink;
+ else
+ blocks[i]->successors = link->nextLink;
+ } else {
+ prev = link;
+ }
+ }
+
+ for (link = loop->body->predecessors, prev = NULL; link; link = link->nextLink) {
+ if (link->block == blocks[i]) {
+ if (prev)
+ prev->nextLink = link->nextLink;
+ else
+ loop->body->predecessors = link->nextLink;
+ } else {
+ prev = link;
+ }
+ }
+
+ link = blocks[i]->successors;
+ while (link && link->block != blocks3[0])
+ link = link->nextLink;
+
+ if (!link) {
+ pcbranch(blocks[i], op->data.label.label);
+ pccomputepredecessors1(blocks[i]);
+ }
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < outputBlockCount; i++)
+ pccomputepredecessors1(blocks3[i]);
+
+ loop->iterationCount /= factor;
+}
+
+static void unrollunknownBDNZ(Loop *loop) {
+ int factor; // r29
+ PCodeBlock *preheader; // r17
+ PCodeBlock *blockA; // r23
+ PCodeBlock *postheader; // r22
+ PCodeBlock *newblock1; // r26
+ PCodeBlock *newblock2; // r31
+ PCodeBlock *newblock3; // r19
+ PCodeBlock *newblock4; // r20
+ PCodeBlock *newblock5; // r24
+ PCode *mtctr; // r21
+ int mtctr_reg; // r27
+ PCode *instr28; // r28
+ PCode *instr6; // r6
+ PCodeBlock *block;
+ PCode *instr;
+ PCodeArg *op;
+ int i;
+ int val;
+ short mtctr_shifted_reg; // r16
+ short reg25; // r25
+ PCLink *link;
+
+ if (loop->bodySize < 4)
+ return;
+
+ factor = 128;
+ while (factor > copts.unroll_factor_limit)
+ factor >>= 1;
+ while (factor > 1 && (loop->bodySize - 2) * factor > copts.unroll_instr_limit)
+ factor >>= 1;
+
+ if (factor < 2)
+ return;
+
+ preheader = loop->preheader;
+ blockA = loop->body->nextBlock;
+ postheader = preheader->nextBlock;
+
+ newblock1 = insertnewpcblock(preheader, loop->loopWeight);
+ newblock2 = insertnewpcblock(newblock1, loop->loopWeight);
+ newblock3 = insertnewpcblock(newblock2, loop->loopWeight);
+ newblock4 = insertnewpcblock(newblock3, loop->loopWeight);
+ newblock5 = insertnewpcblock(newblock4, loop->loopWeight);
+ addblocktoloop(loop, newblock1);
+ addblocktoloop(loop, newblock2);
+ addblocktoloop(loop, newblock3);
+ addblocktoloop(loop, newblock4);
+ addblocktoloop(loop, newblock5);
+
+ for (instr = preheader->lastPCode; instr; instr = instr->prevPCode) {
+ if (instr->op == PC_MTCTR) {
+ mtctr = instr;
+ mtctr_reg = instr->args[0].data.reg.reg;
+ }
+ }
+
+ if (!mtctr)
+ return;
+
+ instr28 = NULL;
+ for (block = postheader; block != loop->body; block = block->successors->block) {
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ if (instr->op != PC_B) {
+ appendpcode(newblock2, copypcode(instr));
+ if (instr == loop->pc18)
+ instr28 = newblock2->lastPCode;
+ }
+ }
+ }
+
+ if (!instr28) {
+ appendpcode(newblock2, copypcode(loop->pc18));
+ instr28 = newblock2->lastPCode;
+ }
+
+ instr6 = NULL;
+ for (instr = newblock2->firstPCode; instr; instr = instr->nextPCode) {
+ if (instr != instr28) {
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ op->data.reg.reg == loop->pc18->args[0].data.reg.reg &&
+ (op->data.reg.effect & (EffectRead | EffectWrite))
+ ) {
+ instr6 = instr;
+ break;
+ }
+ op++;
+ }
+ }
+ if (instr6)
+ break;
+ }
+
+ if (!instr6) {
+ deletepcode(instr28);
+ deletepcode(loop->pc18);
+ if (loop->footer)
+ blockA = loop->footer;
+ else
+ blockA = insertnewpcblock(loop->body, loop->loopWeight);
+ } else {
+ instr28 = NULL;
+ }
+
+ for (i = 1; i < factor; i++) {
+ for (block = postheader; block != loop->body; block = block->successors->block) {
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ if (instr->op != PC_B)
+ appendpcode(newblock2, copypcode(instr));
+ }
+ }
+ }
+
+ mtctr_shifted_reg = used_virtual_registers[RegClass_GPR]++;
+ appendpcode(newblock1, makepcode(
+ PC_RLWINM,
+ mtctr_shifted_reg,
+ mtctr_reg,
+ 32 - ispowerof2(factor),
+ ispowerof2(factor),
+ 31));
+
+ appendpcode(newblock1, makepcode(PC_CMPLI, 0, mtctr_shifted_reg, 0));
+
+ if (instr28) {
+ reg25 = used_virtual_registers[RegClass_GPR]++;
+ if (loop->step == 1) {
+ instr = makepcode(PC_MR, reg25, mtctr_reg);
+ } else if (loop->step == -1) {
+ instr = makepcode(PC_NEG, reg25, mtctr_reg);
+ } else {
+ val = ispowerof2(abs(loop->step));
+ if (val > 0) {
+ instr = makepcode(PC_RLWINM, reg25, mtctr_reg, val, 0, 31 - val);
+ if (loop->step < 0) {
+ appendpcode(newblock1, instr);
+ instr = makepcode(PC_NEG, reg25, reg25);
+ }
+ } else {
+ instr = makepcode(PC_MULLI, reg25, mtctr_reg, loop->step);
+ }
+ }
+ appendpcode(newblock1, instr);
+ }
+
+ appendpcode(newblock1, makepcode(PC_MTCTR, mtctr_shifted_reg));
+ appendpcode(newblock1, makepcode(PC_BT, 0, 2, newblock5->labels));
+ pcbranch(newblock1, newblock5->labels);
+
+ link = lalloc(sizeof(PCLink));
+ link->block = newblock1;
+ link->nextLink = newblock5->predecessors;
+ newblock5->predecessors = link;
+
+ appendpcode(newblock3, makepcode(PC_BDNZ, newblock2->labels));
+ pcbranch(newblock3, newblock2->labels);
+
+ link = lalloc(sizeof(PCLink));
+ link->block = newblock3;
+ link->nextLink = newblock2->predecessors;
+ newblock2->predecessors = link;
+
+ appendpcode(newblock4, makepcode(PC_ANDI, mtctr_reg, mtctr_reg, factor - 1));
+ appendpcode(newblock4, makepcode(PC_BT, 0, 2, blockA->labels));
+ pcbranch(newblock4, blockA->labels);
+
+ link = lalloc(sizeof(PCLink));
+ link->block = newblock4;
+ link->nextLink = blockA->predecessors;
+ blockA->predecessors = link;
+
+ deletepcode(mtctr);
+ appendpcode(newblock5, mtctr);
+
+ if (instr28 && bitvectorgetbit(instr28->args[0].data.reg.reg, liveonexit)) {
+ instr = makepcode(PC_ADD, instr28->args[0].data.reg.reg, instr28->args[0].data.reg.reg, reg25);
+ if (blockA->firstPCode)
+ insertpcodebefore(blockA->firstPCode, instr);
+ else
+ appendpcode(blockA, instr);
+ }
+}
+
+static void deleteloop(Loop *loop) {
+ PCodeBlock *body;
+ PCodeBlock *preheader;
+ PCodeBlock *nextblock;
+ PCodeLabel *label;
+ PCode *instr;
+ PCLink **ptr;
+ PCLink *link;
+ PCodeBlock *block;
+
+ body = loop->body;
+ preheader = loop->preheader;
+ nextblock = body->nextBlock;
+ label = makepclabel();
+
+ while (1) {
+ instr = body->firstPCode;
+ CError_ASSERT(1294, instr != NULL);
+
+ if (instr->op == PC_CMP || instr->op == PC_CMPI || instr->op == PC_CMPLI || instr->op == PC_CMPL)
+ break;
+
+ deletepcode(instr);
+ insertpcodebefore(loop->preheader->lastPCode, instr);
+ loop->bodySize--;
+ }
+
+ pclabel(nextblock, label);
+ preheader->lastPCode->args[0].data.label.label = label;
+ preheader->successors->block = nextblock;
+
+ ptr = &nextblock->predecessors;
+ while ((link = *ptr)) {
+ if (link->block == body) {
+ link->block = preheader;
+ break;
+ }
+ ptr = &link->nextLink;
+ }
+
+ block = pcbasicblocks;
+ while ((nextblock = block->nextBlock)) {
+ if (bitvectorgetbit(nextblock->blockIndex, loop->memberblocks))
+ block->nextBlock = nextblock->nextBlock;
+ else
+ block = nextblock;
+ }
+}
+
+static void deleteloopheader(Loop *loop) {
+ PCLink *link;
+ PCLink **ptr;
+
+ ptr = &loop->body->successors;
+ while ((link = *ptr)) {
+ if (link->block == loop->body->lastPCode->args[2].data.label.label->block) {
+ *ptr = link->nextLink;
+ break;
+ }
+ ptr = &link->nextLink;
+ }
+
+ ptr = &loop->body->lastPCode->args[2].data.label.label->block->predecessors;
+ while ((link = *ptr)) {
+ if (link->block == loop->body) {
+ *ptr = link->nextLink;
+ break;
+ }
+ ptr = &link->nextLink;
+ }
+
+ deletepcode(loop->body->firstPCode);
+ deletepcode(loop->body->lastPCode);
+ optimizedloop_full_unroll = 1;
+}
+
+static void rewriteloopwithBDNZ(Loop *loop) {
+ PCode *instr;
+
+ if (!FITS_IN_SHORT(loop->iterationCount)) {
+ instr = makepcode(PC_LIS, used_virtual_registers[RegClass_GPR]++, 0, HIGH_PART(loop->iterationCount));
+ insertpcodebefore(loop->preheader->lastPCode, instr);
+
+ if (loop->iterationCount != 0)
+ insertpcodeafter(instr, makepcode(PC_ADDI, instr->args[0].data.reg.reg, instr->args[0].data.reg.reg, 0, LOW_PART(loop->iterationCount)));
+ } else {
+ instr = makepcode(PC_LI, used_virtual_registers[RegClass_GPR]++, loop->iterationCount);
+ insertpcodebefore(loop->preheader->lastPCode, instr);
+ }
+
+ insertpcodebefore(loop->preheader->lastPCode, makepcode(PC_MTCTR, instr->args[0].data.reg.reg));
+
+ instr = makepcode(PC_BDNZ, loop->body->lastPCode->args[2].data.label.label);
+ deletepcode(loop->body->firstPCode);
+ deletepcode(loop->body->lastPCode);
+ appendpcode(loop->body, instr);
+
+ for (loop = loop->parent; loop; loop = loop->parent)
+ loop->x4E = 1;
+}
+
+static void rewriteunknownloopwithBDNZ(Loop *loop) {
+ SInt32 value1; // r24
+ SInt32 value2; // r30
+ Opcode branchOpcode; // r19
+ SInt32 absStep; // r28
+ int branchCondition; // r20
+ int counterReg; // r27
+ int reg1; // r26
+ int reg2; // r22
+ unsigned char mode; // r23
+ PCodeBlock *afterLoop; // r25
+ PCode *addiInstr;
+ PCode *instr;
+ PCLink *link;
+ PCLink **ptr;
+
+ absStep = abs(loop->step);
+ afterLoop = NULL;
+
+ for (addiInstr = loop->body->lastPCode->prevPCode; addiInstr->op == PC_ADDI; addiInstr = loop->body->lastPCode->prevPCode) {
+ deletepcode(addiInstr);
+ if (loop->body->lastPCode->args[2].data.label.label->block->firstPCode)
+ insertpcodebefore(loop->body->lastPCode->args[2].data.label.label->block->firstPCode, addiInstr);
+ else
+ appendpcode(loop->body->lastPCode->args[2].data.label.label->block, addiInstr);
+
+ afterLoop = insertnewpcblock(loop->body, loop->loopWeight);
+ appendpcode(afterLoop, copypcode(addiInstr));
+ loop->footer = afterLoop;
+ }
+
+ if (loop->unknownCondition == ELESS) {
+ branchOpcode = PC_BF;
+ if (loop->lowerType == LOOP_BOUND_CONSTANT) {
+ branchCondition = 1; // GT
+ value1 = loop->lower;
+ reg1 = addiInstr->args[2].data.reg.reg;
+ value2 = absStep - 1 - loop->lower;
+ mode = 0;
+ } else if (loop->upperType == LOOP_BOUND_CONSTANT) {
+ branchCondition = 0; // LT
+ value1 = loop->upper;
+ reg1 = addiInstr->args[1].data.reg.reg;
+ value2 = absStep - 1 + loop->upper;
+ mode = 1;
+ } else {
+ branchCondition = 0; // LT
+ reg1 = addiInstr->args[1].data.reg.reg;
+ reg2 = addiInstr->args[2].data.reg.reg;
+ value2 = absStep - 1;
+ mode = 2;
+ }
+ } else if (loop->unknownCondition == ELESSEQU) {
+ branchOpcode = PC_BT;
+ if (loop->lowerType == LOOP_BOUND_CONSTANT) {
+ branchCondition = 0; // LT
+ value1 = loop->lower;
+ reg1 = addiInstr->args[2].data.reg.reg;
+ value2 = absStep - loop->lower;
+ mode = 0;
+ } else if (loop->upperType == LOOP_BOUND_CONSTANT) {
+ branchCondition = 1; // GT
+ value1 = loop->upper;
+ reg1 = addiInstr->args[1].data.reg.reg;
+ value2 = absStep + loop->upper;
+ mode = 1;
+ } else {
+ branchCondition = 1; // GT
+ value1 = 0;
+ reg1 = addiInstr->args[1].data.reg.reg;
+ reg2 = addiInstr->args[2].data.reg.reg;
+ value2 = absStep;
+ mode = 2;
+ }
+ } else if (loop->unknownCondition == EGREATER) {
+ branchOpcode = PC_BF;
+ if (loop->lowerType == LOOP_BOUND_CONSTANT) {
+ branchCondition = 0; // LT
+ value1 = loop->lower;
+ reg1 = addiInstr->args[2].data.reg.reg;
+ value2 = absStep - 1 + loop->lower;
+ mode = 1;
+ } else if (loop->upperType == LOOP_BOUND_CONSTANT) {
+ branchCondition = 1; // GT
+ value1 = loop->upper;
+ reg1 = addiInstr->args[1].data.reg.reg;
+ value2 = absStep - 1 - loop->upper;
+ mode = 0;
+ } else {
+ branchCondition = 1; // GT
+ value1 = 0;
+ reg1 = addiInstr->args[1].data.reg.reg;
+ reg2 = addiInstr->args[2].data.reg.reg;
+ value2 = absStep - 1;
+ mode = 3;
+ }
+ } else if (loop->unknownCondition == EGREATEREQU) {
+ branchOpcode = PC_BT;
+ if (loop->lowerType == LOOP_BOUND_CONSTANT) {
+ branchCondition = 1; // GT
+ value1 = loop->lower;
+ reg1 = addiInstr->args[2].data.reg.reg;
+ value2 = absStep + loop->lower;
+ mode = 1;
+ } else if (loop->upperType == LOOP_BOUND_CONSTANT) {
+ branchCondition = 0; // LT
+ value1 = loop->upper;
+ reg1 = addiInstr->args[1].data.reg.reg;
+ value2 = absStep - loop->upper;
+ mode = 0;
+ } else {
+ branchCondition = 0; // LT
+ reg1 = addiInstr->args[1].data.reg.reg;
+ reg2 = addiInstr->args[2].data.reg.reg;
+ value2 = absStep;
+ mode = 3;
+ }
+ } else if (loop->unknownCondition == ENOTEQU) {
+ branchOpcode = PC_BT;
+ branchCondition = 2; // EQ
+ if (loop->step > 0) {
+ if (loop->lowerType == LOOP_BOUND_CONSTANT) {
+ value1 = loop->lower;
+ reg1 = addiInstr->args[2].data.reg.reg;
+ value2 = absStep - 1 - loop->lower;
+ mode = 0;
+ } else if (loop->upperType == LOOP_BOUND_CONSTANT) {
+ value1 = loop->upper;
+ reg1 = addiInstr->args[1].data.reg.reg;
+ value2 = absStep - 1 + loop->upper;
+ mode = 1;
+ } else {
+ reg1 = addiInstr->args[1].data.reg.reg;
+ reg2 = addiInstr->args[2].data.reg.reg;
+ value2 = absStep - 1;
+ mode = 2;
+ }
+ } else {
+ if (loop->lowerType == LOOP_BOUND_CONSTANT) {
+ value1 = loop->lower;
+ reg1 = addiInstr->args[2].data.reg.reg;
+ value2 = absStep - 1 + loop->lower;
+ mode = 1;
+ } else if (loop->upperType == LOOP_BOUND_CONSTANT) {
+ value1 = loop->upper;
+ reg1 = addiInstr->args[1].data.reg.reg;
+ value2 = absStep - 1 - loop->upper;
+ mode = 0;
+ } else {
+ reg1 = addiInstr->args[1].data.reg.reg;
+ reg2 = addiInstr->args[2].data.reg.reg;
+ value2 = absStep - 1;
+ mode = 3;
+ }
+ }
+ }
+
+ while (1) {
+ instr = loop->body->firstPCode;
+ CError_ASSERT(1857, instr);
+
+ if (instr->op == PC_CMP || instr->op == PC_CMPI || instr->op == PC_CMPLI || instr->op == PC_CMPL)
+ break;
+
+ deletepcode(instr);
+ insertpcodebefore(loop->preheader->lastPCode, instr);
+ loop->bodySize--;
+ }
+
+ // build a value for mtctr
+ counterReg = used_virtual_registers[RegClass_GPR]++;
+
+ if (mode == 1) {
+ if (value2 == 0) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_NEG, counterReg, reg1));
+ } else if (FITS_IN_SHORT(value2)) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_SUBFIC, counterReg, reg1, value2));
+ } else {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_LIS, counterReg, 0, HIGH_PART(value2)));
+ if (value2 != 0) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_ADDI, counterReg, counterReg, 0, LOW_PART(value2)));
+ }
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_SUBF, counterReg, reg1, counterReg));
+ }
+ } else if (mode == 0) {
+ if (value2 == 0) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_MR, counterReg, reg1));
+ } else if (FITS_IN_SHORT(value2)) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_ADDI, counterReg, reg1, 0, value2));
+ } else {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_ADDIS, counterReg, reg1, 0, HIGH_PART(value2)));
+ if (value2 != 0) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_ADDI, counterReg, counterReg, 0, LOW_PART(value2)));
+ }
+ }
+ } else if (mode == 2) {
+ if (value2 == 0) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_SUBF, counterReg, reg1, reg2));
+ } else if (FITS_IN_SHORT(value2)) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_ADDI, counterReg, reg2, 0, value2));
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_SUBF, counterReg, reg1, counterReg));
+ } else {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_ADDIS, counterReg, reg2, 0, HIGH_PART(value2)));
+ if (value2 != 0) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_ADDI, counterReg, counterReg, 0, LOW_PART(value2)));
+ }
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_SUBF, counterReg, reg1, counterReg));
+ }
+ } else {
+ if (value2 == 0) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_SUBF, counterReg, reg2, reg1));
+ } else {
+ if (FITS_IN_SHORT(value2)) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_ADDI, counterReg, reg1, 0, value2));
+ } else {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_ADDIS, counterReg, reg1, 0, HIGH_PART(value2)));
+ if (value2 != 0) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_ADDI, counterReg, counterReg, 0, LOW_PART(value2)));
+ }
+ }
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_SUBF, counterReg, reg2, counterReg));
+ }
+ }
+
+ if (absStep > 1) {
+ unsigned char bits;
+ if ((bits = ispowerof2(absStep))) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_RLWINM, counterReg, counterReg, 32 - bits, bits, 31));
+ } else {
+ int reg = used_virtual_registers[RegClass_GPR]++;
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_LI, reg, absStep));
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_DIVWU, counterReg, counterReg, reg));
+ }
+ }
+
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_MTCTR, counterReg));
+
+ if (mode < 2) {
+ if (addiInstr->op == PC_CMPL || addiInstr->op == PC_CMPLI) {
+ if (FITS_IN_USHORT(value1)) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_CMPLI, 0, reg1, value1));
+ } else {
+ PCode *tmp;
+ tmp = makepcode(PC_LIS, used_virtual_registers[RegClass_GPR]++, 0, HIGH_PART(value1));
+ insertpcodebefore(loop->preheader->lastPCode, tmp);
+
+ if (loop->iterationCount != 0)
+ insertpcodeafter(tmp,
+ makepcode(PC_ADDI,
+ tmp->args[0].data.reg.reg,
+ tmp->args[0].data.reg.reg,
+ 0, LOW_PART(value1)));
+
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_CMPL, 0, reg1, tmp->args[0].data.reg.reg));
+ }
+ } else {
+ if (FITS_IN_SHORT(value1)) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_CMPI, 0, reg1, value1));
+ } else {
+ PCode *tmp;
+ tmp = makepcode(PC_LIS, used_virtual_registers[RegClass_GPR]++, 0, HIGH_PART(value1));
+ insertpcodebefore(loop->preheader->lastPCode, tmp);
+
+ if (loop->iterationCount != 0)
+ insertpcodeafter(tmp,
+ makepcode(PC_ADDI,
+ tmp->args[0].data.reg.reg,
+ tmp->args[0].data.reg.reg,
+ 0, LOW_PART(value1)));
+
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_CMP, 0, reg1, tmp->args[0].data.reg.reg));
+ }
+ }
+ } else {
+ if (addiInstr->op == PC_CMPL || addiInstr->op == PC_CMPLI) {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_CMPL, 0, reg1, reg2));
+ } else {
+ insertpcodebefore(loop->preheader->lastPCode,
+ makepcode(PC_CMP, 0, reg1, reg2));
+ }
+ }
+
+ if (!afterLoop)
+ afterLoop = loop->body->nextBlock;
+
+ instr = makepcode(branchOpcode, 0, branchCondition, afterLoop->labels);
+ deletepcode(loop->preheader->lastPCode);
+ appendpcode(loop->preheader, instr);
+
+ instr = makepcode(PC_BDNZ, loop->body->lastPCode->args[2].data.label.label);
+ deletepcode(loop->body->firstPCode);
+ deletepcode(loop->body->lastPCode);
+ appendpcode(loop->body, instr);
+
+ loop->preheader->successors = NULL;
+ ptr = &loop->body->predecessors;
+ while ((link = *ptr)) {
+ if (link->block == loop->preheader) {
+ *ptr = link->nextLink;
+ break;
+ }
+ ptr = &link->nextLink;
+ }
+
+ link = lalloc(sizeof(PCLink));
+ link->block = loop->preheader->nextBlock;
+ link->nextLink = loop->preheader->successors;
+ loop->preheader->successors = link;
+
+ link = lalloc(sizeof(PCLink));
+ link->block = loop->preheader;
+ link->nextLink = loop->preheader->nextBlock->predecessors;
+ loop->preheader->nextBlock->predecessors = link;
+
+ link = lalloc(sizeof(PCLink));
+ link->block = afterLoop;
+ link->nextLink = loop->preheader->successors;
+ loop->preheader->successors = link;
+
+ link = lalloc(sizeof(PCLink));
+ link->block = loop->preheader;
+ link->nextLink = afterLoop->predecessors;
+ afterLoop->predecessors = link;
+
+ for (loop = loop->parent; loop; loop = loop->parent)
+ loop->x4E = 1;
+}
+
+static void optimizeloop(Loop *loop) {
+ computeliveonexit(loop);
+
+ if (loop->x53 || loop->x54)
+ insertupdateinstructions(loop);
+
+ if (loop->isKnownCountingLoop) {
+ if (loop->iterationCount > 0) {
+ skiplooptest(loop);
+ if (!copts.optimizesize && !loop->x4D && !loop->x57) {
+ if (loop->x4F)
+ unrollloop(loop);
+ else if (!loop->x4E)
+ unrollloopconditional(loop);
+ }
+ }
+
+ if (loop->iterationCount != 0) {
+ if (loop->iterationCount == 1)
+ deleteloopheader(loop);
+ else if (!loop->x4E && !loop->x4D)
+ rewriteloopwithBDNZ(loop);
+ }
+
+ optimizedloops = 1;
+ } else if (loop->isUnknownCountingLoop && !loop->x4E && !loop->x4D) {
+ rewriteunknownloopwithBDNZ(loop);
+ if (copts.unroll_speculative && !copts.optimizesize) {
+ if (loop->x4F && !loop->x57 && !loop->x52)
+ unrollunknownBDNZ(loop);
+ }
+ optimizedloops = 1;
+ }
+
+ eliminateinductionvariables(loop);
+}
+
+typedef struct LocalArray {
+ struct LocalArray *next;
+ Object *object;
+ unsigned int invalid:1;
+ unsigned int isFloat:1;
+ unsigned int isSigned:1;
+ SInt32 elementSize;
+ SInt32 arraySize;
+ SInt32 elementCount;
+ int totalUses;
+ int elements[1];
+} LocalArray;
+
+static LocalArray *scanforlocalarrays(void) {
+ SInt32 elementCount;
+ LocalArray *head;
+ LocalArray *array;
+ ObjectList *list;
+ int i;
+ SInt32 arraySize;
+ SInt32 elementSize;
+
+ head = NULL;
+
+ for (list = locals; list; list = list->next) {
+ if (
+ list->object &&
+ !(IS_TYPE_POINTER(list->object->type) ? (TPTR_QUAL(list->object->type) & Q_VOLATILE) : (list->object->qual & Q_VOLATILE)) &&
+ list->object->type &&
+ IS_TYPE_ARRAY(list->object->type) &&
+ TPTR_TARGET(list->object->type) &&
+ TPTR_TARGET(list->object->type)->type < TYPESTRUCT
+ ) {
+ arraySize = list->object->type->size;
+ elementSize = TPTR_TARGET(list->object->type)->size;
+ elementCount = arraySize / elementSize;
+ if (elementCount > 0 && elementCount <= 8) {
+ array = oalloc(sizeof(int) * (elementCount - 1) + sizeof(LocalArray));
+ array->next = head;
+ head = array;
+
+ array->object = list->object;
+ array->elementSize = elementSize;
+ array->arraySize = arraySize;
+ array->elementCount = elementCount;
+ array->totalUses = 0;
+ array->isSigned = 1;
+ array->isFloat = IS_TYPE_FLOAT(TPTR_TARGET(list->object->type));
+ array->invalid = 0;
+ array->isSigned = 1;
+ if (!array->isFloat && is_unsigned(TPTR_TARGET(list->object->type)))
+ array->isSigned = 0;
+
+ for (i = 0; i < elementCount; i++) {
+ array->elements[i] = 0;
+ }
+ }
+ }
+ }
+
+ return head;
+}
+
+static LocalArray *lookup_array_object(LocalArray *arrays, Object *object) {
+ while (arrays) {
+ if (arrays->object == object)
+ return arrays;
+ arrays = arrays->next;
+ }
+ return NULL;
+}
+
+void changearraytoregisters(void) {
+ LocalArray *arrays;
+ PCodeBlock *block;
+ PCode *instr;
+ int i;
+ PCodeArg *op;
+ LocalArray **ptr;
+ LocalArray *array;
+ int intCounter;
+ int floatCounter;
+ int reg;
+ int reg2;
+ PCode *newInstr;
+
+ arrays = NULL;
+ if ((arrays = scanforlocalarrays())) {
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ if (!(instr->flags & fIsBranch) && instr->argCount) {
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (
+ op->kind == PCOp_MEMORY &&
+ (PCOpMemoryArg) op->arg == PCOpMemory1 &&
+ (array = lookup_array_object(arrays, op->data.mem.obj)) &&
+ !array->invalid
+ ) {
+ if (
+ (instr->flags & (fIsRead | fIsWrite)) &&
+ (op->data.mem.offset % array->elementSize) == 0 &&
+ op->data.mem.offset < array->arraySize
+ ) {
+ switch (instr->op) {
+ case PC_LBZ:
+ case PC_STB:
+ if (array->elementSize != 1)
+ array->invalid = 1;
+ break;
+ case PC_LHZ:
+ case PC_LHA:
+ case PC_STH:
+ if (array->elementSize != 2)
+ array->invalid = 1;
+ break;
+ case PC_LWZ:
+ case PC_STW:
+ if (array->elementSize != 4)
+ array->invalid = 1;
+ break;
+ case PC_LFD:
+ case PC_STFD:
+ if (array->elementSize != 8)
+ array->invalid = 1;
+ break;
+ default:
+ array->invalid = 1;
+ break;
+ }
+
+ if (!array->invalid)
+ array->elements[op->data.mem.offset / array->elementSize]++;
+ } else {
+ array->invalid = 1;
+ }
+ }
+ op++;
+ }
+ }
+ }
+ }
+
+ intCounter = 0;
+ floatCounter = 0;
+ ptr = &arrays;
+ array = *ptr;
+ while (array) {
+ if (array->invalid) {
+ *ptr = array = array->next;
+ continue;
+ }
+
+ if (array->isFloat)
+ floatCounter += array->elementCount;
+ if (!array->isFloat)
+ intCounter += array->elementCount;
+
+ for (i = 0; i < array->elementCount; i++)
+ array->totalUses += array->elements[i];
+
+ array = array->next;
+ }
+
+ if (arrays) {
+ while (intCounter > 8) {
+ LocalArray *best;
+ int score;
+ score = 0;
+ best = NULL;
+ for (array = arrays; array; array = array->next) {
+ if (!array->isFloat) {
+ if (best) {
+ if (array->totalUses < score) {
+ score = array->totalUses;
+ best = array;
+ }
+ } else {
+ best = array;
+ score = array->totalUses;
+ }
+ }
+ }
+
+ if (!best)
+ break;
+
+ if (best == arrays) {
+ arrays = best->next;
+ } else {
+ for (array = arrays; array; array = array->next) {
+ if (array->next == best) {
+ array->next = best->next;
+ break;
+ }
+ }
+ }
+
+ intCounter -= best->elementCount;
+ }
+
+ while (floatCounter > 8) {
+ LocalArray *best;
+ int score;
+ score = 0;
+ best = NULL;
+ for (array = arrays; array; array = array->next) {
+ if (array->isFloat) {
+ if (best) {
+ if (array->totalUses < score) {
+ score = array->totalUses;
+ best = array;
+ }
+ } else {
+ best = array;
+ score = array->totalUses;
+ }
+ }
+ }
+
+ if (!best)
+ break;
+
+ if (best == arrays) {
+ arrays = best->next;
+ } else {
+ for (array = arrays; array; array = array->next) {
+ if (array->next == best) {
+ array->next = best->next;
+ break;
+ }
+ }
+ }
+
+ floatCounter -= best->elementCount;
+ }
+
+ CError_ASSERT(2394, intCounter <= 8 && floatCounter <= 8);
+
+ if (!arrays)
+ return;
+
+ optimizedloop_trans_regs = 1;
+
+ for (array = arrays; array; array = array->next) {
+ for (i = 0; i < array->elementCount; i++) {
+ if (array->isFloat)
+ array->elements[i] = used_virtual_registers[RegClass_FPR]++;
+ else
+ array->elements[i] = used_virtual_registers[RegClass_GPR]++;
+ }
+ }
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ if (
+ !(instr->flags & fIsBranch) &&
+ instr->argCount &&
+ (instr->flags & (fIsRead | fIsWrite)) &&
+ instr->args[2].kind == PCOp_MEMORY &&
+ (PCOpMemoryArg) instr->args[2].arg == PCOpMemory1 &&
+ (array = lookup_array_object(arrays, instr->args[2].data.mem.obj)) &&
+ !(array->invalid)
+ )
+ {
+ reg2 = instr->args[0].data.reg.reg;
+ reg = array->elements[instr->args[2].data.mem.offset / array->elementSize];
+ newInstr = NULL;
+ switch (instr->op) {
+ case PC_LBZ:
+ if (array->isSigned)
+ newInstr = makepcode(PC_MR, reg2, reg);
+ else
+ newInstr = makepcode(PC_RLWINM, reg2, reg, 0, 24, 31);
+ break;
+ case PC_STB:
+ if (array->isSigned)
+ newInstr = makepcode(PC_EXTSB, reg, reg2);
+ else
+ newInstr = makepcode(PC_RLWINM, reg, reg2, 0, 24, 31);
+ break;
+ case PC_LHZ:
+ newInstr = makepcode(PC_RLWINM, reg2, reg, 0, 16, 31);
+ break;
+ case PC_LHA:
+ newInstr = makepcode(PC_EXTSH, reg2, reg);
+ break;
+ case PC_STH:
+ if (array->isSigned)
+ newInstr = makepcode(PC_EXTSH, reg, reg2);
+ else
+ newInstr = makepcode(PC_RLWINM, reg, reg2, 0, 16, 31);
+ break;
+ case PC_LWZ:
+ newInstr = makepcode(PC_MR, reg2, reg);
+ break;
+ case PC_STW:
+ newInstr = makepcode(PC_MR, reg, reg2);
+ break;
+ case PC_LFD:
+ newInstr = makepcode(PC_FMR, reg2, reg);
+ break;
+ case PC_STFD:
+ newInstr = makepcode(PC_FMR, reg, reg2);
+ break;
+ default:
+ CError_FATAL(2494);
+ break;
+ }
+
+ if (newInstr) {
+ insertpcodebefore(instr, newInstr);
+ deletepcode(instr);
+ instr = newInstr;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ freeoheap();
+}
+
+static void optimizenestedloops(Loop *loop) {
+ while (loop) {
+ if (loop->children)
+ optimizenestedloops(loop->children);
+ optimizeloop(loop);
+ loop = loop->nextSibling;
+ }
+}
+
+void optimizeloops(void) {
+ optimizedloops = 0;
+ optimizedloop_full_unroll = 0;
+ optimizedloop_trans_regs = 0;
+ if (loopsinflowgraph) {
+ computeusedefchains(0);
+ last_virtual_GPR = used_virtual_registers[RegClass_GPR];
+ liveonexit = oalloc(4 * ((used_virtual_registers[RegClass_GPR] + 31) >> 5));
+ inductionvariables = oalloc(4 * ((last_virtual_GPR + 31) >> 5));
+ optimizenestedloops(loopsinflowgraph);
+ freeoheap();
+ }
+}
+
diff --git a/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/StrengthReduction.c b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/StrengthReduction.c
new file mode 100644
index 0000000..2b68dca
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/StrengthReduction.c
@@ -0,0 +1,751 @@
+#include "compiler/StrengthReduction.h"
+#include "compiler/BitVectors.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/LoopDetection.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+#include "compiler/Registers.h"
+#include "compiler/UseDefChains.h"
+
+int strengthreducedloops;
+
+static PCode *findinitializer(Loop *loop, short reg) {
+ UInt32 *vec;
+ PCode *best;
+ RegUseOrDef *list;
+
+ vec = usedefinfo[loop->body->blockIndex].defvec8;
+ best = NULL;
+
+ for (list = reg_Defs[RegClass_GPR][reg]; list; list = list->next) {
+ if (
+ !(bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, loop->memberblocks)) &&
+ bitvectorgetbit(list->id, vec)
+ )
+ {
+ if (best)
+ return NULL;
+ best = Defs[list->id].pcode;
+ }
+ }
+
+ if (best) {
+ if (best->op == PC_LI || best->op == PC_ADDI || best->op == PC_ADD)
+ return best;
+ }
+
+ return NULL;
+}
+
+static int isbasicinductionvariable(Loop *loop, short reg, SInt32 step) {
+ RegUseOrDef *list;
+ PCode *instr;
+
+ for (list = reg_Defs[RegClass_GPR][reg]; list; list = list->next) {
+ instr = Defs[list->id].pcode;
+ if (bitvectorgetbit(instr->block->blockIndex, loop->memberblocks)) {
+ if (instr->op != PC_ADDI)
+ return 0;
+ if (instr->args[1].data.reg.reg != reg)
+ return 0;
+ if (instr->args[2].data.imm.value != step)
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void addbasicinductionvariable(Loop *loop, short reg, SInt32 step) {
+ BasicInductionVar *biv;
+ RegUseOrDef *list;
+ PCode *instr;
+ InstrList *instrList;
+
+ for (biv = loop->basicInductionVars; biv; biv = biv->next) {
+ if (biv->reg == reg)
+ return;
+ }
+
+ biv = oalloc(sizeof(BasicInductionVar));
+ biv->next = loop->basicInductionVars;
+ loop->basicInductionVars = biv;
+
+ biv->loop = loop;
+ biv->inductionVars = NULL;
+ biv->instrsC = NULL;
+ biv->step = step;
+ biv->reg = reg;
+
+ for (list = reg_Defs[RegClass_GPR][reg]; list; list = list->next) {
+ instr = Defs[list->id].pcode;
+ if (bitvectorgetbit(instr->block->blockIndex, loop->memberblocks)) {
+ instrList = oalloc(sizeof(InstrList));
+ instrList->next = biv->instrsC;
+ biv->instrsC = instrList;
+ instrList->instr = instr;
+ }
+ }
+
+ biv->initializer = findinitializer(loop, reg);
+}
+
+static void findbasicinductionvariables(Loop *loop) {
+ SInt16 step;
+ BlockList *block;
+ PCode *instr;
+ short reg;
+
+ for (block = loop->blocks; block; block = block->next) {
+ for (instr = block->block->firstPCode; instr; instr = instr->nextPCode) {
+ if (instr->op == PC_ADDI) {
+ if (
+ (reg = instr->args[0].data.reg.reg) >= 32 &&
+ instr->args[1].data.reg.reg == reg &&
+ isbasicinductionvariable(loop, reg, step = instr->args[2].data.imm.value)
+ )
+ addbasicinductionvariable(loop, reg, step);
+ }
+ }
+ }
+}
+
+static void findallbasicinductionvariables(Loop *loop) {
+ while (loop) {
+ if (loop->children)
+ findallbasicinductionvariables(loop->children);
+ findbasicinductionvariables(loop);
+ loop = loop->nextSibling;
+ }
+}
+
+static int isinductionvariable(BasicInductionVar *biv, int useID, SInt32 *result1, short *result2, short *result3, Loop **result4) {
+ RegUseOrDef *list;
+ int counter;
+ Loop *loop;
+ Loop *scanloop;
+ PCode *instr;
+
+ instr = Uses[useID].pcode;
+ *result2 = 0;
+ *result3 = 0;
+ *result4 = NULL;
+
+ switch (instr->op) {
+ case PC_MULLI:
+ *result1 = instr->args[2].data.imm.value;
+ break;
+
+ case PC_RLWINM:
+ if (instr->args[3].data.imm.value)
+ return 0;
+ if (instr->args[2].data.imm.value > 15)
+ return 0;
+ if (instr->args[4].data.imm.value != (31 - instr->args[2].data.imm.value))
+ return 0;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ return 0;
+ *result1 = 1 << instr->args[2].data.imm.value;
+ break;
+
+ case PC_LBZX:
+ case PC_LHZX:
+ case PC_LHAX:
+ case PC_LWZX:
+ case PC_STBX:
+ case PC_STHX:
+ case PC_STWX:
+ case PC_LFSX:
+ case PC_LFDX:
+ case PC_STFSX:
+ case PC_STFDX:
+ *result2 = 0;
+ *result3 = 0;
+ if (instr->args[1].data.reg.reg == biv->reg) {
+ *result2 = 1;
+ *result3 = 2;
+ } else if (instr->args[2].data.reg.reg == biv->reg) {
+ *result2 = 2;
+ *result3 = 1;
+ }
+
+ counter = 0;
+ for (list = reg_Defs[RegClass_GPR][instr->args[*result3].data.reg.reg]; list; list = list->next) {
+ if (bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, biv->loop->memberblocks))
+ counter++;
+ }
+ if (counter)
+ return 0;
+
+ loop = biv->loop;
+ for (scanloop = loop->parent; scanloop; scanloop = scanloop->parent) {
+ counter = 0;
+ for (list = reg_Defs[RegClass_GPR][instr->args[*result3].data.reg.reg]; list; list = list->next) {
+ if (bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, scanloop->memberblocks))
+ counter++;
+ }
+ if (!biv->initializer || bitvectorgetbit(biv->initializer->block->blockIndex, scanloop->memberblocks))
+ counter++;
+ if (counter)
+ break;
+ loop = scanloop;
+ }
+
+ *result4 = loop;
+ *result1 = 1;
+ return 1;
+
+ default:
+ return 0;
+ }
+
+ counter = 0;
+ for (list = reg_Defs[RegClass_GPR][instr->args[0].data.reg.reg]; list; list = list->next) {
+ if (bitvectorgetbit(Defs[list->id].pcode->block->blockIndex, biv->loop->memberblocks))
+ counter++;
+ }
+
+ return counter == 1;
+}
+
+static void addinductionvariable(BasicInductionVar *biv, PCode *instr, SInt32 val1, short val2, short val3, Loop *val4) {
+ InductionVar *iv;
+
+ iv = oalloc(sizeof(InductionVar));
+ iv->next = biv->inductionVars;
+ biv->inductionVars = iv;
+
+ iv->basicVar = biv;
+ iv->instr = instr;
+ iv->instrC = NULL;
+ iv->step = val1;
+ iv->x18 = val2;
+ iv->x1A = val3;
+ iv->someloop = val4;
+ if (instr->flags & (fIsRead | fIsWrite))
+ iv->x1C = -1;
+ else
+ iv->x1C = instr->args[0].data.reg.reg;
+ iv->x1E = -1;
+}
+
+static void findnonbasicinductionvariables(Loop *loop) {
+ BasicInductionVar *biv;
+ RegUseOrDef *list;
+ SInt32 result1;
+ short result2;
+ short result3;
+ Loop *result4;
+
+ for (biv = loop->basicInductionVars; biv; biv = biv->next) {
+ for (list = reg_Uses[RegClass_GPR][biv->reg]; list; list = list->next) {
+ if (bitvectorgetbit(Uses[list->id].pcode->block->blockIndex, loop->memberblocks)) {
+ if (isinductionvariable(biv, list->id, &result1, &result2, &result3, &result4))
+ addinductionvariable(biv, Uses[list->id].pcode, result1, result2, result3, result4);
+ }
+ }
+ }
+}
+
+static void findallnonbasicinductionvariables(Loop *loop) {
+ while (loop) {
+ if (loop->children)
+ findallnonbasicinductionvariables(loop->children);
+ if (loop->basicInductionVars)
+ findnonbasicinductionvariables(loop);
+ loop = loop->nextSibling;
+ }
+}
+
+static void initializeinductionvariable(InductionVar *iv) {
+ BasicInductionVar *biv; // r31
+ PCode *instr; // r27
+ PCodeBlock *preheader; // r30
+ SInt32 value30; // r30
+ short reg29; // r29
+ short reg26; // r26
+
+ biv = iv->basicVar;
+ preheader = biv->loop->preheader;
+
+ if (iv->x1A) {
+ reg29 = iv->instr->args[iv->x1A].data.reg.reg;
+ reg26 = iv->instr->args[iv->x18].data.reg.reg;
+ instr = NULL;
+
+ if (
+ biv->initializer &&
+ biv->initializer->op == PC_LI &&
+ biv->initializer->block == preheader
+ )
+ {
+ if (biv->initializer->args[1].data.imm.value == 0)
+ instr = makepcode(PC_MR, iv->x1E, reg29);
+ else if (FITS_IN_SHORT(biv->initializer->args[1].data.imm.value))
+ instr = makepcode(PC_ADDI, iv->x1E, reg29, 0, biv->initializer->args[1].data.imm.value);
+ }
+
+ if (!instr)
+ instr = makepcode(PC_ADD, iv->x1E, reg29, reg26);
+
+ if (biv->initializer && instr->op != PC_ADD)
+ insertpcodeafter(biv->initializer, instr);
+ else if (iv->someloop && iv->someloop->preheader->lastPCode)
+ insertpcodebefore(iv->someloop->preheader->lastPCode, instr);
+ else
+ insertpcodebefore(preheader->lastPCode, instr);
+
+ iv->instrC = instr;
+ iv->x1C = reg29;
+ return;
+ }
+
+ if (!biv->initializer || biv->initializer->op != PC_LI) {
+ instr = copypcode(iv->instr);
+ instr->args[0].data.reg.reg = iv->x1E;
+ insertpcodebefore(preheader->lastPCode, instr);
+ } else {
+ value30 = biv->initializer->args[1].data.imm.value * iv->step;
+ if (!FITS_IN_SHORT(value30)) {
+ instr = makepcode(PC_LIS, iv->x1E, 0, HIGH_PART(value30));
+ insertpcodeafter(biv->initializer, instr);
+ if (value30 != 0)
+ insertpcodeafter(instr, makepcode(PC_ADDI, iv->x1E, iv->x1E, 0, LOW_PART(value30)));
+ } else {
+ instr = makepcode(PC_LI, iv->x1E, value30);
+ insertpcodeafter(biv->initializer, instr);
+ }
+ }
+}
+
+static void incrementinductionvariable(InductionVar *iv) {
+ SInt32 value;
+ BasicInductionVar *biv;
+ PCode *instr;
+ InstrList *list;
+
+ biv = iv->basicVar;
+ value = iv->step * biv->step;
+ for (list = biv->instrsC; list; list = list->next) {
+ if (!FITS_IN_SHORT(value)) {
+ instr = makepcode(PC_ADDIS, iv->x1E, iv->x1E, 0, HIGH_PART(value));
+ insertpcodeafter(list->instr, instr);
+
+ if (value != 0) {
+ instr = makepcode(PC_ADDI, iv->x1E, iv->x1E, 0, LOW_PART(value));
+ insertpcodeafter(list->instr->nextPCode, instr);
+ }
+ } else {
+ instr = makepcode(PC_ADDI, iv->x1E, iv->x1E, 0, value);
+ insertpcodeafter(list->instr, instr);
+ }
+ }
+}
+
+static void copyinductionvariable(InductionVar *iv) {
+ if (iv->instr->flags & (fIsRead | fIsWrite)) {
+ iv->instr->op -= 2;
+ iv->instr->args[1].data.reg.reg = iv->x1E;
+ iv->instr->args[2].kind = PCOp_IMMEDIATE;
+ iv->instr->args[2].data.imm.value = 0;
+ iv->instr->args[2].data.imm.obj = NULL;
+ } else {
+ insertpcodeafter(iv->instr, makepcode(PC_MR, iv->x1C, iv->x1E));
+ deletepcode(iv->instr);
+ }
+}
+
+static int testnestediv(InductionVar *iv, SInt32 step1, int reg, SInt32 step2, Loop *loop1, Loop *loop2) {
+ SInt32 addend;
+ BlockList *list;
+ PCode *instr;
+ PCodeArg *op;
+ int i;
+
+ if (iv->instrC && iv->x1C == reg) {
+ if (iv->instrC->op == PC_MR)
+ addend = 0;
+ else if (iv->instrC->op == PC_ADDI)
+ addend = iv->instrC->args[2].data.imm.value;
+ else
+ return 0;
+
+ if (step2 == (addend + (step1 * iv->step * loop2->iterationCount))) {
+ for (list = loop1->blocks; list && list->block != loop2->blocks->block; list = list->next) {
+ for (instr = list->block->firstPCode; instr; instr = instr->nextPCode) {
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ op->data.reg.reg == reg
+ )
+ return 0;
+ op++;
+ }
+ }
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void strengthreducenestediv(short reg, SInt32 step, PCode *initializer, Loop *loop) {
+ Loop *scanloop;
+ BasicInductionVar *biv;
+ InductionVar *iv;
+ PCode *instr;
+ PCodeArg *op;
+ int i;
+
+ for (scanloop = loop->children; scanloop; scanloop = scanloop->nextSibling) {
+ if (
+ scanloop->isKnownCountingLoop &&
+ scanloop->x4F &&
+ bitvectorgetbit(scanloop->body->blockIndex, loop->vec2C)
+ )
+ {
+ for (biv = scanloop->basicInductionVars; biv; biv = biv->next) {
+ for (iv = biv->inductionVars; iv; iv = iv->next) {
+ if (testnestediv(iv, biv->step, reg, step, loop, scanloop)) {
+ deletepcode(iv->instrC);
+ if (initializer) {
+ insertpcodeafter(initializer, iv->instrC);
+ } else if (loop->body->lastPCode) {
+ for (instr = loop->body->lastPCode; instr; instr = instr->prevPCode) {
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ (op->data.reg.effect & EffectWrite) &&
+ op->data.reg.reg == reg
+ )
+ break;
+ op++;
+ }
+ }
+
+ if (instr)
+ insertpcodeafter(instr, iv->instrC);
+ else
+ insertpcodebefore(loop->body->firstPCode, iv->instrC);
+ } else {
+ appendpcode(loop->body, iv->instrC);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void strengthreducenestedbiv(BasicInductionVar *biv) {
+ Loop *loop;
+ InductionVar *iv;
+
+ loop = biv->loop;
+ for (iv = biv->inductionVars; iv; iv = iv->next)
+ strengthreducenestediv(iv->x1E, iv->step * biv->step, iv->instrC, loop);
+
+ strengthreducenestediv(biv->reg, biv->step, biv->initializer, loop);
+}
+
+static void strengthreduceinductionvariable(BasicInductionVar *biv) {
+ int counter;
+ InductionVar *iv;
+ InductionVar *otherIv;
+ short reg;
+
+ counter = 0;
+ for (iv = biv->inductionVars; iv; iv = iv->next) {
+ if (iv->step == 1)
+ counter++;
+ }
+
+ for (iv = biv->inductionVars; iv; iv = iv->next) {
+ if (
+ (counter <= 4 || iv->step != 1) &&
+ iv->instr->block &&
+ (iv->x1A == 0 || iv->instr->args[2].kind != PCOp_IMMEDIATE)
+ )
+ {
+ if (iv->x1E == -1) {
+ iv->x1E = used_virtual_registers[RegClass_GPR]++;
+ initializeinductionvariable(iv);
+ incrementinductionvariable(iv);
+ if (iv->step == 1) {
+ reg = iv->instr->args[iv->x1A].data.reg.reg;
+ for (otherIv = iv->next; otherIv; otherIv = otherIv->next) {
+ if (otherIv->x1A != 0 && otherIv->instr->args[otherIv->x1A].data.reg.reg == reg)
+ otherIv->x1E = iv->x1E;
+ }
+ } else {
+ for (otherIv = iv->next; otherIv; otherIv = otherIv->next) {
+ if (otherIv->step == iv->step)
+ otherIv->x1E = iv->x1E;
+ }
+ }
+ }
+
+ copyinductionvariable(iv);
+ strengthreducedloops = 1;
+ }
+ }
+}
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct BivInit {
+ SInt32 x0;
+ short x4;
+ short x6;
+ short x8;
+ Object *xA;
+} BivInit;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static void calc_biv_init(BasicInductionVar *biv, BivInit *init) {
+ PCode *instr;
+ PCode *scan;
+ PCodeArg *op;
+ int i;
+
+ instr = biv->initializer;
+ init->x0 = 0;
+ init->x4 = -1;
+ init->x6 = -1;
+ init->x8 = 0;
+ init->xA = NULL;
+
+ if (!biv->initializer || (biv->initializer->op != PC_ADDI && biv->initializer->op != PC_ADD))
+ return;
+
+ if (instr->op == PC_ADDI) {
+ if (instr->args[1].data.reg.reg == biv->reg) {
+ init->x0 = instr->args[2].data.imm.value;
+ for (scan = instr->prevPCode; scan; scan = scan->prevPCode) {
+ op = scan->args;
+ i = scan->argCount;
+ while (i--) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ op->data.reg.reg == biv->reg &&
+ (op->data.reg.effect & EffectWrite)
+ )
+ {
+ if (scan->op == PC_ADD) {
+ init->x4 = scan->args[1].data.reg.reg;
+ init->x6 = scan->args[2].data.reg.reg;
+ } else if (scan->op == PC_ADDI) {
+ if (scan->args[2].kind == PCOp_IMMEDIATE) {
+ init->x4 = scan->args[1].data.reg.reg;
+ init->x8 = scan->args[2].data.imm.value;
+ } else if (scan->args[2].kind == PCOp_MEMORY) {
+ init->x4 = scan->args[1].data.reg.reg;
+ init->x8 = scan->args[2].data.mem.offset;
+ init->xA = scan->args[2].data.mem.obj;
+ }
+ }
+ return;
+ }
+ op++;
+ }
+ }
+ } else {
+ if (instr->args[2].kind == PCOp_IMMEDIATE) {
+ init->x4 = instr->args[1].data.reg.reg;
+ init->x8 = instr->args[2].data.imm.value;
+ } else if (instr->args[2].kind == PCOp_MEMORY) {
+ init->x4 = instr->args[1].data.reg.reg;
+ init->x8 = instr->args[2].data.mem.offset;
+ init->xA = instr->args[2].data.mem.obj;
+ }
+ }
+ } else if (instr->op == PC_ADD) {
+ if (instr->args[1].data.reg.reg == biv->reg) {
+ init->x6 = instr->args[2].data.reg.reg;
+ for (scan = instr->prevPCode; scan; scan = scan->prevPCode) {
+ op = scan->args;
+ i = scan->argCount;
+ while (i--) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ op->data.reg.reg == biv->reg &&
+ (op->data.reg.effect & EffectWrite) &&
+ scan->op == PC_ADDI
+ )
+ {
+ if (scan->args[2].kind == PCOp_IMMEDIATE) {
+ init->x4 = scan->args[1].data.reg.reg;
+ init->x8 = scan->args[2].data.imm.value;
+ } else if (scan->args[2].kind == PCOp_MEMORY) {
+ init->x4 = scan->args[1].data.reg.reg;
+ init->x8 = scan->args[2].data.mem.offset;
+ init->xA = scan->args[2].data.mem.obj;
+ }
+ return;
+ }
+ op++;
+ }
+ }
+ } else {
+ init->x4 = instr->args[1].data.reg.reg;
+ init->x6 = instr->args[2].data.reg.reg;
+ }
+ }
+}
+
+static void combineinductionvariables(Loop *loop, BasicInductionVar *biv1, BasicInductionVar *biv2, SInt32 difference) {
+ PCode *instr1; // r31
+ int reg1; // r30
+ int reg2; // r29
+ PCode *instr2; // r24
+ PCodeBlock *nextBlock; // r24
+ BlockList *list;
+ PCodeArg *op;
+ int i;
+ PCode *instr;
+
+ instr1 = NULL;
+ instr2 = NULL;
+
+ reg1 = biv1->reg;
+ CError_ASSERT(930, reg1 >= 0);
+
+ reg2 = biv2->reg;
+ CError_ASSERT(934, reg2 >= 0);
+
+ if (!FITS_IN_SHORT(difference))
+ return;
+
+ for (list = loop->blocks; list; list = list->next) {
+ for (instr = list->block->firstPCode; instr; instr = instr->nextPCode) {
+ if (instr1) {
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ op->arg == RegClass_GPR &&
+ op->data.reg.reg == reg1
+ )
+ return;
+ op++;
+ }
+ }
+
+ if (instr->op == PC_ADDI) {
+ if (instr->args[0].data.reg.reg == reg1) {
+ if (instr1)
+ return;
+ instr1 = instr;
+ } else if (instr->args[0].data.reg.reg == reg2) {
+ if (instr2)
+ return;
+ instr2 = instr;
+ }
+ }
+ }
+ }
+
+ if (loop->body->lastPCode->flags & fIsBranch) {
+ nextBlock = NULL;
+
+ for (i = 0; i < loop->body->lastPCode->argCount; i++) {
+ if (loop->body->lastPCode->args[i].kind == PCOp_LABEL) {
+ nextBlock = loop->body->lastPCode->args[i].data.label.label->block;
+ break;
+ }
+ }
+
+ if (!nextBlock)
+ return;
+ } else {
+ nextBlock = loop->body->nextBlock;
+ }
+
+ deletepcode(instr1);
+ instr1->args[1].data.reg.reg = reg2;
+ instr1->args[2].data.imm.value = difference;
+
+ if (nextBlock->firstPCode)
+ insertpcodebefore(nextBlock->firstPCode, instr1);
+ else
+ appendpcode(nextBlock, instr1);
+
+ biv1->reg = -1;
+ strengthreducedloops = 1;
+}
+
+static void strengthreduceinductionvariables(Loop *loop) {
+ BasicInductionVar *biv1;
+ BasicInductionVar *biv2;
+ BivInit init1;
+ BivInit init2;
+
+ for (biv1 = loop->basicInductionVars; biv1; biv1 = biv1->next) {
+ if (biv1->inductionVars)
+ strengthreduceinductionvariable(biv1);
+ strengthreducenestedbiv(biv1);
+ }
+
+ for (biv1 = loop->basicInductionVars; biv1; biv1 = biv1->next) {
+ if (biv1->reg != -1) {
+ calc_biv_init(biv1, &init1);
+ if (init1.x4 != -1) {
+ for (biv2 = loop->basicInductionVars; biv2; biv2 = biv2->next) {
+ if (biv2->reg != -1 && biv2 != biv1) {
+ calc_biv_init(biv2, &init2);
+ if (
+ init2.x4 != -1 &&
+ init1.x4 == init2.x4 &&
+ init1.x6 == init2.x6 &&
+ init1.x8 == init2.x8 &&
+ init1.xA == init2.xA &&
+ biv1->step == biv2->step
+ )
+ {
+ if (init1.x0 < init2.x0) {
+ combineinductionvariables(loop, biv2, biv1, init2.x0 - init1.x0);
+ } else {
+ combineinductionvariables(loop, biv1, biv2, init1.x0 - init2.x0);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void strengthreduceallinductionvariables(Loop *loop) {
+ while (loop) {
+ if (loop->children)
+ strengthreduceallinductionvariables(loop->children);
+ if (loop->basicInductionVars)
+ strengthreduceinductionvariables(loop);
+ loop = loop->nextSibling;
+ }
+}
+
+void strengthreduceloops(void) {
+ strengthreducedloops = 0;
+ if (loopsinflowgraph) {
+ computeusedefchains(0);
+ findallbasicinductionvariables(loopsinflowgraph);
+ findallnonbasicinductionvariables(loopsinflowgraph);
+ strengthreduceallinductionvariables(loopsinflowgraph);
+ freeoheap();
+ }
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/ValueNumbering.c b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/ValueNumbering.c
new file mode 100644
index 0000000..0907fa1
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/ValueNumbering.c
@@ -0,0 +1,661 @@
+#include "compiler/ValueNumbering.h"
+#include "compiler/Alias.h"
+#include "compiler/PCode.h"
+#include "compiler/Registers.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/CError.h"
+
+typedef struct ValueLabel {
+ struct ValueLabel *next;
+ PCodeArg op;
+} ValueLabel;
+
+typedef struct AvailableValue {
+ struct AvailableValue *next;
+ ValueLabel *labelled;
+ PCode *pcode;
+ int killedregister;
+ int aliasnumber;
+ int opnumbers[0];
+} AvailableValue;
+
+typedef struct RegValue {
+ int number;
+ int x4;
+ AvailableValue *available;
+} RegValue;
+
+typedef struct State {
+ void *stackedvalues;
+ int valueceiling;
+} State;
+
+typedef struct StackedValue {
+ struct StackedValue *next;
+ PCodeArg op;
+ RegValue value;
+ Alias *alias;
+ PCode *valuepcode;
+} StackedValue;
+
+int removedcommonsubexpressions;
+int nextvaluenumber;
+static AvailableValue *opvalue[428];
+static RegValue *regvalue[RegClassMax];
+static StackedValue *stackedvalues;
+static int valueceiling;
+static int moreaggressiveoptimization;
+
+static void allocatecsedatastructures(void) {
+ char rclass;
+
+ for (rclass = 0; rclass < RegClassMax; rclass++)
+ regvalue[(char) rclass] = oalloc(sizeof(RegValue) * used_virtual_registers[(char) rclass]);
+}
+
+static void initializecsedatastructures(void) {
+ RegValue *rv;
+ char rclass;
+ int i;
+
+ nextvaluenumber = 0;
+
+ for (i = 0; i < 428; i++)
+ opvalue[i] = NULL;
+
+ for (rclass = 0; rclass < RegClassMax; rclass++) {
+ rv = regvalue[(char) rclass];
+ for (i = 0; i < used_virtual_registers[(char) rclass]; i++, rv++) {
+ rv->number = nextvaluenumber++;
+ rv->x4 = 0;
+ rv->available = NULL;
+ }
+ }
+
+ initialize_alias_values();
+ stackedvalues = NULL;
+ valueceiling = 0x7FFFFFFF;
+}
+
+static void labelvalue(AvailableValue *av, PCodeArg *op) {
+ ValueLabel *label = oalloc(sizeof(ValueLabel));
+ label->op = *op;
+ label->next = av->labelled;
+ av->labelled = label;
+}
+
+static void unlabelvalue(AvailableValue *av, PCodeArg *op) {
+ ValueLabel *labelled;
+ ValueLabel **ptr;
+
+ ptr = &av->labelled;
+ while ((labelled = *ptr)) {
+ if (labelled->op.data.reg.reg == op->data.reg.reg)
+ *ptr = labelled->next;
+ else
+ ptr = &labelled->next;
+ }
+}
+
+static void stackregistervalue(PCodeArg *op, RegValue *value) {
+ StackedValue *stacked = oalloc(sizeof(StackedValue));
+ stacked->next = stackedvalues;
+ stackedvalues = stacked;
+
+ stacked->op = *op;
+ stacked->value = *value;
+}
+
+static void stackmemoryvalue(Alias *alias) {
+ StackedValue *stacked = oalloc(sizeof(StackedValue));
+ stacked->next = stackedvalues;
+ stackedvalues = stacked;
+
+ stacked->op.kind = PCOp_MEMORY;
+ stacked->alias = alias;
+ stacked->value.number = alias->valuenumber;
+ stacked->valuepcode = alias->valuepcode;
+}
+
+static void unstackvalue(StackedValue *stacked) {
+ PCodeArg *op = &stacked->op;
+ RegValue *value;
+
+ if (stacked->op.kind == PCOp_MEMORY) {
+ stacked->alias->valuenumber = stacked->value.number;
+ stacked->alias->valuepcode = stacked->valuepcode;
+ } else {
+ value = &regvalue[op->arg][op->data.reg.reg];
+ if (value->available)
+ unlabelvalue(value->available, op);
+ value->number = stacked->value.number;
+ value->x4 = stacked->value.x4;
+ value->available = stacked->value.available;
+ if (value->available)
+ labelvalue(value->available, op);
+ }
+}
+
+static int samevalue(PCodeArg *op1, PCodeArg *op2) {
+ return regvalue[op1->arg][op1->data.reg.reg].number == regvalue[op2->arg][op2->data.reg.reg].number;
+}
+
+static int killregister(PCodeArg *op) {
+ RegValue *value;
+
+ value = &regvalue[op->arg][op->data.reg.reg];
+ if (value->number < valueceiling && nextvaluenumber >= valueceiling)
+ stackregistervalue(op, value);
+
+ if (value->available)
+ unlabelvalue(value->available, op);
+ value->available = NULL;
+ value->x4 = 0;
+ return value->number = nextvaluenumber++;
+}
+
+void killmemory(Alias *alias, PCode *newValue) {
+ if (alias->valuenumber < valueceiling && nextvaluenumber >= valueceiling)
+ stackmemoryvalue(alias);
+
+ if (newValue) {
+ alias->valuenumber = regvalue[newValue->args[0].arg][newValue->args[0].data.reg.reg].number;
+ alias->valuepcode = newValue;
+ } else {
+ alias->valuenumber = nextvaluenumber++;
+ alias->valuepcode = NULL;
+ }
+}
+
+static void killspecificCSEs(short op) {
+ AvailableValue *av;
+ ValueLabel *labelled;
+
+ for (av = opvalue[op]; av; av = av->next) {
+ for (labelled = av->labelled; labelled; labelled = labelled->next)
+ killregister(&labelled->op);
+ }
+}
+
+static void killallCSEs(void) {
+ AvailableValue *av;
+ ValueLabel *labelled;
+ int i;
+
+ for (i = 0; i < 428; i++) {
+ for (av = opvalue[i]; av; av = av->next) {
+ for (labelled = av->labelled; labelled; labelled = labelled->next)
+ killregister(&labelled->op);
+ }
+ }
+}
+
+static void killregisters(PCode *pcode) {
+ PCodeArg *op;
+ int i;
+
+ for (i = 0, op = pcode->args; i < pcode->argCount; i++, op++) {
+ if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectWrite))
+ killregister(op);
+ }
+}
+
+static void copyregister(PCodeArg *src, PCodeArg *dest) {
+ RegValue *srcvalue;
+ RegValue *destvalue;
+
+ srcvalue = &regvalue[src->arg][src->data.reg.reg];
+ destvalue = &regvalue[dest->arg][dest->data.reg.reg];
+
+ if (destvalue->number < valueceiling && nextvaluenumber >= valueceiling)
+ stackregistervalue(dest, destvalue);
+
+ if (destvalue->available)
+ unlabelvalue(destvalue->available, dest);
+ destvalue->available = srcvalue->available;
+ if (destvalue->available)
+ labelvalue(destvalue->available, dest);
+
+ destvalue->number = srcvalue->number;
+
+ if (srcvalue->x4 && srcvalue->number == regvalue[src->arg][srcvalue->x4].number)
+ destvalue->x4 = srcvalue->x4;
+ else
+ destvalue->x4 = src->data.reg.reg;
+}
+
+static int matchvalues(AvailableValue *av, PCode *match) {
+ PCodeArg *avOp;
+ PCodeArg *matchOp;
+ int i;
+
+ for (avOp = &av->pcode->args[0], matchOp = &match->args[0], i = 0; i < match->argCount; i++, avOp++, matchOp++) {
+ if (i != 0) {
+ switch (avOp->kind) {
+ case PCOp_REGISTER:
+ if (av->opnumbers[i] != regvalue[matchOp->arg][matchOp->data.reg.reg].number)
+ return 0;
+ break;
+ case PCOp_MEMORY:
+ if (matchOp->kind != PCOp_MEMORY)
+ return 0;
+ if (matchOp->data.mem.obj != avOp->data.mem.obj)
+ return 0;
+ if (matchOp->data.mem.offset != avOp->data.mem.offset)
+ return 0;
+ if ((unsigned char) matchOp->arg != (unsigned char) avOp->arg)
+ return 0;
+ break;
+ case PCOp_IMMEDIATE:
+ if (matchOp->kind != PCOp_IMMEDIATE)
+ return 0;
+ if (matchOp->data.imm.value != avOp->data.imm.value)
+ return 0;
+ break;
+ case PCOp_LABEL:
+ if (matchOp->kind != PCOp_LABEL)
+ return 0;
+ if (matchOp->data.label.label != avOp->data.label.label)
+ return 0;
+ break;
+ case PCOp_SYSREG:
+ CError_FATAL(572);
+ }
+ }
+ }
+
+ if ((match->flags & (fIsRead | fPCodeFlag20000)) && match->alias->valuenumber != av->aliasnumber)
+ return 0;
+
+ return 1;
+}
+
+static void chooselocation(AvailableValue *av, PCodeArg *op) {
+ ValueLabel *labelled;
+ PCodeArg *baseop;
+
+ baseop = &av->pcode->args[0];
+ labelled = av->labelled;
+ while (labelled) {
+ if (labelled->op.data.reg.reg == baseop->data.reg.reg) {
+ *op = labelled->op;
+ return;
+ }
+ labelled = labelled->next;
+ }
+
+ *op = av->labelled[0].op;
+}
+
+static int findavailablevalue(PCode *pcode, PCodeArg *op) {
+ AvailableValue *av;
+ PCodeArg tmp1;
+ PCodeArg tmp2;
+
+ for (av = opvalue[pcode->op]; av; av = av->next) {
+ if (av->labelled && av->pcode->flags == pcode->flags && av->pcode->argCount == pcode->argCount) {
+ if (!matchvalues(av, pcode)) {
+ if (!(pcode->flags & fCommutative))
+ continue;
+
+ tmp1 = pcode->args[1];
+ pcode->args[1] = pcode->args[2];
+ pcode->args[2] = tmp1;
+
+ if (!matchvalues(av, pcode)) {
+ tmp2 = pcode->args[1];
+ pcode->args[1] = pcode->args[2];
+ pcode->args[2] = tmp2;
+ continue;
+ }
+ }
+ chooselocation(av, op);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void addavailablevalue(PCode *pcode) {
+ AvailableValue *av;
+ PCodeArg *op;
+ int i;
+
+ av = oalloc(sizeof(AvailableValue) + sizeof(int) * pcode->argCount);
+ av->labelled = NULL;
+ av->pcode = pcode;
+ for (i = 0, op = &pcode->args[0]; i < pcode->argCount; i++, op++) {
+ if (op->kind == PCOp_REGISTER)
+ av->opnumbers[i] = regvalue[op->arg][op->data.reg.reg].number;
+ }
+
+ if (pcode->flags & (fIsRead | fPCodeFlag20000))
+ av->aliasnumber = pcode->alias->valuenumber;
+
+ op = &pcode->args[0];
+ av->killedregister = killregister(op);
+ labelvalue(av, op);
+ regvalue[op->arg][op->data.reg.reg].available = av;
+ av->next = opvalue[pcode->op];
+ opvalue[pcode->op] = av;
+}
+
+static int isCSEop(PCode *pcode) {
+ PCodeArg *baseOp;
+ PCodeArg *op;
+ int i;
+
+ baseOp = &pcode->args[0];
+
+ switch (pcode->op) {
+ case PC_CMPI:
+ case PC_CMP:
+ case PC_CMPLI:
+ case PC_CMPL:
+ case PC_FCMPU:
+ case PC_FCMPO:
+ if (!moreaggressiveoptimization)
+ return 0;
+ break;
+ case PC_LI:
+ case PC_LIS:
+ if (!moreaggressiveoptimization)
+ return 0;
+ if (pcode->args[0].data.reg.reg < first_fe_temporary_register[RegClass_GPR] || pcode->args[0].data.reg.reg > last_temporary_register[RegClass_GPR])
+ return 0;
+ break;
+ }
+
+ if (PCODE_FLAG_SET_F(pcode) & (fIsVolatile | fSideEffects | fOverflow | fSetsCarry | fRecordBit))
+ return 0;
+
+ for (i = 0, op = &pcode->args[0]; i < pcode->argCount; i++, op++) {
+ if (op != baseOp &&
+ op->kind == baseOp->kind &&
+ op->arg == baseOp->arg &&
+ op->data.reg.reg == baseOp->data.reg.reg)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int isCSEload(PCode *pcode) {
+ PCodeArg *op;
+ int i;
+ int count;
+
+ count = 0;
+ for (i = 0, op = &pcode->args[0]; i < pcode->argCount; i++, op++) {
+ if (op->kind == PCOp_REGISTER && (op->data.reg.effect & EffectWrite))
+ count++;
+ }
+
+ return count == 1;
+}
+
+static void registercopy(PCode *pcode) {
+ PCodeArg *op1;
+ PCodeArg *op2;
+
+ op1 = &pcode->args[0];
+ op2 = &pcode->args[1];
+ if (samevalue(op2, op1))
+ deletepcode(pcode);
+ else
+ copyregister(op2, op1);
+}
+
+static PCode *recentlystored(Alias *alias, PCodeArg *op) {
+ PCode *pc;
+ if ((pc = alias->valuepcode) && alias->valuenumber == regvalue[pc->args[0].arg][pc->args[0].data.reg.reg].number) {
+ *op = pc->args[0];
+ return pc;
+ } else {
+ return NULL;
+ }
+}
+
+static void simpleload(PCode *pcode) {
+ PCodeArg *origOp;
+ PCodeArg op;
+ PCode *rs;
+
+ origOp = &pcode->args[0];
+ if ((pcode->flags & fIsVolatile) || !isCSEload(pcode)) {
+ killregisters(pcode);
+ return;
+ }
+
+ if (findavailablevalue(pcode, &op)) {
+ if (!samevalue(origOp, &op)) {
+ insertpcodebefore(pcode, makecopyinstruction(&op, origOp));
+ copyregister(&op, origOp);
+ }
+ deletepcode(pcode);
+ removedcommonsubexpressions = 1;
+ } else if ((rs = recentlystored(pcode->alias, &op)) && can_reuse_stored_value(rs, pcode)) {
+ if (!samevalue(origOp, &op)) {
+ insertpcodebefore(pcode, makecopyinstruction(&op, origOp));
+ copyregister(&op, origOp);
+ }
+ deletepcode(pcode);
+ removedcommonsubexpressions = 1;
+ } else {
+ addavailablevalue(pcode);
+ }
+}
+
+static void simplestore(PCode *pcode) {
+ update_alias_value(pcode->alias, pcode);
+ killregisters(pcode);
+}
+
+static void pointerload(PCode *pcode) {
+ PCodeArg *op;
+ PCodeArg buf;
+
+ op = &pcode->args[0];
+
+ if ((pcode->flags & fIsVolatile) || !isCSEload(pcode)) {
+ killregisters(pcode);
+ return;
+ }
+
+ if (findavailablevalue(pcode, &buf)) {
+ if (!samevalue(op, &buf)) {
+ insertpcodebefore(pcode, makecopyinstruction(&buf, op));
+ copyregister(&buf, op);
+ }
+ deletepcode(pcode);
+ removedcommonsubexpressions = 1;
+ } else {
+ addavailablevalue(pcode);
+ }
+}
+
+static void pointerstore(PCode *pcode) {
+ update_alias_value(pcode->alias, NULL);
+ killregisters(pcode);
+}
+
+static void arithmeticop(PCode *pcode) {
+ PCodeArg *op;
+ PCodeArg buf;
+
+ op = &pcode->args[0];
+
+ if (findavailablevalue(pcode, &buf)) {
+ if (!samevalue(op, &buf)) {
+ insertpcodebefore(pcode, makecopyinstruction(&buf, op));
+ copyregister(&buf, op);
+ }
+ deletepcode(pcode);
+ removedcommonsubexpressions = 1;
+ } else {
+ addavailablevalue(pcode);
+ }
+}
+
+static void functioncall(PCode *pcode) {
+ killregisters(pcode);
+ if (coloring) {
+ update_all_alias_values();
+ killallCSEs();
+ } else {
+ update_alias_value(pcode->alias, NULL);
+ }
+}
+
+static void operatefrommemory(PCode *pcode) {
+ CError_FATAL(980);
+}
+
+static void operatetomemory(PCode *pcode) {
+ CError_FATAL(1011);
+}
+
+static void propagatecopiesto(PCode *pcode) {
+ PCodeArg *op;
+ int i;
+
+ for (i = 0, op = &pcode->args[0]; i < pcode->argCount; i++, op++) {
+ if (
+ op->kind == PCOp_REGISTER &&
+ (op->data.reg.effect & (EffectRead | EffectWrite | Effect8)) == EffectRead &&
+ op->data.reg.reg >= n_real_registers[op->arg] &&
+ regvalue[op->arg][op->data.reg.reg].x4 &&
+ regvalue[op->arg][op->data.reg.reg].x4 >= n_real_registers[op->arg] &&
+ regvalue[op->arg][op->data.reg.reg].number == regvalue[op->arg][regvalue[op->arg][op->data.reg.reg].x4].number
+ ) {
+ op->data.reg.reg = regvalue[op->arg][op->data.reg.reg].x4;
+ }
+ }
+}
+
+static void removecsesfrombasicblock(PCodeBlock *block) {
+ PCode *pcode;
+ PCode *next;
+
+ for (pcode = block->firstPCode; pcode; pcode = next) {
+ next = pcode->nextPCode;
+ propagatecopiesto(pcode);
+ if (pcode->flags & fIsMove) {
+ registercopy(pcode);
+ } else if ((pcode->flags & fIsCall) && (pcode->flags & (fLink | fSideEffects))) {
+ functioncall(pcode);
+ } else if (pcode->flags & fIsRead) {
+ if (pcode->flags & fIsPtrOp)
+ pointerload(pcode);
+ else
+ simpleload(pcode);
+ } else if (pcode->flags & fIsWrite) {
+ if (pcode->flags & fIsPtrOp)
+ pointerstore(pcode);
+ else
+ simplestore(pcode);
+ } else if (pcode->flags & fPCodeFlag20000) {
+ operatefrommemory(pcode);
+ } else if (pcode->flags & fPCodeFlag40000) {
+ operatetomemory(pcode);
+ } else if ((pcode->flags & fIsCSE) && isCSEop(pcode)) {
+ arithmeticop(pcode);
+ } else {
+ killregisters(pcode);
+ }
+ }
+
+ block->flags |= fVisited;
+}
+
+static void getvaluestate(State *state) {
+ state->stackedvalues = stackedvalues;
+ state->valueceiling = valueceiling;
+}
+
+static void setvaluestate(State *state) {
+ stackedvalues = state->stackedvalues;
+ valueceiling = state->valueceiling;
+}
+
+static void forkvaluestate(int number) {
+ stackedvalues = NULL;
+ valueceiling = number;
+}
+
+static void regressvaluestate(void) {
+ AvailableValue *av;
+ AvailableValue **ptr;
+ int i;
+ StackedValue *stacked;
+
+ for (i = 0; i < 428; i++) {
+ ptr = &opvalue[i];
+ while ((av = *ptr)) {
+ if (av->killedregister >= valueceiling)
+ *ptr = av->next;
+ else
+ ptr = &av->next;
+ }
+ }
+
+ for (stacked = stackedvalues; stacked; stacked = stacked->next)
+ unstackvalue(stacked);
+}
+
+static void removecsesfromextendedbasicblock(PCodeBlock *block) {
+ PCLink *succ;
+ int counter;
+ State state;
+
+ removecsesfrombasicblock(block);
+ while (block->successors &&
+ !block->successors->nextLink &&
+ block->successors->block->predecessors &&
+ !block->successors->block->predecessors->nextLink) {
+ block = block->successors->block;
+ removecsesfrombasicblock(block);
+ }
+
+ counter = 0;
+ for (succ = block->successors; succ; succ = succ->nextLink) {
+ if (!(succ->block->flags & fVisited) && succ->block->predecessors && !succ->block->predecessors->nextLink)
+ counter++;
+ }
+
+ if (counter) {
+ getvaluestate(&state);
+ forkvaluestate(nextvaluenumber);
+ for (succ = block->successors; succ; succ = succ->nextLink) {
+ if (!(succ->block->flags & fVisited) && succ->block->predecessors && !succ->block->predecessors->nextLink) {
+ removecsesfromextendedbasicblock(succ->block);
+ regressvaluestate();
+ }
+ }
+ setvaluestate(&state);
+ }
+}
+
+void removecommonsubexpressions(Object *proc, int flag) {
+ PCodeBlock *block;
+
+ moreaggressiveoptimization = flag;
+ removedcommonsubexpressions = 0;
+ gather_alias_info();
+ allocatecsedatastructures();
+
+ for (block = pcbasicblocks; block; block = block->nextBlock)
+ block->flags &= ~fVisited;
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ if (!(block->flags & fVisited)) {
+ initializecsedatastructures();
+ removecsesfromextendedbasicblock(block);
+ }
+ }
+
+ freeoheap();
+}
+
diff --git a/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/VectorArraysToRegs.c b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/VectorArraysToRegs.c
new file mode 100644
index 0000000..fde27f1
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/GlobalOptimizer/VectorArraysToRegs.c
@@ -0,0 +1,548 @@
+#include "compiler/VectorArraysToRegs.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/BitVectors.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+#include "compiler/Registers.h"
+#include "compiler/UseDefChains.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+typedef struct LocalVectorArray {
+ struct LocalVectorArray *next;
+ Object *object;
+ unsigned int invalid:1;
+ SInt32 arraySize;
+ SInt32 elementCount;
+ int totalUses;
+ int elements[1];
+} LocalVectorArray;
+
+typedef struct VectorPropInfo {
+ UInt32 *use;
+ UInt32 *def;
+ UInt32 *in;
+ UInt32 *out;
+} VectorPropInfo;
+
+typedef struct ADDI {
+ PCode *instr;
+ RegUseOrDef *list;
+} ADDI;
+
+static int number_of_ADDIs;
+static ADDI *ADDIs;
+static VectorPropInfo *vectorpropinfo;
+static int *naddsinblock;
+static int *firstaddinblock;
+static Boolean converted_arrays;
+
+static LocalVectorArray *scanforlocalvectorarrays(void) {
+ SInt32 elementCount;
+ LocalVectorArray *head;
+ LocalVectorArray *array;
+ ObjectList *list;
+ int i;
+ SInt32 arraySize;
+
+ head = NULL;
+
+ for (list = locals; list; list = list->next) {
+ if (
+ list->object &&
+ !(IS_TYPE_POINTER(list->object->type) ? (TPTR_QUAL(list->object->type) & Q_VOLATILE) : (list->object->qual & Q_VOLATILE)) &&
+ list->object->type &&
+ IS_TYPE_ARRAY(list->object->type) &&
+ IS_TYPE_VECTOR(TPTR_TARGET(list->object->type))
+ ) {
+ arraySize = list->object->type->size;
+ elementCount = arraySize / 16;
+ if (elementCount > 0 && elementCount <= 8) {
+ array = oalloc(sizeof(int) * (elementCount - 1) + sizeof(LocalVectorArray));
+ array->next = head;
+ head = array;
+
+ array->object = list->object;
+ array->arraySize = arraySize;
+ array->elementCount = elementCount;
+ array->totalUses = 0;
+ array->invalid = 0;
+
+ for (i = 0; i < elementCount; i++) {
+ array->elements[i] = 0;
+ }
+ }
+ }
+ }
+
+ return head;
+}
+
+static LocalVectorArray *lookup_vector_array_object(LocalVectorArray *arrays, Object *object) {
+ while (arrays) {
+ if (arrays->object == object)
+ return arrays;
+ arrays = arrays->next;
+ }
+ return NULL;
+}
+
+static void scaninstructions(LocalVectorArray *arrays) {
+ PCodeBlock *block;
+ PCode *instr;
+ int counter;
+ int i;
+ PCodeArg *op;
+ LocalVectorArray *array;
+ int element;
+
+ naddsinblock = oalloc(sizeof(int) * pcblockcount);
+ memclrw(naddsinblock, sizeof(int) * pcblockcount);
+
+ firstaddinblock = oalloc(sizeof(int) * pcblockcount);
+ memclrw(firstaddinblock, sizeof(int) * pcblockcount);
+
+ number_of_ADDIs = 0;
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ firstaddinblock[block->blockIndex] = number_of_ADDIs;
+ counter = 0;
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ if (!(instr->flags & fIsBranch) && instr->argCount) {
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (
+ op->kind == PCOp_MEMORY &&
+ (PCOpMemoryArg) op->arg == PCOpMemory1 &&
+ (array = lookup_vector_array_object(arrays, op->data.mem.obj)) &&
+ !array->invalid
+ )
+ {
+ if (instr->op != PC_ADDI) {
+ array->invalid = 1;
+ } else if (instr->args[0].data.reg.reg < n_real_registers[RegClass_GPR]) {
+ array->invalid = 1;
+ } else {
+ number_of_ADDIs++;
+ counter++;
+ }
+
+ if (!array->invalid) {
+ element = op->data.mem.offset / 16;
+ if (element < array->elementCount)
+ array->elements[element]++;
+ else
+ array->invalid = 1;
+ }
+ }
+ op++;
+ }
+ }
+ }
+ naddsinblock[block->blockIndex] = counter;
+ }
+}
+
+static void computeaddilist(LocalVectorArray *arrays) {
+ PCodeBlock *block;
+ PCode *instr;
+ RegUseOrDef *list;
+ ADDI *addi;
+ UInt32 *vec;
+ LocalVectorArray *array;
+ UseOrDef *def;
+ int defID;
+ UseOrDef *use;
+ int useID;
+
+ ADDIs = oalloc(sizeof(ADDI) * number_of_ADDIs);
+ memclrw(ADDIs, sizeof(ADDI) * number_of_ADDIs);
+
+ vec = oalloc(4 * ((number_of_Uses + 31) >> 5));
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ if (naddsinblock[block->blockIndex]) {
+ bitvectorcopy(vec, usedefinfo[block->blockIndex].usevec1C, number_of_Uses);
+ addi = &ADDIs[firstaddinblock[block->blockIndex] + naddsinblock[block->blockIndex] - 1];
+ for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
+ if (!(instr->flags & fIsBranch) && instr->argCount) {
+ int reg; // r18
+ if (
+ instr->op == PC_ADDI &&
+ (reg = instr->args[0].data.reg.reg) >= n_real_registers[RegClass_GPR] &&
+ instr->args[2].kind == PCOp_MEMORY &&
+ (PCOpMemoryArg) instr->args[2].arg == PCOpMemory1 &&
+ (array = lookup_vector_array_object(arrays, instr->args[2].data.mem.obj)) &&
+ !array->invalid
+ )
+ {
+ addi->instr = instr;
+ addi->list = NULL;
+ for (list = reg_Uses[RegClass_GPR][reg]; list; list = list->next) {
+ if (bitvectorgetbit(list->id, vec)) {
+ RegUseOrDef *node = oalloc(sizeof(RegUseOrDef));
+ node->id = list->id;
+ node->next = addi->list;
+ addi->list = node;
+ }
+ }
+ addi--;
+ }
+
+ for (def = &Defs[defID = instr->defID]; defID < number_of_Defs && def->pcode == instr; def++, defID++) {
+ if (def->v.kind == PCOp_REGISTER) {
+ RegUseOrDef *l;
+ for (l = reg_Uses[def->v.arg][def->v.u.reg]; l; l = l->next)
+ bitvectorclearbit(l->id, vec);
+ }
+ }
+
+ for (use = &Uses[useID = instr->useID]; useID < number_of_Uses && use->pcode == instr; use++, useID++) {
+ if (use->v.kind == PCOp_REGISTER)
+ bitvectorsetbit(useID, vec);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void allocatevectorpropinfo(void) {
+ VectorPropInfo *info;
+ int i;
+
+ vectorpropinfo = oalloc(sizeof(VectorPropInfo) * pcblockcount);
+ for (i = 0, info = vectorpropinfo; i < pcblockcount; i++, info++) {
+ info->use = oalloc(4 * ((number_of_ADDIs + 31) >> 5));
+ info->def = oalloc(4 * ((number_of_ADDIs + 31) >> 5));
+ info->in = oalloc(4 * ((number_of_ADDIs + 31) >> 5));
+ info->out = oalloc(4 * ((number_of_ADDIs + 31) >> 5));
+ }
+}
+
+static void computelocalvectorpropinfo(LocalVectorArray *arrays) {
+ VectorPropInfo *info;
+ PCodeBlock *block;
+ PCode *instr;
+ UInt32 *vec0;
+ UInt32 *vec4;
+ int index;
+ PCodeArg *op;
+ int i;
+ int addi_i;
+ ADDI *addi;
+ LocalVectorArray *array;
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ info = &vectorpropinfo[block->blockIndex];
+ vec0 = info->use;
+ vec4 = info->def;
+ bitvectorinitialize(vec0, number_of_ADDIs, 0);
+ bitvectorinitialize(vec4, number_of_ADDIs, 0);
+ index = firstaddinblock[block->blockIndex];
+
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ if (!(instr->flags & fIsBranch) && instr->argCount) {
+ i = instr->argCount;
+ op = instr->args;
+ while (i--) {
+ if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR && (op->data.reg.effect & EffectWrite)) {
+ for (addi_i = 0, addi = ADDIs; addi_i < number_of_ADDIs; addi_i++, addi++) {
+ if (
+ addi->instr &&
+ addi->instr->args[0].arg == op->arg &&
+ addi->instr->args[0].data.reg.reg == op->data.reg.reg
+ )
+ {
+ if (addi->instr->block == block)
+ bitvectorclearbit(addi_i, vec0);
+ else
+ bitvectorsetbit(addi_i, vec4);
+ }
+ }
+ }
+ op++;
+ }
+
+ if (
+ instr->op == PC_ADDI &&
+ instr->args[2].kind == PCOp_MEMORY &&
+ (PCOpMemoryArg) instr->args[2].arg == PCOpMemory1 &&
+ (array = lookup_vector_array_object(arrays, instr->args[2].data.mem.obj)) &&
+ !array->invalid
+ )
+ {
+ bitvectorsetbit(index, vec0);
+ index++;
+ }
+ }
+ }
+ }
+}
+
+static void computeglobalvectorpropinfo(void) {
+ VectorPropInfo *info;
+ PCodeBlock *block;
+ UInt32 *vec0;
+ UInt32 *vec4;
+ UInt32 *vec8;
+ UInt32 *vecC;
+ int bitvecsize;
+ int blockIndex;
+ int i;
+ int j;
+ int flag;
+ PCLink *preds;
+ UInt32 val;
+
+ bitvecsize = (number_of_ADDIs + 31) >> 5;
+ flag = 1;
+ info = &vectorpropinfo[pcbasicblocks->blockIndex];
+ bitvectorinitialize(info->in, number_of_ADDIs, 0);
+ bitvectorcopy(info->out, info->use, number_of_ADDIs);
+
+ for (block = pcbasicblocks->nextBlock; block; block = block->nextBlock) {
+ info = &vectorpropinfo[block->blockIndex];
+ vecC = info->out;
+ vec4 = info->def;
+ for (i = 0; i < bitvecsize; vecC++, vec4++, i++)
+ *vecC = ~*vec4;
+ }
+
+ while (flag) {
+ flag = 0;
+ for (blockIndex = 0; blockIndex < pcblockcount; blockIndex++) {
+ if (depthfirstordering[blockIndex]) {
+ info = &vectorpropinfo[depthfirstordering[blockIndex]->blockIndex];
+ if ((preds = depthfirstordering[blockIndex]->predecessors)) {
+ vec8 = info->in;
+ bitvectorcopy(vec8, vectorpropinfo[preds->block->blockIndex].out, number_of_ADDIs);
+ for (preds = preds->nextLink; preds; preds = preds->nextLink)
+ bitvectorintersect(vec8, vectorpropinfo[preds->block->blockIndex].out, number_of_ADDIs);
+ }
+
+ vecC = info->out;
+ vec8 = info->in;
+ vec0 = info->use;
+ vec4 = info->def;
+ for (j = 0; j < bitvecsize; j++) {
+ val = *vec0 | (*vec8 & ~*vec4);
+ if (val != *vecC) {
+ *vecC = val;
+ flag = 1;
+ }
+ vec8++;
+ vecC++;
+ vec4++;
+ vec0++;
+ }
+ }
+ }
+ }
+}
+
+static int precedes(PCode *a, PCode *b) {
+ PCode *scan;
+
+ for (scan = a->nextPCode; scan; scan = scan->nextPCode) {
+ if (scan == b)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int checkvectorstoreorload(int addiID, int useID) {
+ PCode *addiInstr;
+ UseOrDef *use;
+
+ addiInstr = ADDIs[addiID].instr;
+ use = Uses + useID;
+ if (!addiInstr)
+ return 0;
+
+ if (addiInstr->args[0].data.reg.reg < n_real_registers[RegClass_GPR])
+ return 0;
+
+ if (use->pcode->op != PC_LVX && use->pcode->op != PC_STVX)
+ return 0;
+
+ if (
+ use->pcode->args[1].kind != PCOp_REGISTER ||
+ use->pcode->args[1].arg != RegClass_GPR ||
+ use->pcode->args[1].data.reg.reg != 0
+ )
+ return 0;
+
+ return use->pcode->args[2].data.reg.reg == addiInstr->args[0].data.reg.reg;
+}
+
+static int checkalluses(LocalVectorArray *arrays, int addiID) {
+ RegUseOrDef *list;
+ PCode *instr;
+ LocalVectorArray *array;
+
+ instr = ADDIs[addiID].instr;
+ for (list = ADDIs[addiID].list; list; list = list->next) {
+ if (list && !checkvectorstoreorload(addiID, list->id)) {
+ array = lookup_vector_array_object(arrays, instr->args[2].data.mem.obj);
+ array->invalid = 1;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void convert_array_to_register(LocalVectorArray *arrays, int addiID) {
+ ADDI *addi;
+ int newReg;
+ RegUseOrDef *list;
+ PCode *instr;
+ PCode *useInstr;
+ LocalVectorArray *array;
+ int element;
+
+ addi = ADDIs + addiID;
+
+ if (!(instr = addi->instr))
+ return;
+
+ if (
+ !(array = lookup_vector_array_object(arrays, instr->args[2].data.mem.obj)) ||
+ array->invalid
+ )
+ return;
+
+ element = instr->args[2].data.mem.offset / 16;
+ if (element > array->elementCount)
+ return;
+
+ newReg = array->elements[element];
+ for (list = addi->list; list; list = list->next) {
+ useInstr = Uses[list->id].pcode;
+ if (useInstr->op == PC_LVX) {
+ converted_arrays = 1;
+ change_opcode(useInstr, PC_VMR);
+ change_num_operands(useInstr, 2);
+ useInstr->args[1].kind = PCOp_REGISTER;
+ useInstr->args[1].arg = RegClass_VR;
+ useInstr->args[1].data.reg.reg = newReg;
+ useInstr->args[1].data.reg.effect = EffectRead;
+ } else if (useInstr->op == PC_STVX) {
+ converted_arrays = 1;
+ change_opcode(useInstr, PC_VMR);
+ change_num_operands(useInstr, 2);
+ useInstr->args[1] = useInstr->args[0];
+ useInstr->args[0].kind = PCOp_REGISTER;
+ useInstr->args[0].arg = RegClass_VR;
+ useInstr->args[0].data.reg.reg = newReg;
+ useInstr->args[0].data.reg.effect = EffectWrite;
+ } else {
+ CError_FATAL(661);
+ }
+ }
+ deletepcode(addi->instr);
+}
+
+static void convert_arrays_to_registers(LocalVectorArray *arrays) {
+ int i;
+ int counter;
+ LocalVectorArray **ptr;
+ LocalVectorArray *array;
+
+ for (i = 0; i < number_of_ADDIs; i++)
+ checkalluses(arrays, i);
+
+ counter = 0;
+ ptr = &arrays;
+ array = *ptr;
+ while (array) {
+ if (array->invalid) {
+ *ptr = array->next;
+ array = *ptr;
+ continue;
+ }
+
+ counter += array->elementCount;
+
+ for (i = 0; i < array->elementCount; i++)
+ array->totalUses += array->elements[i];
+
+ array = array->next;
+ }
+
+ if (arrays) {
+ while (counter > 32) {
+ LocalVectorArray *best;
+ int score;
+ score = 0;
+ best = NULL;
+ for (array = arrays; array; array = array->next) {
+ if (best) {
+ if (array->totalUses < score) {
+ score = array->totalUses;
+ best = array;
+ }
+ } else {
+ best = array;
+ score = array->totalUses;
+ }
+ }
+
+ if (!best)
+ break;
+
+ if (best == arrays) {
+ arrays = best->next;
+ } else {
+ for (array = arrays; array; array = array->next) {
+ if (array->next == best) {
+ array->next = best->next;
+ break;
+ }
+ }
+ }
+
+ counter -= best->elementCount;
+ }
+
+ if (!(array = arrays))
+ return;
+
+ while (array) {
+ for (i = 0; i < array->elementCount; i++)
+ array->elements[i] = used_virtual_registers[RegClass_VR]++;
+ array = array->next;
+ }
+
+ if (arrays) {
+ for (i = 0; i < number_of_ADDIs; i++)
+ convert_array_to_register(arrays, i);
+ }
+ }
+}
+
+int vectorarraystoregs(void) {
+ LocalVectorArray *arrays;
+
+ converted_arrays = 0;
+ if ((arrays = scanforlocalvectorarrays())) {
+ scaninstructions(arrays);
+ if (number_of_ADDIs > 0) {
+ computeusedefchains(0);
+ computeaddilist(arrays);
+ allocatevectorpropinfo();
+ computelocalvectorpropinfo(arrays);
+ computedepthfirstordering();
+ computeglobalvectorpropinfo();
+ convert_arrays_to_registers(arrays);
+ }
+ }
+
+ freeoheap();
+ return converted_arrays;
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/FuncLevelAsmPPC.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/FuncLevelAsmPPC.c
new file mode 100644
index 0000000..340a54b
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/FuncLevelAsmPPC.c
@@ -0,0 +1,393 @@
+#include "compiler/FuncLevelAsmPPC.h"
+#include "compiler/CCompiler.h"
+#include "compiler/CError.h"
+#include "compiler/CFunc.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CodeGen.h"
+#include "compiler/Coloring.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/DumpIR.h"
+#include "compiler/InlineAsmPPC.h"
+#include "compiler/InlineAsmRegisters.h"
+#include "compiler/ObjGenMachO.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeAssembly.h"
+#include "compiler/PCodeListing.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/PPCError.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/StackFrame.h"
+#include "compiler/TOC.h"
+#include "compiler/objects.h"
+
+static EntryPoint *entrypoints_head;
+static EntryPoint **entrypoints_tail;
+
+void setup_assembly_argument(Object *obj, short reg) {
+ VarInfo *vi;
+ Type *type;
+
+ vi = Registers_GetVarInfo(obj);
+ type = obj->type;
+ vi->used = 1;
+
+ if (!requires_frame) {
+ if (is_register_object(obj)) {
+ if (!reg)
+ CError_Error(CErrorStr263, obj->name->name);
+
+ if (TYPE_IS_8BYTES(type)) {
+ short regLo;
+ short regHi;
+ if (reg < 10) {
+ if (copts.littleendian) {
+ regLo = reg;
+ regHi = reg + 1;
+ } else {
+ regLo = reg + 1;
+ regHi = reg;
+ }
+ retain_GPR_pair(obj, regLo, regHi);
+ InlineAsm_InsertRegister(obj->name->name, RegClass_GPR, regLo, obj);
+ }
+ } else if (IS_TYPE_FLOAT(type)) {
+ retain_register(obj, RegClass_FPR, reg);
+ InlineAsm_InsertRegister(obj->name->name, RegClass_FPR, reg, obj);
+ } else if (IS_TYPE_VECTOR(type)) {
+ retain_register(obj, RegClass_VR, reg);
+ InlineAsm_InsertRegister(obj->name->name, RegClass_VR, reg, obj);
+ } else {
+ retain_register(obj, RegClass_GPR, reg);
+ InlineAsm_InsertRegister(obj->name->name, RegClass_GPR, reg, obj);
+ }
+ }
+ } else {
+ if (is_register_object(obj)) {
+ vi = Registers_GetVarInfo(obj);
+ if (!vi->reg) {
+ assign_register_by_type(obj);
+ if (!(vi->flags & VarInfoFlag2))
+ CError_Error(CErrorStr263, obj->name->name);
+ else
+ InlineAsm_InsertRegister(obj->name->name, vi->rclass, vi->reg, obj);
+ }
+ }
+ }
+}
+
+void assign_local_addresses(void) {
+ VarInfo *vi;
+ ObjectList *list;
+ Object *object;
+
+ for (list = locals; list; list = list->next) {
+ vi = CodeGen_GetNewVarInfo();
+ list->object->u.var.info = vi;
+ list->object->flags |= OBJECT_USED;
+ vi->used = 1;
+ }
+
+ for (list = locals; list; list = list->next) {
+ object = list->object;
+ if (is_register_object(object)) {
+ vi = Registers_GetVarInfo(object);
+ if (!vi->reg) {
+ assign_register_by_type(object);
+ if (!(vi->flags & VarInfoFlag2))
+ CError_Error(CErrorStr263, object->name->name);
+ else
+ InlineAsm_InsertRegister(object->name->name, vi->rclass, vi->reg, object);
+ }
+ }
+ }
+
+ for (list = locals; list; list = list->next) {
+ object = list->object;
+ if (OBJECT_REG(object) == 0)
+ assign_local_memory(object);
+ }
+}
+
+static void FuncAsm_PreScanDirectives(void) {
+ SInt32 directive;
+ Boolean save_eoltokens;
+
+ in_assembler = 1;
+ save_eoltokens = cprep_eoltokens;
+ cprep_eoltokens = 1;
+
+ if (setjmp(InlineAsm_assemblererror) == 0) {
+ while (tk == TK_IDENTIFIER && (directive = InlineAsm_IsDirective(AssemblerType_1))) {
+ InlineAsm_ProcessDirective(directive);
+
+ if (tk == ';' || tk == TK_EOL) {
+ CPrep_TokenStreamFlush();
+ tk = lex();
+ } else {
+ InlineAsm_SyntaxError(CErrorStr113);
+ }
+
+ if (directive == IADirective_FrAlloc) {
+ requires_frame = 1;
+ break;
+ } else if (directive == IADirective_NoFrAlloc) {
+ user_responsible_for_frame = 1;
+ break;
+ }
+ }
+ }
+
+ in_assembler = 0;
+ cprep_eoltokens = save_eoltokens;
+}
+
+static void FuncAsm_AddEntryPoint(Statement *stmt, PCodeBlock *block) {
+ EntryPoint *ep;
+ IAEntryPoint *ia_ep;
+
+ ia_ep = (IAEntryPoint *) stmt->expr;
+ ep = lalloc(sizeof(EntryPoint));
+ memclrw(ep, sizeof(EntryPoint));
+
+ ep->object = ia_ep->x8;
+ ep->block = block;
+
+ *entrypoints_tail = ep;
+ entrypoints_tail = &ep->next;
+
+ block->flags |= fPCBlockFlag8000;
+}
+
+void Assembler(Object *func) {
+ PCodeBlock *block;
+ Statement *stmt;
+ Boolean flag17;
+ Boolean flag16;
+ char *name;
+ InlineAsm *ia;
+ Boolean save_unusedvar;
+ Boolean save_unusedarg;
+
+ flag17 = 0;
+ flag16 = 0;
+
+ init_endian();
+ init_stack_globals(func);
+ memclrw(asm_alloc_flags, sizeof(asm_alloc_flags));
+ fralloc_parameter_area_size = 0;
+ user_responsible_for_frame = 0;
+ assembledinstructions = 0;
+
+ entrypoints_head = NULL;
+ entrypoints_tail = &entrypoints_head;
+
+ stmt = curstmt;
+
+ if (func && func->name)
+ PrintProgressFunction(func->name->name);
+
+ CodeGen_InitialSanityCheck();
+
+ if (func->qual & Q_INLINE)
+ PPCError_Warning(PPCErrorStr173);
+
+ CheckCLabels();
+
+ if (fatalerrors)
+ return;
+
+ if (copts.filesyminfo)
+ CPrep_SetSourceFile(&cparser_fileoffset);
+
+ sm_section = SECT_TEXT;
+
+ initpcode();
+
+ pclabel(prologue = makepcblock(), makepclabel());
+ pclabel(block = makepcblock(), makepclabel());
+ pcbranch(prologue, block->labels);
+
+ resetTOCvarinfo();
+ InlineAsm_InitializePPC();
+ FuncAsm_PreScanDirectives();
+
+ disable_optimizer = 1;
+
+ init_registers();
+ assign_arguments_to_memory(func, 0, 0);
+ init_frame_sizes(0);
+
+ if (copts.debuglisting)
+ DumpIR(stmt, func);
+
+ cprep_eoltokens = 1;
+ in_assembler = 1;
+
+ save_unusedvar = copts.warn_unusedvar;
+ save_unusedarg = copts.warn_unusedarg;
+ copts.warn_unusedvar = 0;
+ copts.warn_unusedarg = 0;
+
+ InlineAsm_ScanFunction('}');
+
+ expandTOCreferences(&stmt->next);
+
+ if (!anyerrors && copts.debuglisting)
+ DumpIR(stmt, func);
+
+ in_assembler = 0;
+ cprep_eoltokens = 0;
+
+ name = CMangler_GetLinkName(func)->name;
+ func->flags |= OBJECT_DEFINED;
+
+ if (fralloc_parameter_area_size)
+ update_out_param_size(fralloc_parameter_area_size);
+ if (!user_responsible_for_frame)
+ process_arguments(move_assigned_argument, 0);
+
+ branch_label(makepclabel());
+ assign_labels(stmt->next);
+
+ copts.warn_unusedvar = save_unusedvar;
+ copts.warn_unusedarg = save_unusedarg;
+
+ for (stmt = stmt->next; stmt; stmt = stmt->next) {
+ current_statement = stmt;
+ switch (stmt->type) {
+ case ST_ASM:
+ if ((ia = (InlineAsm *) stmt->expr)) {
+ if (ia->flags & IAFlag1) {
+ if (ia->opcode == IADirective_Entry) {
+ branch_label(makepclabel());
+ FuncAsm_AddEntryPoint(stmt, pclastblock);
+ } else if (ia->opcode == IADirective_FrFree) {
+ if (flag16)
+ PPCError_Error(PPCErrorStr188);
+ else
+ flag16 = 1;
+
+ asm_alloc_flags[3] = 1;
+ asm_alloc_flags[4] = 1;
+ branch_label(makepclabel());
+
+ epilogue = pclastblock;
+ pclastblock->flags |= fIsEpilogue;
+
+ CheckCLabels();
+ if (fatalerrors)
+ return;
+
+ pccomputepredecessors();
+ if (copts.debuglisting)
+ pclistblocks(name, "[FUNCTION-LEVEL ASM] INITIAL CODE");
+ colorinstructions(func);
+ if (copts.debuglisting)
+ pclistblocks(name, "[FUNCTION-LEVEL ASM] AFTER REGISTER COLORING");
+ compute_frame_sizes();
+ generate_prologue(prologue, 0);
+ epilogue = pclastblock;
+ generate_epilogue(epilogue, 0);
+ if (copts.debuglisting)
+ pclistblocks(name, "[FUNCTION-LEVEL ASM] AFTER PROLOGUE/EPILOGUE CREATION");
+
+ flag17 = 1;
+ }
+ } else {
+ branch_label(makepclabel());
+ asm_alloc_flags[6] = 0;
+ asm_alloc_flags[7] = 0;
+ InlineAsm_TranslateIRtoPCode(stmt);
+ asm_alloc_flags[4] = 0;
+ }
+ }
+ break;
+ case ST_LABEL:
+ if (!stmt->label->pclabel->resolved)
+ branch_label(stmt->label->pclabel);
+ break;
+ default:
+ CError_FATAL(525);
+ }
+ }
+
+ current_statement = NULL;
+
+ if (fatalerrors)
+ return;
+ CheckCLabels();
+ if (fatalerrors)
+ return;
+
+ if (!flag17) {
+ branch_label(makepclabel());
+
+ epilogue = pclastblock;
+ pclastblock->flags |= fIsEpilogue;
+
+ pccomputepredecessors();
+ if (copts.debuglisting)
+ pclistblocks(name, "[FUNCTION-LEVEL ASM] INITIAL CODE");
+
+ if (!asm_alloc_flags[1]) {
+ colorinstructions(func);
+ if (fatalerrors)
+ return;
+
+ if (copts.debuglisting)
+ pclistblocks(name, "[FUNCTION-LEVEL ASM] AFTER REGISTER COLORING");
+ }
+
+ compute_frame_sizes();
+ if (asm_alloc_flags[1])
+ no_frame_for_asm();
+
+ if (fatalerrors)
+ return;
+
+ if (!asm_alloc_flags[1]) {
+ generate_prologue(prologue, 0);
+ generate_epilogue(epilogue, !asm_alloc_flags[6] && !asm_alloc_flags[7]);
+ }
+
+ if (copts.debuglisting)
+ pclistblocks(name, "[FUNCTION-LEVEL ASM] AFTER PROLOGUE/EPILOGUE CREATION");
+ }
+
+ if (fatalerrors)
+ return;
+
+ if (!asm_alloc_flags[1] && needs_frame()) {
+ if (asm_alloc_flags[3]) {
+ if (!asm_alloc_flags[5] || !asm_alloc_flags[6])
+ PPCError_Warning(PPCErrorStr187, "blr");
+ if (asm_alloc_flags[8])
+ PPCError_Warning(PPCErrorStr186);
+ } else {
+ PPCError_Warning(PPCErrorStr185, "blr");
+ }
+ }
+
+ func->section = sm_section;
+
+ if (copts.filesyminfo)
+ symdeclend = CPrep_GetFileOffsetInfo(&cparser_fileoffset);
+
+ copts.peephole = 0;
+ if (pic_base_label)
+ pic_base_pcodelabel = pic_base_label->pclabel;
+ assemblefunction(func, entrypoints_head);
+
+ if (copts.debuglisting)
+ pclistblocks(CMangler_GetLinkName(func)->name, "[FUNCTION-LEVEL ASM] FINAL CODE");
+
+ CFunc_WarnUnused();
+}
+
+void SetupAssembler(void) {
+}
+
+void CleanupAssembler(void) {
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c
new file mode 100644
index 0000000..897df9b
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c
@@ -0,0 +1,230 @@
+#include "compiler/GCCInlineAsm.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInt64.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/objects.h"
+
+Statement *first_ST_ASM;
+IALookupResult gcc_name_list[20];
+int gcc_name_list_index;
+
+void InlineAsm_SkipComment(void) {
+ while (1) {
+ if (tk != '/')
+ break;
+ if (lookahead() != '*')
+ break;
+
+ tk = lex();
+ while (!((tk = lex()) == '*' && (tk = lex()) == '/')) {
+ // nothing
+ }
+ tk = lex();
+ }
+}
+
+static char gcc_parse_attribute(void) {
+ char ch;
+
+ while (tk == TK_EOL)
+ tk = lex();
+
+ if (tk != '"')
+ CError_Error(CErrorStr105);
+
+ while ((tk = lex()) != TK_IDENTIFIER) {
+ // nothing
+ }
+
+ ch = tkidentifier->name[0];
+
+ if ((tk = lex()) != '"')
+ CError_Error(CErrorStr105);
+ tk = lex();
+
+ return ch;
+}
+
+static void gcc_parse_name(Boolean flag, char attribute) {
+ IALookupResult *nameentry;
+ ENode *expr;
+ Object *tempobj;
+ ENode *tempexpr;
+ Statement *stmt;
+
+ while (tk == TK_EOL)
+ tk = lex();
+
+ if (tk != '(')
+ CError_Error(CErrorStr114);
+
+ tk = lex();
+
+ if (flag) {
+ if (tk != TK_IDENTIFIER)
+ CError_Error(CErrorStr105);
+
+ InlineAsm_LookupSymbol(tkidentifier, &gcc_name_list[++gcc_name_list_index]);
+ if (gcc_name_list[gcc_name_list_index].object && gcc_name_list[gcc_name_list_index].object->u.var.info)
+ gcc_name_list[gcc_name_list_index].object->u.var.info->used = 1;
+
+ tk = lex();
+ } else {
+ in_assembler = 0;
+ cprep_nostring = 0;
+ nameentry = &gcc_name_list[++gcc_name_list_index];
+
+ expr = expression();
+ if (attribute == 'i' || attribute == 'I') {
+ if (!ENODE_IS(expr, EINTCONST))
+ CError_Error(CErrorStr144);
+ nameentry->value = CInt64_GetULong(&expr->data.intval);
+ nameentry->has_value = 1;
+ } else {
+ tempobj = create_temp_object(expr->rtype);
+ tempexpr = create_objectnode(tempobj);
+ if (tempobj->u.var.info)
+ tempobj->u.var.info->used = 1;
+ expr = makediadicnode(tempexpr, expr, EASS);
+
+ stmt = CFunc_InsertBeforeStatement(ST_EXPRESSION, first_ST_ASM);
+ first_ST_ASM = stmt->next;
+ if (!first_ST_ASM->next)
+ curstmt = first_ST_ASM;
+ stmt->expr = expr;
+
+ nameentry->name = tempobj->name;
+ nameentry->object = tempobj;
+ nameentry->label = NULL;
+ nameentry->type = NULL;
+ nameentry->has_value = 0;
+ }
+ }
+
+ cprep_nostring = 1;
+ in_assembler = 1;
+
+ if (tk != ')')
+ CError_Error(CErrorStr115);
+ tk = lex();
+}
+
+static void gcc_parse_expression(Boolean flag) {
+ while (1) {
+ gcc_parse_name(flag, gcc_parse_attribute());
+ if (tk != ',')
+ break;
+ tk = lex();
+ }
+}
+
+static void gcc_parse_input(void) {
+ if (tk == ':') {
+ if ((tk = lex()) == ':' || tk == ')' || tk == '}')
+ return;
+ gcc_parse_expression(0);
+ }
+}
+
+static void gcc_parse_output(void) {
+ if (tk == ':') {
+ if ((tk = lex()) == ':' || tk == ')' || tk == '}')
+ return;
+ gcc_parse_expression(1);
+ }
+}
+
+static void gcc_parse_killed(void) {
+ if (tk == ':') {
+ while (1) {
+ if ((tk = lex()) != '"')
+ return;
+
+ tk = lex();
+ while (1) {
+ if (tk == '"') {
+ if (lookahead() == ',') {
+ tk = lex();
+ break;
+ }
+ tk = lex();
+ return;
+ }
+ tk = lex();
+ }
+ }
+ }
+}
+
+static void gcc_replace_arg_st_asm(Statement *stmt) {
+ InlineAsm *ia;
+ int i;
+ IAOperand *op;
+ short effect;
+ short rclass;
+ SInt32 num;
+
+ if ((ia = (InlineAsm *) stmt->expr)) {
+ for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+ switch (op->type) {
+ case IAOpnd_Imm:
+ case IAOpnd_Reg:
+ case IAOpnd_3:
+ case IAOpnd_4:
+ case IAOpnd_Lab:
+ break;
+
+ case IAOpnd_6:
+ if (op->u.unk6.unk4 == 2) {
+ effect = op->u.unk6.effect;
+ rclass = op->u.unk6.rclass;
+ num = op->u.unk6.num;
+ op->type = IAOpnd_Reg;
+ op->u.reg.effect = effect;
+ op->u.reg.rclass = rclass;
+ op->u.reg.object = NULL;
+ if (num <= gcc_name_list_index)
+ op->u.reg.object = gcc_name_list[num].object;
+ else
+ CError_Error(CErrorStr144);
+ op->u.reg.num = 0;
+ } else {
+ CError_FATAL(365);
+ }
+ break;
+
+ case IAOpnd_7:
+ op->type = IAOpnd_Imm;
+ op->u.imm.value = gcc_name_list[op->u.unk7.value].value;
+ break;
+ }
+ }
+ }
+}
+
+static void gcc_replace_arg(void) {
+ Statement *stmt;
+
+ for (stmt = first_ST_ASM; stmt; stmt = stmt->next) {
+ if (stmt->type == ST_ASM)
+ gcc_replace_arg_st_asm(stmt);
+ }
+}
+
+void InlineAsm_gcc_parse(void) {
+ gcc_name_list_index = -1;
+ cprep_eoltokens = 0;
+
+ if (tk == TK_EOL)
+ tk = lex();
+
+ gcc_parse_output();
+ gcc_parse_input();
+ gcc_parse_killed();
+ gcc_replace_arg();
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c
new file mode 100644
index 0000000..46a95d2
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c
@@ -0,0 +1,680 @@
+#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_EOL || 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_INLINE_DATA))
+ 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:
+ CError_FATAL(245);
+ }
+ }
+ }
+
+ 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(void) {
+ 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, AssemblerType mode) {
+ if (setjmp(InlineAsm_assemblererror)) {
+ while (tk != TK_EOL && tk != endToken && tk != '}' && tk)
+ tk = lex();
+ if (tk == ';' || tk == TK_EOL)
+ tk = lex();
+ } else {
+ InlineAsm_Initialize(mode);
+ InlineAsm_gccmode = 0;
+ if (setjmp(InlineAsm_assemblererror)) {
+ while (tk != ';' && tk != TK_EOL && tk != endToken && tk != '}' && tk)
+ tk = lex();
+ if (tk == ';' || tk == TK_EOL)
+ 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_EOL) {
+ 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, AssemblerType_0);
+}
+
+void InlineAsm_ScanFunction(volatile short endToken) {
+ ScanStatements(endToken, AssemblerType_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 = ((intptr_t) &op->u.obj.obj) - ((intptr_t) 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/BackEnd/PowerPC/InlineAssembler/InlineAsmPPC.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsmPPC.c
new file mode 100644
index 0000000..464f9f9
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsmPPC.c
@@ -0,0 +1,2586 @@
+#include "compiler/InlineAsmPPC.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.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/Alias.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CodeGenOptPPC.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/Exceptions.h"
+#include "compiler/FuncLevelAsmPPC.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/InlineAsmMnemonicsPPC.h"
+#include "compiler/InlineAsmRegisters.h"
+#include "compiler/InlineAsmRegistersPPC.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/PPCError.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/StackFrame.h"
+#include "compiler/TOC.h"
+#include "compiler/objects.h"
+
+char asm_alloc_flags[10];
+Section sm_section;
+UInt32 cpu;
+SInt32 fralloc_parameter_area_size;
+Boolean user_responsible_for_frame;
+Boolean supports_hardware_fpu;
+UInt32 assembledinstructions;
+AssemblerType assembler_type;
+char volatileasm;
+Boolean InlineAsm_gccmode;
+Boolean InlineAsm_labelref;
+CLabel *pic_base_label;
+
+// 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);
+
+CW_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;
+ // bug? these two seem swapped
+ 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(PPCErrorStr119, opstr, name1->name);
+ } else if (!name1) {
+ PPCError_Error(PPCErrorStr120, opstr, name2->name);
+ } else {
+ PPCError_Error(PPCErrorStr118, name1->name, opstr, name2->name);
+ }
+}
+
+static void IllegalObjectInConst(IAExpr *expr) {
+ if (expr->xC) {
+ PPCError_Error(PPCErrorStr122, expr->xC->name->name);
+ } else if (expr->object) {
+ PPCError_Error(PPCErrorStr122, expr->object->name->name);
+ } else if (expr->label) {
+ PPCError_Error(PPCErrorStr166, expr->label->name->name);
+ }
+}
+
+static void NotInRegisterError(char *name, char rclass) {
+ PPCError_Error(PPCErrorStr167, 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(PPCErrorStr167, 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(PPCErrorStr124, left->xC->name->name, right->label->name->name);
+
+ if (right->xC) {
+ if (left->x10) {
+ PPCError_Error(PPCErrorStr121, left->xC->name->name, left->x10->name->name, right->xC->name->name);
+ } else if (right->x10) {
+ PPCError_Error(PPCErrorStr121, 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(PPCErrorStr124, 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(PPCErrorStr124, left->label->name->name, left->xC->name->name);
+
+ if (right->label) {
+ if (left->x18) {
+ PPCError_Error(PPCErrorStr121, left->label->name->name, left->x18->name->name, right->label->name->name);
+ } else if (right->x18) {
+ PPCError_Error(PPCErrorStr121, 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(PPCErrorStr126);
+ }
+}
+
+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(PPCErrorStr179);
+ 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(PPCErrorStr122, 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(PPCErrorStr180);
+ 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_USED;
+ return;
+ }
+
+ if (expr.xC) {
+ if (expr.x10)
+ PPCError_Error(PPCErrorStr123, 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(PPCErrorStr180);
+ }
+ 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_USED;
+ 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(PPCErrorStr125, 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_USED;
+ 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(PPCErrorStr171);
+ }
+
+ 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(PPCErrorStr168);
+ tk = lex();
+ } else if (rclass == RegClass_GPR) {
+ if (reg->object && reg->object->type->size == 8) {
+ HashNameNode *name = reg->object->name;
+ PPCError_Error(PPCErrorStr127, 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(PPCErrorStr180);
+ }
+ } 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_INLINE_DATA)) {
+ 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(PPCErrorStr125, 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(PPCErrorStr180);
+ }
+ op->u.obj.unk = expr.type;
+ }
+ op->u.obj.obj = expr.xC;
+ op->u.obj.offset = expr.value;
+ } else {
+ PPCError_Error(PPCErrorStr123, 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) & fCanSetRecordBit)
+ argcount++;
+ if (!(PCODE_FLAG_SET_F(info) & fSetsCarry) && (PCODE_FLAG_SET_F(info) & fCanSetCarry))
+ argcount++;
+ if (PCODE_FLAG_SET_T(info) & fCanLink)
+ 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++) {
+ CError_ASSERT(1664, 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
+ CError_FATAL(1804);
+ }
+
+ 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))
+ CError_FATAL(1838);
+
+ 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;
+ CError_ASSERT(1971, format[1] == '(');
+ format++;
+ effect2 = EffectRead;
+ if (format[1] == '=') {
+ effect2 = EffectWrite;
+ format++;
+ } else if (format[1] == '+') {
+ effect2 = EffectRead | EffectWrite;
+ format++;
+ }
+
+ CError_ASSERT(1983, format[1] == 'b');
+ CError_ASSERT(1985, 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:
+ CError_FATAL(2266);
+ }
+
+ 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
+ CError_FATAL(2312);
+
+ 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
+ CError_FATAL(2322);
+ } else if (isdigit(format[1])) {
+ format += pcode_const_from_format(format + 1, &value2);
+ } else {
+ CError_FATAL(2327);
+ }
+
+ switch (code) {
+ case '<':
+ value = value2 - value;
+ break;
+ case '>':
+ value = value - value2;
+ break;
+ case '|':
+ value = value + value2;
+ break;
+ case '*':
+ value = value * value2;
+ break;
+ default:
+ CError_FATAL(2348);
+ }
+
+ if (op->type == IAOpnd_Imm)
+ op->u.imm.value = value;
+ else if (op->type == IAOpnd_Reg)
+ op->u.reg.num = value;
+ else
+ CError_FATAL(2355);
+ 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(const 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(const 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.processor) {
+ 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:
+ CError_FATAL(2613);
+ }
+
+ if (copts.altivec_model)
+ cpu |= 0x40000000;
+}
+
+void InlineAsm_Initialize(AssemblerType 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_DEFINED)))
+ CError_Error(CErrorStr122, name->name);
+
+ obj->flags |= OBJECT_DEFINED;
+ 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(AssemblerType 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 == 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_EOL && 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.filesyminfo)
+ 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 = SECT_TEXT;
+ 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;
+ OpcodeInfo *info;
+ 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.filesyminfo)
+ 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);
+
+ info = &opcodeinfo[mnemonic->x4];
+ flag3 = (FLAG_SET_F(info->flags) & fCanSetCarry) && (mnemonic->x10 & 0x400);
+ flag4 = (FLAG_SET_T(info->flags) & fCanBeAbsolute) && (mnemonic->x10 & 2);
+ flag5 = (FLAG_SET_T(info->flags) & fCanLink) && (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, AssemblerType assemblertype) {
+ PCode *pc;
+ int index;
+ int extra_args;
+ int reg;
+ int newargcount;
+ SInt32 buffersize;
+ IAOperand *src;
+ PCodeArg *dest;
+ OpcodeInfo *info;
+
+ info = &opcodeinfo[ia->opcode];
+ index = 0;
+ extra_args = 0;
+ reg = 0;
+
+ if ((PCODE_FLAG_SET_F(info) & fCanSetRecordBit) && !(PCODE_FLAG_SET_F(info) & fRecordBit))
+ extra_args++;
+
+ if (!(PCODE_FLAG_SET_F(info) & fSetsCarry) && (PCODE_FLAG_SET_F(info) & fCanSetCarry))
+ extra_args++;
+
+ if (argcount < ia->argcount) {
+ if ((argcount + extra_args) >= ia->argcount) {
+ extra_args -= (ia->argcount - argcount);
+ argcount = ia->argcount;
+ } else {
+ CError_FATAL(3317);
+ }
+ }
+
+ 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 & (fIsRead | fIsWrite))
+ pc->flags |= fIsPtrOp;
+ 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(PPCErrorStr172, src->u.reg.object->name->name);
+ else
+ PPCError_Error(PPCErrorStr167, 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))
+ CError_FATAL(3442);
+
+ 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;
+ CError_ASSERT(3474, 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 & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000)) {
+ pc->alias = 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 & (fIsRead | fIsWrite))
+ pc->flags |= fIsPtrOp;
+ 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:
+ CError_FATAL(3528);
+ }
+ }
+
+ 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 = ((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) & fCanSetRecordBit)
+ pcsetrecordbit(pclastblock->lastPCode);
+ else
+ CError_Error(CErrorStr261);
+ }
+
+ if (ia->flags2 & IAFlagsB_2) {
+ if (PCODE_FLAG_SET_F(pc) & fCanSetCarry)
+ setpcodeflags(fOverflow); // idk?
+ else
+ CError_Error(CErrorStr261);
+ }
+
+ if (ia->flags2 & IAFlagsB_4) {
+ if (PCODE_FLAG_SET_T(pc) & fCanBeAbsolute) {
+ int i;
+ for (i = 0; i < pc->argCount; i++) {
+ if (pc->args[i].kind == PCOp_LABEL || pc->args[i].kind == PCOp_MEMORY) {
+ PPCError_Error(PPCErrorStr177);
+ break;
+ }
+ }
+ setpcodeflags(fAbsolute);
+ } else {
+ CError_Error(CErrorStr261);
+ }
+ }
+
+ if (ia->flags2 & IAFlagsB_8) {
+ if (PCODE_FLAG_SET_T(pc) & fCanLink) {
+ pcsetlinkbit(pclastblock->lastPCode);
+ if (!(ia->flags & IAFlag2)) {
+ pclastblock->lastPCode->flags &= ~fIsCall;
+ pclastblock->lastPCode->flags |= fIsBranch;
+ }
+ makes_call = 1;
+ } else {
+ CError_Error(CErrorStr261);
+ }
+ }
+
+ if (ia->flags2 & IAFlagsB_10)
+ setpcodeflags(fCanSetRecordBit);
+ if (ia->flags2 & IAFlagsB_20)
+ setpcodeflags(fCanSetCarry);
+
+ 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:
+ CError_FATAL(3715);
+ }
+
+ 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 & (fIsRead | fIsWrite)) {
+ 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:
+ CError_FATAL(3924);
+ }
+ } else {
+ if (opcodeinfo[ia->opcode].flags & fOpTypeGPR)
+ return 4;
+ if (opcodeinfo[ia->opcode].flags & fOpTypeFPR)
+ return 8;
+ if (opcodeinfo[ia->opcode].flags & fOpTypeVR)
+ return 16;
+
+ if (opcodeinfo[ia->opcode].flags & fSideEffects) {
+ switch (ia->opcode) {
+ case PC_TLBIE:
+ case PC_TLBLD:
+ case PC_TLBLI:
+ return 4;
+ default:
+ CError_FATAL(3941);
+ }
+ }
+ }
+
+ CError_FATAL(3944);
+ 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 & fIsPtrOp) {
+ if (info->flags & fIsRead)
+ effects->x1 = 1;
+ if (info->flags & fIsWrite)
+ effects->x2 = 1;
+ }
+
+ if (PCODE_FLAG_SET_T(info) & fCanLink) {
+ if (ia->flags2 & IAFlagsB_8)
+ effects->x4 = 1;
+ else if ((info->flags & fIsCall) || (info->flags & fIsWrite))
+ 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 {
+ CError_FATAL(4051);
+ }
+ }
+ }
+ break;
+ case IAOpnd_3:
+ case IAOpnd_4:
+ if (op->u.obj.obj) {
+ if (info->flags & fIsRead) {
+ 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 & (fIsBranch | fIsCall))) {
+ 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:
+ CError_FATAL(4087);
+ }
+
+ CError_ASSERT(4090, (UInt32) effects->numoperands <= IAMaxOperands);
+ CError_ASSERT(4093, (UInt32) effects->numlabels <= IAMaxLabels);
+ }
+
+ 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 {
+ CError_FATAL(4132);
+ }
+ }
+ }
+ break;
+ case IAOpnd_3:
+ case IAOpnd_4:
+ if (op->u.obj.obj) {
+ if (info->flags & fIsWrite) {
+ 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;
+ }
+
+ CError_ASSERT(4151, (UInt32) effects->numoperands <= IAMaxOperands);
+ }
+
+ if ((info->flags & (fIsBranch | fIsCall)) && (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 & (fIsWrite | 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/BackEnd/PowerPC/PCode/PCodeInfo.c b/compiler_and_linker/BackEnd/PowerPC/PCode/PCodeInfo.c
new file mode 100644
index 0000000..b2e2385
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/PCode/PCodeInfo.c
@@ -0,0 +1,1354 @@
+#include "compiler/PCodeInfo.h"
+#include "compiler/CError.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/Alias.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeListing.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/StackFrame.h"
+#include "compiler/TOC.h"
+#include "compiler/objects.h"
+#include "compiler/types.h"
+
+#pragma pool_strings on
+
+int pcode_bad_operand;
+char *orig_buf;
+static int do_show_basic_blocks;
+
+void pcode_get_hi_lo(int bits, char typechar, SInt32 *hi, SInt32 *lo) {
+ if (bits == 0) {
+ *hi = 0;
+ *lo = 0;
+ return;
+ }
+ if (bits == 32) {
+ *hi = 0x7FFFFFFF;
+ *lo = -0x80000000;
+ return;
+ }
+
+ if (bits < 32 && bits > 0) {
+ switch (typechar) {
+ case 'u':
+ *hi = (1 << bits) - 1;
+ *lo = 0;
+ break;
+ case 'i':
+ case 'x':
+ *hi = (1 << bits) - 1;
+ *lo = -(1 << (bits - 1));
+ break;
+ default:
+ *hi = (1 << (bits - 1)) - 1;
+ *lo = -(1 << (bits - 1));
+ }
+ } else {
+ CError_FATAL(65);
+ }
+}
+
+int pcode_check_imm_bits(SInt32 value, int bits, char typechar) {
+ char buf[2];
+ int forcedBits;
+ SInt32 r6;
+ SInt32 r0;
+
+ forcedBits = 0;
+ if (bits >= 0 && bits < 32) {
+ if (bits == 0) {
+ r6 = 0;
+ r0 = 0;
+ } else {
+ switch (typechar) {
+ case 'u':
+ r6 = (1 << bits) - 1;
+ r0 = 0;
+ break;
+ case 'i':
+ case 'x':
+ r6 = (1 << bits) - 1;
+ r0 = -(1 << (bits - 1));
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ buf[0] = typechar;
+ buf[1] = 0;
+ forcedBits = atoi(buf);
+ default:
+ r6 = (1 << (bits - 1)) - 1;
+ r0 = -(1 << (bits - 1));
+ }
+ }
+
+ if ((value < r0) || (value > r6))
+ return 1;
+ if (forcedBits > 0 && value != ((value >> forcedBits) << forcedBits))
+ return 1;
+ } else if (bits > 32) {
+ CError_FATAL(110);
+ }
+
+ return 0;
+}
+
+int pcode_const_from_format(const char *format, SInt32 *pResult) {
+ char buf[32];
+ int len = 0;
+
+ for (len = 0; len < 30 && isdigit(format[len]); len++) {
+ buf[len] = format[len];
+ }
+ buf[len] = 0;
+
+ *pResult = atoi(buf);
+ return len;
+}
+
+PCode *vformatpcode(short opcode, va_list argList) {
+ // has many wrong registers but probably ok otherwise
+ int argcount; // r29
+ OpcodeInfo *info; // r27 for a short time
+ int effect; // r27
+ const char *format; // r26
+ PCode *pcode; // r25
+ PCodeArg *arg; // r24
+ int unkreg_r23; // r23
+ int unkreg_r22; // r22
+ PCodeArg *lastArg; // r21
+ int pcode_size; // r20 for a short time
+ int tmp;
+ int tmp2; // r19
+ int i;
+ SInt32 thing;
+ SInt32 thing2;
+ SInt32 thing3;
+ SInt32 thing4;
+ Object *obj;
+ PCodeLabel *label;
+ char c;
+
+ info = &opcodeinfo[opcode];
+ format = info->format;
+ argcount = info->x8;
+ unkreg_r23 = 0;
+ unkreg_r22 = 0;
+
+ if (format[0] == '#') {
+ unkreg_r23 = va_arg(argList, int);
+ argcount += unkreg_r23;
+ format++;
+ }
+
+ if (info->flags & fCanSetRecordBit)
+ unkreg_r22 = 1;
+
+ if ((argcount + unkreg_r22) < 5)
+ unkreg_r22 += 5 - (argcount + unkreg_r22);
+
+ pcode_size = (argcount + unkreg_r22) * sizeof(PCodeArg) + sizeof(PCode);
+ pcode = lalloc(pcode_size);
+ memclrw(pcode, pcode_size);
+
+ pcode->op = opcode;
+ pcode->argCount = argcount;
+ pcode->flags = info->flags;
+ lastArg = pcode->args + pcode->argCount;
+ arg = pcode->args;
+ while (*format) {
+ if (arg >= lastArg)
+ CError_FATAL(189);
+
+ if (*format == ',' || *format == ';')
+ format++;
+ if (*format == '[' || *format == '(')
+ format++;
+
+ effect = EffectRead;
+ if (*format == '=') {
+ effect = EffectWrite;
+ format++;
+ } else if (*format == '+') {
+ effect = EffectRead | EffectWrite;
+ format++;
+ }
+
+ if (*format == '-')
+ format++;
+ if (*format == '?')
+ format++;
+ if (*format == '!')
+ format++;
+
+ switch ((c = *format)) {
+ case 'b':
+ tmp = va_arg(argList, int);
+ if (!tmp)
+ effect = 0;
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_GPR;
+ arg->data.reg.reg = tmp;
+ arg->data.reg.effect = effect;
+ break;
+ case 'r':
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_GPR;
+ arg->data.reg.reg = va_arg(argList, int);
+ arg->data.reg.effect = effect;
+ break;
+ case 'f':
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_FPR;
+ arg->data.reg.reg = va_arg(argList, int);
+ arg->data.reg.effect = effect;
+ break;
+ case 'v':
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_VR;
+ arg->data.reg.reg = va_arg(argList, int);
+ arg->data.reg.effect = effect;
+ break;
+ case 'c':
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_CRFIELD;
+ arg->data.reg.reg = va_arg(argList, int);
+ arg->data.reg.effect = effect;
+ break;
+ case 'C':
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_SPR;
+ arg->data.reg.reg = 2;
+ arg->data.reg.effect = effect;
+ break;
+ case 'L':
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_SPR;
+ arg->data.reg.reg = 1;
+ arg->data.reg.effect = effect;
+ break;
+ case 'V':
+ i = unkreg_r23;
+ while (i > 0) {
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_GPR;
+ arg->data.reg.reg = 31 - --i;
+ arg->data.reg.effect = effect;
+ arg++;
+ }
+ arg--;
+ break;
+ case 'X':
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_SPR;
+ arg->data.reg.reg = 0;
+ arg->data.reg.effect = effect;
+ break;
+ case 'Y':
+ if (pcode->op == PC_MTCRF) {
+ tmp = pcode->args[0].data.imm.value;
+ for (i = 0; i < 8; i++) {
+ if (tmp & (0x80 >> i)) {
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_CRFIELD;
+ arg->data.reg.reg = i;
+ arg->data.reg.effect = EffectWrite;
+ arg++;
+ }
+ }
+ } else {
+ i = 0;
+ while (i < 8) {
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_CRFIELD;
+ arg->data.reg.reg = i++;
+ arg->data.reg.effect = EffectRead;
+ arg++;
+ }
+ }
+ arg--;
+ break;
+ case 'Z':
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_CRFIELD;
+ arg->data.reg.reg = 0;
+ arg->data.reg.effect = effect;
+ break;
+ case 'P':
+ if (isdigit(format[1]))
+ format += pcode_const_from_format(format + 1, &thing);
+ else
+ CError_FATAL(319);
+ case 's':
+ tmp = va_arg(argList, int);
+ tmp2 = -1;
+ for (i = 0; i < 4; i++) {
+ if (tmp == spr_to_sysreg[i]) {
+ tmp2 = i;
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_SPR;
+ arg->data.reg.reg = i;
+ arg->data.reg.effect = effect;
+ if ((effect & EffectWrite) && (tmp == 0x100))
+ pcsetsideeffects(pcode);
+ break;
+ }
+ }
+
+ if (tmp2 < 0) {
+ pcsetsideeffects(pcode);
+ arg->kind = PCOp_SYSREG;
+ arg->arg = RegClass_SPR;
+ arg->data.reg.reg = tmp;
+ arg->data.reg.effect = effect;
+ }
+
+ break;
+
+ case 'T':
+ tmp = va_arg(argList, int);
+ if (tmp == 0x10C) {
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_SPR;
+ arg->data.reg.reg = 0x11C;
+ arg->data.reg.effect = effect;
+ } else if (tmp == 0x10D) {
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_SPR;
+ arg->data.reg.reg = 0x11D;
+ arg->data.reg.effect = effect;
+ } else {
+ CError_FATAL(353);
+ }
+ pcsetsideeffects(pcode);
+ arg->kind = PCOp_SYSREG;
+ arg->arg = RegClass_SPR;
+ arg->data.reg.reg = va_arg(argList, int);
+ arg->data.reg.effect = effect;
+ break;
+
+ case 'S':
+ tmp2 = -1;
+ if (isdigit(format[1]))
+ format += pcode_const_from_format(format + 1, &thing2);
+ else
+ CError_FATAL(371);
+
+ for (i = 0; i < 4; i++) {
+ if (thing2 == spr_to_sysreg[i]) {
+ tmp2 = i;
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_SPR;
+ arg->data.reg.reg = i;
+ arg->data.reg.effect = effect;
+ if ((effect & EffectWrite) && (thing2 == 0x100))
+ pcsetsideeffects(pcode);
+ break;
+ }
+ }
+
+ if (tmp2 < 0) {
+ pcsetsideeffects(pcode);
+ arg->kind = PCOp_SYSREG;
+ arg->arg = RegClass_SPR;
+ arg->data.reg.reg = va_arg(argList, int);
+ arg->data.reg.effect = effect;
+ }
+ break;
+
+ case 'a':
+ case 'i':
+ case 'n':
+ case 'u':
+ case 'w':
+ case 'x':
+ tmp2 = (unsigned char) c;
+ thing3 = 16;
+ if (*format == 'a') {
+ if (isdigit(format[1]))
+ tmp2 = (unsigned char) *(++format);
+ else
+ CError_FATAL(408);
+ }
+ if (isdigit(format[1])) {
+ format += pcode_const_from_format(format + 1, &thing3);
+ }
+ arg->kind = PCOp_IMMEDIATE;
+ arg->data.imm.value = va_arg(argList, int);
+ arg->data.imm.obj = NULL;
+ if (pcode_check_imm_bits(arg->data.imm.value, thing3, tmp2))
+ CError_FATAL(419);
+ break;
+
+ case 'N':
+ arg->kind = PCOp_IMMEDIATE;
+ arg->data.imm.value = va_arg(argList, int);
+ arg->data.imm.obj = NULL;
+ if (pcode_check_imm_bits(arg->data.imm.value, 6, 'u'))
+ CError_FATAL(429);
+ break;
+
+ case 'D':
+ arg->kind = PCOp_IMMEDIATE;
+ arg->data.imm.value = va_arg(argList, int);
+ arg->data.imm.obj = NULL;
+ if (pcode_check_imm_bits(arg->data.imm.value, 10, 'u'))
+ CError_FATAL(438);
+ break;
+
+ case 'B':
+ case 't':
+ arg->kind = PCOp_IMMEDIATE;
+ arg->data.imm.value = va_arg(argList, int);
+ arg->data.imm.obj = NULL;
+ if (pcode_check_imm_bits(arg->data.imm.value, 5, 'u'))
+ CError_FATAL(448);
+ break;
+
+ case 'Q':
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_CRFIELD;
+ arg->data.reg.reg = va_arg(argList, int);
+ arg->data.reg.effect = effect;
+ arg++;
+ case 'q':
+ arg->kind = PCOp_IMMEDIATE;
+ arg->data.imm.value = va_arg(argList, int);
+ arg->data.imm.obj = NULL;
+ if (pcode_check_imm_bits(arg->data.imm.value, 4, 'u'))
+ CError_FATAL(463);
+ break;
+
+ case 'l':
+ if ((label = va_arg(argList, PCodeLabel *))) {
+ arg->kind = PCOp_LABEL;
+ arg->data.label.label = label;
+ } else {
+ arg->kind = PCOp_MEMORY;
+ obj = va_arg(argList, Object *);
+ CError_ASSERT(476, obj->otype == OT_OBJECT);
+ arg->data.mem.obj = obj;
+ arg->data.mem.offset = 0;
+ arg->arg = RefType_4;
+ }
+ break;
+
+ case 'd':
+ CError_ASSERT(490, format[1] == '(');
+ effect = EffectRead;
+ format += 2;
+ if (*format == '=') {
+ effect = EffectWrite;
+ format++;
+ } else if (*format == '+') {
+ effect = EffectRead | EffectWrite;
+ format++;
+ }
+
+ CError_ASSERT(502, format[0] == 'b');
+
+ tmp = va_arg(argList, int);
+ if (tmp == 0)
+ effect = 0;
+ arg->kind = PCOp_REGISTER;
+ arg->arg = RegClass_GPR;
+ arg->data.reg.reg = tmp;
+ arg->data.reg.effect = effect;
+ arg++;
+
+ case 'm':
+ obj = va_arg(argList, Object *);
+ if (obj) {
+ CError_ASSERT(515, obj->otype == OT_OBJECT);
+
+ if (obj->datatype == DABSOLUTE) {
+ arg->kind = PCOp_IMMEDIATE;
+ arg->data.imm.obj = obj;
+ arg->data.imm.value = va_arg(argList, SInt32);
+ } else {
+ arg->kind = PCOp_MEMORY;
+ arg->data.mem.obj = obj;
+ arg->data.mem.offset = va_arg(argList, SInt32);
+
+ if (pcode->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000)) {
+ pcode->alias = make_alias(obj, arg->data.mem.offset, nbytes_loaded_or_stored_by(pcode));
+ if (is_volatile_object(obj))
+ pcode->flags |= fIsVolatile;
+ //if ((obj->type->type == TYPEPOINTER || obj->type->type == TYPEARRAY) ? (TYPE_POINTER(obj->type)->qual & Q_CONST) : (obj->qual & Q_CONST))
+ if (OBJ_GET_TARGET_CONST(obj))
+ pcode->flags |= fIsConst;
+ } else {
+ if (pcode->op == PC_ADDI)
+ pcode->alias = make_alias(obj, arg->data.mem.offset, 1);
+ }
+ CError_ASSERT(536, obj->datatype == DLOCAL || arg->data.mem.offset == 0);
+ if (pcode->flags & (fIsRead | fIsWrite)) {
+ //if ((obj->type->type == TYPEPOINTER || obj->type->type == TYPEARRAY) ? (TYPE_POINTER(obj->type)->qual & Q_VOLATILE) : (obj->qual & Q_VOLATILE))
+ if (OBJ_GET_TARGET_VOLATILE(obj))
+ pcode->flags |= fIsVolatile;
+ //if ((obj->type->type == TYPEPOINTER || obj->type->type == TYPEARRAY) ? (TYPE_POINTER(obj->type)->qual & Q_CONST) : (obj->qual & Q_CONST))
+ if (OBJ_GET_TARGET_CONST(obj))
+ pcode->flags |= fIsConst;
+ }
+
+ if (pcode->flags & (fIsBranch | fIsCall)) {
+ arg->arg = RefType_4;
+ } else if (obj->datatype == DLOCAL) {
+ if (!local_is_16bit_offset(obj))
+ arg->arg = RefType_D;
+ else
+ arg->arg = RefType_1;
+ } else {
+ arg->arg = RefType_6;
+ }
+ }
+ } else {
+ arg->kind = PCOp_IMMEDIATE;
+ arg->data.imm.value = va_arg(argList, SInt32);
+ arg->data.imm.obj = NULL;
+ if (pcode->flags & (fIsRead | fIsWrite))
+ pcode->flags |= fIsPtrOp;
+ }
+ break;
+
+ case 'M':
+ obj = va_arg(argList, Object *);
+ if (obj) {
+ CError_ASSERT(578, obj->otype == OT_OBJECT);
+
+ if (obj->datatype == DABSOLUTE) {
+ arg->kind = PCOp_IMMEDIATE;
+ arg->data.imm.obj = obj;
+ arg->data.imm.value = va_arg(argList, SInt32);
+ } else {
+ arg->kind = PCOp_MEMORY;
+ arg->data.mem.obj = obj;
+ arg->data.mem.offset = va_arg(argList, SInt32);
+
+ CError_ASSERT(590, obj->datatype == DLOCAL || arg->data.mem.offset == 0);
+ if (pcode->flags & (fIsRead | fIsWrite)) {
+ //if ((obj->type->type == TYPEPOINTER || obj->type->type == TYPEARRAY) ? (TYPE_POINTER(obj->type)->qual & Q_VOLATILE) : (obj->qual & Q_VOLATILE))
+ if (OBJ_GET_TARGET_VOLATILE(obj))
+ pcode->flags |= fIsVolatile;
+ //if ((obj->type->type == TYPEPOINTER || obj->type->type == TYPEARRAY) ? (TYPE_POINTER(obj->type)->qual & Q_CONST) : (obj->qual & Q_CONST))
+ if (OBJ_GET_TARGET_CONST(obj))
+ pcode->flags |= fIsConst;
+ }
+
+ if (obj->datatype == DLOCAL) {
+ arg->arg = RefType_C;
+ } else {
+ arg->arg = RefType_8;
+ }
+ }
+ } else {
+ arg->kind = PCOp_IMMEDIATE;
+ arg->data.imm.value = va_arg(argList, SInt32);
+ arg->data.imm.obj = NULL;
+ if (pcode->flags & (fIsRead | fIsWrite))
+ pcode->flags |= fIsPtrOp;
+ }
+ break;
+
+ case 'p':
+ arg->kind = PCOp_PLACEHOLDEROPERAND;
+ break;
+
+ case 'O':
+ arg--;
+ break;
+
+ default:
+ CError_FATAL(629);
+ }
+
+ while (format[1] && strchr("/<>|*", format[1])) {
+ switch (*(++format)) {
+ case '/':
+ if (format[1] == '2')
+ format++;
+ break;
+ case '<':
+ case '*':
+ case '|':
+ case '>':
+ if (format[1] == 'p')
+ format++;
+ else if (isdigit(format[1]))
+ format += pcode_const_from_format(format + 1, &thing4);
+ else
+ CError_FATAL(659);
+ break;
+ }
+ }
+
+ if ((c = *(++format)) == ']' || c == ')')
+ format++;
+ arg++;
+ }
+
+ while (arg < lastArg) {
+ arg->kind = PCOp_PLACEHOLDEROPERAND;
+ arg++;
+ }
+ while (unkreg_r22) {
+ arg->kind = PCOp_PLACEHOLDEROPERAND;
+ arg++;
+ unkreg_r22--;
+ }
+ return pcode;
+}
+
+int expectandformatoperand(PCodeArg *operand, PCOpKind expectedKind, char a3, int bitCount, char *buf) {
+ int errorlen;
+ char *name;
+ int tmp;
+ int regclass;
+ int refis1;
+ int b_null;
+
+ errorlen = 0;
+
+ if (operand->kind != expectedKind) {
+ char *kindstr;
+ switch (expectedKind) {
+ case PCOp_REGISTER: kindstr = "REGISTER"; break;
+ case PCOp_SYSREG: kindstr = "SYSREG"; break;
+ case PCOp_IMMEDIATE: kindstr = "IMMEDIATE"; break;
+ case PCOp_MEMORY: kindstr = "MEMORY"; break;
+ case PCOp_LABEL: kindstr = "LABEL"; break;
+ case PCOp_LABELDIFF: kindstr = "LABELDIFF"; break;
+ case PCOp_PLACEHOLDEROPERAND: kindstr = "PLACEHOLDEROPERAND"; break;
+ default: kindstr = "unknown kind";
+ }
+ tmp = sprintf(buf, "{EXPECTED %s}", kindstr);
+ errorlen += tmp;
+ buf += tmp;
+ pclist_bad_operand = 1;
+ }
+
+ switch (operand->kind) {
+ case PCOp_REGISTER:
+ if (operand->arg != (regclass = a3)) {
+ tmp = sprintf(buf, "{EXPECTED %s}", register_class_name[regclass]);
+ errorlen += tmp;
+ buf += tmp;
+ }
+ if (operand->data.reg.reg < n_real_registers[regclass] && (name = special_register_names[operand->arg][operand->data.reg.reg]))
+ tmp = sprintf(buf, "%s", name);
+ else
+ tmp = sprintf(buf, register_class_format[operand->arg], operand->data.reg.reg);
+ errorlen += tmp;
+ break;
+ case PCOp_SYSREG:
+ if (operand->arg != RegClass_SPR) {
+ tmp = sprintf(buf, "{EXPECTED %s}", register_class_name[RegClass_SPR]);
+ errorlen += tmp;
+ buf += tmp;
+ }
+ tmp = sprintf(buf, register_class_format[RegClass_SPR], operand->data.reg.reg);
+ errorlen += tmp;
+ break;
+ case PCOp_IMMEDIATE:
+ switch (a3) {
+ case 'x':
+ tmp = sprintf(buf, "0x%x", operand->data.imm.value);
+ break;
+ case 'u':
+ tmp = sprintf(buf, "%u", operand->data.imm.value);
+ break;
+ default:
+ tmp = sprintf(buf, "%" PRId32, operand->data.imm.value);
+ break;
+ }
+ errorlen += tmp;
+ buf += tmp;
+ if (operand->data.imm.obj) {
+ name = CMangler_GetLinkName(operand->data.imm.obj)->name;
+ if (strlen(name) > 50)
+ tmp = sprintf(buf, "{%45.45s...}", name);
+ else
+ tmp = sprintf(buf, "{%s}", name);
+ errorlen += tmp;
+ buf += tmp;
+ }
+ if (pcode_check_imm_bits(operand->data.imm.value, bitCount, (char) a3)) {
+ errorlen += sprintf(buf, "{IMM too large %i bits}", bitCount);
+ pclist_bad_operand = 1;
+ }
+ break;
+ case PCOp_MEMORY:
+ switch ((unsigned char) operand->arg) {
+ case RefType_0:
+ case RefType_1:
+ case RefType_2:
+ case RefType_3:
+ case RefType_4:
+ case RefType_5:
+ case RefType_9:
+ break;
+ case RefType_8:
+ case RefType_B:
+ case RefType_C:
+ tmp = sprintf(buf, "HA(");
+ errorlen += tmp;
+ buf += tmp;
+ break;
+ case RefType_7:
+ tmp = sprintf(buf, "HI(");
+ errorlen += tmp;
+ buf += tmp;
+ break;
+ case RefType_6:
+ case RefType_A:
+ case RefType_D:
+ tmp = sprintf(buf, "LO(");
+ errorlen += tmp;
+ buf += tmp;
+ break;
+ default:
+ tmp = sprintf(buf, "{UNEXPECTED reftype = %d}", (unsigned char) operand->arg);
+ errorlen += tmp;
+ buf += tmp;
+ }
+ name = CMangler_GetLinkName(operand->data.mem.obj)->name;
+ if (strlen(name) == 0 || strlen(name) > 3200 || name[0] < 0)
+ CError_FATAL(849);
+ if (strlen(name) > 50)
+ tmp = sprintf(buf, "%45.45s...", name);
+ else
+ tmp = sprintf(buf, "%s", name);
+ errorlen += tmp;
+ buf += tmp;
+ if (operand->data.mem.offset > 0)
+ tmp = sprintf(buf, "+%d", operand->data.mem.offset);
+ else if (operand->data.mem.offset != 0)
+ tmp = sprintf(buf, "-%d", -operand->data.mem.offset);
+ else
+ tmp = 0;
+ errorlen += tmp;
+ buf += tmp;
+ if (copts.codegen_pic && uses_globals && pic_base_reg) {
+ tmp = sprintf(buf, "-B%d", pic_base_pcodelabel->block->blockIndex);
+ errorlen += tmp;
+ buf += tmp;
+ }
+ switch ((unsigned char) operand->arg) {
+ case RefType_6:
+ case RefType_7:
+ case RefType_8:
+ case RefType_A:
+ case RefType_B:
+ case RefType_C:
+ case RefType_D:
+ errorlen += sprintf(buf, ")");
+ }
+ break;
+ case PCOp_LABEL:
+ if (do_show_basic_blocks) {
+ if (!operand->data.label.label->block)
+ tmp = sprintf(buf, "B<unknown>");
+ else
+ tmp = sprintf(buf, "B%" PRId32, operand->data.label.label->block->blockIndex);
+ } else {
+ tmp = sprintf(buf, "%.8" PRIX32, operand->data.label.label->block->codeOffset);
+ }
+ errorlen += tmp;
+ break;
+ case PCOp_LABELDIFF:
+ refis1 = ((unsigned char) operand->arg == 1);
+ b_null = !operand->data.labeldiff.labelB->block;
+ if (operand->data.labeldiff.labelA->block == NULL) {
+ if (b_null)
+ tmp = sprintf(buf, "%sB<unknown>-B<unknown>+%" PRId32, refis1 ? "-" : "", operand->data.labeldiff.offset);
+ else
+ tmp = sprintf(buf, "%sB<unknown>-B%" PRId32 "+%" PRId32, refis1 ? "-" : "", operand->data.labeldiff.labelB->block->blockIndex, operand->data.labeldiff.offset);
+ } else {
+ if (b_null)
+ tmp = sprintf(buf, "%sB%" PRId32 "-B<unknown>+%" PRId32, refis1 ? "-" : "", operand->data.labeldiff.labelA->block->blockIndex, operand->data.labeldiff.offset);
+ else
+ tmp = sprintf(buf, "%sB%" PRId32 "-B%" PRId32 "+%" PRId32, refis1 ? "-" : "", operand->data.labeldiff.labelA->block->blockIndex, operand->data.labeldiff.labelB->block->blockIndex, operand->data.labeldiff.offset);
+ }
+ errorlen += tmp;
+ break;
+ case PCOp_PLACEHOLDEROPERAND:
+ errorlen += sprintf(buf, "{placeholder}");
+ break;
+ default:
+ errorlen += sprintf(buf, "{UNEXPECTED kind = %d}", operand->kind);
+ }
+
+ return errorlen;
+}
+
+int formatoperand(PCodeArg *operand, char *buf) {
+ return expectandformatoperand(
+ operand,
+ operand->kind,
+ (operand->kind == PCOp_REGISTER) ? operand->arg : 'x',
+ -1,
+ buf);
+}
+
+void formatoperands(PCode *pcode, char *buf, int showBasicBlocks) {
+ const char *format; // r29
+ // there might be a PCodeArg *arg in r28
+ // not sure lol
+ PCodeArg *pa;
+ int arg_index; // r27
+
+ char *name;
+ int i;
+ int tmp;
+ int tmp2;
+ SInt32 thing;
+ SInt32 thing2;
+ SInt32 thing4;
+ char c;
+ int flagSetT;
+ int flagSetF;
+
+ static char *cc[] = {
+ "lt", "gt", "eq", "un"
+ };
+ static char *to[] = {
+ "", "lgt", "llt", "",
+ "eq", "lge", "lle", "",
+ "gt", "", "", "",
+ "ge", "", "", "",
+ "lt", "", "", "",
+ "le", "", "", "",
+ "ne", "", "", "",
+ "", "", ""
+ };
+
+ format = opcodeinfo[pcode->op].format;
+ orig_buf = buf;
+ do_show_basic_blocks = showBasicBlocks;
+
+ if (format[0] == '#') {
+ format++;
+ if (format[0] == ',')
+ format++;
+ }
+
+ arg_index = 0;
+ pa = pcode->args;
+ while (*format) {
+ if (*format == ';')
+ break;
+ if (arg_index == pcode->argCount) {
+ pclist_bad_operand = 1;
+ buf += sprintf(buf, "{EXCEDED noperands, remaning format = %s}", format);
+ break;
+ }
+
+ if (*format == ',') {
+ *(buf++) = ',';
+ format++;
+ }
+
+ if (*format == '[' || *format == '(') {
+ *(buf++) = *format;
+ format++;
+ }
+
+ if (*format == '=' || *format == '+')
+ format++;
+ if (*format == '-')
+ format++;
+
+ if (*format == '?') {
+ format++;
+ if (*format != 'c')
+ *(buf++) = ',';
+ }
+
+ if (*format == '!')
+ format++;
+
+ switch (*format) {
+ case 'b':
+ if (pa->kind == PCOp_REGISTER && pa->arg == RegClass_GPR && pa->data.reg.reg == 0) {
+ if (pa->data.reg.effect & EffectWrite) {
+ pclist_bad_operand = 1;
+ buf += sprintf(buf, "!!!r");
+ }
+ buf += sprintf(buf, "0");
+ break;
+ }
+ case 'r':
+ buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_GPR, -1, buf);
+ break;
+ case 'f':
+ buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_FPR, -1, buf);
+ break;
+ case 'v':
+ buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_VR, -1, buf);
+ break;
+ case 'c':
+ buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_CRFIELD, -1, buf);
+ break;
+ case 'X':
+ CError_ASSERT(1124, pa->data.reg.reg == 0);
+ buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_SPR, -1, buf);
+ break;
+ case 'C':
+ CError_ASSERT(1129, pa->data.reg.reg == 2);
+ buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_SPR, -1, buf);
+ break;
+ case 'L':
+ CError_ASSERT(1134, pa->data.reg.reg == 1);
+ buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_SPR, -1, buf);
+ break;
+ case 'Z':
+ CError_ASSERT(1139, pa->data.reg.reg == 0);
+ buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_SPR, -1, buf);
+ break;
+ case 'P':
+ if (isdigit(format[1]))
+ format += pcode_const_from_format(format + 1, &thing);
+ else
+ CError_FATAL(1149);
+ case 'S':
+ case 'T':
+ case 's':
+ if (pa->kind == PCOp_REGISTER && pa->arg == RegClass_SPR) {
+ buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_SPR, -1, buf);
+ } else {
+ for (i = 0; i < 4; i++) {
+ if (pa->data.reg.reg == spr_to_sysreg[i]) {
+ CError_FATAL(1161);
+ break;
+ }
+ }
+
+ buf += expectandformatoperand(pa, PCOp_SYSREG, RegClass_SPR, -1, buf);
+ }
+ break;
+
+ case 'V':
+ do {
+ buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_GPR, -1, buf);
+ *(buf++) = ',';
+ pa++;
+ arg_index++;
+ } while (arg_index < pcode->argCount && pa->kind == PCOp_REGISTER && pa->arg == RegClass_GPR);
+ buf--;
+ pa--;
+ arg_index--;
+ break;
+
+ case 'Y':
+ do {
+ buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_CRFIELD, -1, buf);
+ *(buf++) = ',';
+ pa++;
+ arg_index++;
+ } while (arg_index < pcode->argCount && pa->kind == PCOp_REGISTER && pa->arg == RegClass_CRFIELD);
+ buf--;
+ pa--;
+ arg_index--;
+ break;
+
+ case 'Q':
+ buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_CRFIELD, -1, buf);
+ *(buf++) = ',';
+ pa++;
+ arg_index++;
+ case 'q':
+ if (pa->kind == PCOp_IMMEDIATE && pa->data.imm.value >= 0 && pa->data.imm.value < 4 && (name = cc[pa->data.imm.value])[0]) {
+ buf += sprintf(buf, "%s", name);
+ } else {
+ buf += sprintf(buf, "{OUT OF RANGE}");
+ buf += expectandformatoperand(pa, PCOp_IMMEDIATE, 0, -1, buf);
+ }
+ break;
+ case 'a':
+ case 'i':
+ case 'u':
+ case 'x':
+ tmp = *format;
+ if (tmp == 'a') {
+ if (isdigit(format[1])) {
+ format++;
+ tmp = *format;
+ } else {
+ CError_FATAL(1227);
+ }
+ }
+ if ((tmp2 = isdigit(format[1])))
+ format += pcode_const_from_format(format + 1, &thing2);
+ if (!tmp2)
+ thing2 = -1;
+ buf += expectandformatoperand(pa, PCOp_IMMEDIATE, tmp, thing2, buf);
+ break;
+
+ case 'N':
+ buf += expectandformatoperand(pa, PCOp_IMMEDIATE, 'u', 6, buf);
+ break;
+
+ case 'D':
+ buf += expectandformatoperand(pa, PCOp_IMMEDIATE, 'u', 10, buf);
+ break;
+
+ case 't':
+ if (pa->kind == PCOp_IMMEDIATE && pa->data.imm.value > 0 && pa->data.imm.value < 31 && (name = to[pa->data.imm.value])[0]) {
+ buf += sprintf(buf, "%s", name);
+ break;
+ }
+
+ case 'B':
+ buf += expectandformatoperand(pa, PCOp_IMMEDIATE, 'x', 5, buf);
+ break;
+
+ case 'l':
+ if (pa->kind == PCOp_IMMEDIATE) {
+ buf += sprintf(buf, "*%s%" PRId32, (pa->data.imm.value >= 0) ? "+" : "", pa->data.imm.value);
+ } else if (pa->kind == PCOp_LABELDIFF) {
+ buf += expectandformatoperand(pa, PCOp_LABELDIFF, 0, -1, buf);
+ } else if (pa->kind == PCOp_LABEL) {
+ buf += expectandformatoperand(pa, PCOp_LABEL, 0, -1, buf);
+ } else {
+ buf += expectandformatoperand(pa, PCOp_MEMORY, 0, -1, buf);
+ }
+ break;
+
+ case 'd':
+ if (pa[1].kind == PCOp_MEMORY)
+ buf += expectandformatoperand(pa + 1, PCOp_MEMORY, 0, -1, buf);
+ else
+ buf += expectandformatoperand(pa + 1, PCOp_IMMEDIATE, 0, -1, buf);
+ CError_ASSERT(1283, format[1] == '(');
+ format++;
+ *(buf++) = *(format++);
+ if (*format == '+')
+ format++;
+ CError_ASSERT(1291, format[0] == 'b');
+ if (pa->kind == PCOp_REGISTER && pa->arg == RegClass_GPR && pa->data.reg.reg == 0) {
+ if (pa->data.reg.effect & (EffectRead | EffectWrite)) {
+ pclist_bad_operand = 1;
+ buf += sprintf(buf, "!!!r");
+ }
+ buf += sprintf(buf, "0");
+ } else {
+ buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_GPR, -1, buf);
+ }
+ pa++;
+ i++;
+ break;
+
+ case 'w':
+ if (pa->kind == PCOp_LABELDIFF)
+ buf += expectandformatoperand(pa, PCOp_LABELDIFF, 0, -1, buf);
+ else
+ buf += expectandformatoperand(pa, PCOp_IMMEDIATE, 0, -1, buf);
+ break;
+
+ case 'm':
+ case 'n':
+ if (pa->kind == PCOp_MEMORY)
+ buf += expectandformatoperand(pa, PCOp_MEMORY, 0, -1, buf);
+ else if (pa->kind == PCOp_LABELDIFF)
+ buf += expectandformatoperand(pa, PCOp_LABELDIFF, 0, -1, buf);
+ else if ((pcode->flags & (fIsBranch | fIsCall)) && (pa->kind == PCOp_LABEL))
+ buf += expectandformatoperand(pa, PCOp_LABEL, 0, -1, buf);
+ else
+ buf += expectandformatoperand(pa, PCOp_IMMEDIATE, 0, -1, buf);
+ break;
+
+ case 'M':
+ if (pa->kind == PCOp_MEMORY) {
+ CError_ASSERT(1335, pa->arg == RefType_8 || pa->arg == RefType_B || pa->arg == RefType_C);
+ buf += expectandformatoperand(pa, PCOp_MEMORY, 0, -1, buf);
+ } else if (pa->kind == PCOp_LABELDIFF)
+ buf += expectandformatoperand(pa, PCOp_LABELDIFF, 0, -1, buf);
+ else
+ buf += expectandformatoperand(pa, PCOp_IMMEDIATE, 0, -1, buf);
+ break;
+
+ case 'O':
+ pa--;
+ arg_index--;
+ break;
+
+ case 'p':
+ buf += expectandformatoperand(pa, PCOp_PLACEHOLDEROPERAND, 0, -1, buf);
+ break;
+
+ default:
+ CError_FATAL(1465);
+ }
+
+ while (format[1] && strchr("/<>|*", format[1])) {
+ switch (*(++format)) {
+ case '/':
+ if (format[1] == '2')
+ format++;
+ break;
+ case '<':
+ case '*':
+ case '|':
+ case '>':
+ if (format[1] == 'p')
+ format++;
+ else if (isdigit(format[1]))
+ format += pcode_const_from_format(format + 1, &thing4);
+ else
+ CError_FATAL(1495);
+ break;
+ }
+ }
+
+ if ((c = *(++format)) == ']' || c == ')') {
+ *(buf++) = c;
+ format++;
+ }
+
+ pa++;
+ arg_index++;
+ }
+
+ if (buf[-1] == ',')
+ buf--;
+
+ flagSetT = PCODE_FLAG_SET_T(pcode);
+ flagSetF = PCODE_FLAG_SET_F(pcode);
+ if (pcode->flags & fIsConst)
+ buf += sprintf(buf, "; fIsConst");
+ if (pcode->flags & fIsVolatile)
+ buf += sprintf(buf, "; fIsVolatile");
+ if (pcode->flags & fSideEffects)
+ buf += sprintf(buf, "; fSideEffects");
+ if (pcode->flags & fIsCSE)
+ buf += sprintf(buf, "; fIsCSE");
+ if (pcode->flags & fCommutative)
+ buf += sprintf(buf, "; fCommutative");
+
+ if (flagSetF & fIsPtrOp)
+ buf += sprintf(buf, "; fIsPtrOp");
+
+ if (flagSetT) {
+ if (flagSetT & fLink)
+ buf += sprintf(buf, "; fLink");
+ if (flagSetT & fAbsolute)
+ buf += sprintf(buf, "; fAbsolute");
+ if (flagSetT & fBranchTaken)
+ buf += sprintf(buf, "; fBranchTaken");
+ if (flagSetT & fBranchNotTaken)
+ buf += sprintf(buf, "; fBranchNotTaken");
+ } else if (flagSetF) {
+ if (flagSetF & fSetsCarry)
+ buf += sprintf(buf, "; fSetsCarry");
+ if (flagSetF & fOverflow)
+ buf += sprintf(buf, "; fOverflow");
+ }
+
+ *buf = 0;
+}
+
+PCode *makecopyinstruction(PCodeArg *a, PCodeArg *b) {
+ if (b->kind == PCOp_REGISTER) {
+ switch (b->arg) {
+ case RegClass_GPR:
+ return makepcode(PC_MR, b->data.reg.reg, a->data.reg.reg);
+ case RegClass_FPR:
+ return makepcode(PC_FMR, b->data.reg.reg, a->data.reg.reg);
+ case RegClass_VR:
+ return makepcode(PC_VMR, b->data.reg.reg, a->data.reg.reg);
+ case RegClass_CRFIELD:
+ return makepcode(PC_MCRF, b->data.reg.reg, a->data.reg.reg);
+ }
+ }
+
+ CError_FATAL(1622);
+ return NULL;
+}
+
+int is_location_independent(PCode *pcode) {
+ switch (pcode->op) {
+ case PC_LI:
+ case PC_LIS:
+ case PC_VSPLTISB:
+ case PC_VSPLTISH:
+ case PC_VSPLTISW:
+ return 1;
+ case PC_ADDI:
+ case PC_ADDIS:
+ case PC_ORI:
+ case PC_ORIS:
+ return pcode->args[1].data.reg.reg == _FP_;
+ case PC_LWZ:
+ if (
+ pcode->args[1].data.reg.reg == 1 &&
+ pcode->args[2].kind == PCOp_IMMEDIATE &&
+ pcode->args[2].data.imm.value == 0
+ )
+ return 1;
+ }
+
+ return 0;
+}
+
+int can_reuse_stored_value(PCode *a, PCode *b) {
+ switch (b->op) {
+ case PC_LWZ:
+ case PC_LWZU:
+ case PC_LWZX:
+ case PC_LWZUX:
+ switch (a->op) {
+ case PC_STW:
+ case PC_STWU:
+ case PC_STWX:
+ case PC_STWUX:
+ return 1;
+ }
+ break;
+
+ case PC_LFD:
+ case PC_LFDU:
+ case PC_LFDX:
+ case PC_LFDUX:
+ switch (a->op) {
+ case PC_STFD:
+ case PC_STFDU:
+ case PC_STFDX:
+ case PC_STFDUX:
+ return 1;
+ }
+ break;
+
+ case PC_LVX:
+ if (a->op == PC_STVX)
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+
+int nbytes_loaded_or_stored_by(PCode *pcode) {
+ OpcodeInfo *oinfo = opcodeinfo + pcode->op;
+ if (oinfo->flags & (fIsRead | fIsWrite)) {
+ switch (pcode->op) {
+ 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 (pcode->args[0].kind == PCOp_REGISTER && pcode->args[0].arg == RegClass_GPR)
+ return (32 - pcode->args[0].data.reg.reg) * 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 pcode->args[2].data.imm.value; // not sure if imm is the right union type here
+ case PC_LSWX:
+ case PC_STSWX:
+ return 128;
+
+ // there's probably an ifdef here lmao
+ 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:
+ CError_FATAL(2011);
+ }
+ }
+
+ CError_FATAL(2014);
+ return 0;
+}
+
+void change_num_operands(PCode *pcode, int newNum) {
+ int i;
+
+ CError_ASSERT(2026, ((pcode->argCount > 5) ? pcode->argCount : 5) >= newNum);
+
+ for (i = pcode->argCount - 1; i >= newNum; i--)
+ pcode->args[i].kind = PCOp_PLACEHOLDEROPERAND;
+
+ pcode->argCount = newNum;
+}
+
+void change_opcode(PCode *pcode, short opcode) {
+ pcode->flags = (pcode->flags & ~(opcodeinfo[pcode->op].flags & ~fIsPtrOp)) | opcodeinfo[opcode].flags;
+ if ((pcode->flags & fIsMove) && (PCODE_FLAG_SET_F(pcode) & fRecordBit))
+ pcode->flags &= ~fIsMove;
+ pcode->op = opcode;
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/PPCError.c b/compiler_and_linker/BackEnd/PowerPC/PPCError.c
new file mode 100644
index 0000000..2d4c469
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/PPCError.c
@@ -0,0 +1,70 @@
+#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;
+ CError_ASSERT(40, scode >= 100 && scode < PPCErrorStrMAX);
+
+ 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/BackEnd/PowerPC/RegisterAllocator/Coloring.c b/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/Coloring.c
new file mode 100644
index 0000000..8036435
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/Coloring.c
@@ -0,0 +1,268 @@
+#include "compiler/Coloring.h"
+#include "compiler/CFunc.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/InterferenceGraph.h"
+#include "compiler/PCode.h"
+#include "compiler/PPCError.h"
+#include "compiler/Registers.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/SpillCode.h"
+#include "compiler/StackFrame.h"
+#include "compiler/objects.h"
+
+RegClass coloring_class;
+static short used_regs_before_coloring;
+
+static void markspecialregisters(RegClass rclass) {
+ ObjectList *list;
+ Object *object;
+ VarInfo *vi;
+ UInt32 i;
+
+ for (i = 0; i < n_real_registers[rclass]; i++)
+ interferencegraph[i]->x14 = i;
+
+ for (list = arguments; list; list = list->next) {
+ object = list->object;
+ vi = Registers_GetVarInfo(object);
+ if ((vi->flags & VarInfoFlag2) && vi->rclass == rclass) {
+ interferencegraph[vi->reg]->spillTemporary = object;
+ if (vi->flags & VarInfoFlag4) {
+ interferencegraph[vi->reg]->flags |= fPairLow;
+ interferencegraph[vi->regHi]->flags |= fPairHigh;
+ interferencegraph[vi->regHi]->spillTemporary = object;
+ }
+ }
+ }
+
+ for (list = locals; list; list = list->next) {
+ object = list->object;
+ vi = Registers_GetVarInfo(object);
+ if ((vi->flags & VarInfoFlag2) && vi->rclass == rclass) {
+ interferencegraph[vi->reg]->spillTemporary = object;
+ if (vi->flags & VarInfoFlag4) {
+ interferencegraph[vi->reg]->flags |= fPairLow;
+ interferencegraph[vi->regHi]->flags |= fPairHigh;
+ interferencegraph[vi->regHi]->spillTemporary = object;
+ }
+ }
+ }
+}
+
+static IGNode *simplifygraph(void) {
+ int availableRegs;
+ IGNode *spilledNodes;
+ IGNode *pushedNodes;
+ IGNode *best;
+ IGNode *node;
+ UInt32 i;
+ UInt32 j;
+ int flag;
+ float bestScore;
+ float score;
+
+ availableRegs = available_registers(coloring_class);
+ pushedNodes = NULL;
+
+ do {
+ spilledNodes = NULL;
+ flag = 0;
+ for (i = n_real_registers[coloring_class]; i < used_virtual_registers[coloring_class]; i++) {
+ node = interferencegraph[i];
+ if (!(node->flags & (fPushed | fCoalesced))) {
+ if (node->x12 < availableRegs) {
+ for (j = 0; j < node->arraySize; j++)
+ interferencegraph[node->array[j]]->x12--;
+ node->flags |= fPushed;
+ node->next = pushedNodes;
+ pushedNodes = node;
+ flag = 1;
+ } else {
+ node->next = spilledNodes;
+ spilledNodes = node;
+ }
+ }
+ }
+ } while (flag);
+
+ if (spilledNodes)
+ estimatespillcosts();
+
+ while (spilledNodes) {
+ best = spilledNodes;
+ bestScore = (spilledNodes->x10 >= used_regs_before_coloring) ? FLT_MAX : ((float) spilledNodes->spillCost / (float) spilledNodes->x12);
+
+ for (node = spilledNodes->next; node; node = node->next) {
+ score = (node->x10 >= used_regs_before_coloring) ? FLT_MAX : ((float) node->spillCost / (float) node->x12);
+ if (score < bestScore) {
+ best = node;
+ bestScore = score;
+ }
+ }
+
+ for (i = 0; i < best->arraySize; i++)
+ interferencegraph[best->array[i]]->x12--;
+
+ best->flags |= fPushed;
+ best->next = pushedNodes;
+ pushedNodes = best;
+
+ do {
+ spilledNodes = NULL;
+ flag = 0;
+ for (i = n_real_registers[coloring_class]; i < used_virtual_registers[coloring_class]; i++) {
+ node = interferencegraph[i];
+ if (!(node->flags & (fPushed | fCoalesced))) {
+ if (node->x12 < availableRegs) {
+ for (j = 0; j < node->arraySize; j++)
+ interferencegraph[node->array[j]]->x12--;
+ node->flags |= fPushed;
+ node->next = pushedNodes;
+ pushedNodes = node;
+ flag = 1;
+ } else {
+ node->next = spilledNodes;
+ spilledNodes = node;
+ }
+ }
+ }
+ } while (flag);
+ }
+
+ return pushedNodes;
+}
+
+static int colorgraph(IGNode *node) {
+ UInt32 volatileRegs;
+ int result;
+ IGNode *otherNode;
+ int reg;
+ UInt32 workingMask;
+ int i;
+ short *array;
+
+ result = 1;
+
+ reset_nonvolatile_registers(coloring_class);
+ volatileRegs = volatile_registers(coloring_class);
+
+ while (node) {
+ workingMask = volatileRegs;
+ for (array = node->array, i = 0; i < node->arraySize; i++) {
+ otherNode = interferencegraph[*(array++)];
+ reg = otherNode->x14;
+ if (reg != -1 && reg < n_real_registers[coloring_class])
+ workingMask &= ~(1 << reg);
+ }
+
+ if (workingMask) {
+ for (i = 0; i < n_real_registers[coloring_class]; i++) {
+ if (workingMask & (1 << i)) {
+ node->x14 = i;
+ break;
+ }
+ }
+ } else {
+ reg = obtain_nonvolatile_register(coloring_class);
+ if (reg != -1) {
+ volatileRegs |= 1 << (node->x14 = reg);
+ } else {
+ node->flags |= fSpilled;
+ result = 0;
+ }
+ }
+
+ node = node->next;
+ }
+
+ return result;
+}
+
+static void rewritepcode(void) {
+ PCodeBlock *block;
+ PCode *instr;
+ PCodeArg *op;
+ UInt32 i;
+ IGNode *node;
+ int reg;
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (PC_OP_IS_ANY_REGISTER(op, coloring_class))
+ op->data.reg.reg = interferencegraph[op->data.reg.reg]->x14;
+ op++;
+ }
+
+ if (
+ (instr->flags & fIsMove) &&
+ (instr->args[1].arg == coloring_class) &&
+ instr->args[1].data.reg.reg == instr->args[0].data.reg.reg
+ )
+ deletepcode(instr);
+ }
+ }
+
+ for (i = n_real_registers[coloring_class]; i < used_virtual_registers[coloring_class]; i++) {
+ node = interferencegraph[i];
+ if (node->spillTemporary && !(node->flags & fSpilled)) {
+ if (node->flags & fCoalesced) {
+ reg = node->x14;
+ while (reg >= n_real_registers[coloring_class]) {
+ reg = interferencegraph[reg]->x14;
+ if (reg < 0)
+ break;
+ }
+ node->x14 = reg;
+ }
+
+ if (node->flags & fPairHigh) {
+ reg = node->x14;
+ Registers_GetVarInfo(node->spillTemporary)->regHi = reg;
+ } else {
+ reg = node->x14;
+ Registers_GetVarInfo(node->spillTemporary)->reg = reg;
+ }
+ }
+ }
+}
+
+void colorinstructions(Object *proc) {
+ RegClass rclass;
+ int flag;
+
+ for (rclass = 0; rclass < RegClassMax; rclass++) {
+ coloring_class = rclass;
+
+ if (rclass == RegClass_GPR)
+ check_dynamic_aligned_frame();
+
+ if (used_virtual_registers[rclass] > n_real_registers[rclass]) {
+ save_before_coloring_nonvolatile_registers(rclass);
+ used_regs_before_coloring = used_virtual_registers[rclass];
+ if (!available_registers(rclass)) {
+ PPCError_Error(PPCErrorStr102, register_class_name[rclass]);
+ return;
+ }
+
+ flag = 1;
+ while (flag && used_virtual_registers[rclass] > n_real_registers[rclass]) {
+ buildinterferencegraph(proc);
+ markspecialregisters(rclass);
+ flag = colorgraph(simplifygraph()) ? 0 : 1;
+
+ if (flag)
+ insertspillcode();
+ else
+ rewritepcode();
+ freeoheap();
+ }
+ }
+
+ used_virtual_registers[rclass] = n_real_registers[rclass];
+ }
+
+ coloring = 0;
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/InterferenceGraph.c b/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/InterferenceGraph.c
new file mode 100644
index 0000000..d589502
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/InterferenceGraph.c
@@ -0,0 +1,364 @@
+#include "compiler/InterferenceGraph.h"
+#include "compiler/CError.h"
+#include "compiler/CParser.h"
+#include "compiler/BitVectors.h"
+#include "compiler/Coloring.h"
+#include "compiler/LiveInfo.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeListing.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/Registers.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/CompilerTools.h"
+
+IGNode **interferencegraph;
+static UInt32 *interferencematrix;
+Boolean coalesced_nregisters;
+static SInt16 *coalesced;
+
+static void makeinterfere(UInt32 a, UInt32 b) {
+ if (a < b)
+ bitvectorsetbit(((b * b) / 2) + a, interferencematrix);
+ else if (a > b)
+ bitvectorsetbit(((a * a) / 2) + b, interferencematrix);
+}
+
+int interferes(UInt32 a, UInt32 b) {
+ if (a < b)
+ return bitvectorgetbit(((b * b) / 2) + a, interferencematrix) > 0;
+ else if (a > b)
+ return bitvectorgetbit(((a * a) / 2) + b, interferencematrix) > 0;
+ else
+ return 0;
+}
+
+static void buildinterferencematrix(void) {
+ PCodeBlock *block; // r30
+ PCode *instr; // r29
+ PCodeArg *op;
+ UInt32 *vec; // r28
+ UInt32 i;
+ UInt32 j;
+
+ UInt32 regs = used_virtual_registers[coloring_class];
+ interferencematrix = oalloc(4 * ((((regs * regs) / 2) + 31) >> 5));
+ bitvectorinitialize(interferencematrix, (regs * regs) / 2, 0);
+
+ for (i = 0; i < 32; i++)
+ for (j = 0; j < 32; j++)
+ if (i != j)
+ makeinterfere(i, j);
+
+ vec = oalloc(4 * ((regs + 31) >> 5));
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ bitvectorcopy(vec, liveinfo[block->blockIndex].out, regs);
+ for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
+ for (op = instr->args, i = instr->argCount; i--; op++) {
+ if (PC_OP_IS_WRITE_ANY_REGISTER(op, coloring_class)) {
+ int reg = op->data.reg.reg;
+ bitvectorclearbit(reg, vec);
+ for (j = 0; j < regs; j++) {
+ if (bitvectorgetbit(j, vec)) {
+ if (
+ (instr->flags & fIsMove) &&
+ PC_OP_IS_ANY_REGISTER(&instr->args[0], coloring_class) &&
+ instr->args[1].data.reg.reg == j
+ )
+ continue;
+ makeinterfere(reg, j);
+ }
+ }
+ }
+ }
+
+ for (op = instr->args, i = instr->argCount; i--; op++) {
+ if (PC_OP_IS_READ_ANY_REGISTER(op, coloring_class)) {
+ int reg = op->data.reg.reg;
+ if (bitvectorgetbit(op->data.reg.reg, vec) == 0)
+ op->data.reg.effect |= Effect4;
+ bitvectorsetbit(reg, vec);
+ }
+ }
+
+ if (coloring_class == RegClass_GPR) {
+ if (PCODE_FLAG_SET_F(instr) & (fIsRead | fIsWrite | fPCodeFlag400000)) {
+ if (instr->args[1].data.reg.reg >= n_real_registers[coloring_class])
+ makeinterfere(0, instr->args[1].data.reg.reg);
+ if (PCODE_FLAG_SET_F(instr) & fUpdatesPtr)
+ makeinterfere(instr->args[0].data.reg.reg, instr->args[1].data.reg.reg);
+ } else {
+ switch (instr->op) {
+ case PC_DCBF:
+ case PC_DCBST:
+ case PC_DCBT:
+ case PC_DCBTST:
+ case PC_DCBZ:
+ case PC_DCBI:
+ case PC_ICBI:
+ case PC_DCCCI:
+ case PC_ICBT:
+ case PC_ICCCI:
+ case PC_ICREAD:
+ case PC_DCBA:
+ case PC_DST:
+ case PC_DSTT:
+ case PC_DSTST:
+ case PC_DSTSTT:
+ if (instr->args[0].data.reg.reg >= n_real_registers[coloring_class])
+ makeinterfere(0, instr->args[0].data.reg.reg);
+ break;
+ }
+ }
+ }
+
+ if (coloring_class == RegClass_GPR && (instr->flags & fIsCall)) {
+ i = branch_count_volatiles();
+ op = instr->args;
+ CError_ASSERT(219, instr->argCount != 0);
+
+ while (op->kind != PCOp_REGISTER || !(op->data.reg.effect & EffectWrite)) {
+ i++;
+ op++;
+ CError_ASSERT(226, i <= instr->argCount);
+ }
+
+ for (op = instr->args + i; i < instr->argCount; i++, op++) {
+ if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR) {
+ for (j = 0; j < n_scratch_registers[coloring_class]; j++)
+ makeinterfere(op->data.reg.reg, scratch_registers[coloring_class][j]);
+ }
+ }
+ }
+ }
+ }
+}
+
+static short coalesced_path(short id) {
+ while (id != coalesced[id])
+ id = coalesced[id];
+ return id;
+}
+
+static void coalescenodes(void) {
+ PCodeArg *op;
+ UInt32 regs;
+ PCodeBlock *block;
+ PCode *instr;
+ UInt32 i;
+ short path1;
+ short path2;
+ short node1;
+ short node2;
+
+ regs = used_virtual_registers[coloring_class];
+ coalesced = oalloc(sizeof(SInt16) * regs);
+
+ for (i = 0; i < regs; i++)
+ coalesced[i] = i;
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ if ((instr->flags & fIsMove) && !(instr->flags & fSideEffects)) {
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit) {
+ CError_FATAL(309);
+ continue;
+ }
+
+ if (instr->argCount > 2) {
+ if (instr->argCount != 3 || instr->args[2].kind != PCOp_PLACEHOLDEROPERAND) {
+ CError_FATAL(316);
+ continue;
+ }
+ }
+
+ if (PC_OP_IS_ANY_REGISTER(&instr->args[0], coloring_class)) {
+ path1 = coalesced_path(instr->args[0].data.reg.reg);
+ path2 = coalesced_path(instr->args[1].data.reg.reg);
+ if (path1 == path2) {
+ deletepcode(instr);
+ continue;
+ }
+
+ if (!interferes(path1, path2)) {
+ if (path1 >= n_real_registers[coloring_class] && path2 >= n_real_registers[coloring_class]) {
+ if (path1 < first_fe_temporary_register[coloring_class])
+ continue;
+ if (path1 > last_temporary_register[coloring_class])
+ continue;
+ if (path2 < first_fe_temporary_register[coloring_class])
+ continue;
+ if (path2 > last_temporary_register[coloring_class])
+ continue;
+ }
+
+ node1 = (path2 < path1) ? path2 : path1;
+ node2 = (path2 > path1) ? path2 : path1;
+
+ if (coloring_class == RegClass_GPR && node2 == _CALLER_SP_)
+ continue;
+
+ coalesced[node2] = node1;
+ for (i = 0; i < regs; i++) {
+ if (interferes(node2, i))
+ makeinterfere(node1, i);
+ }
+
+ deletepcode(instr);
+ }
+ }
+ }
+ }
+ }
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (PC_OP_IS_ANY_REGISTER(op, coloring_class) && op->data.reg.reg != coalesced[op->data.reg.reg])
+ op->data.reg.reg = coalesced_path(op->data.reg.reg);
+ op++;
+ }
+ }
+ }
+}
+
+static void buildadjacencyvectors(void) {
+ IGNode *node;
+ UInt32 regs;
+ UInt32 i;
+ UInt32 counter;
+ short *array;
+ short *dest;
+ short *src;
+ UInt32 j;
+
+ regs = used_virtual_registers[coloring_class];
+ interferencegraph = oalloc(sizeof(IGNode *) * regs);
+ array = oalloc(sizeof(short) * regs);
+
+ for (i = 0; i < regs; i++) {
+ counter = 0;
+ for (j = 0; j < regs; j++) {
+ if (interferes(i, j))
+ array[counter++] = j;
+ }
+
+ node = interferencegraph[i] = oalloc(sizeof(IGNode) + sizeof(short) * (counter - 1));
+ memclrw(node, sizeof(IGNode) + sizeof(short) * (counter - 1));
+
+ node->x10 = i;
+ node->x14 = -1;
+ node->arraySize = counter;
+ node->x12 = counter;
+
+ dest = node->array;
+ src = array;
+ for (j = 0; j < counter; j++)
+ *(dest++) = *(src++);
+
+ if (i != coalesced[i]) {
+ node->flags |= fCoalesced;
+ j = coalesced_path(i);
+ interferencegraph[j]->flags |= fCoalescedInto;
+ node->x14 = j;
+ }
+ }
+}
+
+static void eliminatedeadcode(void) {
+ UInt32 regs;
+ PCodeBlock *block;
+ PCode *instr;
+ UInt32 *vec;
+ UInt32 i;
+ PCodeArg *op;
+
+ regs = used_virtual_registers[coloring_class];
+ vec = oalloc(4 * ((regs + 31) >> 5));
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ bitvectorcopy(vec, liveinfo[block->blockIndex].out, regs);
+ for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
+ if (dead(instr, coloring_class, vec)) {
+ deletepcode(instr);
+ continue;
+ }
+
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (PC_OP_IS_WRITE_ANY_REGISTER(op, coloring_class))
+ bitvectorclearbit(op->data.reg.reg, vec);
+ op++;
+ }
+
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (PC_OP_IS_READ_ANY_REGISTER(op, coloring_class)) {
+ int reg = op->data.reg.reg;
+ if (!bitvectorgetbit(reg, vec))
+ op->data.reg.effect |= Effect4;
+ bitvectorsetbit(reg, vec);
+ }
+ op++;
+ }
+ }
+ }
+}
+
+static void findrematerializations(void) {
+ UInt32 regs;
+ UInt32 i;
+ PCodeBlock *block;
+ PCode *instr;
+ PCodeArg *op;
+ IGNode *node;
+
+ regs = used_virtual_registers[coloring_class];
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (
+ PC_OP_IS_WRITE_ANY_REGISTER(op, coloring_class) &&
+ op->data.reg.reg >= n_real_registers[coloring_class] &&
+ !(interferencegraph[op->data.reg.reg]->flags & (fPairLow | fPairHigh)) &&
+ !(interferencegraph[op->data.reg.reg]->flags & fIGNode40)
+ )
+ {
+ node = interferencegraph[op->data.reg.reg];
+ if (!node->instr8) {
+ node->instr8 = instr;
+ } else {
+ node->instr8 = NULL;
+ node->flags |= fIGNode40;
+ }
+ }
+ op++;
+ }
+ }
+ }
+
+ for (i = 0; i < regs; i++) {
+ node = interferencegraph[i];
+ if (node->instr8 && !is_location_independent(node->instr8))
+ node->instr8 = NULL;
+ }
+}
+
+void buildinterferencegraph(Object *proc) {
+ int regs = used_virtual_registers[coloring_class];
+
+ computelivevariables(proc);
+ eliminatedeadcode();
+ buildinterferencematrix();
+ if (copts.debuglisting)
+ pclistinterferences(register_class_format[coloring_class], regs);
+ coalescenodes();
+ buildadjacencyvectors();
+ findrematerializations();
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/RegisterInfo.c b/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/RegisterInfo.c
new file mode 100644
index 0000000..177c2e0
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/RegisterInfo.c
@@ -0,0 +1,381 @@
+#include "compiler/RegisterInfo.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CError.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];
+short last_argument_register[RegClassMax];
+short _FP_;
+short _CALLER_SP_;
+char *special_register_names[RegClassMax][RegisterMax];
+static short used_regs_before_coloring;
+static UInt8 save_state[RegisterMax];
+
+short spr_to_sysreg[4] = {1, 8, 9, 0x100};
+
+void asm_used_register(RegClass rclass, short reg) {
+ int i;
+
+ if ((reg < n_real_registers[rclass]) && (reg_state[rclass][reg] == RegState0)) {
+ if (reg == nonvolatile_registers[rclass][used_nonvolatile_registers[rclass]]) {
+ if (assignable_registers[rclass] > 0)
+ assignable_registers[rclass]--;
+ reg_state[rclass][reg] = RegState1;
+ used_nonvolatile_registers[rclass]++;
+ } else {
+ for (i = used_nonvolatile_registers[rclass]; i < n_nonvolatile_registers[rclass]; i++) {
+ if (reg == nonvolatile_registers[rclass][i]) {
+ reg_state[rclass][reg] = RegState1;
+ if (assignable_registers[rclass] > 0)
+ assignable_registers[rclass]--;
+ }
+ }
+ }
+ }
+}
+
+void retain_register(Object *obj, RegClass rclass, short reg) {
+ VarInfo *vi;
+
+ CError_ASSERT(95, (short) reg < RegisterMax);
+
+ if (reg_state[rclass][reg] == RegState0) {
+ assignable_registers[rclass]--;
+ reg_state[rclass][reg] = RegState1;
+ if (reg == nonvolatile_registers[rclass][used_nonvolatile_registers[rclass]])
+ used_nonvolatile_registers[rclass]++;
+ }
+
+ if (obj) {
+ vi = Registers_GetVarInfo(obj);
+ vi->rclass = rclass;
+ vi->flags |= VarInfoFlag2;
+ vi->reg = reg;
+ }
+}
+
+void retain_GPR_pair(Object *obj, short reg, short regHi) {
+ VarInfo *vi;
+
+ retain_register(NULL, RegClass_GPR, reg);
+ retain_register(NULL, RegClass_GPR, regHi);
+
+ if (obj) {
+ vi = Registers_GetVarInfo(obj);
+ vi->rclass = RegClass_GPR;
+ vi->flags |= VarInfoFlag2 | VarInfoFlag4;
+ vi->reg = reg;
+ vi->regHi = regHi;
+ }
+}
+
+int is_register_object(Object *obj) {
+ return obj->sclass == TK_REGISTER;
+}
+
+int GetABIFirstNonVolatile(RegClass rclass) {
+ switch (rclass) {
+ case RegClass_SPR: return 3;
+ case RegClass_CRFIELD: return 2;
+ case RegClass_VR: return 20;
+ case RegClass_GPR: return 13;
+ case RegClass_FPR: return 14;
+ default: return -1;
+ }
+}
+
+char GetRegisterClassName(RegClass rclass) {
+ switch (rclass) {
+ case RegClass_VR: return 'v';
+ case RegClass_GPR: return 'r';
+ case RegClass_FPR: return 'f';
+ default:
+ CError_FATAL(242);
+ return '?';
+ }
+}
+
+static int first_nonvolatile_reg(RegClass rclass) {
+ return GetABIFirstNonVolatile(rclass);
+}
+
+void setup_diagnostic_reg_strings(void) {
+ register_class_name[RegClass_SPR] = "SPR";
+ register_class_format[RegClass_SPR] = "spr%" PRId32;
+ register_class_name[RegClass_CRFIELD] = "CRFIELD";
+ register_class_format[RegClass_CRFIELD] = "cr%" PRId32;
+ register_class_name[RegClass_VR] = "VR";
+ register_class_format[RegClass_VR] = "vr%" PRId32;
+ register_class_name[RegClass_FPR] = "FPR";
+ register_class_format[RegClass_FPR] = "f%" PRId32;
+ register_class_name[RegClass_GPR] = "GPR";
+ register_class_format[RegClass_GPR] = "r%" PRId32;
+}
+
+void init_target_registers(void) {
+ int reg;
+ int end;
+ RegClass rclass;
+
+ static int last_nonvolatile_reg[] = {3, 5, 31, 31, 31};
+ static int nonvol_reserve[] = {0, 0, 0, 4, 3};
+
+ for (rclass = 0; rclass < RegClassMax; rclass++) {
+ for (reg = 0; reg < RegisterMax; reg++)
+ special_register_names[rclass][reg] = NULL;
+ }
+
+ special_register_names[RegClass_SPR][0] = "XER";
+ special_register_names[RegClass_SPR][1] = "LR";
+ special_register_names[RegClass_SPR][2] = "CTR";
+ special_register_names[RegClass_SPR][3] = "VRSAVE";
+ special_register_names[RegClass_GPR][1] = "SP";
+
+ setup_diagnostic_reg_strings();
+ n_real_registers[RegClass_SPR] = 4;
+ n_real_registers[RegClass_CRFIELD] = 8;
+ n_real_registers[RegClass_VR] = 32;
+ n_real_registers[RegClass_FPR] = 32;
+ n_real_registers[RegClass_GPR] = 32;
+ reg_state[RegClass_GPR][1] = RegState2;
+ reg_state[RegClass_GPR][2] = RegState2;
+ reg_state[RegClass_CRFIELD][5] = RegState2;
+
+ for (rclass = 0; rclass < RegClassMax; rclass++) {
+ n_nonvolatile_registers[rclass] = 0;
+ if (last_nonvolatile_reg[rclass] >= 0) {
+ end = first_nonvolatile_reg(rclass);
+ for (reg = last_nonvolatile_reg[rclass]; reg >= end; reg--) {
+ if (reg_state[rclass][reg] == RegState0) {
+ nonvolatile_registers[rclass][n_nonvolatile_registers[rclass]++] = reg;
+ }
+ }
+ }
+
+ assignable_registers[rclass] = n_nonvolatile_registers[rclass] - nonvol_reserve[rclass];
+ if (assignable_registers[rclass] < 0)
+ assignable_registers[rclass] = 0;
+
+ n_scratch_registers[rclass] = 0;
+ for (reg = 0; reg < n_real_registers[rclass]; reg++) {
+ if (reg < GetABIFirstNonVolatile(rclass) || reg > last_nonvolatile_reg[rclass]) {
+ if (reg_state[rclass][reg] == RegState0) {
+ scratch_registers[rclass][n_scratch_registers[rclass]++] = reg;
+ }
+ }
+ }
+ }
+
+ _FP_ = -1;
+ _CALLER_SP_ = -1;
+ optimizing = (copts.optimizationlevel > 0) && !disable_optimizer;
+}
+
+void assign_register_by_type(Object *obj) {
+ VarInfo *vi;
+ Type *ty;
+ Boolean flag;
+
+ ty = obj->type;
+ vi = Registers_GetVarInfo(obj);
+ flag = 0;
+ vi->rclass = RegClassMax;
+ vi->reg = 0;
+ vi->regHi = 0;
+
+ if ((ty->type == TYPEINT) || (ty->type == TYPEENUM) || ((ty->type == TYPEPOINTER || ty->type == TYPEARRAY) && (ty->type != TYPEARRAY)) || ((ty->type == TYPEMEMBERPOINTER) && (ty->size == 4U))) {
+ if (((ty->type == TYPEINT) || (ty->type == TYPEENUM)) && (ty->size == 8))
+ flag = 1;
+ vi->rclass = RegClass_GPR;
+ } else if (ty->type == TYPEFLOAT) {
+ vi->rclass = RegClass_FPR;
+ } else if ((ty->type == TYPESTRUCT) && (TYPE_STRUCT(ty)->stype >= STRUCT_VECTOR_UCHAR) && (TYPE_STRUCT(ty)->stype <= STRUCT_VECTOR_PIXEL)) {
+ vi->rclass = RegClass_VR;
+ } else {
+ return;
+ }
+
+ if (vi->rclass < RegClassMax) {
+ if (flag) {
+ CError_ASSERT(520, vi->rclass == RegClass_GPR);
+ if (assignable_registers[vi->rclass] > 1)
+ assign_GPR_pair(obj);
+ } else {
+ if (assignable_registers[vi->rclass] > 0)
+ assign_register_to_variable(obj, vi->rclass);
+ }
+ }
+}
+
+void assign_GPR_pair(Object *obj) {
+ VarInfo *vi;
+ short reg;
+ short regHi;
+
+ vi = Registers_GetVarInfo(obj);
+ if (optimizing) {
+ reg = used_virtual_registers[RegClass_GPR]++;
+ regHi = used_virtual_registers[RegClass_GPR]++;
+ } else {
+ CError_ASSERT(554, assignable_registers[RegClass_GPR] >= 2);
+ reg = obtain_nonvolatile_register(RegClass_GPR);
+ regHi = obtain_nonvolatile_register(RegClass_GPR);
+ retain_GPR_pair(obj, reg, regHi);
+ }
+
+ vi->rclass = RegClass_GPR;
+ if (reg > 0 && regHi > 0) {
+ vi->flags |= VarInfoFlag2 | VarInfoFlag4;
+ vi->reg = reg;
+ vi->regHi = regHi;
+ } else {
+ CError_FATAL(567);
+ }
+}
+
+void open_fe_temp_registers(void) {
+ int r;
+
+ r = used_virtual_registers[RegClass_GPR];
+ first_fe_temporary_register[RegClass_GPR] = last_temporary_register[RegClass_GPR] = r;
+ r = used_virtual_registers[RegClass_FPR];
+ first_fe_temporary_register[RegClass_FPR] = last_temporary_register[RegClass_FPR] = r;
+ r = used_virtual_registers[RegClass_VR];
+ first_fe_temporary_register[RegClass_VR] = last_temporary_register[RegClass_VR] = r;
+}
+
+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(void) {
+ VarInfo *vi = galloc(sizeof(VarInfo));
+ memclrw(vi, sizeof(VarInfo));
+ return vi;
+}
+
+VarInfo *Registers_GetVarInfo(Object *obj) {
+ switch (obj->datatype) {
+ case DDATA:
+ if (!obj->u.data.info)
+ obj->u.data.info = Registers_GetNewVarInfo();
+ return obj->u.data.info;
+ case DNONLAZYPTR:
+ if (!obj->u.toc.info) {
+ CError_FATAL(639);
+ obj->u.toc.info = CodeGen_GetNewVarInfo();
+ }
+ return obj->u.toc.info;
+ case DLOCAL:
+ if (!obj->u.var.info)
+ CError_FATAL(647);
+ return obj->u.var.info;
+ case DABSOLUTE:
+ // not sure if this is the right union
+ if (!obj->u.data.info)
+ obj->u.data.info = Registers_GetNewVarInfo();
+ return obj->u.data.info;
+ default:
+ CError_FATAL(660);
+ return NULL;
+ }
+}
+
+int used_vrstate_VRs(void) {
+ int count = 0;
+ int i;
+ for (i = 0; i < RegisterMax; i++) {
+ if (reg_state[RegClass_VR][i])
+ count++;
+ }
+ return count;
+}
+
+UInt32 colored_vrs_as_vrsave(PCodeBlock *block) {
+ PCode *pc;
+ UInt32 mask;
+ int i;
+
+ mask = 0;
+ if (copts.altivec_vrsave == 2)
+ return 0xFFFFFFFF;
+ if (copts.altivec_vrsave == 0)
+ return 0;
+
+ while (block) {
+ for (pc = block->firstPCode; pc; pc = pc->nextPCode) {
+ if (pc->flags & fOpTypeVR) {
+ for (i = 0; i < pc->argCount; i++) {
+ if (pc->args[i].kind == PCOp_REGISTER && pc->args[i].arg == RegClass_VR)
+ mask |= 1 << (31 - pc->args[i].data.reg.reg);
+ }
+ }
+ }
+ block = block->nextBlock;
+ }
+
+ return mask;
+}
+
+void save_before_coloring_nonvolatile_registers(RegClass rclass) {
+ used_regs_before_coloring = used_nonvolatile_registers[rclass];
+ memcpy(save_state, reg_state[rclass], sizeof(save_state));
+}
+
+void reset_nonvolatile_registers(RegClass rclass) {
+ used_nonvolatile_registers[rclass] = used_regs_before_coloring;
+ memcpy(reg_state[rclass], save_state, sizeof(save_state));
+}
+
+int is_nonvolatile_register(RegClass rclass, int reg) {
+ int i;
+
+ for (i = 0; i < n_nonvolatile_registers[rclass]; i++) {
+ if (reg == nonvolatile_registers[rclass][i])
+ return 1;
+ }
+
+ return 0;
+}
+
+void init_endian(void) {
+ if (copts.littleendian) {
+ high_offset = 4;
+ low_offset = 0;
+ high_reg = 4;
+ low_reg = 3;
+ high_reg2 = 6;
+ low_reg2 = 5;
+ } else {
+ high_offset = 0;
+ low_offset = 4;
+ high_reg = 3;
+ low_reg = 4;
+ high_reg2 = 5;
+ low_reg2 = 6;
+ }
+}
+
+void update_asm_nonvolatile_registers(void) {
+ RegClass rclass;
+ int i;
+ int reg;
+
+ for (rclass = 0; rclass < RegClassMax; rclass++) {
+ reg = n_nonvolatile_registers[rclass];
+ for (i = n_nonvolatile_registers[rclass] - 1; i >= 0; i--) {
+ if (reg_state[rclass][nonvolatile_registers[rclass][i]] == RegState1)
+ break;
+ reg--;
+ }
+ if (reg > used_nonvolatile_registers[rclass])
+ used_nonvolatile_registers[rclass] = reg;
+ }
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/SpillCode.c b/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/SpillCode.c
new file mode 100644
index 0000000..69e7e43
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/SpillCode.c
@@ -0,0 +1,452 @@
+#include "compiler/SpillCode.h"
+#include "compiler/CError.h"
+#include "compiler/CMachine.h"
+#include "compiler/CParser.h"
+#include "compiler/CodeGen.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/Coloring.h"
+#include "compiler/InterferenceGraph.h"
+#include "compiler/Operands.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/Registers.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/StackFrame.h"
+#include "compiler/objects.h"
+
+static int last_unused_vreg_before_spilling;
+static short rTEMP_for_VR_spill;
+
+void estimatespillcosts(void) {
+ PCodeBlock *block;
+ PCode *instr;
+ IGNode *node;
+ PCodeArg *op;
+ int i;
+ int weight;
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ if (copts.optimizesize)
+ weight = 1;
+ else
+ weight = block->loopWeight;
+
+ for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (PC_OP_IS_READ_ANY_REGISTER(op, coloring_class)) {
+ node = interferencegraph[op->data.reg.reg];
+ if (node->instr8 || copts.optimizesize)
+ node->spillCost += weight;
+ else
+ node->spillCost += weight * 2;
+ }
+ op++;
+ }
+
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (PC_OP_IS_WRITE_ANY_REGISTER(op, coloring_class)) {
+ node = interferencegraph[op->data.reg.reg];
+ if (node->instr8 || (instr->flags & fIsArgInit))
+ node->spillCost -= weight;
+ else
+ node->spillCost += weight;
+ }
+ op++;
+ }
+ }
+ }
+}
+
+static Object *makespilltemporary(Type *type) {
+ Object *obj = lalloc(sizeof(Object));
+ memclrw(obj, sizeof(Object));
+
+ obj->otype = OT_OBJECT;
+ obj->access = ACCESSPUBLIC;
+ obj->datatype = DLOCAL;
+ obj->type = type;
+ obj->name = CParser_GetUniqueName();
+ obj->u.var.info = CodeGen_GetNewVarInfo();
+ obj->u.var.uid = 0;
+
+ return obj;
+}
+
+static PCode *rematerialize_spilled_register(short reg, IGNode *node) {
+ PCode *instr = copypcode(node->instr8);
+
+ CError_ASSERT(128, instr->args[0].kind == PCOp_REGISTER);
+
+ instr->args[0].data.reg.reg = reg;
+ return instr;
+}
+
+static void insert_load_spilled_register(PCode *instr, short reg, IGNode *node) {
+ Type *type;
+ Opcode opcode;
+ Object *object;
+ PCode *newInstr;
+ PCode *newInstr2;
+ SInt32 offset;
+ Operand operand;
+
+ type = node->spillTemporary->type;
+ switch (coloring_class) {
+ case RegClass_CRFIELD:
+ case RegClass_GPR:
+ switch (type->size) {
+ case 1:
+ opcode = PC_LBZ;
+ break;
+ case 2:
+ opcode = is_unsigned(type) ? PC_LHZ : PC_LHA;
+ break;
+ case 4:
+ opcode = PC_LWZ;
+ break;
+ case 8:
+ opcode = PC_LWZ;
+ break;
+ default:
+ CError_FATAL(187);
+ }
+
+ memclrw(&operand, sizeof(Operand));
+ operand.optype = OpndType_Symbol;
+ operand.object = node->spillTemporary;
+ CError_ASSERT(222, node->spillTemporary->datatype == DLOCAL);
+
+ coerce_to_addressable(&operand);
+
+ CError_ASSERT(233, operand.optype == OpndType_GPR_ImmOffset);
+
+ CError_ASSERT(237, node->spillTemporary->datatype == DLOCAL);
+
+ if (node->flags & fPairLow)
+ offset = low_offset;
+ else if (node->flags & fPairHigh)
+ offset = high_offset;
+ else
+ offset = 0;
+ insertpcodebefore(instr, makepcode(opcode, reg, operand.reg, operand.object, operand.immOffset + offset));
+ break;
+
+ case RegClass_FPR:
+ CError_ASSERT(253, node->spillTemporary->datatype == DLOCAL);
+
+ if (node->flags & fPairLow)
+ offset = low_offset;
+ else if (node->flags & fPairHigh)
+ offset = high_offset;
+ else
+ offset = 0;
+
+ object = node->spillTemporary;
+ insertpcodebefore(
+ instr,
+ makepcode(
+ (type->size == 8) ? PC_LFD : PC_LFS,
+ reg,
+ local_base_register(object),
+ object,
+ offset
+ )
+ );
+ break;
+
+ case RegClass_VR:
+ CError_ASSERT(320, node->spillTemporary->datatype == DLOCAL);
+
+ object = node->spillTemporary;
+ newInstr = makepcode(PC_ADDI, rTEMP_for_VR_spill, local_base_register(object), object, 0);
+ newInstr2 = makepcode(PC_LVX, reg, 0, rTEMP_for_VR_spill);
+ insertpcodebefore(instr, newInstr);
+ insertpcodeafter(newInstr, newInstr2);
+ break;
+
+ default:
+ CError_FATAL(333);
+ }
+}
+
+static void insert_store_spilled_register(PCode *instr, Boolean flag, short reg, IGNode *node) {
+ Object *object; // r31
+ Opcode opcode; // r30
+ SInt32 offset; // r26
+ PCode *newInstr2; // r26
+ PCode *newInstr; // r25
+ Type *type; // r25
+
+ object = node->spillTemporary;
+ type = object->type;
+
+ switch (coloring_class) {
+ case RegClass_CRFIELD:
+ case RegClass_GPR:
+ switch (type->size) {
+ case 1:
+ opcode = PC_STB;
+ break;
+ case 2:
+ opcode = PC_STH;
+ break;
+ case 4:
+ opcode = PC_STW;
+ break;
+ case 8:
+ opcode = PC_STW;
+ break;
+ default:
+ CError_FATAL(391);
+ }
+
+ if (node->flags & fPairLow)
+ offset = low_offset;
+ else if (node->flags & fPairHigh)
+ offset = high_offset;
+ else
+ offset = 0;
+
+ newInstr = makepcode(opcode, reg, local_base_register(object), object, offset);
+ if (flag)
+ insertpcodebefore(instr, newInstr);
+ else
+ insertpcodeafter(instr, newInstr);
+
+ break;
+
+ case RegClass_FPR:
+ newInstr = makepcode((type->size == 8) ? PC_STFD : PC_STFS, reg, local_base_register(object), object, 0);
+ if (flag)
+ insertpcodebefore(instr, newInstr);
+ else
+ insertpcodeafter(instr, newInstr);
+
+ break;
+
+ case RegClass_VR:
+ newInstr = makepcode(PC_ADDI, rTEMP_for_VR_spill, local_base_register(object), object, 0);
+ newInstr2 = makepcode(PC_STVX, reg, 0, rTEMP_for_VR_spill);
+ if (flag)
+ insertpcodebefore(instr, newInstr);
+ else
+ insertpcodeafter(instr, newInstr);
+ insertpcodeafter(newInstr, newInstr2);
+
+ break;
+
+ default:
+ CError_FATAL(527);
+ }
+}
+
+static void spillinstruction(PCodeBlock *block, PCode *instr) {
+ int reg;
+ int reg2;
+ int regs;
+ IGNode *node;
+ PCodeArg *op;
+ int i;
+ PCodeArg *op2;
+ int j;
+ int readCounter;
+ int writeCounter;
+ Boolean flag;
+
+ regs = used_virtual_registers[coloring_class];
+ flag = 0;
+ for (i = 0, op = instr->args; i < instr->argCount; i++, op++) {
+ CError_ASSERT(563, instr->block != NULL);
+
+ if (
+ PC_OP_IS_ANY_REGISTER(op, coloring_class) &&
+ (reg = op->data.reg.reg) < regs &&
+ ((node = interferencegraph[op->data.reg.reg])->flags & fSpilled)
+ )
+ {
+ reg2 = used_virtual_registers[coloring_class]++;
+ readCounter = 0;
+ writeCounter = 0;
+
+ for (j = i, op2 = op; j < instr->argCount; j++, op2++) {
+ if (PC_OP_IS_REGISTER(op2, coloring_class, reg)) {
+ if (op2->data.reg.effect & EffectRead)
+ readCounter++;
+ if (op2->data.reg.effect & EffectWrite)
+ writeCounter++;
+ op2->data.reg.reg = reg2;
+ op2->data.reg.effect |= Effect40;
+ }
+ }
+
+ if (readCounter) {
+ if (node->instr8)
+ insertpcodebefore(instr, rematerialize_spilled_register(reg2, node));
+ else
+ insert_load_spilled_register(instr, reg2, node);
+ }
+
+ if (writeCounter) {
+ if (node->instr8 || (instr->flags & fIsArgInit))
+ flag = 1;
+ else
+ insert_store_spilled_register(instr, 0, reg2, node);
+ }
+ }
+ }
+
+ if (flag)
+ deletepcode(instr);
+}
+
+static void spillcopy(PCodeBlock *block, PCode *instr) {
+ IGNode *node1;
+ IGNode *node2;
+ int reg;
+
+ node1 = interferencegraph[instr->args[1].data.reg.reg];
+ node2 = interferencegraph[instr->args[0].data.reg.reg];
+
+ if (node1->flags & fSpilled) {
+ if (node2->flags & fSpilled) {
+ reg = used_virtual_registers[coloring_class]++;
+ if (node1->instr8)
+ insertpcodebefore(instr, rematerialize_spilled_register(reg, node1));
+ else
+ insert_load_spilled_register(instr, reg, node1);
+ insert_store_spilled_register(instr, 1, reg, node2);
+ } else {
+ if (node1->instr8)
+ insertpcodebefore(instr, rematerialize_spilled_register(instr->args[0].data.reg.reg, node1));
+ else
+ insert_load_spilled_register(instr, instr->args[0].data.reg.reg, node1);
+ }
+ } else {
+ insert_store_spilled_register(instr, 1, instr->args[1].data.reg.reg, node2);
+ }
+
+ deletepcode(instr);
+}
+
+static void spillcall(PCodeBlock *block, PCode *instr) {
+ PCodeArg *opSrc;
+ PCodeArg *opDst;
+ int opCount;
+ int volatileCount;
+ int i;
+
+ opCount = instr->argCount;
+ volatileCount = branch_count_volatiles();
+
+ opDst = instr->args + volatileCount;
+ opSrc = instr->args + volatileCount;
+ for (i = volatileCount; i < opCount; i++) {
+ if (
+ PC_OP_IS_ANY_REGISTER(opSrc, coloring_class) &&
+ opSrc->data.reg.reg >= n_real_registers[coloring_class] &&
+ (interferencegraph[opSrc->data.reg.reg]->flags & fSpilled)
+ )
+ {
+ instr->argCount--;
+ } else {
+ *opDst = *opSrc;
+ opDst++;
+ }
+ opSrc++;
+ }
+
+ spillinstruction(block, instr);
+}
+
+static void assign_spill_locations(void) {
+ UInt32 i;
+ IGNode *node;
+ Type *type;
+
+ last_unused_vreg_before_spilling = used_virtual_registers[coloring_class];
+ for (i = n_real_registers[coloring_class]; i < last_unused_vreg_before_spilling; i++) {
+ node = interferencegraph[i];
+ if (node->flags & fCoalesced)
+ continue;
+ if (!(node->flags & fSpilled))
+ continue;
+
+ if (!node->spillTemporary) {
+ switch (coloring_class) {
+ case RegClass_GPR:
+ type = TYPE(&stunsignedlong);
+ break;
+ case RegClass_CRFIELD:
+ type = TYPE(&stunsignedlong);
+ break;
+ case RegClass_FPR:
+ type = TYPE(&stunsignedlong);
+ break;
+ case RegClass_VR:
+ type = TYPE(&stvectorunsignedchar);
+ break;
+ default:
+ CError_FATAL(771);
+ }
+
+ node->spillTemporary = makespilltemporary(type);
+ }
+
+ if (node->spillTemporary->datatype == DLOCAL && !(node->spillTemporary->u.var.info->flags & VarInfoFlag1))
+ assign_local_memory(node->spillTemporary);
+
+ if (node->flags & fPairHigh)
+ Registers_GetVarInfo(node->spillTemporary)->regHi = Register0;
+ else
+ Registers_GetVarInfo(node->spillTemporary)->reg = Register0;
+ }
+}
+
+void insertspillcode(void) {
+ PCodeBlock *block;
+ PCode *instr;
+ PCode *nextInstr;
+ PCodeArg *op;
+ UInt32 i;
+ int flag;
+
+ rTEMP_for_VR_spill = 0;
+ assign_spill_locations();
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ for (instr = block->firstPCode; instr; instr = nextInstr) {
+ nextInstr = instr->nextPCode;
+ flag = 0;
+ op = instr->args;
+ i = instr->argCount;
+ while (i--) {
+ if (
+ PC_OP_IS_ANY_REGISTER(op, coloring_class) &&
+ op->data.reg.reg < last_unused_vreg_before_spilling &&
+ (interferencegraph[op->data.reg.reg]->flags & fSpilled)
+ )
+ {
+ flag = 1;
+ break;
+ }
+ op++;
+ }
+
+ if (flag) {
+ if (coloring_class == RegClass_VR && rTEMP_for_VR_spill == 0)
+ rTEMP_for_VR_spill = used_virtual_registers[RegClass_GPR]++;
+
+ if (instr->flags & fIsMove)
+ spillcopy(block, instr);
+ else if (instr->flags & fIsCall)
+ spillcall(block, instr);
+ else
+ spillinstruction(block, instr);
+ }
+ }
+ }
+}
diff --git a/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation601.c b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation601.c
new file mode 100644
index 0000000..2d54678
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation601.c
@@ -0,0 +1,552 @@
+#include "compiler/Scheduler.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+
+// https://stuff.mit.edu/afs/sipb/contrib/doc/specs/ic/cpu/powerpc/mpc601.pdf
+// https://www.nxp.com/docs/en/user-guide/MPC601UMAD.pdf
+
+typedef enum Stage {
+ IU, // Integer Unit
+ FD, // FP Decode
+ FPM, // FP Multiply
+ FPA, // FP Add
+ FWA, // FP Arithmetic Writeback
+ BPU, // Branch Processing Unit
+ NumStages,
+ Serialize, // special form for instructions that use IU but are serialised
+ Unsupported // instructions not supported by this processor
+} Stage;
+
+static struct {
+ // the instruction currently in this pipeline stage
+ PCode *instr;
+
+ // how many cycles are left for this instruction to finish
+ int remaining;
+} pipeline[NumStages];
+
+static struct {
+ // the initial stage for this instruction
+ Stage stage;
+
+ // the total amount of cycles required by this instruction
+ char latency;
+
+ // how long it takes to finish each stage
+ char cycles[4];
+} instruction_timing[OPCODE_MAX] = {
+ BPU, 0, 0, 0, 0, 1, // PC_B
+ BPU, 0, 0, 0, 0, 1, // PC_BL
+ BPU, 0, 0, 0, 0, 1, // PC_BC
+ BPU, 0, 0, 0, 0, 1, // PC_BCLR
+ BPU, 0, 0, 0, 0, 1, // PC_BCCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BT
+ BPU, 0, 0, 0, 0, 1, // PC_BTLR
+ BPU, 0, 0, 0, 0, 1, // PC_BTCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BF
+ BPU, 0, 0, 0, 0, 1, // PC_BFLR
+ BPU, 0, 0, 0, 0, 1, // PC_BFCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZ
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZT
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZF
+ BPU, 0, 0, 0, 0, 1, // PC_BDZ
+ BPU, 0, 0, 0, 0, 1, // PC_BDZT
+ BPU, 0, 0, 0, 0, 1, // PC_BDZF
+ BPU, 0, 0, 0, 0, 1, // PC_BLR
+ BPU, 0, 0, 0, 0, 1, // PC_BCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BCTRL
+ BPU, 0, 0, 0, 0, 1, // PC_BLRL
+ IU, 2, 1, 0, 0, 0, // PC_LBZ
+ IU, 2, 1, 0, 0, 0, // PC_LBZU
+ IU, 2, 1, 0, 0, 0, // PC_LBZX
+ IU, 2, 1, 0, 0, 0, // PC_LBZUX
+ IU, 2, 1, 0, 0, 0, // PC_LHZ
+ IU, 2, 1, 0, 0, 0, // PC_LHZU
+ IU, 2, 1, 0, 0, 0, // PC_LHZX
+ IU, 2, 1, 0, 0, 0, // PC_LHZUX
+ IU, 2, 1, 0, 0, 0, // PC_LHA
+ IU, 2, 1, 0, 0, 0, // PC_LHAU
+ IU, 2, 1, 0, 0, 0, // PC_LHAX
+ IU, 2, 1, 0, 0, 0, // PC_LHAUX
+ IU, 2, 1, 0, 0, 0, // PC_LHBRX
+ IU, 2, 1, 0, 0, 0, // PC_LWZ
+ IU, 2, 1, 0, 0, 0, // PC_LWZU
+ IU, 2, 1, 0, 0, 0, // PC_LWZX
+ IU, 2, 1, 0, 0, 0, // PC_LWZUX
+ IU, 2, 1, 0, 0, 0, // PC_LWBRX
+ IU, 1, 1, 0, 0, 0, // PC_LMW
+ IU, 1, 1, 0, 0, 0, // PC_STB
+ IU, 1, 1, 0, 0, 0, // PC_STBU
+ IU, 1, 1, 0, 0, 0, // PC_STBX
+ IU, 1, 1, 0, 0, 0, // PC_STBUX
+ IU, 1, 1, 0, 0, 0, // PC_STH
+ IU, 1, 1, 0, 0, 0, // PC_STHU
+ IU, 1, 1, 0, 0, 0, // PC_STHX
+ IU, 1, 1, 0, 0, 0, // PC_STHUX
+ IU, 1, 1, 0, 0, 0, // PC_STHBRX
+ IU, 1, 1, 0, 0, 0, // PC_STW
+ IU, 1, 1, 0, 0, 0, // PC_STWU
+ IU, 1, 1, 0, 0, 0, // PC_STWX
+ IU, 1, 1, 0, 0, 0, // PC_STWUX
+ IU, 1, 1, 0, 0, 0, // PC_STWBRX
+ IU, 1, 1, 0, 0, 0, // PC_STMW
+ IU, 2, 1, 0, 0, 0, // PC_DCBF
+ IU, 2, 1, 0, 0, 0, // PC_DCBST
+ IU, 2, 1, 0, 0, 0, // PC_DCBT
+ IU, 2, 1, 0, 0, 0, // PC_DCBTST
+ IU, 2, 1, 0, 0, 0, // PC_DCBZ
+ IU, 1, 1, 0, 0, 0, // PC_ADD
+ IU, 1, 1, 0, 0, 0, // PC_ADDC
+ IU, 1, 1, 0, 0, 0, // PC_ADDE
+ IU, 1, 1, 0, 0, 0, // PC_ADDI
+ IU, 1, 1, 0, 0, 0, // PC_ADDIC
+ IU, 1, 1, 0, 0, 0, // PC_ADDICR
+ IU, 1, 1, 0, 0, 0, // PC_ADDIS
+ IU, 1, 1, 0, 0, 0, // PC_ADDME
+ IU, 1, 1, 0, 0, 0, // PC_ADDZE
+ IU, 36, 36, 0, 0, 0, // PC_DIVW
+ IU, 36, 36, 0, 0, 0, // PC_DIVWU
+ IU, 5, 5, 0, 0, 0, // PC_MULHW
+ IU, 5, 5, 0, 0, 0, // PC_MULHWU
+ IU, 5, 5, 0, 0, 0, // PC_MULLI
+ IU, 5, 5, 0, 0, 0, // PC_MULLW
+ IU, 1, 1, 0, 0, 0, // PC_NEG
+ IU, 1, 1, 0, 0, 0, // PC_SUBF
+ IU, 1, 1, 0, 0, 0, // PC_SUBFC
+ IU, 1, 1, 0, 0, 0, // PC_SUBFE
+ IU, 1, 1, 0, 0, 0, // PC_SUBFIC
+ IU, 1, 1, 0, 0, 0, // PC_SUBFME
+ IU, 1, 1, 0, 0, 0, // PC_SUBFZE
+ IU, 3, 1, 0, 0, 0, // PC_CMPI
+ IU, 3, 1, 0, 0, 0, // PC_CMP
+ IU, 3, 1, 0, 0, 0, // PC_CMPLI
+ IU, 3, 1, 0, 0, 0, // PC_CMPL
+ IU, 1, 1, 0, 0, 0, // PC_ANDI
+ IU, 1, 1, 0, 0, 0, // PC_ANDIS
+ IU, 1, 1, 0, 0, 0, // PC_ORI
+ IU, 1, 1, 0, 0, 0, // PC_ORIS
+ IU, 1, 1, 0, 0, 0, // PC_XORI
+ IU, 1, 1, 0, 0, 0, // PC_XORIS
+ IU, 1, 1, 0, 0, 0, // PC_AND
+ IU, 1, 1, 0, 0, 0, // PC_OR
+ IU, 1, 1, 0, 0, 0, // PC_XOR
+ IU, 1, 1, 0, 0, 0, // PC_NAND
+ IU, 1, 1, 0, 0, 0, // PC_NOR
+ IU, 1, 1, 0, 0, 0, // PC_EQV
+ IU, 1, 1, 0, 0, 0, // PC_ANDC
+ IU, 1, 1, 0, 0, 0, // PC_ORC
+ IU, 1, 1, 0, 0, 0, // PC_EXTSB
+ IU, 1, 1, 0, 0, 0, // PC_EXTSH
+ IU, 1, 1, 0, 0, 0, // PC_CNTLZW
+ IU, 1, 1, 0, 0, 0, // PC_RLWINM
+ IU, 1, 1, 0, 0, 0, // PC_RLWNM
+ IU, 1, 1, 0, 0, 0, // PC_RLWIMI
+ IU, 1, 1, 0, 0, 0, // PC_SLW
+ IU, 1, 1, 0, 0, 0, // PC_SRW
+ IU, 1, 1, 0, 0, 0, // PC_SRAWI
+ IU, 1, 1, 0, 0, 0, // PC_SRAW
+ IU, 1, 1, 0, 0, 0, // PC_CRAND
+ IU, 1, 1, 0, 0, 0, // PC_CRANDC
+ IU, 1, 1, 0, 0, 0, // PC_CREQV
+ IU, 1, 1, 0, 0, 0, // PC_CRNAND
+ IU, 1, 1, 0, 0, 0, // PC_CRNOR
+ IU, 1, 1, 0, 0, 0, // PC_CROR
+ IU, 1, 1, 0, 0, 0, // PC_CRORC
+ IU, 1, 1, 0, 0, 0, // PC_CRXOR
+ IU, 1, 1, 0, 0, 0, // PC_MCRF
+ IU, 4, 1, 0, 0, 0, // PC_MTXER
+ IU, 4, 1, 0, 0, 0, // PC_MTCTR
+ IU, 4, 1, 0, 0, 0, // PC_MTLR
+ IU, 2, 1, 0, 0, 0, // PC_MTCRF
+ IU, 1, 0, 0, 0, 0, // PC_MTMSR
+ IU, 1, 0, 0, 0, 0, // PC_MTSPR
+ IU, 1, 0, 0, 0, 0, // PC_MFMSR
+ IU, 1, 0, 0, 0, 0, // PC_MFSPR
+ IU, 1, 1, 0, 0, 0, // PC_MFXER
+ IU, 1, 1, 0, 0, 0, // PC_MFCTR
+ IU, 1, 1, 0, 0, 0, // PC_MFLR
+ IU, 1, 1, 0, 0, 0, // PC_MFCR
+ FD, 4, 1, 1, 1, 1, // PC_MFFS
+ FD, 4, 1, 1, 1, 1, // PC_MTFSF
+ Serialize, 1, 1, 0, 0, 1, // PC_EIEIO
+ Serialize, 1, 1, 0, 0, 1, // PC_ISYNC
+ Serialize, 1, 1, 0, 0, 1, // PC_SYNC
+ Serialize, 0, 0, 0, 0, 1, // PC_RFI
+ IU, 1, 1, 0, 0, 0, // PC_LI
+ IU, 1, 1, 0, 0, 0, // PC_LIS
+ IU, 1, 1, 0, 0, 0, // PC_MR
+ IU, 1, 1, 0, 0, 0, // PC_NOP
+ IU, 1, 1, 0, 0, 0, // PC_NOT
+ IU, 3, 1, 0, 0, 0, // PC_LFS
+ IU, 3, 1, 0, 0, 0, // PC_LFSU
+ IU, 3, 1, 0, 0, 0, // PC_LFSX
+ IU, 3, 1, 0, 0, 0, // PC_LFSUX
+ IU, 3, 1, 0, 0, 0, // PC_LFD
+ IU, 3, 1, 0, 0, 0, // PC_LFDU
+ IU, 3, 1, 0, 0, 0, // PC_LFDX
+ IU, 3, 1, 0, 0, 0, // PC_LFDUX
+ IU, 1, 1, 0, 0, 0, // PC_STFS
+ IU, 1, 1, 0, 0, 0, // PC_STFSU
+ IU, 1, 1, 0, 0, 0, // PC_STFSX
+ IU, 1, 1, 0, 0, 0, // PC_STFSUX
+ IU, 1, 1, 0, 0, 0, // PC_STFD
+ IU, 1, 1, 0, 0, 0, // PC_STFDU
+ IU, 1, 1, 0, 0, 0, // PC_STFDX
+ IU, 1, 1, 0, 0, 0, // PC_STFDUX
+ FD, 4, 1, 1, 1, 1, // PC_FMR
+ FD, 4, 1, 1, 1, 1, // PC_FABS
+ FD, 4, 1, 1, 1, 1, // PC_FNEG
+ FD, 4, 1, 1, 1, 1, // PC_FNABS
+ FD, 4, 1, 1, 1, 1, // PC_FADD
+ FD, 4, 1, 1, 1, 1, // PC_FADDS
+ FD, 4, 1, 1, 1, 1, // PC_FSUB
+ FD, 4, 1, 1, 1, 1, // PC_FSUBS
+ FD, 5, 1, 1, 2, 1, // PC_FMUL
+ FD, 4, 1, 1, 1, 1, // PC_FMULS
+ FD, 31, 1, 1, 28, 1, // PC_FDIV
+ FD, 17, 1, 1, 14, 1, // PC_FDIVS
+ FD, 5, 1, 1, 2, 1, // PC_FMADD
+ FD, 4, 1, 1, 1, 1, // PC_FMADDS
+ FD, 5, 1, 1, 2, 1, // PC_FMSUB
+ FD, 4, 1, 1, 1, 1, // PC_FMSUBS
+ FD, 5, 1, 1, 2, 1, // PC_FNMADD
+ FD, 4, 1, 1, 1, 1, // PC_FNMADDS
+ FD, 5, 1, 1, 2, 1, // PC_FNMSUB
+ FD, 4, 1, 1, 1, 1, // PC_FNMSUBS
+ FD, 4, 1, 1, 1, 1, // PC_FRES
+ FD, 4, 1, 1, 1, 1, // PC_FRSQRTE
+ FD, 4, 1, 1, 1, 1, // PC_FSEL
+ FD, 4, 1, 1, 1, 1, // PC_FRSP
+ FD, 4, 1, 1, 1, 1, // PC_FCTIW
+ FD, 4, 1, 1, 1, 1, // PC_FCTIWZ
+ FD, 6, 1, 1, 1, 1, // PC_FCMPU
+ FD, 6, 1, 1, 1, 1, // PC_FCMPO
+ IU, 0, 0, 0, 0, 0, // PC_LWARX
+ IU, 0, 0, 0, 0, 0, // PC_LSWI
+ IU, 0, 0, 0, 0, 0, // PC_LSWX
+ IU, 0, 0, 0, 0, 0, // PC_STFIWX
+ IU, 0, 0, 0, 0, 0, // PC_STSWI
+ IU, 0, 0, 0, 0, 0, // PC_STSWX
+ IU, 0, 0, 0, 0, 0, // PC_STWCX
+ IU, 0, 0, 0, 0, 0, // PC_ECIWX
+ IU, 0, 0, 0, 0, 0, // PC_ECOWX
+ IU, 0, 0, 0, 0, 0, // PC_DCBI
+ IU, 0, 0, 0, 0, 0, // PC_ICBI
+ IU, 0, 0, 0, 0, 0, // PC_MCRFS
+ IU, 0, 0, 0, 0, 0, // PC_MCRXR
+ IU, 0, 0, 0, 0, 0, // PC_MFTB
+ IU, 0, 0, 0, 0, 0, // PC_MFSR
+ IU, 0, 0, 0, 0, 0, // PC_MTSR
+ IU, 0, 0, 0, 0, 0, // PC_MFSRIN
+ IU, 0, 0, 0, 0, 0, // PC_MTSRIN
+ IU, 0, 0, 0, 0, 0, // PC_MTFSB0
+ IU, 0, 0, 0, 0, 0, // PC_MTFSB1
+ IU, 0, 0, 0, 0, 0, // PC_MTFSFI
+ Serialize, 0, 0, 0, 0, 0, // PC_SC
+ IU, 0, 0, 0, 0, 0, // PC_FSQRT
+ IU, 0, 0, 0, 0, 0, // PC_FSQRTS
+ IU, 0, 0, 0, 0, 0, // PC_TLBIA
+ IU, 0, 0, 0, 0, 0, // PC_TLBIE
+ IU, 0, 0, 0, 0, 0, // PC_TLBLD
+ IU, 0, 0, 0, 0, 0, // PC_TLBLI
+ IU, 0, 0, 0, 0, 0, // PC_TLBSYNC
+ Serialize, 0, 0, 0, 0, 0, // PC_TW
+ Serialize, 0, 0, 0, 0, 0, // PC_TRAP
+ Serialize, 0, 0, 0, 0, 0, // PC_TWI
+ Serialize, 0, 0, 0, 0, 0, // PC_OPWORD
+ IU, 0, 0, 0, 0, 0, // PC_MFROM
+ IU, 0, 0, 0, 0, 0, // PC_DSA
+ IU, 0, 0, 0, 0, 0, // PC_ESA
+ IU, 0, 0, 0, 0, 0, // PC_DCCCI
+ IU, 0, 0, 0, 0, 0, // PC_DCREAD
+ IU, 0, 0, 0, 0, 0, // PC_ICBT
+ IU, 0, 0, 0, 0, 0, // PC_ICCCI
+ IU, 0, 0, 0, 0, 0, // PC_ICREAD
+ IU, 0, 0, 0, 0, 0, // PC_RFCI
+ IU, 0, 0, 0, 0, 0, // PC_TLBRE
+ IU, 0, 0, 0, 0, 0, // PC_TLBSX
+ IU, 0, 0, 0, 0, 0, // PC_TLBWE
+ IU, 0, 0, 0, 0, 0, // PC_WRTEE
+ IU, 0, 0, 0, 0, 0, // PC_WRTEEI
+ IU, 0, 0, 0, 0, 0, // PC_MFDCR
+ IU, 0, 0, 0, 0, 0, // PC_MTDCR
+ Unsupported, 0, 0, 0, 0, 0, // PC_DCBA
+ Unsupported, 0, 0, 0, 0, 0, // PC_DSS
+ Unsupported, 0, 0, 0, 0, 0, // PC_DSSALL
+ Unsupported, 0, 0, 0, 0, 0, // PC_DST
+ Unsupported, 0, 0, 0, 0, 0, // PC_DSTT
+ Unsupported, 0, 0, 0, 0, 0, // PC_DSTST
+ Unsupported, 0, 0, 0, 0, 0, // PC_DSTSTT
+ Unsupported, 0, 0, 0, 0, 0, // PC_LVEBX
+ Unsupported, 0, 0, 0, 0, 0, // PC_LVEHX
+ Unsupported, 0, 0, 0, 0, 0, // PC_LVEWX
+ Unsupported, 0, 0, 0, 0, 0, // PC_LVSL
+ Unsupported, 0, 0, 0, 0, 0, // PC_LVSR
+ Unsupported, 0, 0, 0, 0, 0, // PC_LVX
+ Unsupported, 0, 0, 0, 0, 0, // PC_LVXL
+ Unsupported, 0, 0, 0, 0, 0, // PC_STVEBX
+ Unsupported, 0, 0, 0, 0, 0, // PC_STVEHX
+ Unsupported, 0, 0, 0, 0, 0, // PC_STVEWX
+ Unsupported, 0, 0, 0, 0, 0, // PC_STVX
+ Unsupported, 0, 0, 0, 0, 0, // PC_STVXL
+ Unsupported, 0, 0, 0, 0, 0, // PC_MFVSCR
+ Unsupported, 0, 0, 0, 0, 0, // PC_MTVSCR
+ Unsupported, 0, 0, 0, 0, 0, // PC_VADDCUW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VADDFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VADDSBS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VADDSHS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VADDSWS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VADDUBM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VADDUBS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VADDUHM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VADDUHS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VADDUWM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VADDUWS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VAND
+ Unsupported, 0, 0, 0, 0, 0, // PC_VANDC
+ Unsupported, 0, 0, 0, 0, 0, // PC_VAVGSB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VAVGSH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VAVGSW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VAVGUB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VAVGUH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VAVGUW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCFSX
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCFUX
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCMPBFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCMPEQFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCMPEQUB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCMPEQUH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCMPEQUW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCMPGEFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCMPGTFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCMPGTSB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCMPGTSH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCMPGTSW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCMPGTUB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCMPGTUH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCMPGTUW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCTSXS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VCTUXS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VEXPTEFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VLOGEFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMAXFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMAXSB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMAXSH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMAXSW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMAXUB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMAXUH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMAXUW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMINFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMINSB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMINSH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMINSW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMINUB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMINUH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMINUW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMRGHB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMRGHH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMRGHW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMRGLB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMRGLH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMRGLW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMULESB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMULESH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMULEUB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMULEUH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMULOSB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMULOSH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMULOUB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMULOUH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VNOR
+ Unsupported, 0, 0, 0, 0, 0, // PC_VOR
+ Unsupported, 0, 0, 0, 0, 0, // PC_VPKPX
+ Unsupported, 0, 0, 0, 0, 0, // PC_VPKSHSS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VPKSHUS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VPKSWSS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VPKSWUS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VPKUHUM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VPKUHUS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VPKUWUM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VPKUWUS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VREFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VRFIM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VRFIN
+ Unsupported, 0, 0, 0, 0, 0, // PC_VRFIP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VRFIZ
+ Unsupported, 0, 0, 0, 0, 0, // PC_VRLB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VRLH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VRLW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VRSQRTEFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSL
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSLB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSLH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSLO
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSLW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSPLTB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSPLTH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSPLTW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSPLTISB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSPLTISH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSPLTISW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSR
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSRAB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSRAH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSRAW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSRB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSRH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSRO
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSRW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUBCUW
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUBFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUBSBS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUBSHS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUBSWS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUBUBM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUBUBS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUBUHM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUBUHS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUBUWM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUBUWS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUMSWS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUFPMSWS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUFWASBS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUFWASHS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSUFWAUBS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VUPKHPX
+ Unsupported, 0, 0, 0, 0, 0, // PC_VUPKHSB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VUPKHSH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VUPKLPX
+ Unsupported, 0, 0, 0, 0, 0, // PC_VUPKLSB
+ Unsupported, 0, 0, 0, 0, 0, // PC_VUPKLSH
+ Unsupported, 0, 0, 0, 0, 0, // PC_VXOR
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMADDFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMHADDSHS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMHRADDSHS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMLADDUHM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMSUMMBM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMSUMSHM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMSUMSHS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMSUMUBM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMSUMUHM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMSUMUHS
+ Unsupported, 0, 0, 0, 0, 0, // PC_VNMSUBFP
+ Unsupported, 0, 0, 0, 0, 0, // PC_VPERM
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSEL
+ Unsupported, 0, 0, 0, 0, 0, // PC_VSLDOI
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMR
+ Unsupported, 0, 0, 0, 0, 0, // PC_VMRP
+ IU, 0, 0, 0, 0, 0, // PC_SLE
+ IU, 0, 0, 0, 0, 0, // PC_SLEQ
+ IU, 0, 0, 0, 0, 0, // PC_SLIQ
+ IU, 0, 0, 0, 0, 0, // PC_SLLIQ
+ IU, 0, 0, 0, 0, 0, // PC_SLLQ
+ IU, 0, 0, 0, 0, 0, // PC_SLQ
+ IU, 0, 0, 0, 0, 0, // PC_SRAIQ
+ IU, 0, 0, 0, 0, 0, // PC_SRAQ
+ IU, 0, 0, 0, 0, 0, // PC_SRE
+ IU, 0, 0, 0, 0, 0, // PC_SREA
+ IU, 0, 0, 0, 0, 0, // PC_SREQ
+ IU, 0, 0, 0, 0, 0, // PC_SRIQ
+ IU, 0, 0, 0, 0, 0, // PC_SRLIQ
+ IU, 0, 0, 0, 0, 0, // PC_SRLQ
+ IU, 0, 0, 0, 0, 0, // PC_SRQ
+ IU, 0, 0, 0, 0, 0, // PC_MASKG
+ IU, 0, 0, 0, 0, 0, // PC_MASKIR
+ IU, 0, 0, 0, 0, 0, // PC_LSCBX
+ IU, 0, 0, 0, 0, 0, // PC_DIV
+ IU, 0, 0, 0, 0, 0, // PC_DIVS
+ IU, 0, 0, 0, 0, 0, // PC_DOZ
+ IU, 0, 0, 0, 0, 0, // PC_MUL
+ IU, 0, 0, 0, 0, 0, // PC_NABS
+ IU, 0, 0, 0, 0, 0, // PC_ABS
+ IU, 0, 0, 0, 0, 0, // PC_CLCS
+ IU, 0, 0, 0, 0, 0, // PC_DOZI
+ IU, 0, 0, 0, 0, 0, // PC_RLMI
+ IU, 0, 0, 0, 0, 0, // PC_RRIB
+};
+
+static void advance(int stageCount, int oldStage, int newStage) {
+ PCode *instr = pipeline[oldStage].instr;
+ int cycles = instruction_timing[instr->op].cycles[newStage - stageCount];
+ pipeline[newStage].instr = instr;
+ pipeline[newStage].remaining = cycles;
+ pipeline[oldStage].instr = NULL;
+}
+
+static void complete_instruction(int stage) {
+ pipeline[stage].instr = NULL;
+}
+
+static int latency(PCode *instr) {
+ int cycles = instruction_timing[instr->op].latency;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ cycles += 2;
+ if (instr->op == PC_LMW || instr->op == PC_STMW)
+ cycles += instr->argCount - 2;
+ return cycles;
+}
+
+static void initialize(void) {
+ int stage;
+
+ for (stage = 0; stage < NumStages; stage++)
+ pipeline[stage].instr = NULL;
+}
+
+static int can_issue(PCode *instr) {
+ int stage = instruction_timing[instr->op].stage;
+ if (stage == Serialize)
+ stage = IU;
+ if (pipeline[stage].instr)
+ return 0;
+ return 1;
+}
+
+static void issue(PCode *instr) {
+ int stage = instruction_timing[instr->op].stage;
+ int cycles = instruction_timing[instr->op].cycles[IU];
+ if (stage == Serialize)
+ stage = IU;
+ pipeline[stage].instr = instr;
+ pipeline[stage].remaining = cycles;
+}
+
+static void advance_clock(void) {
+ int stage;
+
+ for (stage = 0; stage < NumStages; stage++) {
+ if (pipeline[stage].instr && pipeline[stage].remaining)
+ --pipeline[stage].remaining;
+ }
+
+ if (pipeline[IU].instr && pipeline[IU].remaining == 0)
+ complete_instruction(IU);
+ if (pipeline[FWA].instr && pipeline[FWA].remaining == 0)
+ complete_instruction(FWA);
+ if (pipeline[BPU].instr && pipeline[BPU].remaining == 0)
+ complete_instruction(BPU);
+
+ if (pipeline[FPA].instr && pipeline[FPA].remaining == 0 && !pipeline[FWA].instr)
+ advance(1, FPA, FWA);
+ if (pipeline[FPM].instr && pipeline[FPM].remaining == 0 && !pipeline[FPA].instr)
+ advance(1, FPM, FPA);
+ if (pipeline[FD].instr && pipeline[FD].remaining == 0 && !pipeline[FPM].instr)
+ advance(1, FD, FPM);
+}
+
+static int serializes(PCode *instr) {
+ return instruction_timing[instr->op].stage == Serialize;
+}
+
+MachineInfo machine601 = {
+ 2,
+ 0,
+ 0,
+ &latency,
+ &initialize,
+ &can_issue,
+ &issue,
+ &advance_clock,
+ &serializes,
+ &default_uses_vpermute_unit
+};
diff --git a/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation603.c b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation603.c
new file mode 100644
index 0000000..49d1ea0
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation603.c
@@ -0,0 +1,626 @@
+#include "compiler/Scheduler.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+
+// this is actually for 603e, but i couldn't find the 603 doc
+// https://www.nxp.com/docs/en/reference-manual/MPC603EUM.pdf
+
+typedef enum Stage {
+ BPU, // Branch Prediction Unit
+ IU, // Integer Unit
+ LSU1, // Load/Store Unit
+ LSU2,
+ FPU1, // Floating Point Unit
+ FPU2,
+ FPU3,
+ SRU, // System Register Unit
+ NumStages
+} Stage;
+
+static struct {
+ // the instruction currently in this pipeline stage
+ PCode *instr;
+
+ // how many cycles are left for this instruction to finish
+ int remaining;
+} pipeline[NumStages];
+
+enum {
+ MaxEntries = 5
+};
+
+static struct {
+ // how many entries remain unused in the queue
+ unsigned int free;
+
+ // how many entries are currently used in the queue
+ unsigned int used;
+
+ // the index of the next instruction that will be retired
+ unsigned int nextToRetire;
+
+ // the index of the next free slot that will be used when an instruction is dispatched
+ unsigned int nextFreeSlot;
+
+ // circular array of entries in the completion queue
+ struct {
+ PCode *instr;
+ int completed;
+ } entries[MaxEntries];
+} completionbuffers;
+
+static struct {
+ // the initial stage for this instruction
+ Stage stage;
+
+ // the total amount of cycles required by this instruction
+ char latency;
+
+ // how long it takes to finish each stage
+ char cycles[3];
+
+ // does this instruction serialise?
+ char serializes;
+} instruction_timing[OPCODE_MAX] = {
+ BPU, 0, 0, 0, 0, 1, // PC_B
+ BPU, 0, 0, 0, 0, 1, // PC_BL
+ BPU, 0, 0, 0, 0, 1, // PC_BC
+ BPU, 0, 0, 0, 0, 1, // PC_BCLR
+ BPU, 0, 0, 0, 0, 1, // PC_BCCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BT
+ BPU, 0, 0, 0, 0, 1, // PC_BTLR
+ BPU, 0, 0, 0, 0, 1, // PC_BTCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BF
+ BPU, 0, 0, 0, 0, 1, // PC_BFLR
+ BPU, 0, 0, 0, 0, 1, // PC_BFCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZ
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZT
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZF
+ BPU, 0, 0, 0, 0, 1, // PC_BDZ
+ BPU, 0, 0, 0, 0, 1, // PC_BDZT
+ BPU, 0, 0, 0, 0, 1, // PC_BDZF
+ BPU, 0, 0, 0, 0, 1, // PC_BLR
+ BPU, 0, 0, 0, 0, 1, // PC_BCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BCTRL
+ BPU, 0, 0, 0, 0, 1, // PC_BLRL
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHA
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAU
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_LMW
+ LSU1, 2, 1, 1, 0, 0, // PC_STB
+ LSU1, 2, 1, 1, 0, 0, // PC_STBU
+ LSU1, 2, 1, 1, 0, 0, // PC_STBX
+ LSU1, 2, 1, 1, 0, 0, // PC_STBUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STH
+ LSU1, 2, 1, 1, 0, 0, // PC_STHU
+ LSU1, 2, 1, 1, 0, 0, // PC_STHX
+ LSU1, 2, 1, 1, 0, 0, // PC_STHUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STHBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_STW
+ LSU1, 2, 1, 1, 0, 0, // PC_STWU
+ LSU1, 2, 1, 1, 0, 0, // PC_STWX
+ LSU1, 2, 1, 1, 0, 0, // PC_STWUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STWBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_STMW
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBF
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBST
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBT
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBTST
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBZ
+ IU, 1, 1, 0, 0, 0, // PC_ADD
+ IU, 1, 1, 0, 0, 0, // PC_ADDC
+ IU, 1, 1, 0, 0, 0, // PC_ADDE
+ IU, 1, 1, 0, 0, 0, // PC_ADDI
+ IU, 1, 1, 0, 0, 0, // PC_ADDIC
+ IU, 1, 1, 0, 0, 0, // PC_ADDICR
+ IU, 1, 1, 0, 0, 0, // PC_ADDIS
+ IU, 1, 1, 0, 0, 0, // PC_ADDME
+ IU, 1, 1, 0, 0, 0, // PC_ADDZE
+ IU, 37, 37, 0, 0, 0, // PC_DIVW
+ IU, 37, 37, 0, 0, 0, // PC_DIVWU
+ IU, 5, 5, 0, 0, 0, // PC_MULHW
+ IU, 5, 5, 0, 0, 0, // PC_MULHWU
+ IU, 3, 3, 0, 0, 0, // PC_MULLI
+ IU, 5, 5, 0, 0, 0, // PC_MULLW
+ IU, 1, 1, 0, 0, 0, // PC_NEG
+ IU, 1, 1, 0, 0, 0, // PC_SUBF
+ IU, 1, 1, 0, 0, 0, // PC_SUBFC
+ IU, 1, 1, 0, 0, 0, // PC_SUBFE
+ IU, 1, 1, 0, 0, 0, // PC_SUBFIC
+ IU, 1, 1, 0, 0, 0, // PC_SUBFME
+ IU, 1, 1, 0, 0, 0, // PC_SUBFZE
+ IU, 3, 1, 0, 0, 0, // PC_CMPI
+ IU, 3, 1, 0, 0, 0, // PC_CMP
+ IU, 3, 1, 0, 0, 0, // PC_CMPLI
+ IU, 3, 1, 0, 0, 0, // PC_CMPL
+ IU, 1, 1, 0, 0, 0, // PC_ANDI
+ IU, 1, 1, 0, 0, 0, // PC_ANDIS
+ IU, 1, 1, 0, 0, 0, // PC_ORI
+ IU, 1, 1, 0, 0, 0, // PC_ORIS
+ IU, 1, 1, 0, 0, 0, // PC_XORI
+ IU, 1, 1, 0, 0, 0, // PC_XORIS
+ IU, 1, 1, 0, 0, 0, // PC_AND
+ IU, 1, 1, 0, 0, 0, // PC_OR
+ IU, 1, 1, 0, 0, 0, // PC_XOR
+ IU, 1, 1, 0, 0, 0, // PC_NAND
+ IU, 1, 1, 0, 0, 0, // PC_NOR
+ IU, 1, 1, 0, 0, 0, // PC_EQV
+ IU, 1, 1, 0, 0, 0, // PC_ANDC
+ IU, 1, 1, 0, 0, 0, // PC_ORC
+ IU, 1, 1, 0, 0, 0, // PC_EXTSB
+ IU, 1, 1, 0, 0, 0, // PC_EXTSH
+ IU, 1, 1, 0, 0, 0, // PC_CNTLZW
+ IU, 1, 1, 0, 0, 0, // PC_RLWINM
+ IU, 1, 1, 0, 0, 0, // PC_RLWNM
+ IU, 1, 1, 0, 0, 0, // PC_RLWIMI
+ IU, 1, 1, 0, 0, 0, // PC_SLW
+ IU, 1, 1, 0, 0, 0, // PC_SRW
+ IU, 1, 1, 0, 0, 0, // PC_SRAWI
+ IU, 1, 1, 0, 0, 0, // PC_SRAW
+ SRU, 1, 1, 0, 0, 0, // PC_CRAND
+ SRU, 1, 1, 0, 0, 0, // PC_CRANDC
+ SRU, 1, 1, 0, 0, 0, // PC_CREQV
+ SRU, 1, 1, 0, 0, 0, // PC_CRNAND
+ SRU, 1, 1, 0, 0, 0, // PC_CRNOR
+ SRU, 1, 1, 0, 0, 0, // PC_CROR
+ SRU, 1, 1, 0, 0, 0, // PC_CRORC
+ SRU, 1, 1, 0, 0, 0, // PC_CRXOR
+ SRU, 1, 1, 0, 0, 0, // PC_MCRF
+ SRU, 2, 2, 0, 0, 0, // PC_MTXER
+ SRU, 2, 2, 0, 0, 0, // PC_MTCTR
+ SRU, 2, 2, 0, 0, 0, // PC_MTLR
+ SRU, 1, 1, 0, 0, 0, // PC_MTCRF
+ SRU, 1, 1, 0, 0, 1, // PC_MTMSR
+ SRU, 1, 1, 0, 0, 1, // PC_MTSPR
+ SRU, 1, 1, 0, 0, 1, // PC_MFMSR
+ SRU, 1, 1, 0, 0, 1, // PC_MFSPR
+ SRU, 1, 1, 0, 0, 0, // PC_MFXER
+ SRU, 1, 1, 0, 0, 0, // PC_MFCTR
+ SRU, 1, 1, 0, 0, 0, // PC_MFLR
+ SRU, 1, 1, 0, 0, 0, // PC_MFCR
+ FPU1, 3, 1, 1, 1, 0, // PC_MFFS
+ FPU1, 3, 1, 1, 1, 0, // PC_MTFSF
+ SRU, 1, 1, 0, 0, 1, // PC_EIEIO
+ SRU, 1, 1, 0, 0, 1, // PC_ISYNC
+ SRU, 1, 1, 0, 0, 1, // PC_SYNC
+ SRU, 1, 1, 0, 0, 1, // PC_RFI
+ IU, 1, 1, 0, 0, 0, // PC_LI
+ IU, 1, 1, 0, 0, 0, // PC_LIS
+ IU, 1, 1, 0, 0, 0, // PC_MR
+ IU, 1, 1, 0, 0, 0, // PC_NOP
+ IU, 1, 1, 0, 0, 0, // PC_NOT
+ LSU1, 2, 1, 1, 0, 0, // PC_LFS
+ LSU1, 2, 1, 1, 0, 0, // PC_LFSU
+ LSU1, 2, 1, 1, 0, 0, // PC_LFSX
+ LSU1, 2, 1, 1, 0, 0, // PC_LFSUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LFD
+ LSU1, 2, 1, 1, 0, 0, // PC_LFDU
+ LSU1, 2, 1, 1, 0, 0, // PC_LFDX
+ LSU1, 2, 1, 1, 0, 0, // PC_LFDUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFS
+ LSU1, 2, 1, 1, 0, 0, // PC_STFSU
+ LSU1, 2, 1, 1, 0, 0, // PC_STFSX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFSUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFD
+ LSU1, 2, 1, 1, 0, 0, // PC_STFDU
+ LSU1, 2, 1, 1, 0, 0, // PC_STFDX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFDUX
+ FPU1, 3, 1, 1, 1, 0, // PC_FMR
+ FPU1, 3, 1, 1, 1, 0, // PC_FABS
+ FPU1, 3, 1, 1, 1, 0, // PC_FNEG
+ FPU1, 3, 1, 1, 1, 0, // PC_FNABS
+ FPU1, 3, 1, 1, 1, 0, // PC_FADD
+ FPU1, 3, 1, 1, 1, 0, // PC_FADDS
+ FPU1, 3, 1, 1, 1, 0, // PC_FSUB
+ FPU1, 3, 1, 1, 1, 0, // PC_FSUBS
+ FPU1, 4, 2, 1, 1, 0, // PC_FMUL
+ FPU1, 3, 1, 1, 1, 0, // PC_FMULS
+ FPU1, 33, 33, 0, 0, 0, // PC_FDIV
+ FPU1, 18, 18, 0, 0, 0, // PC_FDIVS
+ FPU1, 4, 2, 1, 1, 0, // PC_FMADD
+ FPU1, 3, 1, 1, 1, 0, // PC_FMADDS
+ FPU1, 4, 2, 1, 1, 0, // PC_FMSUB
+ FPU1, 3, 1, 1, 1, 0, // PC_FMSUBS
+ FPU1, 4, 2, 1, 1, 0, // PC_FNMADD
+ FPU1, 3, 1, 1, 1, 0, // PC_FNMADDS
+ FPU1, 4, 2, 1, 1, 0, // PC_FNMSUB
+ FPU1, 3, 1, 1, 1, 0, // PC_FNMSUBS
+ FPU1, 18, 18, 0, 0, 0, // PC_FRES
+ FPU1, 3, 1, 1, 1, 0, // PC_FRSQRTE
+ FPU1, 3, 1, 1, 1, 0, // PC_FSEL
+ FPU1, 3, 1, 1, 1, 0, // PC_FRSP
+ FPU1, 3, 1, 1, 1, 0, // PC_FCTIW
+ FPU1, 3, 1, 1, 1, 0, // PC_FCTIWZ
+ FPU1, 5, 1, 1, 1, 0, // PC_FCMPU
+ FPU1, 5, 1, 1, 1, 0, // PC_FCMPO
+ LSU1, 1, 1, 0, 0, 0, // PC_LWARX
+ LSU1, 1, 1, 0, 0, 0, // PC_LSWI
+ LSU1, 1, 1, 0, 0, 0, // PC_LSWX
+ LSU1, 1, 1, 0, 0, 0, // PC_STFIWX
+ LSU1, 1, 1, 0, 0, 0, // PC_STSWI
+ LSU1, 1, 1, 0, 0, 0, // PC_STSWX
+ LSU1, 1, 1, 0, 0, 0, // PC_STWCX
+ IU, 1, 1, 0, 0, 1, // PC_ECIWX
+ IU, 1, 1, 0, 0, 1, // PC_ECOWX
+ IU, 1, 1, 0, 0, 0, // PC_DCBI
+ IU, 1, 1, 0, 0, 0, // PC_ICBI
+ IU, 1, 1, 0, 0, 0, // PC_MCRFS
+ IU, 1, 1, 0, 0, 0, // PC_MCRXR
+ IU, 1, 1, 0, 0, 0, // PC_MFTB
+ IU, 1, 1, 0, 0, 0, // PC_MFSR
+ IU, 1, 1, 0, 0, 0, // PC_MTSR
+ IU, 1, 1, 0, 0, 0, // PC_MFSRIN
+ IU, 1, 1, 0, 0, 0, // PC_MTSRIN
+ IU, 1, 1, 0, 0, 0, // PC_MTFSB0
+ IU, 1, 1, 0, 0, 0, // PC_MTFSB1
+ IU, 1, 1, 0, 0, 0, // PC_MTFSFI
+ IU, 1, 1, 0, 0, 1, // PC_SC
+ FPU1, 1, 1, 0, 0, 0, // PC_FSQRT
+ FPU1, 1, 1, 0, 0, 0, // PC_FSQRTS
+ IU, 1, 1, 0, 0, 0, // PC_TLBIA
+ IU, 1, 1, 0, 0, 0, // PC_TLBIE
+ IU, 1, 1, 0, 0, 0, // PC_TLBLD
+ IU, 1, 1, 0, 0, 0, // PC_TLBLI
+ IU, 1, 1, 0, 0, 0, // PC_TLBSYNC
+ IU, 1, 1, 0, 0, 1, // PC_TW
+ IU, 1, 1, 0, 0, 1, // PC_TRAP
+ IU, 1, 1, 0, 0, 1, // PC_TWI
+ IU, 1, 1, 0, 0, 1, // PC_OPWORD
+ IU, 1, 1, 0, 0, 0, // PC_MFROM
+ IU, 1, 1, 0, 0, 1, // PC_DSA
+ IU, 1, 1, 0, 0, 1, // PC_ESA
+ IU, 0, 0, 0, 0, 0, // PC_DCCCI
+ IU, 0, 0, 0, 0, 0, // PC_DCREAD
+ IU, 0, 0, 0, 0, 0, // PC_ICBT
+ IU, 0, 0, 0, 0, 0, // PC_ICCCI
+ IU, 0, 0, 0, 0, 0, // PC_ICREAD
+ IU, 0, 0, 0, 0, 0, // PC_RFCI
+ IU, 0, 0, 0, 0, 0, // PC_TLBRE
+ IU, 0, 0, 0, 0, 0, // PC_TLBSX
+ IU, 0, 0, 0, 0, 0, // PC_TLBWE
+ IU, 0, 0, 0, 0, 0, // PC_WRTEE
+ IU, 0, 0, 0, 0, 0, // PC_WRTEEI
+ IU, 0, 0, 0, 0, 0, // PC_MFDCR
+ IU, 0, 0, 0, 0, 0, // PC_MTDCR
+ IU, 0, 0, 0, 0, 0, // PC_DCBA
+ BPU, 0, 0, 0, 0, 0, // PC_DSS
+ BPU, 0, 0, 0, 0, 0, // PC_DSSALL
+ BPU, 0, 0, 0, 0, 0, // PC_DST
+ BPU, 0, 0, 0, 0, 0, // PC_DSTT
+ BPU, 0, 0, 0, 0, 0, // PC_DSTST
+ BPU, 0, 0, 0, 0, 0, // PC_DSTSTT
+ BPU, 0, 0, 0, 0, 0, // PC_LVEBX
+ BPU, 0, 0, 0, 0, 0, // PC_LVEHX
+ BPU, 0, 0, 0, 0, 0, // PC_LVEWX
+ BPU, 0, 0, 0, 0, 0, // PC_LVSL
+ BPU, 0, 0, 0, 0, 0, // PC_LVSR
+ BPU, 0, 0, 0, 0, 0, // PC_LVX
+ BPU, 0, 0, 0, 0, 0, // PC_LVXL
+ BPU, 0, 0, 0, 0, 0, // PC_STVEBX
+ BPU, 0, 0, 0, 0, 0, // PC_STVEHX
+ BPU, 0, 0, 0, 0, 0, // PC_STVEWX
+ BPU, 0, 0, 0, 0, 0, // PC_STVX
+ BPU, 0, 0, 0, 0, 0, // PC_STVXL
+ BPU, 0, 0, 0, 0, 0, // PC_MFVSCR
+ BPU, 0, 0, 0, 0, 0, // PC_MTVSCR
+ BPU, 0, 0, 0, 0, 0, // PC_VADDCUW
+ BPU, 0, 0, 0, 0, 0, // PC_VADDFP
+ BPU, 0, 0, 0, 0, 0, // PC_VADDSBS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDSWS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUBM
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUBS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUHM
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUHS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUWM
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUWS
+ BPU, 0, 0, 0, 0, 0, // PC_VAND
+ BPU, 0, 0, 0, 0, 0, // PC_VANDC
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGSB
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGSH
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGSW
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGUB
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGUH
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGUW
+ BPU, 0, 0, 0, 0, 0, // PC_VCFSX
+ BPU, 0, 0, 0, 0, 0, // PC_VCFUX
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPBFP
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPEQFP
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPEQUB
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPEQUH
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPEQUW
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGEFP
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTFP
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTSB
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTSH
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTSW
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTUB
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTUH
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTUW
+ BPU, 0, 0, 0, 0, 0, // PC_VCTSXS
+ BPU, 0, 0, 0, 0, 0, // PC_VCTUXS
+ BPU, 0, 0, 0, 0, 0, // PC_VEXPTEFP
+ BPU, 0, 0, 0, 0, 0, // PC_VLOGEFP
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXFP
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXSB
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXSH
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXSW
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXUB
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXUH
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXUW
+ BPU, 0, 0, 0, 0, 0, // PC_VMINFP
+ BPU, 0, 0, 0, 0, 0, // PC_VMINSB
+ BPU, 0, 0, 0, 0, 0, // PC_VMINSH
+ BPU, 0, 0, 0, 0, 0, // PC_VMINSW
+ BPU, 0, 0, 0, 0, 0, // PC_VMINUB
+ BPU, 0, 0, 0, 0, 0, // PC_VMINUH
+ BPU, 0, 0, 0, 0, 0, // PC_VMINUW
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGHB
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGHH
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGHW
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGLB
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGLH
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGLW
+ BPU, 0, 0, 0, 0, 0, // PC_VMULESB
+ BPU, 0, 0, 0, 0, 0, // PC_VMULESH
+ BPU, 0, 0, 0, 0, 0, // PC_VMULEUB
+ BPU, 0, 0, 0, 0, 0, // PC_VMULEUH
+ BPU, 0, 0, 0, 0, 0, // PC_VMULOSB
+ BPU, 0, 0, 0, 0, 0, // PC_VMULOSH
+ BPU, 0, 0, 0, 0, 0, // PC_VMULOUB
+ BPU, 0, 0, 0, 0, 0, // PC_VMULOUH
+ BPU, 0, 0, 0, 0, 0, // PC_VNOR
+ BPU, 0, 0, 0, 0, 0, // PC_VOR
+ BPU, 0, 0, 0, 0, 0, // PC_VPKPX
+ BPU, 0, 0, 0, 0, 0, // PC_VPKSHSS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKSHUS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKSWSS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKSWUS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKUHUM
+ BPU, 0, 0, 0, 0, 0, // PC_VPKUHUS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKUWUM
+ BPU, 0, 0, 0, 0, 0, // PC_VPKUWUS
+ BPU, 0, 0, 0, 0, 0, // PC_VREFP
+ BPU, 0, 0, 0, 0, 0, // PC_VRFIM
+ BPU, 0, 0, 0, 0, 0, // PC_VRFIN
+ BPU, 0, 0, 0, 0, 0, // PC_VRFIP
+ BPU, 0, 0, 0, 0, 0, // PC_VRFIZ
+ BPU, 0, 0, 0, 0, 0, // PC_VRLB
+ BPU, 0, 0, 0, 0, 0, // PC_VRLH
+ BPU, 0, 0, 0, 0, 0, // PC_VRLW
+ BPU, 0, 0, 0, 0, 0, // PC_VRSQRTEFP
+ BPU, 0, 0, 0, 0, 0, // PC_VSL
+ BPU, 0, 0, 0, 0, 0, // PC_VSLB
+ BPU, 0, 0, 0, 0, 0, // PC_VSLH
+ BPU, 0, 0, 0, 0, 0, // PC_VSLO
+ BPU, 0, 0, 0, 0, 0, // PC_VSLW
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTB
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTH
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTW
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTISB
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTISH
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTISW
+ BPU, 0, 0, 0, 0, 0, // PC_VSR
+ BPU, 0, 0, 0, 0, 0, // PC_VSRAB
+ BPU, 0, 0, 0, 0, 0, // PC_VSRAH
+ BPU, 0, 0, 0, 0, 0, // PC_VSRAW
+ BPU, 0, 0, 0, 0, 0, // PC_VSRB
+ BPU, 0, 0, 0, 0, 0, // PC_VSRH
+ BPU, 0, 0, 0, 0, 0, // PC_VSRO
+ BPU, 0, 0, 0, 0, 0, // PC_VSRW
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBCUW
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBFP
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBSBS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBSWS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUBM
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUBS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUHM
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUHS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUWM
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUWS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUMSWS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUM2SWS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUM4SBS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUM4SHS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUM4UBS
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKHPX
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKHSB
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKHSH
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKLPX
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKLSB
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKLSH
+ BPU, 0, 0, 0, 0, 0, // PC_VXOR
+ BPU, 0, 0, 0, 0, 0, // PC_VMADDFP
+ BPU, 0, 0, 0, 0, 0, // PC_VMHADDSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VMHRADDSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VMLADDUHM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMMBM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMSHM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMUBM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMUHM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMUHS
+ BPU, 0, 0, 0, 0, 0, // PC_VNMSUBFP
+ BPU, 0, 0, 0, 0, 0, // PC_VPERM
+ BPU, 0, 0, 0, 0, 0, // PC_VSEL
+ BPU, 0, 0, 0, 0, 0, // PC_VSLDOI
+ BPU, 0, 0, 0, 0, 0, // PC_VMR
+ BPU, 0, 0, 0, 0, 0, // PC_VMRP
+ BPU, 0, 0, 0, 0, 0, // PC_SLE
+ BPU, 0, 0, 0, 0, 0, // PC_SLEQ
+ BPU, 0, 0, 0, 0, 0, // PC_SLIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SLLIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SLLQ
+ BPU, 0, 0, 0, 0, 0, // PC_SLQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRAIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRAQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRE
+ BPU, 0, 0, 0, 0, 0, // PC_SREA
+ BPU, 0, 0, 0, 0, 0, // PC_SREQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRLIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRLQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRQ
+ BPU, 0, 0, 0, 0, 0, // PC_MASKG
+ BPU, 0, 0, 0, 0, 0, // PC_MASKIR
+ BPU, 0, 0, 0, 0, 0, // PC_LSCBX
+ BPU, 0, 0, 0, 0, 0, // PC_DIV
+ BPU, 0, 0, 0, 0, 0, // PC_DIVS
+ BPU, 0, 0, 0, 0, 0, // PC_DOZ
+ BPU, 0, 0, 0, 0, 0, // PC_MUL
+ BPU, 0, 0, 0, 0, 0, // PC_NABS
+ BPU, 0, 0, 0, 0, 0, // PC_ABS
+ BPU, 0, 0, 0, 0, 0, // PC_CLCS
+ BPU, 0, 0, 0, 0, 0, // PC_DOZI
+ BPU, 0, 0, 0, 0, 0, // PC_RLMI
+ BPU, 0, 0, 0, 0, 0, // PC_RRIB
+};
+
+static void advance(int firstStage, int oldStage, int newStage) {
+ PCode *instr = pipeline[oldStage].instr;
+ int cycles = instruction_timing[instr->op].cycles[newStage - firstStage];
+ pipeline[newStage].instr = instr;
+ pipeline[newStage].remaining = cycles;
+ pipeline[oldStage].instr = NULL;
+}
+
+static void assign_completion_buffer(PCode *instr) {
+ completionbuffers.used++;
+ completionbuffers.free--;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].instr = instr;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].completed = 0;
+ completionbuffers.nextFreeSlot = (completionbuffers.nextFreeSlot + 1) % MaxEntries;
+}
+
+static void complete_instruction(int stage) {
+ PCode *instr = pipeline[stage].instr;
+ int buf = 0;
+ while (buf < MaxEntries && completionbuffers.entries[buf].instr != instr)
+ buf++;
+
+ completionbuffers.entries[buf].completed = 1;
+ pipeline[stage].instr = NULL;
+}
+
+static void retire_instruction(void) {
+ completionbuffers.entries[completionbuffers.nextToRetire].instr = NULL;
+ completionbuffers.used--;
+ completionbuffers.free++;
+ completionbuffers.nextToRetire = (completionbuffers.nextToRetire + 1) % MaxEntries;
+}
+
+static int latency(PCode *instr) {
+ int cycles = instruction_timing[instr->op].latency;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ cycles += 2;
+ if (instr->op == PC_LMW || instr->op == PC_STMW)
+ cycles += instr->argCount - 2;
+ return cycles;
+}
+
+static void initialize(void) {
+ int stage;
+ int i;
+
+ for (stage = 0; stage < NumStages; stage++)
+ pipeline[stage].instr = NULL;
+
+ completionbuffers.free = 5;
+ completionbuffers.used = 0;
+ completionbuffers.nextToRetire = 0;
+ completionbuffers.nextFreeSlot = 0;
+ for (i = 0; i < MaxEntries; i++)
+ completionbuffers.entries[i].instr = NULL;
+}
+
+static int can_issue(PCode *instr) {
+ if (completionbuffers.free == 0)
+ return 0;
+ if (pipeline[instruction_timing[instr->op].stage].instr)
+ return 0;
+ if ((instr->flags & fIsWrite) && pipeline[LSU2].instr && (pipeline[LSU2].instr->flags & fIsWrite))
+ return 0;
+ return 1;
+}
+
+static void issue(PCode *instr) {
+ int stage = instruction_timing[instr->op].stage;
+ int cycles = instruction_timing[instr->op].cycles[0];
+ assign_completion_buffer(instr);
+ pipeline[stage].instr = instr;
+ pipeline[stage].remaining = cycles;
+}
+
+static void advance_clock(void) {
+ int stage;
+
+ for (stage = 0; stage < NumStages; stage++) {
+ if (pipeline[stage].instr && pipeline[stage].remaining)
+ --pipeline[stage].remaining;
+ }
+
+ if (completionbuffers.used && completionbuffers.entries[completionbuffers.nextToRetire].completed) {
+ retire_instruction();
+ if (completionbuffers.used && completionbuffers.entries[completionbuffers.nextToRetire].completed) {
+ retire_instruction();
+ }
+ }
+
+ if (pipeline[IU].instr && pipeline[IU].remaining == 0)
+ complete_instruction(IU);
+ if (pipeline[LSU2].instr && pipeline[LSU2].remaining == 0)
+ complete_instruction(LSU2);
+ if (pipeline[FPU3].instr && pipeline[FPU3].remaining == 0)
+ complete_instruction(FPU3);
+ if (pipeline[SRU].instr && pipeline[SRU].remaining == 0)
+ complete_instruction(SRU);
+ if (pipeline[BPU].instr && pipeline[BPU].remaining == 0)
+ complete_instruction(BPU);
+
+ if (
+ pipeline[FPU1].instr &&
+ pipeline[FPU1].remaining == 0 &&
+ (pipeline[FPU1].instr->op == PC_FDIV || pipeline[FPU1].instr->op == PC_FDIVS)
+ )
+ complete_instruction(FPU1);
+
+ if (pipeline[FPU2].instr && pipeline[FPU2].remaining == 0 && !pipeline[FPU3].instr)
+ advance(FPU1, FPU2, FPU3);
+ if (pipeline[FPU1].instr && pipeline[FPU1].remaining == 0 && !pipeline[FPU2].instr)
+ advance(FPU1, FPU1, FPU2);
+ if (pipeline[LSU1].instr && pipeline[LSU1].remaining == 0 && !pipeline[LSU2].instr)
+ advance(LSU1, LSU1, LSU2);
+}
+
+static int serializes(PCode *instr) {
+ return instruction_timing[instr->op].serializes;
+}
+
+MachineInfo machine603 = {
+ 2,
+ 1,
+ 0,
+ &latency,
+ &initialize,
+ &can_issue,
+ &issue,
+ &advance_clock,
+ &serializes,
+ &default_uses_vpermute_unit
+};
diff --git a/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation603e.c b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation603e.c
new file mode 100644
index 0000000..d3e1e47
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation603e.c
@@ -0,0 +1,650 @@
+#include "compiler/Scheduler.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+
+// https://www.nxp.com/docs/en/reference-manual/MPC603EUM.pdf
+
+typedef enum Stage {
+ BPU, // Branch Prediction Unit
+ IU, // Integer Unit
+ LSU1, // Load/Store Unit
+ LSU2,
+ FPU1, // Floating Point Unit
+ FPU2,
+ FPU3,
+ SRU, // System Register Unit
+ NumStages
+} Stage;
+
+static struct {
+ // the instruction currently in this pipeline stage
+ PCode *instr;
+
+ // how many cycles are left for this instruction to finish
+ int remaining;
+} pipeline[NumStages];
+
+enum {
+ MaxEntries = 5
+};
+
+static struct {
+ // how many entries remain unused in the queue
+ unsigned int free;
+
+ // how many entries are currently used in the queue
+ unsigned int used;
+
+ // the index of the next instruction that will be retired
+ unsigned int nextToRetire;
+
+ // the index of the next free slot that will be used when an instruction is dispatched
+ unsigned int nextFreeSlot;
+
+ // circular array of entries in the completion queue
+ struct {
+ PCode *instr;
+ int completed;
+ } entries[MaxEntries];
+} completionbuffers;
+
+static struct {
+ // the initial stage for this instruction
+ Stage stage;
+
+ // the total amount of cycles required by this instruction
+ char latency;
+
+ // how long it takes to finish each stage
+ char cycles[3];
+
+ // does this instruction serialise?
+ char serializes;
+} instruction_timing[OPCODE_MAX] = {
+ BPU, 0, 0, 0, 0, 1, // PC_B
+ BPU, 0, 0, 0, 0, 1, // PC_BL
+ BPU, 0, 0, 0, 0, 1, // PC_BC
+ BPU, 0, 0, 0, 0, 1, // PC_BCLR
+ BPU, 0, 0, 0, 0, 1, // PC_BCCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BT
+ BPU, 0, 0, 0, 0, 1, // PC_BTLR
+ BPU, 0, 0, 0, 0, 1, // PC_BTCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BF
+ BPU, 0, 0, 0, 0, 1, // PC_BFLR
+ BPU, 0, 0, 0, 0, 1, // PC_BFCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZ
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZT
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZF
+ BPU, 0, 0, 0, 0, 1, // PC_BDZ
+ BPU, 0, 0, 0, 0, 1, // PC_BDZT
+ BPU, 0, 0, 0, 0, 1, // PC_BDZF
+ BPU, 0, 0, 0, 0, 1, // PC_BLR
+ BPU, 0, 0, 0, 0, 1, // PC_BCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BCTRL
+ BPU, 0, 0, 0, 0, 1, // PC_BLRL
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHA
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAU
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_LMW
+ LSU1, 2, 1, 1, 0, 0, // PC_STB
+ LSU1, 2, 1, 1, 0, 0, // PC_STBU
+ LSU1, 2, 1, 1, 0, 0, // PC_STBX
+ LSU1, 2, 1, 1, 0, 0, // PC_STBUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STH
+ LSU1, 2, 1, 1, 0, 0, // PC_STHU
+ LSU1, 2, 1, 1, 0, 0, // PC_STHX
+ LSU1, 2, 1, 1, 0, 0, // PC_STHUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STHBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_STW
+ LSU1, 2, 1, 1, 0, 0, // PC_STWU
+ LSU1, 2, 1, 1, 0, 0, // PC_STWX
+ LSU1, 2, 1, 1, 0, 0, // PC_STWUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STWBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_STMW
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBF
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBST
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBT
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBTST
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBZ
+ IU, 1, 1, 0, 0, 0, // PC_ADD
+ IU, 1, 1, 0, 0, 0, // PC_ADDC
+ IU, 1, 1, 0, 0, 0, // PC_ADDE
+ IU, 1, 1, 0, 0, 0, // PC_ADDI
+ IU, 1, 1, 0, 0, 0, // PC_ADDIC
+ IU, 1, 1, 0, 0, 0, // PC_ADDICR
+ IU, 1, 1, 0, 0, 0, // PC_ADDIS
+ IU, 1, 1, 0, 0, 0, // PC_ADDME
+ IU, 1, 1, 0, 0, 0, // PC_ADDZE
+ IU, 37, 37, 0, 0, 0, // PC_DIVW
+ IU, 37, 37, 0, 0, 0, // PC_DIVWU
+ IU, 5, 5, 0, 0, 0, // PC_MULHW
+ IU, 5, 5, 0, 0, 0, // PC_MULHWU
+ IU, 3, 3, 0, 0, 0, // PC_MULLI
+ IU, 5, 5, 0, 0, 0, // PC_MULLW
+ IU, 1, 1, 0, 0, 0, // PC_NEG
+ IU, 1, 1, 0, 0, 0, // PC_SUBF
+ IU, 1, 1, 0, 0, 0, // PC_SUBFC
+ IU, 1, 1, 0, 0, 0, // PC_SUBFE
+ IU, 1, 1, 0, 0, 0, // PC_SUBFIC
+ IU, 1, 1, 0, 0, 0, // PC_SUBFME
+ IU, 1, 1, 0, 0, 0, // PC_SUBFZE
+ IU, 3, 1, 0, 0, 0, // PC_CMPI
+ IU, 3, 1, 0, 0, 0, // PC_CMP
+ IU, 3, 1, 0, 0, 0, // PC_CMPLI
+ IU, 3, 1, 0, 0, 0, // PC_CMPL
+ IU, 1, 1, 0, 0, 0, // PC_ANDI
+ IU, 1, 1, 0, 0, 0, // PC_ANDIS
+ IU, 1, 1, 0, 0, 0, // PC_ORI
+ IU, 1, 1, 0, 0, 0, // PC_ORIS
+ IU, 1, 1, 0, 0, 0, // PC_XORI
+ IU, 1, 1, 0, 0, 0, // PC_XORIS
+ IU, 1, 1, 0, 0, 0, // PC_AND
+ IU, 1, 1, 0, 0, 0, // PC_OR
+ IU, 1, 1, 0, 0, 0, // PC_XOR
+ IU, 1, 1, 0, 0, 0, // PC_NAND
+ IU, 1, 1, 0, 0, 0, // PC_NOR
+ IU, 1, 1, 0, 0, 0, // PC_EQV
+ IU, 1, 1, 0, 0, 0, // PC_ANDC
+ IU, 1, 1, 0, 0, 0, // PC_ORC
+ IU, 1, 1, 0, 0, 0, // PC_EXTSB
+ IU, 1, 1, 0, 0, 0, // PC_EXTSH
+ IU, 1, 1, 0, 0, 0, // PC_CNTLZW
+ IU, 1, 1, 0, 0, 0, // PC_RLWINM
+ IU, 1, 1, 0, 0, 0, // PC_RLWNM
+ IU, 1, 1, 0, 0, 0, // PC_RLWIMI
+ IU, 1, 1, 0, 0, 0, // PC_SLW
+ IU, 1, 1, 0, 0, 0, // PC_SRW
+ IU, 1, 1, 0, 0, 0, // PC_SRAWI
+ IU, 1, 1, 0, 0, 0, // PC_SRAW
+ SRU, 1, 1, 0, 0, 0, // PC_CRAND
+ SRU, 1, 1, 0, 0, 0, // PC_CRANDC
+ SRU, 1, 1, 0, 0, 0, // PC_CREQV
+ SRU, 1, 1, 0, 0, 0, // PC_CRNAND
+ SRU, 1, 1, 0, 0, 0, // PC_CRNOR
+ SRU, 1, 1, 0, 0, 0, // PC_CROR
+ SRU, 1, 1, 0, 0, 0, // PC_CRORC
+ SRU, 1, 1, 0, 0, 0, // PC_CRXOR
+ SRU, 1, 1, 0, 0, 0, // PC_MCRF
+ SRU, 2, 2, 0, 0, 0, // PC_MTXER
+ SRU, 2, 2, 0, 0, 0, // PC_MTCTR
+ SRU, 2, 2, 0, 0, 0, // PC_MTLR
+ SRU, 1, 1, 0, 0, 0, // PC_MTCRF
+ SRU, 1, 1, 0, 0, 1, // PC_MTMSR
+ SRU, 1, 1, 0, 0, 1, // PC_MTSPR
+ SRU, 1, 1, 0, 0, 1, // PC_MFMSR
+ SRU, 1, 1, 0, 0, 1, // PC_MFSPR
+ SRU, 1, 1, 0, 0, 0, // PC_MFXER
+ SRU, 1, 1, 0, 0, 0, // PC_MFCTR
+ SRU, 1, 1, 0, 0, 0, // PC_MFLR
+ SRU, 1, 1, 0, 0, 0, // PC_MFCR
+ FPU1, 3, 1, 1, 1, 0, // PC_MFFS
+ FPU1, 3, 1, 1, 1, 0, // PC_MTFSF
+ SRU, 1, 1, 0, 0, 1, // PC_EIEIO
+ SRU, 1, 1, 0, 0, 1, // PC_ISYNC
+ SRU, 1, 1, 0, 0, 1, // PC_SYNC
+ SRU, 1, 1, 0, 0, 1, // PC_RFI
+ IU, 1, 1, 0, 0, 0, // PC_LI
+ IU, 1, 1, 0, 0, 0, // PC_LIS
+ IU, 1, 1, 0, 0, 0, // PC_MR
+ IU, 1, 1, 0, 0, 0, // PC_NOP
+ IU, 1, 1, 0, 0, 0, // PC_NOT
+ LSU1, 2, 1, 1, 0, 0, // PC_LFS
+ LSU1, 2, 1, 1, 0, 0, // PC_LFSU
+ LSU1, 2, 1, 1, 0, 0, // PC_LFSX
+ LSU1, 2, 1, 1, 0, 0, // PC_LFSUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LFD
+ LSU1, 2, 1, 1, 0, 0, // PC_LFDU
+ LSU1, 2, 1, 1, 0, 0, // PC_LFDX
+ LSU1, 2, 1, 1, 0, 0, // PC_LFDUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFS
+ LSU1, 2, 1, 1, 0, 0, // PC_STFSU
+ LSU1, 2, 1, 1, 0, 0, // PC_STFSX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFSUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFD
+ LSU1, 2, 1, 1, 0, 0, // PC_STFDU
+ LSU1, 2, 1, 1, 0, 0, // PC_STFDX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFDUX
+ FPU1, 3, 1, 1, 1, 0, // PC_FMR
+ FPU1, 3, 1, 1, 1, 0, // PC_FABS
+ FPU1, 3, 1, 1, 1, 0, // PC_FNEG
+ FPU1, 3, 1, 1, 1, 0, // PC_FNABS
+ FPU1, 3, 1, 1, 1, 0, // PC_FADD
+ FPU1, 3, 1, 1, 1, 0, // PC_FADDS
+ FPU1, 3, 1, 1, 1, 0, // PC_FSUB
+ FPU1, 3, 1, 1, 1, 0, // PC_FSUBS
+ FPU1, 4, 2, 1, 1, 0, // PC_FMUL
+ FPU1, 3, 1, 1, 1, 0, // PC_FMULS
+ FPU1, 33, 33, 0, 0, 0, // PC_FDIV
+ FPU1, 18, 18, 0, 0, 0, // PC_FDIVS
+ FPU1, 4, 2, 1, 1, 0, // PC_FMADD
+ FPU1, 3, 1, 1, 1, 0, // PC_FMADDS
+ FPU1, 4, 2, 1, 1, 0, // PC_FMSUB
+ FPU1, 3, 1, 1, 1, 0, // PC_FMSUBS
+ FPU1, 4, 2, 1, 1, 0, // PC_FNMADD
+ FPU1, 3, 1, 1, 1, 0, // PC_FNMADDS
+ FPU1, 4, 2, 1, 1, 0, // PC_FNMSUB
+ FPU1, 3, 1, 1, 1, 0, // PC_FNMSUBS
+ FPU1, 18, 18, 0, 0, 0, // PC_FRES
+ FPU1, 3, 1, 1, 1, 0, // PC_FRSQRTE
+ FPU1, 3, 1, 1, 1, 0, // PC_FSEL
+ FPU1, 3, 1, 1, 1, 0, // PC_FRSP
+ FPU1, 3, 1, 1, 1, 0, // PC_FCTIW
+ FPU1, 3, 1, 1, 1, 0, // PC_FCTIWZ
+ FPU1, 5, 1, 1, 1, 0, // PC_FCMPU
+ FPU1, 5, 1, 1, 1, 0, // PC_FCMPO
+ LSU1, 1, 1, 0, 0, 0, // PC_LWARX
+ LSU1, 1, 1, 0, 0, 0, // PC_LSWI
+ LSU1, 1, 1, 0, 0, 0, // PC_LSWX
+ LSU1, 1, 1, 0, 0, 0, // PC_STFIWX
+ LSU1, 1, 1, 0, 0, 0, // PC_STSWI
+ LSU1, 1, 1, 0, 0, 0, // PC_STSWX
+ LSU1, 1, 1, 0, 0, 0, // PC_STWCX
+ IU, 1, 1, 0, 0, 1, // PC_ECIWX
+ IU, 1, 1, 0, 0, 1, // PC_ECOWX
+ IU, 1, 1, 0, 0, 0, // PC_DCBI
+ IU, 1, 1, 0, 0, 0, // PC_ICBI
+ IU, 1, 1, 0, 0, 0, // PC_MCRFS
+ IU, 1, 1, 0, 0, 0, // PC_MCRXR
+ IU, 1, 1, 0, 0, 0, // PC_MFTB
+ IU, 1, 1, 0, 0, 0, // PC_MFSR
+ IU, 1, 1, 0, 0, 0, // PC_MTSR
+ IU, 1, 1, 0, 0, 0, // PC_MFSRIN
+ IU, 1, 1, 0, 0, 0, // PC_MTSRIN
+ IU, 1, 1, 0, 0, 0, // PC_MTFSB0
+ IU, 1, 1, 0, 0, 0, // PC_MTFSB1
+ IU, 1, 1, 0, 0, 0, // PC_MTFSFI
+ IU, 1, 1, 0, 0, 1, // PC_SC
+ FPU1, 1, 1, 0, 0, 0, // PC_FSQRT
+ FPU1, 1, 1, 0, 0, 0, // PC_FSQRTS
+ IU, 1, 1, 0, 0, 0, // PC_TLBIA
+ IU, 1, 1, 0, 0, 0, // PC_TLBIE
+ IU, 1, 1, 0, 0, 0, // PC_TLBLD
+ IU, 1, 1, 0, 0, 0, // PC_TLBLI
+ IU, 1, 1, 0, 0, 0, // PC_TLBSYNC
+ IU, 1, 1, 0, 0, 1, // PC_TW
+ IU, 1, 1, 0, 0, 1, // PC_TRAP
+ IU, 1, 1, 0, 0, 1, // PC_TWI
+ IU, 1, 1, 0, 0, 1, // PC_OPWORD
+ IU, 1, 1, 0, 0, 0, // PC_MFROM
+ IU, 1, 1, 0, 0, 1, // PC_DSA
+ IU, 1, 1, 0, 0, 1, // PC_ESA
+ IU, 0, 0, 0, 0, 0, // PC_DCCCI
+ IU, 0, 0, 0, 0, 0, // PC_DCREAD
+ IU, 0, 0, 0, 0, 0, // PC_ICBT
+ IU, 0, 0, 0, 0, 0, // PC_ICCCI
+ IU, 0, 0, 0, 0, 0, // PC_ICREAD
+ IU, 0, 0, 0, 0, 0, // PC_RFCI
+ IU, 0, 0, 0, 0, 0, // PC_TLBRE
+ IU, 0, 0, 0, 0, 0, // PC_TLBSX
+ IU, 0, 0, 0, 0, 0, // PC_TLBWE
+ IU, 0, 0, 0, 0, 0, // PC_WRTEE
+ IU, 0, 0, 0, 0, 0, // PC_WRTEEI
+ IU, 0, 0, 0, 0, 0, // PC_MFDCR
+ IU, 0, 0, 0, 0, 0, // PC_MTDCR
+ IU, 0, 0, 0, 0, 0, // PC_DCBA
+ BPU, 0, 0, 0, 0, 0, // PC_DSS
+ BPU, 0, 0, 0, 0, 0, // PC_DSSALL
+ BPU, 0, 0, 0, 0, 0, // PC_DST
+ BPU, 0, 0, 0, 0, 0, // PC_DSTT
+ BPU, 0, 0, 0, 0, 0, // PC_DSTST
+ BPU, 0, 0, 0, 0, 0, // PC_DSTSTT
+ BPU, 0, 0, 0, 0, 0, // PC_LVEBX
+ BPU, 0, 0, 0, 0, 0, // PC_LVEHX
+ BPU, 0, 0, 0, 0, 0, // PC_LVEWX
+ BPU, 0, 0, 0, 0, 0, // PC_LVSL
+ BPU, 0, 0, 0, 0, 0, // PC_LVSR
+ BPU, 0, 0, 0, 0, 0, // PC_LVX
+ BPU, 0, 0, 0, 0, 0, // PC_LVXL
+ BPU, 0, 0, 0, 0, 0, // PC_STVEBX
+ BPU, 0, 0, 0, 0, 0, // PC_STVEHX
+ BPU, 0, 0, 0, 0, 0, // PC_STVEWX
+ BPU, 0, 0, 0, 0, 0, // PC_STVX
+ BPU, 0, 0, 0, 0, 0, // PC_STVXL
+ BPU, 0, 0, 0, 0, 0, // PC_MFVSCR
+ BPU, 0, 0, 0, 0, 0, // PC_MTVSCR
+ BPU, 0, 0, 0, 0, 0, // PC_VADDCUW
+ BPU, 0, 0, 0, 0, 0, // PC_VADDFP
+ BPU, 0, 0, 0, 0, 0, // PC_VADDSBS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDSWS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUBM
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUBS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUHM
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUHS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUWM
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUWS
+ BPU, 0, 0, 0, 0, 0, // PC_VAND
+ BPU, 0, 0, 0, 0, 0, // PC_VANDC
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGSB
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGSH
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGSW
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGUB
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGUH
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGUW
+ BPU, 0, 0, 0, 0, 0, // PC_VCFSX
+ BPU, 0, 0, 0, 0, 0, // PC_VCFUX
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPBFP
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPEQFP
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPEQUB
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPEQUH
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPEQUW
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGEFP
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTFP
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTSB
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTSH
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTSW
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTUB
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTUH
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTUW
+ BPU, 0, 0, 0, 0, 0, // PC_VCTSXS
+ BPU, 0, 0, 0, 0, 0, // PC_VCTUXS
+ BPU, 0, 0, 0, 0, 0, // PC_VEXPTEFP
+ BPU, 0, 0, 0, 0, 0, // PC_VLOGEFP
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXFP
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXSB
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXSH
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXSW
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXUB
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXUH
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXUW
+ BPU, 0, 0, 0, 0, 0, // PC_VMINFP
+ BPU, 0, 0, 0, 0, 0, // PC_VMINSB
+ BPU, 0, 0, 0, 0, 0, // PC_VMINSH
+ BPU, 0, 0, 0, 0, 0, // PC_VMINSW
+ BPU, 0, 0, 0, 0, 0, // PC_VMINUB
+ BPU, 0, 0, 0, 0, 0, // PC_VMINUH
+ BPU, 0, 0, 0, 0, 0, // PC_VMINUW
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGHB
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGHH
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGHW
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGLB
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGLH
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGLW
+ BPU, 0, 0, 0, 0, 0, // PC_VMULESB
+ BPU, 0, 0, 0, 0, 0, // PC_VMULESH
+ BPU, 0, 0, 0, 0, 0, // PC_VMULEUB
+ BPU, 0, 0, 0, 0, 0, // PC_VMULEUH
+ BPU, 0, 0, 0, 0, 0, // PC_VMULOSB
+ BPU, 0, 0, 0, 0, 0, // PC_VMULOSH
+ BPU, 0, 0, 0, 0, 0, // PC_VMULOUB
+ BPU, 0, 0, 0, 0, 0, // PC_VMULOUH
+ BPU, 0, 0, 0, 0, 0, // PC_VNOR
+ BPU, 0, 0, 0, 0, 0, // PC_VOR
+ BPU, 0, 0, 0, 0, 0, // PC_VPKPX
+ BPU, 0, 0, 0, 0, 0, // PC_VPKSHSS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKSHUS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKSWSS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKSWUS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKUHUM
+ BPU, 0, 0, 0, 0, 0, // PC_VPKUHUS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKUWUM
+ BPU, 0, 0, 0, 0, 0, // PC_VPKUWUS
+ BPU, 0, 0, 0, 0, 0, // PC_VREFP
+ BPU, 0, 0, 0, 0, 0, // PC_VRFIM
+ BPU, 0, 0, 0, 0, 0, // PC_VRFIN
+ BPU, 0, 0, 0, 0, 0, // PC_VRFIP
+ BPU, 0, 0, 0, 0, 0, // PC_VRFIZ
+ BPU, 0, 0, 0, 0, 0, // PC_VRLB
+ BPU, 0, 0, 0, 0, 0, // PC_VRLH
+ BPU, 0, 0, 0, 0, 0, // PC_VRLW
+ BPU, 0, 0, 0, 0, 0, // PC_VRSQRTEFP
+ BPU, 0, 0, 0, 0, 0, // PC_VSL
+ BPU, 0, 0, 0, 0, 0, // PC_VSLB
+ BPU, 0, 0, 0, 0, 0, // PC_VSLH
+ BPU, 0, 0, 0, 0, 0, // PC_VSLO
+ BPU, 0, 0, 0, 0, 0, // PC_VSLW
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTB
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTH
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTW
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTISB
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTISH
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTISW
+ BPU, 0, 0, 0, 0, 0, // PC_VSR
+ BPU, 0, 0, 0, 0, 0, // PC_VSRAB
+ BPU, 0, 0, 0, 0, 0, // PC_VSRAH
+ BPU, 0, 0, 0, 0, 0, // PC_VSRAW
+ BPU, 0, 0, 0, 0, 0, // PC_VSRB
+ BPU, 0, 0, 0, 0, 0, // PC_VSRH
+ BPU, 0, 0, 0, 0, 0, // PC_VSRO
+ BPU, 0, 0, 0, 0, 0, // PC_VSRW
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBCUW
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBFP
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBSBS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBSWS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUBM
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUBS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUHM
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUHS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUWM
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUWS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUMSWS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUM2SWS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUM4SBS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUM4SHS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUM4UBS
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKHPX
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKHSB
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKHSH
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKLPX
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKLSB
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKLSH
+ BPU, 0, 0, 0, 0, 0, // PC_VXOR
+ BPU, 0, 0, 0, 0, 0, // PC_VMADDFP
+ BPU, 0, 0, 0, 0, 0, // PC_VMHADDSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VMHRADDSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VMLADDUHM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMMBM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMSHM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMUBM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMUHM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMUHS
+ BPU, 0, 0, 0, 0, 0, // PC_VNMSUBFP
+ BPU, 0, 0, 0, 0, 0, // PC_VPERM
+ BPU, 0, 0, 0, 0, 0, // PC_VSEL
+ BPU, 0, 0, 0, 0, 0, // PC_VSLDOI
+ BPU, 0, 0, 0, 0, 0, // PC_VMR
+ BPU, 0, 0, 0, 0, 0, // PC_VMRP
+ BPU, 0, 0, 0, 0, 0, // PC_SLE
+ BPU, 0, 0, 0, 0, 0, // PC_SLEQ
+ BPU, 0, 0, 0, 0, 0, // PC_SLIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SLLIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SLLQ
+ BPU, 0, 0, 0, 0, 0, // PC_SLQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRAIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRAQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRE
+ BPU, 0, 0, 0, 0, 0, // PC_SREA
+ BPU, 0, 0, 0, 0, 0, // PC_SREQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRLIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRLQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRQ
+ BPU, 0, 0, 0, 0, 0, // PC_MASKG
+ BPU, 0, 0, 0, 0, 0, // PC_MASKIR
+ BPU, 0, 0, 0, 0, 0, // PC_LSCBX
+ BPU, 0, 0, 0, 0, 0, // PC_DIV
+ BPU, 0, 0, 0, 0, 0, // PC_DIVS
+ BPU, 0, 0, 0, 0, 0, // PC_DOZ
+ BPU, 0, 0, 0, 0, 0, // PC_MUL
+ BPU, 0, 0, 0, 0, 0, // PC_NABS
+ BPU, 0, 0, 0, 0, 0, // PC_ABS
+ BPU, 0, 0, 0, 0, 0, // PC_CLCS
+ BPU, 0, 0, 0, 0, 0, // PC_DOZI
+ BPU, 0, 0, 0, 0, 0, // PC_RLMI
+ BPU, 0, 0, 0, 0, 0, // PC_RRIB
+};
+
+static void advance(int firstStage, int oldStage, int newStage) {
+ PCode *instr = pipeline[oldStage].instr;
+ int cycles = instruction_timing[instr->op].cycles[newStage - firstStage];
+ pipeline[newStage].instr = instr;
+ pipeline[newStage].remaining = cycles;
+ pipeline[oldStage].instr = NULL;
+}
+
+static void assign_completion_buffer(PCode *instr) {
+ completionbuffers.used++;
+ completionbuffers.free--;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].instr = instr;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].completed = 0;
+ completionbuffers.nextFreeSlot = (completionbuffers.nextFreeSlot + 1) % MaxEntries;
+}
+
+static void complete_instruction(int stage) {
+ PCode *instr = pipeline[stage].instr;
+ int buf = 0;
+ while (buf < MaxEntries && completionbuffers.entries[buf].instr != instr)
+ buf++;
+
+ completionbuffers.entries[buf].completed = 1;
+ pipeline[stage].instr = NULL;
+}
+
+static void retire_instruction(void) {
+ completionbuffers.entries[completionbuffers.nextToRetire].instr = NULL;
+ completionbuffers.used--;
+ completionbuffers.free++;
+ completionbuffers.nextToRetire = (completionbuffers.nextToRetire + 1) % MaxEntries;
+}
+
+static int latency(PCode *instr) {
+ int cycles = instruction_timing[instr->op].latency;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ cycles += 2;
+ if (instr->op == PC_LMW || instr->op == PC_STMW)
+ cycles += instr->argCount - 2;
+ return cycles;
+}
+
+static void initialize(void) {
+ int stage;
+ int i;
+
+ for (stage = 0; stage < NumStages; stage++)
+ pipeline[stage].instr = NULL;
+
+ completionbuffers.free = MaxEntries;
+ completionbuffers.used = 0;
+ completionbuffers.nextToRetire = 0;
+ completionbuffers.nextFreeSlot = 0;
+ for (i = 0; i < MaxEntries; i++)
+ completionbuffers.entries[i].instr = NULL;
+}
+
+static int can_issue(PCode *instr) {
+ int stage;
+
+ if (completionbuffers.free == 0)
+ return 0;
+
+ stage = instruction_timing[instr->op].stage;
+ if (pipeline[stage].instr) {
+ if (stage == IU) {
+ switch (instr->op) {
+ case PC_ADD:
+ case PC_ADDC:
+ case PC_ADDI:
+ case PC_ADDIS:
+ case PC_CMPI:
+ case PC_CMP:
+ case PC_CMPLI:
+ case PC_CMPL:
+ if (is_dependent(instr, pipeline[IU].instr, RegClass_GPR))
+ return 0;
+ if (!pipeline[SRU].instr)
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ if ((instr->flags & fIsWrite) && pipeline[LSU2].instr && (pipeline[LSU2].instr->flags & fIsWrite))
+ return 0;
+
+ return 1;
+}
+
+static void issue(PCode *instr) {
+ int stage = instruction_timing[instr->op].stage;
+ int cycles = instruction_timing[instr->op].cycles[0];
+ if (stage == IU && pipeline[IU].instr)
+ stage = SRU;
+ assign_completion_buffer(instr);
+ pipeline[stage].instr = instr;
+ pipeline[stage].remaining = cycles;
+}
+
+static void advance_clock(void) {
+ int stage;
+
+ for (stage = 0; stage < NumStages; stage++) {
+ if (pipeline[stage].instr && pipeline[stage].remaining)
+ --pipeline[stage].remaining;
+ }
+
+ if (completionbuffers.used && completionbuffers.entries[completionbuffers.nextToRetire].completed) {
+ retire_instruction();
+ if (completionbuffers.used && completionbuffers.entries[completionbuffers.nextToRetire].completed) {
+ retire_instruction();
+ }
+ }
+
+ if (pipeline[IU].instr && pipeline[IU].remaining == 0)
+ complete_instruction(IU);
+ if (pipeline[LSU2].instr && pipeline[LSU2].remaining == 0)
+ complete_instruction(LSU2);
+ if (pipeline[FPU3].instr && pipeline[FPU3].remaining == 0)
+ complete_instruction(FPU3);
+ if (pipeline[SRU].instr && pipeline[SRU].remaining == 0)
+ complete_instruction(SRU);
+ if (pipeline[BPU].instr && pipeline[BPU].remaining == 0)
+ complete_instruction(BPU);
+
+ if (
+ pipeline[FPU1].instr &&
+ pipeline[FPU1].remaining == 0 &&
+ (pipeline[FPU1].instr->op == PC_FDIV || pipeline[FPU1].instr->op == PC_FDIVS)
+ )
+ complete_instruction(FPU1);
+
+ if (pipeline[FPU2].instr && pipeline[FPU2].remaining == 0 && !pipeline[FPU3].instr)
+ advance(FPU1, FPU2, FPU3);
+ if (pipeline[FPU1].instr && pipeline[FPU1].remaining == 0 && !pipeline[FPU2].instr)
+ advance(FPU1, FPU1, FPU2);
+ if (pipeline[LSU1].instr && pipeline[LSU1].remaining == 0 && !pipeline[LSU2].instr)
+ advance(LSU1, LSU1, LSU2);
+}
+
+static int serializes(PCode *instr) {
+ return instruction_timing[instr->op].serializes;
+}
+
+MachineInfo machine603e = {
+ 2,
+ 1,
+ 0,
+ &latency,
+ &initialize,
+ &can_issue,
+ &issue,
+ &advance_clock,
+ &serializes,
+ &default_uses_vpermute_unit
+};
diff --git a/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation604.c b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation604.c
new file mode 100644
index 0000000..9775c9e
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation604.c
@@ -0,0 +1,670 @@
+#include "compiler/Scheduler.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+
+// https://archive.org/details/bitsavers_motorolaPosManualNov94_22719504
+
+typedef enum Stage {
+ SCIU, // Single-Cycle Integer Unit 1
+ SCIU2, // Single-Cycle Integer Unit 2
+ MCIU, // Multiple-Cycle Integer Unit
+ FPU1, // Floating Point Unit
+ FPU2,
+ FPU3,
+ LSU1, // Load/Store Unit
+ LSU2,
+ BPU, // Branch Prediction Unit
+ NumStages
+} Stage;
+
+static struct {
+ // the instruction currently in this pipeline stage
+ PCode *instr;
+
+ // how many cycles are left for this instruction to finish
+ int remaining;
+} pipeline[NumStages];
+
+enum {
+ MaxEntries = 16
+};
+
+static struct {
+ // how many entries remain unused in the queue
+ unsigned int free;
+
+ // how many entries are currently used in the queue
+ unsigned int used;
+
+ // the index of the next instruction that will be retired
+ unsigned int nextToRetire;
+
+ // the index of the next free slot that will be used when an instruction is dispatched
+ unsigned int nextFreeSlot;
+
+ // circular array of entries in the completion queue
+ struct {
+ PCode *instr;
+ int completed;
+ } entries[MaxEntries];
+} completionbuffers;
+
+static PCode *sciu_completed_instruction;
+static PCode *sciu2_completed_instruction;
+
+static struct {
+ // the initial stage for this instruction
+ Stage stage;
+
+ // the total amount of cycles required by this instruction
+ char latency;
+
+ // how long it takes to finish each stage
+ char cycles[3];
+
+ // does this instruction serialise?
+ char serializes;
+} instruction_timing[OPCODE_MAX] = {
+ BPU, 0, 0, 0, 0, 1, // PC_B
+ BPU, 0, 0, 0, 0, 1, // PC_BL
+ BPU, 0, 0, 0, 0, 1, // PC_BC
+ BPU, 0, 0, 0, 0, 1, // PC_BCLR
+ BPU, 0, 0, 0, 0, 1, // PC_BCCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BT
+ BPU, 0, 0, 0, 0, 1, // PC_BTLR
+ BPU, 0, 0, 0, 0, 1, // PC_BTCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BF
+ BPU, 0, 0, 0, 0, 1, // PC_BFLR
+ BPU, 0, 0, 0, 0, 1, // PC_BFCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZ
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZT
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZF
+ BPU, 0, 0, 0, 0, 1, // PC_BDZ
+ BPU, 0, 0, 0, 0, 1, // PC_BDZT
+ BPU, 0, 0, 0, 0, 1, // PC_BDZF
+ BPU, 0, 0, 0, 0, 1, // PC_BLR
+ BPU, 0, 0, 0, 0, 1, // PC_BCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BCTRL
+ BPU, 0, 0, 0, 0, 1, // PC_BLRL
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHA
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAU
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_LMW
+ LSU1, 3, 1, 1, 0, 0, // PC_STB
+ LSU1, 3, 1, 1, 0, 0, // PC_STBU
+ LSU1, 3, 1, 1, 0, 0, // PC_STBX
+ LSU1, 3, 1, 1, 0, 0, // PC_STBUX
+ LSU1, 3, 1, 1, 0, 0, // PC_STH
+ LSU1, 3, 1, 1, 0, 0, // PC_STHU
+ LSU1, 3, 1, 1, 0, 0, // PC_STHX
+ LSU1, 3, 1, 1, 0, 0, // PC_STHUX
+ LSU1, 3, 1, 1, 0, 0, // PC_STHBRX
+ LSU1, 3, 1, 1, 0, 0, // PC_STW
+ LSU1, 3, 1, 1, 0, 0, // PC_STWU
+ LSU1, 3, 1, 1, 0, 0, // PC_STWX
+ LSU1, 3, 1, 1, 0, 0, // PC_STWUX
+ LSU1, 3, 1, 1, 0, 0, // PC_STWBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_STMW
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBF
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBST
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBT
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBTST
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBZ
+ SCIU, 1, 1, 0, 0, 0, // PC_ADD
+ SCIU, 1, 1, 0, 0, 0, // PC_ADDC
+ SCIU, 1, 1, 0, 0, 0, // PC_ADDE
+ SCIU, 1, 1, 0, 0, 0, // PC_ADDI
+ SCIU, 1, 1, 0, 0, 0, // PC_ADDIC
+ SCIU, 1, 1, 0, 0, 0, // PC_ADDICR
+ SCIU, 1, 1, 0, 0, 0, // PC_ADDIS
+ SCIU, 1, 1, 0, 0, 0, // PC_ADDME
+ SCIU, 1, 1, 0, 0, 0, // PC_ADDZE
+ MCIU, 20, 20, 0, 0, 0, // PC_DIVW
+ MCIU, 20, 20, 0, 0, 0, // PC_DIVWU
+ MCIU, 4, 4, 0, 0, 0, // PC_MULHW
+ MCIU, 4, 4, 0, 0, 0, // PC_MULHWU
+ MCIU, 3, 3, 0, 0, 0, // PC_MULLI
+ MCIU, 4, 4, 0, 0, 0, // PC_MULLW
+ SCIU, 1, 1, 0, 0, 0, // PC_NEG
+ SCIU, 1, 1, 0, 0, 0, // PC_SUBF
+ SCIU, 1, 1, 0, 0, 0, // PC_SUBFC
+ SCIU, 1, 1, 0, 0, 0, // PC_SUBFE
+ SCIU, 1, 1, 0, 0, 0, // PC_SUBFIC
+ SCIU, 1, 1, 0, 0, 0, // PC_SUBFME
+ SCIU, 1, 1, 0, 0, 0, // PC_SUBFZE
+ SCIU, 3, 1, 0, 0, 0, // PC_CMPI
+ SCIU, 3, 1, 0, 0, 0, // PC_CMP
+ SCIU, 3, 1, 0, 0, 0, // PC_CMPLI
+ SCIU, 3, 1, 0, 0, 0, // PC_CMPL
+ SCIU, 1, 1, 0, 0, 0, // PC_ANDI
+ SCIU, 1, 1, 0, 0, 0, // PC_ANDIS
+ SCIU, 1, 1, 0, 0, 0, // PC_ORI
+ SCIU, 1, 1, 0, 0, 0, // PC_ORIS
+ SCIU, 1, 1, 0, 0, 0, // PC_XORI
+ SCIU, 1, 1, 0, 0, 0, // PC_XORIS
+ SCIU, 1, 1, 0, 0, 0, // PC_AND
+ SCIU, 1, 1, 0, 0, 0, // PC_OR
+ SCIU, 1, 1, 0, 0, 0, // PC_XOR
+ SCIU, 1, 1, 0, 0, 0, // PC_NAND
+ SCIU, 1, 1, 0, 0, 0, // PC_NOR
+ SCIU, 1, 1, 0, 0, 0, // PC_EQV
+ SCIU, 1, 1, 0, 0, 0, // PC_ANDC
+ SCIU, 1, 1, 0, 0, 0, // PC_ORC
+ SCIU, 1, 1, 0, 0, 0, // PC_EXTSB
+ SCIU, 1, 1, 0, 0, 0, // PC_EXTSH
+ SCIU, 1, 1, 0, 0, 0, // PC_CNTLZW
+ SCIU, 1, 1, 0, 0, 0, // PC_RLWINM
+ SCIU, 1, 1, 0, 0, 0, // PC_RLWNM
+ SCIU, 1, 1, 0, 0, 0, // PC_RLWIMI
+ SCIU, 1, 1, 0, 0, 0, // PC_SLW
+ SCIU, 1, 1, 0, 0, 0, // PC_SRW
+ SCIU, 1, 1, 0, 0, 0, // PC_SRAWI
+ SCIU, 1, 1, 0, 0, 0, // PC_SRAW
+ BPU, 1, 1, 0, 0, 0, // PC_CRAND
+ BPU, 1, 1, 0, 0, 0, // PC_CRANDC
+ BPU, 1, 1, 0, 0, 0, // PC_CREQV
+ BPU, 1, 1, 0, 0, 0, // PC_CRNAND
+ BPU, 1, 1, 0, 0, 0, // PC_CRNOR
+ BPU, 1, 1, 0, 0, 0, // PC_CROR
+ BPU, 1, 1, 0, 0, 0, // PC_CRORC
+ BPU, 1, 1, 0, 0, 0, // PC_CRXOR
+ BPU, 1, 1, 0, 0, 0, // PC_MCRF
+ MCIU, 1, 1, 0, 0, 0, // PC_MTXER
+ MCIU, 1, 1, 0, 0, 0, // PC_MTCTR
+ MCIU, 1, 1, 0, 0, 0, // PC_MTLR
+ MCIU, 1, 1, 0, 0, 0, // PC_MTCRF
+ MCIU, 1, 1, 0, 0, 0, // PC_MTMSR
+ MCIU, 1, 1, 0, 0, 0, // PC_MTSPR
+ MCIU, 1, 1, 0, 0, 0, // PC_MFMSR
+ MCIU, 1, 1, 0, 0, 0, // PC_MFSPR
+ MCIU, 3, 3, 0, 0, 0, // PC_MFXER
+ MCIU, 3, 3, 0, 0, 0, // PC_MFCTR
+ MCIU, 3, 3, 0, 0, 0, // PC_MFLR
+ MCIU, 3, 3, 0, 0, 0, // PC_MFCR
+ FPU1, 3, 1, 1, 1, 0, // PC_MFFS
+ FPU1, 3, 1, 1, 1, 0, // PC_MTFSF
+ LSU1, 1, 0, 0, 0, 1, // PC_EIEIO
+ LSU1, 1, 0, 0, 0, 1, // PC_ISYNC
+ LSU1, 1, 0, 0, 0, 1, // PC_SYNC
+ LSU1, 1, 1, 0, 0, 1, // PC_RFI
+ SCIU, 1, 1, 0, 0, 0, // PC_LI
+ SCIU, 1, 1, 0, 0, 0, // PC_LIS
+ SCIU, 1, 1, 0, 0, 0, // PC_MR
+ SCIU, 1, 1, 0, 0, 0, // PC_NOP
+ SCIU, 1, 1, 0, 0, 0, // PC_NOT
+ LSU1, 3, 1, 1, 0, 0, // PC_LFS
+ LSU1, 3, 1, 1, 0, 0, // PC_LFSU
+ LSU1, 3, 1, 1, 0, 0, // PC_LFSX
+ LSU1, 3, 1, 1, 0, 0, // PC_LFSUX
+ LSU1, 3, 1, 1, 0, 0, // PC_LFD
+ LSU1, 3, 1, 1, 0, 0, // PC_LFDU
+ LSU1, 3, 1, 1, 0, 0, // PC_LFDX
+ LSU1, 3, 1, 1, 0, 0, // PC_LFDUX
+ LSU1, 3, 1, 1, 0, 0, // PC_STFS
+ LSU1, 3, 1, 1, 0, 0, // PC_STFSU
+ LSU1, 3, 1, 1, 0, 0, // PC_STFSX
+ LSU1, 3, 1, 1, 0, 0, // PC_STFSUX
+ LSU1, 3, 1, 1, 0, 0, // PC_STFD
+ LSU1, 3, 1, 1, 0, 0, // PC_STFDU
+ LSU1, 3, 1, 1, 0, 0, // PC_STFDX
+ LSU1, 3, 1, 1, 0, 0, // PC_STFDUX
+ FPU1, 3, 1, 1, 1, 0, // PC_FMR
+ FPU1, 3, 1, 1, 1, 0, // PC_FABS
+ FPU1, 3, 1, 1, 1, 0, // PC_FNEG
+ FPU1, 3, 1, 1, 1, 0, // PC_FNABS
+ FPU1, 3, 1, 1, 1, 0, // PC_FADD
+ FPU1, 3, 1, 1, 1, 0, // PC_FADDS
+ FPU1, 3, 1, 1, 1, 0, // PC_FSUB
+ FPU1, 3, 1, 1, 1, 0, // PC_FSUBS
+ FPU1, 3, 1, 1, 1, 0, // PC_FMUL
+ FPU1, 3, 1, 1, 1, 0, // PC_FMULS
+ FPU1, 32, 32, 0, 0, 0, // PC_FDIV
+ FPU1, 18, 18, 0, 0, 0, // PC_FDIVS
+ FPU1, 3, 1, 1, 1, 0, // PC_FMADD
+ FPU1, 3, 1, 1, 1, 0, // PC_FMADDS
+ FPU1, 3, 1, 1, 1, 0, // PC_FMSUB
+ FPU1, 3, 1, 1, 1, 0, // PC_FMSUBS
+ FPU1, 3, 1, 1, 1, 0, // PC_FNMADD
+ FPU1, 3, 1, 1, 1, 0, // PC_FNMADDS
+ FPU1, 3, 1, 1, 1, 0, // PC_FNMSUB
+ FPU1, 3, 1, 1, 1, 0, // PC_FNMSUBS
+ FPU1, 18, 18, 0, 0, 0, // PC_FRES
+ FPU1, 3, 1, 1, 1, 0, // PC_FRSQRTE
+ FPU1, 3, 1, 1, 1, 0, // PC_FSEL
+ FPU1, 3, 1, 1, 1, 0, // PC_FRSP
+ FPU1, 3, 1, 1, 1, 0, // PC_FCTIW
+ FPU1, 3, 1, 1, 1, 0, // PC_FCTIWZ
+ FPU1, 5, 1, 1, 1, 0, // PC_FCMPU
+ FPU1, 5, 1, 1, 1, 0, // PC_FCMPO
+ LSU1, 1, 1, 0, 0, 0, // PC_LWARX
+ LSU1, 1, 1, 0, 0, 0, // PC_LSWI
+ LSU1, 1, 1, 0, 0, 0, // PC_LSWX
+ LSU1, 1, 1, 0, 0, 0, // PC_STFIWX
+ LSU1, 1, 1, 0, 0, 0, // PC_STSWI
+ LSU1, 1, 1, 0, 0, 0, // PC_STSWX
+ LSU1, 1, 1, 0, 0, 0, // PC_STWCX
+ MCIU, 1, 1, 0, 0, 1, // PC_ECIWX
+ MCIU, 1, 1, 0, 0, 1, // PC_ECOWX
+ MCIU, 1, 1, 0, 0, 0, // PC_DCBI
+ MCIU, 1, 1, 0, 0, 0, // PC_ICBI
+ MCIU, 1, 1, 0, 0, 0, // PC_MCRFS
+ MCIU, 1, 1, 0, 0, 0, // PC_MCRXR
+ MCIU, 1, 1, 0, 0, 0, // PC_MFTB
+ MCIU, 1, 1, 0, 0, 0, // PC_MFSR
+ MCIU, 1, 1, 0, 0, 0, // PC_MTSR
+ MCIU, 1, 1, 0, 0, 0, // PC_MFSRIN
+ MCIU, 1, 1, 0, 0, 0, // PC_MTSRIN
+ MCIU, 1, 1, 0, 0, 0, // PC_MTFSB0
+ MCIU, 1, 1, 0, 0, 0, // PC_MTFSB1
+ MCIU, 1, 1, 0, 0, 0, // PC_MTFSFI
+ MCIU, 1, 1, 0, 0, 1, // PC_SC
+ FPU1, 1, 1, 0, 0, 0, // PC_FSQRT
+ FPU1, 1, 1, 0, 0, 0, // PC_FSQRTS
+ MCIU, 1, 1, 0, 0, 0, // PC_TLBIA
+ MCIU, 1, 1, 0, 0, 0, // PC_TLBIE
+ MCIU, 1, 1, 0, 0, 0, // PC_TLBLD
+ MCIU, 1, 1, 0, 0, 0, // PC_TLBLI
+ MCIU, 1, 1, 0, 0, 0, // PC_TLBSYNC
+ MCIU, 1, 1, 0, 0, 1, // PC_TW
+ MCIU, 1, 1, 0, 0, 1, // PC_TRAP
+ MCIU, 1, 1, 0, 0, 1, // PC_TWI
+ MCIU, 1, 1, 0, 0, 1, // PC_OPWORD
+ MCIU, 1, 1, 0, 0, 0, // PC_MFROM
+ MCIU, 1, 1, 0, 0, 1, // PC_DSA
+ MCIU, 1, 1, 0, 0, 1, // PC_ESA
+ MCIU, 0, 0, 0, 0, 0, // PC_DCCCI
+ MCIU, 0, 0, 0, 0, 0, // PC_DCREAD
+ MCIU, 0, 0, 0, 0, 0, // PC_ICBT
+ MCIU, 0, 0, 0, 0, 0, // PC_ICCCI
+ MCIU, 0, 0, 0, 0, 0, // PC_ICREAD
+ MCIU, 0, 0, 0, 0, 0, // PC_RFCI
+ MCIU, 0, 0, 0, 0, 0, // PC_TLBRE
+ MCIU, 0, 0, 0, 0, 0, // PC_TLBSX
+ MCIU, 0, 0, 0, 0, 0, // PC_TLBWE
+ MCIU, 0, 0, 0, 0, 0, // PC_WRTEE
+ MCIU, 0, 0, 0, 0, 0, // PC_WRTEEI
+ MCIU, 0, 0, 0, 0, 0, // PC_MFDCR
+ MCIU, 0, 0, 0, 0, 0, // PC_MTDCR
+ MCIU, 0, 0, 0, 0, 0, // PC_DCBA
+ SCIU, 0, 0, 0, 0, 0, // PC_DSS
+ SCIU, 0, 0, 0, 0, 0, // PC_DSSALL
+ SCIU, 0, 0, 0, 0, 0, // PC_DST
+ SCIU, 0, 0, 0, 0, 0, // PC_DSTT
+ SCIU, 0, 0, 0, 0, 0, // PC_DSTST
+ SCIU, 0, 0, 0, 0, 0, // PC_DSTSTT
+ SCIU, 0, 0, 0, 0, 0, // PC_LVEBX
+ SCIU, 0, 0, 0, 0, 0, // PC_LVEHX
+ SCIU, 0, 0, 0, 0, 0, // PC_LVEWX
+ SCIU, 0, 0, 0, 0, 0, // PC_LVSL
+ SCIU, 0, 0, 0, 0, 0, // PC_LVSR
+ SCIU, 0, 0, 0, 0, 0, // PC_LVX
+ SCIU, 0, 0, 0, 0, 0, // PC_LVXL
+ SCIU, 0, 0, 0, 0, 0, // PC_STVEBX
+ SCIU, 0, 0, 0, 0, 0, // PC_STVEHX
+ SCIU, 0, 0, 0, 0, 0, // PC_STVEWX
+ SCIU, 0, 0, 0, 0, 0, // PC_STVX
+ SCIU, 0, 0, 0, 0, 0, // PC_STVXL
+ SCIU, 0, 0, 0, 0, 0, // PC_MFVSCR
+ SCIU, 0, 0, 0, 0, 0, // PC_MTVSCR
+ SCIU, 0, 0, 0, 0, 0, // PC_VADDCUW
+ SCIU, 0, 0, 0, 0, 0, // PC_VADDFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VADDSBS
+ SCIU, 0, 0, 0, 0, 0, // PC_VADDSHS
+ SCIU, 0, 0, 0, 0, 0, // PC_VADDSWS
+ SCIU, 0, 0, 0, 0, 0, // PC_VADDUBM
+ SCIU, 0, 0, 0, 0, 0, // PC_VADDUBS
+ SCIU, 0, 0, 0, 0, 0, // PC_VADDUHM
+ SCIU, 0, 0, 0, 0, 0, // PC_VADDUHS
+ SCIU, 0, 0, 0, 0, 0, // PC_VADDUWM
+ SCIU, 0, 0, 0, 0, 0, // PC_VADDUWS
+ SCIU, 0, 0, 0, 0, 0, // PC_VAND
+ SCIU, 0, 0, 0, 0, 0, // PC_VANDC
+ SCIU, 0, 0, 0, 0, 0, // PC_VAVGSB
+ SCIU, 0, 0, 0, 0, 0, // PC_VAVGSH
+ SCIU, 0, 0, 0, 0, 0, // PC_VAVGSW
+ SCIU, 0, 0, 0, 0, 0, // PC_VAVGUB
+ SCIU, 0, 0, 0, 0, 0, // PC_VAVGUH
+ SCIU, 0, 0, 0, 0, 0, // PC_VAVGUW
+ SCIU, 0, 0, 0, 0, 0, // PC_VCFSX
+ SCIU, 0, 0, 0, 0, 0, // PC_VCFUX
+ SCIU, 0, 0, 0, 0, 0, // PC_VCMPBFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VCMPEQFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VCMPEQUB
+ SCIU, 0, 0, 0, 0, 0, // PC_VCMPEQUH
+ SCIU, 0, 0, 0, 0, 0, // PC_VCMPEQUW
+ SCIU, 0, 0, 0, 0, 0, // PC_VCMPGEFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VCMPGTFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VCMPGTSB
+ SCIU, 0, 0, 0, 0, 0, // PC_VCMPGTSH
+ SCIU, 0, 0, 0, 0, 0, // PC_VCMPGTSW
+ SCIU, 0, 0, 0, 0, 0, // PC_VCMPGTUB
+ SCIU, 0, 0, 0, 0, 0, // PC_VCMPGTUH
+ SCIU, 0, 0, 0, 0, 0, // PC_VCMPGTUW
+ SCIU, 0, 0, 0, 0, 0, // PC_VCTSXS
+ SCIU, 0, 0, 0, 0, 0, // PC_VCTUXS
+ SCIU, 0, 0, 0, 0, 0, // PC_VEXPTEFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VLOGEFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VMAXFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VMAXSB
+ SCIU, 0, 0, 0, 0, 0, // PC_VMAXSH
+ SCIU, 0, 0, 0, 0, 0, // PC_VMAXSW
+ SCIU, 0, 0, 0, 0, 0, // PC_VMAXUB
+ SCIU, 0, 0, 0, 0, 0, // PC_VMAXUH
+ SCIU, 0, 0, 0, 0, 0, // PC_VMAXUW
+ SCIU, 0, 0, 0, 0, 0, // PC_VMINFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VMINSB
+ SCIU, 0, 0, 0, 0, 0, // PC_VMINSH
+ SCIU, 0, 0, 0, 0, 0, // PC_VMINSW
+ SCIU, 0, 0, 0, 0, 0, // PC_VMINUB
+ SCIU, 0, 0, 0, 0, 0, // PC_VMINUH
+ SCIU, 0, 0, 0, 0, 0, // PC_VMINUW
+ SCIU, 0, 0, 0, 0, 0, // PC_VMRGHB
+ SCIU, 0, 0, 0, 0, 0, // PC_VMRGHH
+ SCIU, 0, 0, 0, 0, 0, // PC_VMRGHW
+ SCIU, 0, 0, 0, 0, 0, // PC_VMRGLB
+ SCIU, 0, 0, 0, 0, 0, // PC_VMRGLH
+ SCIU, 0, 0, 0, 0, 0, // PC_VMRGLW
+ SCIU, 0, 0, 0, 0, 0, // PC_VMULESB
+ SCIU, 0, 0, 0, 0, 0, // PC_VMULESH
+ SCIU, 0, 0, 0, 0, 0, // PC_VMULEUB
+ SCIU, 0, 0, 0, 0, 0, // PC_VMULEUH
+ SCIU, 0, 0, 0, 0, 0, // PC_VMULOSB
+ SCIU, 0, 0, 0, 0, 0, // PC_VMULOSH
+ SCIU, 0, 0, 0, 0, 0, // PC_VMULOUB
+ SCIU, 0, 0, 0, 0, 0, // PC_VMULOUH
+ SCIU, 0, 0, 0, 0, 0, // PC_VNOR
+ SCIU, 0, 0, 0, 0, 0, // PC_VOR
+ SCIU, 0, 0, 0, 0, 0, // PC_VPKPX
+ SCIU, 0, 0, 0, 0, 0, // PC_VPKSHSS
+ SCIU, 0, 0, 0, 0, 0, // PC_VPKSHUS
+ SCIU, 0, 0, 0, 0, 0, // PC_VPKSWSS
+ SCIU, 0, 0, 0, 0, 0, // PC_VPKSWUS
+ SCIU, 0, 0, 0, 0, 0, // PC_VPKUHUM
+ SCIU, 0, 0, 0, 0, 0, // PC_VPKUHUS
+ SCIU, 0, 0, 0, 0, 0, // PC_VPKUWUM
+ SCIU, 0, 0, 0, 0, 0, // PC_VPKUWUS
+ SCIU, 0, 0, 0, 0, 0, // PC_VREFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VRFIM
+ SCIU, 0, 0, 0, 0, 0, // PC_VRFIN
+ SCIU, 0, 0, 0, 0, 0, // PC_VRFIP
+ SCIU, 0, 0, 0, 0, 0, // PC_VRFIZ
+ SCIU, 0, 0, 0, 0, 0, // PC_VRLB
+ SCIU, 0, 0, 0, 0, 0, // PC_VRLH
+ SCIU, 0, 0, 0, 0, 0, // PC_VRLW
+ SCIU, 0, 0, 0, 0, 0, // PC_VRSQRTEFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VSL
+ SCIU, 0, 0, 0, 0, 0, // PC_VSLB
+ SCIU, 0, 0, 0, 0, 0, // PC_VSLH
+ SCIU, 0, 0, 0, 0, 0, // PC_VSLO
+ SCIU, 0, 0, 0, 0, 0, // PC_VSLW
+ SCIU, 0, 0, 0, 0, 0, // PC_VSPLTB
+ SCIU, 0, 0, 0, 0, 0, // PC_VSPLTH
+ SCIU, 0, 0, 0, 0, 0, // PC_VSPLTW
+ SCIU, 0, 0, 0, 0, 0, // PC_VSPLTISB
+ SCIU, 0, 0, 0, 0, 0, // PC_VSPLTISH
+ SCIU, 0, 0, 0, 0, 0, // PC_VSPLTISW
+ SCIU, 0, 0, 0, 0, 0, // PC_VSR
+ SCIU, 0, 0, 0, 0, 0, // PC_VSRAB
+ SCIU, 0, 0, 0, 0, 0, // PC_VSRAH
+ SCIU, 0, 0, 0, 0, 0, // PC_VSRAW
+ SCIU, 0, 0, 0, 0, 0, // PC_VSRB
+ SCIU, 0, 0, 0, 0, 0, // PC_VSRH
+ SCIU, 0, 0, 0, 0, 0, // PC_VSRO
+ SCIU, 0, 0, 0, 0, 0, // PC_VSRW
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUBCUW
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUBFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUBSBS
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUBSHS
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUBSWS
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUBUBM
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUBUBS
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUBUHM
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUBUHS
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUBUWM
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUBUWS
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUMSWS
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUM2SWS
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUM4SBS
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUM4SHS
+ SCIU, 0, 0, 0, 0, 0, // PC_VSUM4UBS
+ SCIU, 0, 0, 0, 0, 0, // PC_VUPKHPX
+ SCIU, 0, 0, 0, 0, 0, // PC_VUPKHSB
+ SCIU, 0, 0, 0, 0, 0, // PC_VUPKHSH
+ SCIU, 0, 0, 0, 0, 0, // PC_VUPKLPX
+ SCIU, 0, 0, 0, 0, 0, // PC_VUPKLSB
+ SCIU, 0, 0, 0, 0, 0, // PC_VUPKLSH
+ SCIU, 0, 0, 0, 0, 0, // PC_VXOR
+ SCIU, 0, 0, 0, 0, 0, // PC_VMADDFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VMHADDSHS
+ SCIU, 0, 0, 0, 0, 0, // PC_VMHRADDSHS
+ SCIU, 0, 0, 0, 0, 0, // PC_VMLADDUHM
+ SCIU, 0, 0, 0, 0, 0, // PC_VMSUMMBM
+ SCIU, 0, 0, 0, 0, 0, // PC_VMSUMSHM
+ SCIU, 0, 0, 0, 0, 0, // PC_VMSUMSHS
+ SCIU, 0, 0, 0, 0, 0, // PC_VMSUMUBM
+ SCIU, 0, 0, 0, 0, 0, // PC_VMSUMUHM
+ SCIU, 0, 0, 0, 0, 0, // PC_VMSUMUHS
+ SCIU, 0, 0, 0, 0, 0, // PC_VNMSUBFP
+ SCIU, 0, 0, 0, 0, 0, // PC_VPERM
+ SCIU, 0, 0, 0, 0, 0, // PC_VSEL
+ SCIU, 0, 0, 0, 0, 0, // PC_VSLDOI
+ SCIU, 0, 0, 0, 0, 0, // PC_VMR
+ SCIU, 0, 0, 0, 0, 0, // PC_VMRP
+ SCIU, 0, 0, 0, 0, 0, // PC_SLE
+ SCIU, 0, 0, 0, 0, 0, // PC_SLEQ
+ SCIU, 0, 0, 0, 0, 0, // PC_SLIQ
+ SCIU, 0, 0, 0, 0, 0, // PC_SLLIQ
+ SCIU, 0, 0, 0, 0, 0, // PC_SLLQ
+ SCIU, 0, 0, 0, 0, 0, // PC_SLQ
+ SCIU, 0, 0, 0, 0, 0, // PC_SRAIQ
+ SCIU, 0, 0, 0, 0, 0, // PC_SRAQ
+ SCIU, 0, 0, 0, 0, 0, // PC_SRE
+ SCIU, 0, 0, 0, 0, 0, // PC_SREA
+ SCIU, 0, 0, 0, 0, 0, // PC_SREQ
+ SCIU, 0, 0, 0, 0, 0, // PC_SRIQ
+ SCIU, 0, 0, 0, 0, 0, // PC_SRLIQ
+ SCIU, 0, 0, 0, 0, 0, // PC_SRLQ
+ SCIU, 0, 0, 0, 0, 0, // PC_SRQ
+ SCIU, 0, 0, 0, 0, 0, // PC_MASKG
+ SCIU, 0, 0, 0, 0, 0, // PC_MASKIR
+ SCIU, 0, 0, 0, 0, 0, // PC_LSCBX
+ SCIU, 0, 0, 0, 0, 0, // PC_DIV
+ SCIU, 0, 0, 0, 0, 0, // PC_DIVS
+ SCIU, 0, 0, 0, 0, 0, // PC_DOZ
+ SCIU, 0, 0, 0, 0, 0, // PC_MUL
+ SCIU, 0, 0, 0, 0, 0, // PC_NABS
+ SCIU, 0, 0, 0, 0, 0, // PC_ABS
+ SCIU, 0, 0, 0, 0, 0, // PC_CLCS
+ SCIU, 0, 0, 0, 0, 0, // PC_DOZI
+ SCIU, 0, 0, 0, 0, 0, // PC_RLMI
+ SCIU, 0, 0, 0, 0, 0, // PC_RRIB
+};
+
+static void advance(int firstStage, int oldStage, int newStage) {
+ PCode *instr = pipeline[oldStage].instr;
+ int cycles = instruction_timing[instr->op].cycles[newStage - firstStage];
+ pipeline[newStage].instr = instr;
+ pipeline[newStage].remaining = cycles;
+ pipeline[oldStage].instr = NULL;
+}
+
+static void assign_completion_buffer(PCode *instr) {
+ completionbuffers.used++;
+ completionbuffers.free--;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].instr = instr;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].completed = 0;
+ completionbuffers.nextFreeSlot = (completionbuffers.nextFreeSlot + 1) % MaxEntries;
+}
+
+static void complete_instruction(int stage) {
+ PCode *instr = pipeline[stage].instr;
+ int buf = 0;
+ while (buf < MaxEntries && completionbuffers.entries[buf].instr != instr)
+ buf++;
+
+ completionbuffers.entries[buf].completed = 1;
+ pipeline[stage].instr = NULL;
+
+ if (stage == SCIU)
+ sciu_completed_instruction = instr;
+ else if (stage == SCIU2)
+ sciu2_completed_instruction = instr;
+}
+
+static void retire_instruction(void) {
+ completionbuffers.entries[completionbuffers.nextToRetire].instr = NULL;
+ completionbuffers.used--;
+ completionbuffers.free++;
+ completionbuffers.nextToRetire = (completionbuffers.nextToRetire + 1) % MaxEntries;
+}
+
+static int latency(PCode *instr) {
+ int cycles = instruction_timing[instr->op].latency;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ cycles += 2;
+ if (instr->op == PC_LMW || instr->op == PC_STMW)
+ cycles += instr->argCount - 2;
+ return cycles;
+}
+
+static void initialize(void) {
+ int stage;
+ int i;
+
+ for (stage = 0; stage < NumStages; stage++)
+ pipeline[stage].instr = NULL;
+
+ completionbuffers.free = MaxEntries;
+ completionbuffers.used = 0;
+ completionbuffers.nextToRetire = 0;
+ completionbuffers.nextFreeSlot = 0;
+ for (i = 0; i < MaxEntries; i++)
+ completionbuffers.entries[i].instr = NULL;
+
+ sciu_completed_instruction = NULL;
+ sciu2_completed_instruction = NULL;
+}
+
+static int can_issue(PCode *instr) {
+ PCode *check;
+ int stage = instruction_timing[instr->op].stage;
+
+ if (completionbuffers.free == 0)
+ return 0;
+
+ if (stage == SCIU) {
+ int isClear1 = !pipeline[SCIU].instr;
+ int isClear2 = !pipeline[SCIU2].instr;
+ if (!isClear1 && !isClear2)
+ return 0;
+ if (isClear1 && isClear2)
+ return 1;
+
+ if (isClear1)
+ check = pipeline[SCIU2].instr;
+ else
+ check = pipeline[SCIU].instr;
+
+ if (is_dependent(instr, check, RegClass_GPR))
+ return 0;
+ if (is_dependent(instr, sciu_completed_instruction, RegClass_GPR))
+ return 0;
+ if (is_dependent(instr, sciu2_completed_instruction, RegClass_GPR))
+ return 0;
+ } else {
+ if (pipeline[stage].instr)
+ return 0;
+ }
+
+ return 1;
+}
+
+static void issue(PCode *instr) {
+ int stage = instruction_timing[instr->op].stage;
+ int cycles = instruction_timing[instr->op].cycles[0];
+ if (stage == SCIU && pipeline[SCIU].instr)
+ stage = SCIU2;
+ assign_completion_buffer(instr);
+ pipeline[stage].instr = instr;
+ pipeline[stage].remaining = cycles;
+}
+
+static void advance_clock(void) {
+ int stage;
+ int i;
+
+ sciu_completed_instruction = NULL;
+ sciu2_completed_instruction = NULL;
+
+ for (stage = 0; stage < NumStages; stage++) {
+ if (pipeline[stage].instr && pipeline[stage].remaining)
+ --pipeline[stage].remaining;
+ }
+
+ for (i = 0; i < 5; i++) {
+ if (completionbuffers.used == 0)
+ break;
+ if (completionbuffers.entries[completionbuffers.nextToRetire].completed == 0)
+ break;
+ retire_instruction();
+ }
+
+ if (pipeline[SCIU].instr && pipeline[SCIU].remaining == 0)
+ complete_instruction(SCIU);
+ if (pipeline[SCIU2].instr && pipeline[SCIU2].remaining == 0)
+ complete_instruction(SCIU2);
+ if (pipeline[MCIU].instr && pipeline[MCIU].remaining == 0)
+ complete_instruction(MCIU);
+ if (pipeline[LSU2].instr && pipeline[LSU2].remaining == 0)
+ complete_instruction(LSU2);
+ if (pipeline[FPU3].instr && pipeline[FPU3].remaining == 0)
+ complete_instruction(FPU3);
+ if (pipeline[BPU].instr && pipeline[BPU].remaining == 0)
+ complete_instruction(BPU);
+
+ if (
+ pipeline[FPU1].instr &&
+ pipeline[FPU1].remaining == 0 &&
+ (pipeline[FPU1].instr->op == PC_FDIV || pipeline[FPU1].instr->op == PC_FDIVS)
+ )
+ complete_instruction(FPU1);
+
+ if (pipeline[FPU2].instr && pipeline[FPU2].remaining == 0 && !pipeline[FPU3].instr)
+ advance(FPU1, FPU2, FPU3);
+ if (pipeline[FPU1].instr && pipeline[FPU1].remaining == 0 && !pipeline[FPU2].instr)
+ advance(FPU1, FPU1, FPU2);
+ if (pipeline[LSU1].instr && pipeline[LSU1].remaining == 0 && !pipeline[LSU2].instr)
+ advance(LSU1, LSU1, LSU2);
+}
+
+static int serializes(PCode *instr) {
+ return instruction_timing[instr->op].serializes;
+}
+
+MachineInfo machine604 = {
+ 4,
+ 1,
+ 0,
+ &latency,
+ &initialize,
+ &can_issue,
+ &issue,
+ &advance_clock,
+ &serializes,
+ &default_uses_vpermute_unit
+};
diff --git a/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation7400.c b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation7400.c
new file mode 100644
index 0000000..56b375c
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation7400.c
@@ -0,0 +1,744 @@
+#include "compiler/Scheduler.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+
+// https://www.nxp.com/docs/en/reference-manual/MPC7410UM.pdf
+
+typedef enum Stage {
+ BPU, // Branch Prediction Unit
+ IU1, // Integer Unit 1
+ IU2, // Integer Unit 2
+
+ LSU1, // Load/Store Unit
+ LSU2,
+
+ FPU1, // Floating Point Unit
+ FPU2,
+ FPU3,
+
+ SRU, // System Register Unit
+ VSIU, // Vector Simple Integer Unit
+ VPU, // AltiVec Permute Unit
+
+ VCIU1, // Vector Complex Integer Unit
+ VCIU2,
+ VCIU3,
+
+ VFPU1, // Vector Floating-Point Unit
+ VFPU2,
+ VFPU3,
+ VFPU4,
+
+ NumStages
+} Stage;
+
+static struct {
+ // the instruction currently in this pipeline stage
+ PCode *instr;
+
+ // how many cycles are left for this instruction to finish
+ int remaining;
+} pipeline[NumStages];
+
+static PCode *iu1_completed_instruction;
+static PCode *iu2_completed_instruction;
+
+enum {
+ MaxEntries = 8
+};
+
+static struct {
+ // how many entries remain unused in the queue
+ unsigned int free;
+
+ // how many entries are currently used in the queue
+ unsigned int used;
+
+ // the index of the next instruction that will be retired
+ unsigned int nextToRetire;
+
+ // the index of the next free slot that will be used when an instruction is dispatched
+ unsigned int nextFreeSlot;
+
+ // circular array of entries in the completion queue
+ struct {
+ PCode *instr;
+ int completed;
+ } entries[MaxEntries];
+} completionbuffers;
+
+static struct {
+ // the initial stage for this instruction
+ Stage stage;
+
+ // the total amount of cycles required by this instruction
+ char latency;
+
+ // how long it takes to finish each stage
+ char cycles[4];
+
+ // does this instruction serialise?
+ char serializes;
+
+ char unused;
+} instruction_timing[OPCODE_MAX] = {
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_B
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BL
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BC
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BCLR
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BCCTR
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BT
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BTLR
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BTCTR
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BF
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BFLR
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BFCTR
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BDNZ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BDNZT
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BDNZF
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BDZ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BDZT
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BDZF
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BLR
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BCTR
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BCTRL
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BLRL
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LBZ
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LBZU
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LBZX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LBZUX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LHZ
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LHZU
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LHZX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LHZUX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LHA
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LHAU
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LHAX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LHAUX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LHBRX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LWZ
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LWZU
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LWZX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LWZUX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LWBRX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LMW
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STB
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STBU
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STBX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STBUX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STH
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STHU
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STHX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STHUX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STHBRX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STW
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STWU
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STWX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STWUX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STWBRX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STMW
+ LSU1, 3, 1, 2, 0, 0, 0, 0, // PC_DCBF
+ LSU1, 3, 1, 2, 0, 0, 0, 0, // PC_DCBST
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_DCBT
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_DCBTST
+ LSU1, 3, 1, 2, 0, 0, 0, 0, // PC_DCBZ
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ADD
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ADDC
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ADDE
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ADDI
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ADDIC
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ADDICR
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ADDIS
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ADDME
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ADDZE
+ IU1, 19, 19, 0, 0, 0, 0, 0, // PC_DIVW
+ IU1, 19, 19, 0, 0, 0, 0, 0, // PC_DIVWU
+ IU1, 5, 5, 0, 0, 0, 0, 0, // PC_MULHW
+ IU1, 6, 5, 0, 0, 0, 0, 0, // PC_MULHWU
+ IU1, 3, 3, 0, 0, 0, 0, 0, // PC_MULLI
+ IU1, 5, 5, 0, 0, 0, 0, 0, // PC_MULLW
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_NEG
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_SUBF
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_SUBFC
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_SUBFE
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_SUBFIC
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_SUBFME
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_SUBFZE
+ IU2, 3, 1, 0, 0, 0, 0, 0, // PC_CMPI
+ IU2, 3, 1, 0, 0, 0, 0, 0, // PC_CMP
+ IU2, 3, 1, 0, 0, 0, 0, 0, // PC_CMPLI
+ IU2, 3, 1, 0, 0, 0, 0, 0, // PC_CMPL
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ANDI
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ANDIS
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ORI
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ORIS
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_XORI
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_XORIS
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_AND
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_OR
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_XOR
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_NAND
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_NOR
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_EQV
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ANDC
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ORC
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_EXTSB
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_EXTSH
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_CNTLZW
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_RLWINM
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_RLWNM
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_RLWIMI
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_SLW
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_SRW
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_SRAWI
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_SRAW
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_CRAND
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_CRANDC
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_CREQV
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_CRNAND
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_CRNOR
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_CROR
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_CRORC
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_CRXOR
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_MCRF
+ SRU, 2, 2, 0, 0, 0, 1, 0, // PC_MTXER
+ SRU, 2, 2, 0, 0, 0, 1, 0, // PC_MTCTR
+ SRU, 2, 2, 0, 0, 0, 1, 0, // PC_MTLR
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_MTCRF
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_MTMSR
+ SRU, 2, 2, 0, 0, 0, 1, 0, // PC_MTSPR
+ SRU, 1, 1, 0, 0, 0, 0, 0, // PC_MFMSR
+ SRU, 3, 3, 0, 0, 0, 1, 0, // PC_MFSPR
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_MFXER
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_MFCTR
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_MFLR
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_MFCR
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_MFFS
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_MTFSF
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_EIEIO
+ SRU, 2, 2, 0, 0, 0, 1, 0, // PC_ISYNC
+ SRU, 3, 3, 0, 0, 0, 1, 0, // PC_SYNC
+ SRU, 2, 2, 0, 0, 0, 1, 0, // PC_RFI
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_LI
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_LIS
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_MR
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_NOP
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_NOT
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LFS
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LFSU
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LFSX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LFSUX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LFD
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LFDU
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LFDX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LFDUX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STFS
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STFSU
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STFSX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STFSUX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STFD
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STFDU
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STFDX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STFDUX
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FMR
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FABS
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FNEG
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FNABS
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FADD
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FADDS
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FSUB
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FSUBS
+ FPU1, 4, 2, 1, 1, 0, 0, 0, // PC_FMUL
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FMULS
+ FPU1, 31, 31, 0, 0, 0, 0, 0, // PC_FDIV
+ FPU1, 17, 17, 0, 0, 0, 0, 0, // PC_FDIVS
+ FPU1, 4, 2, 1, 1, 0, 0, 0, // PC_FMADD
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FMADDS
+ FPU1, 4, 2, 1, 1, 0, 0, 0, // PC_FMSUB
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FMSUBS
+ FPU1, 4, 2, 1, 1, 0, 0, 0, // PC_FNMADD
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FNMADDS
+ FPU1, 4, 2, 1, 1, 0, 0, 0, // PC_FNMSUB
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FNMSUBS
+ FPU1, 10, 10, 0, 0, 0, 0, 0, // PC_FRES
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FRSQRTE
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FSEL
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FRSP
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FCTIW
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FCTIWZ
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FCMPU
+ FPU1, 3, 1, 1, 1, 0, 0, 0, // PC_FCMPO
+ LSU1, 2, 1, 1, 0, 0, 1, 0, // PC_LWARX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LSWI
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LSWX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STFIWX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STSWI
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STSWX
+ LSU1, 2, 1, 1, 0, 0, 1, 0, // PC_STWCX
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ECIWX
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ECOWX
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_DCBI
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ICBI
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_MCRFS
+ SRU, 1, 1, 0, 0, 0, 1, 0, // PC_MCRXR
+ SRU, 1, 1, 0, 0, 0, 0, 0, // PC_MFTB
+ SRU, 3, 3, 0, 0, 0, 0, 0, // PC_MFSR
+ SRU, 2, 2, 0, 0, 0, 1, 0, // PC_MTSR
+ SRU, 3, 3, 0, 0, 0, 0, 0, // PC_MFSRIN
+ SRU, 2, 2, 0, 0, 0, 1, 0, // PC_MTSRIN
+ FPU1, 1, 1, 0, 0, 0, 0, 0, // PC_MTFSB0
+ FPU1, 1, 1, 0, 0, 0, 0, 0, // PC_MTFSB1
+ FPU1, 1, 1, 0, 0, 0, 0, 0, // PC_MTFSFI
+ SRU, 2, 2, 0, 0, 0, 1, 0, // PC_SC
+ FPU1, 1, 1, 0, 0, 0, 0, 0, // PC_FSQRT
+ FPU1, 1, 1, 0, 0, 0, 0, 0, // PC_FSQRTS
+ LSU1, 1, 1, 0, 0, 0, 0, 0, // PC_TLBIA
+ LSU1, 1, 1, 0, 0, 0, 0, 0, // PC_TLBIE
+ LSU1, 1, 1, 0, 0, 0, 0, 0, // PC_TLBLD
+ LSU1, 1, 1, 0, 0, 0, 0, 0, // PC_TLBLI
+ LSU1, 1, 1, 0, 0, 0, 1, 0, // PC_TLBSYNC
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_TW
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_TRAP
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_TWI
+ IU2, 1, 1, 0, 0, 0, 1, 0, // PC_OPWORD
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_MFROM
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_DSA
+ IU2, 1, 1, 0, 0, 0, 0, 0, // PC_ESA
+ IU2, 1, 0, 0, 0, 0, 0, 0, // PC_DCCCI
+ IU2, 1, 0, 0, 0, 0, 0, 0, // PC_DCREAD
+ IU2, 1, 0, 0, 0, 0, 0, 0, // PC_ICBT
+ IU2, 1, 0, 0, 0, 0, 0, 0, // PC_ICCCI
+ IU2, 1, 0, 0, 0, 0, 0, 0, // PC_ICREAD
+ IU2, 1, 0, 0, 0, 0, 0, 0, // PC_RFCI
+ IU2, 1, 0, 0, 0, 0, 0, 0, // PC_TLBRE
+ IU2, 1, 0, 0, 0, 0, 0, 0, // PC_TLBSX
+ IU2, 1, 0, 0, 0, 0, 0, 0, // PC_TLBWE
+ IU2, 1, 0, 0, 0, 0, 0, 0, // PC_WRTEE
+ IU2, 1, 0, 0, 0, 0, 0, 0, // PC_WRTEEI
+ IU2, 1, 0, 0, 0, 0, 0, 0, // PC_MFDCR
+ IU2, 1, 0, 0, 0, 0, 0, 0, // PC_MTDCR
+ LSU1, 3, 1, 2, 0, 0, 0, 0, // PC_DCBA
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_DSS
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_DSSALL
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_DST
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_DSTT
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_DSTST
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_DSTSTT
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LVEBX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LVEHX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LVEWX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LVSL
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LVSR
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LVX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_LVXL
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STVEBX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STVEHX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STVEWX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STVX
+ LSU1, 2, 1, 1, 0, 0, 0, 0, // PC_STVXL
+ VSIU, 1, 1, 0, 0, 0, 1, 0, // PC_MFVSCR
+ VSIU, 1, 1, 0, 0, 0, 1, 0, // PC_MTVSCR
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VADDCUW
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VADDFP
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VADDSBS
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VADDSHS
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VADDSWS
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VADDUBM
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VADDUBS
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VADDUHM
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VADDUHS
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VADDUWM
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VADDUWS
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VAND
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VANDC
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VAVGSB
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VAVGSH
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VAVGSW
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VAVGUB
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VAVGUH
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VAVGUW
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VCFSX
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VCFUX
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VCMPBFP
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VCMPEQFP
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPEQUB
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPEQUH
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPEQUW
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VCMPGEFP
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VCMPGTFP
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPGTSB
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPGTSH
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPGTSW
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPGTUB
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPGTUH
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPGTUW
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VCTSXS
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VCTUXS
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VEXPTEFP
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VLOGEFP
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VMAXFP
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VMAXSB
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VMAXSH
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VMAXSW
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VMAXUB
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VMAXUH
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VMAXUW
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VMINFP
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VMINSB
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VMINSH
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VMINSW
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VMINUB
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VMINUH
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VMINUW
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VMRGHB
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VMRGHH
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VMRGHW
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VMRGLB
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VMRGLH
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VMRGLW
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMULESB
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMULESH
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMULEUB
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMULEUH
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMULOSB
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMULOSH
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMULOUB
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMULOUH
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VNOR
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VOR
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VPKPX
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VPKSHSS
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VPKSHUS
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VPKSWSS
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VPKSWUS
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VPKUHUM
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VPKUHUS
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VPKUWUM
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VPKUWUS
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VREFP
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VRFIM
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VRFIN
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VRFIP
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VRFIZ
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VRLB
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VRLH
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VRLW
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VRSQRTEFP
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSL
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSLB
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSLH
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VSLO
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSLW
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VSPLTB
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VSPLTH
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VSPLTW
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VSPLTISB
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VSPLTISH
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VSPLTISW
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSR
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSRAB
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSRAH
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSRAW
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSRB
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSRH
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VSRO
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSRW
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBCUW
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VSUBFP
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBSBS
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBSHS
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBSWS
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBUBM
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBUBS
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBUHM
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBUHS
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBUWM
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBUWS
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VSUMSWS
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VSUM2SWS
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VSUM4SBS
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VSUM4SHS
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VSUM4UBS
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VUPKHPX
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VUPKHSB
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VUPKHSH
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VUPKLPX
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VUPKLSB
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VUPKLSH
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VXOR
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VMADDFP
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMHADDSHS
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMHRADDSHS
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMLADDUHM
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMSUMMBM
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMSUMSHM
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMSUMSHS
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMSUMUBM
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMSUMUHM
+ VCIU1, 3, 1, 1, 1, 0, 0, 0, // PC_VMSUMUHS
+ VFPU1, 4, 1, 1, 1, 1, 0, 0, // PC_VNMSUBFP
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VPERM
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VSEL
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VSLDOI
+ VSIU, 1, 1, 0, 0, 0, 0, 0, // PC_VMR
+ VPU, 1, 1, 0, 0, 0, 0, 0, // PC_VMRP
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SLE
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SLEQ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SLIQ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SLLIQ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SLLQ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SLQ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SRAIQ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SRAQ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SRE
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SREA
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SREQ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SRIQ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SRLIQ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SRLQ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_SRQ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_MASKG
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_MASKIR
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_LSCBX
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_DIV
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_DIVS
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_DOZ
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_MUL
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_NABS
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_ABS
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_CLCS
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_DOZI
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_RLMI
+ BPU, 0, 0, 0, 0, 0, 0, 0, // PC_RRIB
+};
+
+static void advance(int firstStage, int oldStage, int newStage) {
+ PCode *instr = pipeline[oldStage].instr;
+ int cycles = instruction_timing[instr->op].cycles[newStage - firstStage];
+ pipeline[newStage].instr = instr;
+ pipeline[newStage].remaining = cycles;
+ pipeline[oldStage].instr = NULL;
+}
+
+static void assign_completion_buffer(PCode *instr) {
+ completionbuffers.used++;
+ completionbuffers.free--;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].instr = instr;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].completed = 0;
+ completionbuffers.nextFreeSlot = (completionbuffers.nextFreeSlot + 1) % MaxEntries;
+}
+
+static void complete_instruction(int stage) {
+ PCode *instr = pipeline[stage].instr;
+ int buf = 0;
+ while (buf < MaxEntries && completionbuffers.entries[buf].instr != instr)
+ buf++;
+
+ completionbuffers.entries[buf].completed = 1;
+ pipeline[stage].instr = NULL;
+
+ if (stage == IU1)
+ iu1_completed_instruction = instr;
+ else if (stage == IU2)
+ iu2_completed_instruction = instr;
+}
+
+static void retire_instruction(void) {
+ completionbuffers.entries[completionbuffers.nextToRetire].instr = NULL;
+ completionbuffers.used--;
+ completionbuffers.free++;
+ completionbuffers.nextToRetire = (completionbuffers.nextToRetire + 1) % MaxEntries;
+}
+
+static int latency(PCode *instr) {
+ int cycles = instruction_timing[instr->op].latency;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ cycles += 2;
+ if (instr->op == PC_LMW || instr->op == PC_STMW)
+ cycles += instr->argCount - 2;
+ return cycles;
+}
+
+static void initialize(void) {
+ int stage;
+ int i;
+
+ for (stage = 0; stage < NumStages; stage++)
+ pipeline[stage].instr = NULL;
+
+ completionbuffers.free = MaxEntries;
+ completionbuffers.used = 0;
+ completionbuffers.nextToRetire = 0;
+ completionbuffers.nextFreeSlot = 0;
+ for (i = 0; i < MaxEntries; i++)
+ completionbuffers.entries[i].instr = NULL;
+
+ iu1_completed_instruction = NULL;
+ iu2_completed_instruction = NULL;
+}
+
+static int can_issue(PCode *instr) {
+ int stage;
+
+ if (completionbuffers.free == 0)
+ return 0;
+
+ stage = instruction_timing[instr->op].stage;
+
+ if (stage == IU2) {
+ PCode *check;
+ int isClear1 = !pipeline[IU1].instr;
+ int isClear2 = !pipeline[IU2].instr;
+ if (!isClear1 && !isClear2)
+ return 0;
+ if (isClear1 && isClear2)
+ return 1;
+
+ if (isClear1)
+ check = pipeline[IU2].instr;
+ else
+ check = pipeline[IU1].instr;
+
+ if (is_dependent(instr, check, RegClass_GPR))
+ return 0;
+ if (is_dependent(instr, iu1_completed_instruction, RegClass_GPR))
+ return 0;
+ if (is_dependent(instr, iu2_completed_instruction, RegClass_GPR))
+ return 0;
+ } else if (stage == VFPU1 || stage == VCIU1 || stage == VSIU || stage == VPU) {
+ PCode *check;
+ int isVpuClear = !pipeline[VPU].instr;
+ int isVFpuClear = !pipeline[VFPU1].instr;
+ int isVCiuClear = !pipeline[VCIU1].instr;
+ int isVSiuClear = !pipeline[VSIU].instr;
+
+ if (stage == VPU) {
+ if (!isVpuClear)
+ return 0;
+
+ if (!isVFpuClear)
+ check = pipeline[VFPU1].instr;
+ else if (!isVCiuClear)
+ check = pipeline[VCIU1].instr;
+ else if (!isVSiuClear)
+ check = pipeline[VSIU].instr;
+ else
+ check = NULL;
+
+ if (is_dependent(instr, check, RegClass_VR))
+ return 0;
+ } else {
+ if (!isVFpuClear || !isVCiuClear || !isVSiuClear)
+ return 0;
+
+ if (!isVpuClear && is_dependent(instr, pipeline[VPU].instr, RegClass_VR))
+ return 0;
+ }
+ } else {
+ if (pipeline[stage].instr)
+ return 0;
+ }
+
+ if ((instr->flags & fIsWrite) && pipeline[LSU2].instr && (pipeline[LSU2].instr->flags & fIsWrite))
+ return 0;
+
+ return 1;
+}
+
+static void issue(PCode *instr) {
+ int stage = instruction_timing[instr->op].stage;
+ int cycles = instruction_timing[instr->op].cycles[0];
+ assign_completion_buffer(instr);
+ if (stage == IU2 && !pipeline[IU1].instr)
+ stage = IU1;
+ pipeline[stage].instr = instr;
+ pipeline[stage].remaining = cycles;
+}
+
+static void advance_clock(void) {
+ int stage;
+
+ iu1_completed_instruction = NULL;
+ iu2_completed_instruction = NULL;
+
+ for (stage = 0; stage < NumStages; stage++) {
+ if (pipeline[stage].instr && pipeline[stage].remaining)
+ --pipeline[stage].remaining;
+ }
+
+ if (completionbuffers.used && completionbuffers.entries[completionbuffers.nextToRetire].completed) {
+ retire_instruction();
+ if (completionbuffers.used && completionbuffers.entries[completionbuffers.nextToRetire].completed) {
+ retire_instruction();
+ }
+ }
+
+ if (pipeline[IU1].instr && pipeline[IU1].remaining == 0)
+ complete_instruction(IU1);
+ if (pipeline[VPU].instr && pipeline[VPU].remaining == 0)
+ complete_instruction(VPU);
+ if (pipeline[LSU2].instr && pipeline[LSU2].remaining == 0)
+ complete_instruction(LSU2);
+ if (pipeline[FPU3].instr && pipeline[FPU3].remaining == 0)
+ complete_instruction(FPU3);
+ if (pipeline[SRU].instr && pipeline[SRU].remaining == 0)
+ complete_instruction(SRU);
+ if (pipeline[BPU].instr && pipeline[BPU].remaining == 0)
+ complete_instruction(BPU);
+ if (pipeline[VSIU].instr && pipeline[VSIU].remaining == 0)
+ complete_instruction(VSIU);
+ if (pipeline[VCIU3].instr && pipeline[VCIU3].remaining == 0)
+ complete_instruction(VCIU3);
+ if (pipeline[VFPU4].instr && pipeline[VFPU4].remaining == 0)
+ complete_instruction(VFPU4);
+ if (pipeline[IU2].instr && pipeline[IU2].remaining == 0)
+ complete_instruction(IU2);
+
+ if (
+ pipeline[FPU1].instr &&
+ pipeline[FPU1].remaining == 0 &&
+ (pipeline[FPU1].instr->op == PC_FDIV || pipeline[FPU1].instr->op == PC_FDIVS)
+ )
+ complete_instruction(FPU1);
+
+ if (pipeline[FPU2].instr && pipeline[FPU2].remaining == 0 && !pipeline[FPU3].instr)
+ advance(FPU1, FPU2, FPU3);
+ if (pipeline[FPU1].instr && pipeline[FPU1].remaining == 0 && !pipeline[FPU2].instr)
+ advance(FPU1, FPU1, FPU2);
+
+ if (pipeline[LSU1].instr && pipeline[LSU1].remaining == 0 && !pipeline[LSU2].instr)
+ advance(LSU1, LSU1, LSU2);
+
+ if (pipeline[VCIU2].instr && pipeline[VCIU2].remaining == 0 && !pipeline[VCIU3].instr)
+ advance(VCIU1, VCIU2, VCIU3);
+ if (pipeline[VCIU1].instr && pipeline[VCIU1].remaining == 0 && !pipeline[VCIU2].instr)
+ advance(VCIU1, VCIU1, VCIU2);
+
+ if (pipeline[VFPU3].instr && pipeline[VFPU3].remaining == 0 && !pipeline[VFPU4].instr)
+ advance(VFPU1, VFPU3, VFPU4);
+ if (pipeline[VFPU2].instr && pipeline[VFPU2].remaining == 0 && !pipeline[VFPU3].instr)
+ advance(VFPU1, VFPU2, VFPU3);
+ if (pipeline[VFPU1].instr && pipeline[VFPU1].remaining == 0 && !pipeline[VFPU2].instr)
+ advance(VFPU1, VFPU1, VFPU2);
+}
+
+static int serializes(PCode *instr) {
+ return instruction_timing[instr->op].serializes;
+}
+
+static int uses_vpermute_unit_7400(PCode *instr) {
+ return instruction_timing[instr->op].stage == VPU;
+}
+
+MachineInfo machine7400 = {
+ 2,
+ 1,
+ 0,
+ &latency,
+ &initialize,
+ &can_issue,
+ &issue,
+ &advance_clock,
+ &serializes,
+ &uses_vpermute_unit_7400
+};
diff --git a/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation750.c b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation750.c
new file mode 100644
index 0000000..d412df3
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation750.c
@@ -0,0 +1,678 @@
+#include "compiler/Scheduler.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+
+// https://www.nxp.com/docs/en/reference-manual/MPC750UM.pdf
+
+typedef enum Stage {
+ BPU, // Branch Prediction Unit
+ IU1, // Integer Unit 1
+ IU2, // Integer Unit 2
+
+ LSU1, // Load/Store Unit
+ LSU2,
+
+ FPU1, // Floating Point Unit
+ FPU2,
+ FPU3,
+
+ SRU, // System Register Unit
+
+ NumStages
+} Stage;
+
+static struct {
+ // the instruction currently in this pipeline stage
+ PCode *instr;
+
+ // how many cycles are left for this instruction to finish
+ int remaining;
+} pipeline[NumStages];
+
+static PCode *iu1_completed_instruction;
+static PCode *iu2_completed_instruction;
+
+enum {
+ MaxEntries = 6
+};
+
+static struct {
+ // how many entries remain unused in the queue
+ unsigned int free;
+
+ // how many entries are currently used in the queue
+ unsigned int used;
+
+ // the index of the next instruction that will be retired
+ unsigned int nextToRetire;
+
+ // the index of the next free slot that will be used when an instruction is dispatched
+ unsigned int nextFreeSlot;
+
+ // circular array of entries in the completion queue
+ struct {
+ PCode *instr;
+ int completed;
+ } entries[MaxEntries];
+} completionbuffers;
+
+static struct {
+ // the initial stage for this instruction
+ Stage stage;
+
+ // the total amount of cycles required by this instruction
+ char latency;
+
+ // how long it takes to finish each stage
+ char cycles[3];
+
+ // does this instruction serialise?
+ char serializes;
+} instruction_timing[OPCODE_MAX] = {
+ BPU, 0, 0, 0, 0, 1, // PC_B
+ BPU, 0, 0, 0, 0, 1, // PC_BL
+ BPU, 0, 0, 0, 0, 1, // PC_BC
+ BPU, 0, 0, 0, 0, 1, // PC_BCLR
+ BPU, 0, 0, 0, 0, 1, // PC_BCCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BT
+ BPU, 0, 0, 0, 0, 1, // PC_BTLR
+ BPU, 0, 0, 0, 0, 1, // PC_BTCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BF
+ BPU, 0, 0, 0, 0, 1, // PC_BFLR
+ BPU, 0, 0, 0, 0, 1, // PC_BFCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZ
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZT
+ BPU, 0, 0, 0, 0, 1, // PC_BDNZF
+ BPU, 0, 0, 0, 0, 1, // PC_BDZ
+ BPU, 0, 0, 0, 0, 1, // PC_BDZT
+ BPU, 0, 0, 0, 0, 1, // PC_BDZF
+ BPU, 0, 0, 0, 0, 1, // PC_BLR
+ BPU, 0, 0, 0, 0, 1, // PC_BCTR
+ BPU, 0, 0, 0, 0, 1, // PC_BCTRL
+ BPU, 0, 0, 0, 0, 1, // PC_BLRL
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHA
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAU
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_LMW
+ LSU1, 2, 1, 1, 0, 0, // PC_STB
+ LSU1, 2, 1, 1, 0, 0, // PC_STBU
+ LSU1, 2, 1, 1, 0, 0, // PC_STBX
+ LSU1, 2, 1, 1, 0, 0, // PC_STBUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STH
+ LSU1, 2, 1, 1, 0, 0, // PC_STHU
+ LSU1, 2, 1, 1, 0, 0, // PC_STHX
+ LSU1, 2, 1, 1, 0, 0, // PC_STHUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STHBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_STW
+ LSU1, 2, 1, 1, 0, 0, // PC_STWU
+ LSU1, 2, 1, 1, 0, 0, // PC_STWX
+ LSU1, 2, 1, 1, 0, 0, // PC_STWUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STWBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_STMW
+ LSU1, 3, 1, 2, 0, 0, // PC_DCBF
+ LSU1, 3, 1, 2, 0, 0, // PC_DCBST
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBT
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBTST
+ LSU1, 3, 1, 2, 0, 0, // PC_DCBZ
+ IU2, 1, 1, 0, 0, 0, // PC_ADD
+ IU2, 1, 1, 0, 0, 0, // PC_ADDC
+ IU2, 1, 1, 0, 0, 0, // PC_ADDE
+ IU2, 1, 1, 0, 0, 0, // PC_ADDI
+ IU2, 1, 1, 0, 0, 0, // PC_ADDIC
+ IU2, 1, 1, 0, 0, 0, // PC_ADDICR
+ IU2, 1, 1, 0, 0, 0, // PC_ADDIS
+ IU2, 1, 1, 0, 0, 0, // PC_ADDME
+ IU2, 1, 1, 0, 0, 0, // PC_ADDZE
+ IU1, 19, 19, 0, 0, 0, // PC_DIVW
+ IU1, 19, 19, 0, 0, 0, // PC_DIVWU
+ IU1, 5, 5, 0, 0, 0, // PC_MULHW
+ IU1, 6, 5, 0, 0, 0, // PC_MULHWU
+ IU1, 3, 3, 0, 0, 0, // PC_MULLI
+ IU1, 5, 5, 0, 0, 0, // PC_MULLW
+ IU2, 1, 1, 0, 0, 0, // PC_NEG
+ IU2, 1, 1, 0, 0, 0, // PC_SUBF
+ IU2, 1, 1, 0, 0, 0, // PC_SUBFC
+ IU2, 1, 1, 0, 0, 0, // PC_SUBFE
+ IU2, 1, 1, 0, 0, 0, // PC_SUBFIC
+ IU2, 1, 1, 0, 0, 0, // PC_SUBFME
+ IU2, 1, 1, 0, 0, 0, // PC_SUBFZE
+ IU2, 3, 1, 0, 0, 0, // PC_CMPI
+ IU2, 3, 1, 0, 0, 0, // PC_CMP
+ IU2, 3, 1, 0, 0, 0, // PC_CMPLI
+ IU2, 3, 1, 0, 0, 0, // PC_CMPL
+ IU2, 1, 1, 0, 0, 0, // PC_ANDI
+ IU2, 1, 1, 0, 0, 0, // PC_ANDIS
+ IU2, 1, 1, 0, 0, 0, // PC_ORI
+ IU2, 1, 1, 0, 0, 0, // PC_ORIS
+ IU2, 1, 1, 0, 0, 0, // PC_XORI
+ IU2, 1, 1, 0, 0, 0, // PC_XORIS
+ IU2, 1, 1, 0, 0, 0, // PC_AND
+ IU2, 1, 1, 0, 0, 0, // PC_OR
+ IU2, 1, 1, 0, 0, 0, // PC_XOR
+ IU2, 1, 1, 0, 0, 0, // PC_NAND
+ IU2, 1, 1, 0, 0, 0, // PC_NOR
+ IU2, 1, 1, 0, 0, 0, // PC_EQV
+ IU2, 1, 1, 0, 0, 0, // PC_ANDC
+ IU2, 1, 1, 0, 0, 0, // PC_ORC
+ IU2, 1, 1, 0, 0, 0, // PC_EXTSB
+ IU2, 1, 1, 0, 0, 0, // PC_EXTSH
+ IU2, 1, 1, 0, 0, 0, // PC_CNTLZW
+ IU2, 1, 1, 0, 0, 0, // PC_RLWINM
+ IU2, 1, 1, 0, 0, 0, // PC_RLWNM
+ IU2, 1, 1, 0, 0, 0, // PC_RLWIMI
+ IU2, 1, 1, 0, 0, 0, // PC_SLW
+ IU2, 1, 1, 0, 0, 0, // PC_SRW
+ IU2, 1, 1, 0, 0, 0, // PC_SRAWI
+ IU2, 1, 1, 0, 0, 0, // PC_SRAW
+ SRU, 1, 1, 0, 0, 1, // PC_CRAND
+ SRU, 1, 1, 0, 0, 1, // PC_CRANDC
+ SRU, 1, 1, 0, 0, 1, // PC_CREQV
+ SRU, 1, 1, 0, 0, 1, // PC_CRNAND
+ SRU, 1, 1, 0, 0, 1, // PC_CRNOR
+ SRU, 1, 1, 0, 0, 1, // PC_CROR
+ SRU, 1, 1, 0, 0, 1, // PC_CRORC
+ SRU, 1, 1, 0, 0, 1, // PC_CRXOR
+ SRU, 1, 1, 0, 0, 1, // PC_MCRF
+ SRU, 2, 2, 0, 0, 1, // PC_MTXER
+ SRU, 2, 2, 0, 0, 1, // PC_MTCTR
+ SRU, 2, 2, 0, 0, 1, // PC_MTLR
+ SRU, 1, 1, 0, 0, 1, // PC_MTCRF
+ SRU, 1, 1, 0, 0, 0, // PC_MTMSR
+ SRU, 1, 1, 0, 0, 1, // PC_MTSPR
+ SRU, 1, 1, 0, 0, 1, // PC_MFMSR
+ SRU, 1, 1, 0, 0, 1, // PC_MFSPR
+ SRU, 1, 1, 0, 0, 1, // PC_MFXER
+ SRU, 1, 1, 0, 0, 1, // PC_MFCTR
+ SRU, 1, 1, 0, 0, 1, // PC_MFLR
+ SRU, 1, 1, 0, 0, 1, // PC_MFCR
+ FPU1, 3, 1, 1, 1, 0, // PC_MFFS
+ FPU1, 3, 1, 1, 1, 0, // PC_MTFSF
+ SRU, 1, 1, 0, 0, 1, // PC_EIEIO
+ SRU, 2, 2, 0, 0, 1, // PC_ISYNC
+ SRU, 3, 3, 0, 0, 1, // PC_SYNC
+ SRU, 1, 1, 0, 0, 1, // PC_RFI
+ IU2, 1, 1, 0, 0, 0, // PC_LI
+ IU2, 1, 1, 0, 0, 0, // PC_LIS
+ IU2, 1, 1, 0, 0, 0, // PC_MR
+ IU2, 1, 1, 0, 0, 0, // PC_NOP
+ IU2, 1, 1, 0, 0, 0, // PC_NOT
+ LSU1, 2, 1, 1, 0, 0, // PC_LFS
+ LSU1, 2, 1, 1, 0, 0, // PC_LFSU
+ LSU1, 2, 1, 1, 0, 0, // PC_LFSX
+ LSU1, 2, 1, 1, 0, 0, // PC_LFSUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LFD
+ LSU1, 2, 1, 1, 0, 0, // PC_LFDU
+ LSU1, 2, 1, 1, 0, 0, // PC_LFDX
+ LSU1, 2, 1, 1, 0, 0, // PC_LFDUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFS
+ LSU1, 2, 1, 1, 0, 0, // PC_STFSU
+ LSU1, 2, 1, 1, 0, 0, // PC_STFSX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFSUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFD
+ LSU1, 2, 1, 1, 0, 0, // PC_STFDU
+ LSU1, 2, 1, 1, 0, 0, // PC_STFDX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFDUX
+ FPU1, 3, 1, 1, 1, 0, // PC_FMR
+ FPU1, 3, 1, 1, 1, 0, // PC_FABS
+ FPU1, 3, 1, 1, 1, 0, // PC_FNEG
+ FPU1, 3, 1, 1, 1, 0, // PC_FNABS
+ FPU1, 3, 1, 1, 1, 0, // PC_FADD
+ FPU1, 3, 1, 1, 1, 0, // PC_FADDS
+ FPU1, 3, 1, 1, 1, 0, // PC_FSUB
+ FPU1, 3, 1, 1, 1, 0, // PC_FSUBS
+ FPU1, 4, 2, 1, 1, 0, // PC_FMUL
+ FPU1, 3, 1, 1, 1, 0, // PC_FMULS
+ FPU1, 31, 31, 0, 0, 0, // PC_FDIV
+ FPU1, 17, 17, 0, 0, 0, // PC_FDIVS
+ FPU1, 4, 2, 1, 1, 0, // PC_FMADD
+ FPU1, 3, 1, 1, 1, 0, // PC_FMADDS
+ FPU1, 4, 2, 1, 1, 0, // PC_FMSUB
+ FPU1, 3, 1, 1, 1, 0, // PC_FMSUBS
+ FPU1, 4, 2, 1, 1, 0, // PC_FNMADD
+ FPU1, 3, 1, 1, 1, 0, // PC_FNMADDS
+ FPU1, 4, 2, 1, 1, 0, // PC_FNMSUB
+ FPU1, 3, 1, 1, 1, 0, // PC_FNMSUBS
+ FPU1, 10, 10, 0, 0, 0, // PC_FRES
+ FPU1, 3, 1, 1, 1, 0, // PC_FRSQRTE
+ FPU1, 3, 1, 1, 1, 0, // PC_FSEL
+ FPU1, 3, 1, 1, 1, 0, // PC_FRSP
+ FPU1, 3, 1, 1, 1, 0, // PC_FCTIW
+ FPU1, 3, 1, 1, 1, 0, // PC_FCTIWZ
+ FPU1, 3, 1, 1, 1, 0, // PC_FCMPU
+ FPU1, 3, 1, 1, 1, 0, // PC_FCMPO
+ LSU1, 1, 1, 0, 0, 0, // PC_LWARX
+ LSU1, 1, 1, 0, 0, 0, // PC_LSWI
+ LSU1, 1, 1, 0, 0, 0, // PC_LSWX
+ LSU1, 1, 1, 0, 0, 0, // PC_STFIWX
+ LSU1, 1, 1, 0, 0, 0, // PC_STSWI
+ LSU1, 1, 1, 0, 0, 0, // PC_STSWX
+ LSU1, 1, 1, 0, 0, 0, // PC_STWCX
+ IU1, 1, 1, 0, 0, 1, // PC_ECIWX
+ IU1, 1, 1, 0, 0, 1, // PC_ECOWX
+ IU1, 1, 1, 0, 0, 0, // PC_DCBI
+ IU1, 1, 1, 0, 0, 0, // PC_ICBI
+ IU1, 1, 1, 0, 0, 0, // PC_MCRFS
+ IU1, 1, 1, 0, 0, 0, // PC_MCRXR
+ IU1, 1, 1, 0, 0, 0, // PC_MFTB
+ IU1, 1, 1, 0, 0, 0, // PC_MFSR
+ IU1, 1, 1, 0, 0, 0, // PC_MTSR
+ IU1, 1, 1, 0, 0, 0, // PC_MFSRIN
+ IU1, 1, 1, 0, 0, 0, // PC_MTSRIN
+ IU1, 1, 1, 0, 0, 0, // PC_MTFSB0
+ IU1, 1, 1, 0, 0, 0, // PC_MTFSB1
+ IU1, 1, 1, 0, 0, 0, // PC_MTFSFI
+ IU1, 1, 1, 0, 0, 1, // PC_SC
+ FPU1, 1, 1, 0, 0, 0, // PC_FSQRT
+ FPU1, 1, 1, 0, 0, 0, // PC_FSQRTS
+ IU1, 1, 1, 0, 0, 0, // PC_TLBIA
+ IU1, 1, 1, 0, 0, 0, // PC_TLBIE
+ IU1, 1, 1, 0, 0, 0, // PC_TLBLD
+ IU1, 1, 1, 0, 0, 0, // PC_TLBLI
+ IU1, 1, 1, 0, 0, 0, // PC_TLBSYNC
+ IU1, 1, 1, 0, 0, 1, // PC_TW
+ IU1, 1, 1, 0, 0, 1, // PC_TRAP
+ IU1, 1, 1, 0, 0, 1, // PC_TWI
+ IU1, 1, 1, 0, 0, 1, // PC_OPWORD
+ IU1, 1, 1, 0, 0, 0, // PC_MFROM
+ IU1, 1, 1, 0, 0, 1, // PC_DSA
+ IU1, 1, 1, 0, 0, 1, // PC_ESA
+ IU1, 0, 0, 0, 0, 0, // PC_DCCCI
+ IU1, 0, 0, 0, 0, 0, // PC_DCREAD
+ IU1, 0, 0, 0, 0, 0, // PC_ICBT
+ IU1, 0, 0, 0, 0, 0, // PC_ICCCI
+ IU1, 0, 0, 0, 0, 0, // PC_ICREAD
+ IU1, 0, 0, 0, 0, 0, // PC_RFCI
+ IU1, 0, 0, 0, 0, 0, // PC_TLBRE
+ IU1, 0, 0, 0, 0, 0, // PC_TLBSX
+ IU1, 0, 0, 0, 0, 0, // PC_TLBWE
+ IU1, 0, 0, 0, 0, 0, // PC_WRTEE
+ IU1, 0, 0, 0, 0, 0, // PC_WRTEEI
+ IU1, 0, 0, 0, 0, 0, // PC_MFDCR
+ IU1, 0, 0, 0, 0, 0, // PC_MTDCR
+ IU1, 0, 0, 0, 0, 0, // PC_DCBA
+ BPU, 0, 0, 0, 0, 0, // PC_DSS
+ BPU, 0, 0, 0, 0, 0, // PC_DSSALL
+ BPU, 0, 0, 0, 0, 0, // PC_DST
+ BPU, 0, 0, 0, 0, 0, // PC_DSTT
+ BPU, 0, 0, 0, 0, 0, // PC_DSTST
+ BPU, 0, 0, 0, 0, 0, // PC_DSTSTT
+ BPU, 0, 0, 0, 0, 0, // PC_LVEBX
+ BPU, 0, 0, 0, 0, 0, // PC_LVEHX
+ BPU, 0, 0, 0, 0, 0, // PC_LVEWX
+ BPU, 0, 0, 0, 0, 0, // PC_LVSL
+ BPU, 0, 0, 0, 0, 0, // PC_LVSR
+ BPU, 0, 0, 0, 0, 0, // PC_LVX
+ BPU, 0, 0, 0, 0, 0, // PC_LVXL
+ BPU, 0, 0, 0, 0, 0, // PC_STVEBX
+ BPU, 0, 0, 0, 0, 0, // PC_STVEHX
+ BPU, 0, 0, 0, 0, 0, // PC_STVEWX
+ BPU, 0, 0, 0, 0, 0, // PC_STVX
+ BPU, 0, 0, 0, 0, 0, // PC_STVXL
+ BPU, 0, 0, 0, 0, 0, // PC_MFVSCR
+ BPU, 0, 0, 0, 0, 0, // PC_MTVSCR
+ BPU, 0, 0, 0, 0, 0, // PC_VADDCUW
+ BPU, 0, 0, 0, 0, 0, // PC_VADDFP
+ BPU, 0, 0, 0, 0, 0, // PC_VADDSBS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDSWS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUBM
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUBS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUHM
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUHS
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUWM
+ BPU, 0, 0, 0, 0, 0, // PC_VADDUWS
+ BPU, 0, 0, 0, 0, 0, // PC_VAND
+ BPU, 0, 0, 0, 0, 0, // PC_VANDC
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGSB
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGSH
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGSW
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGUB
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGUH
+ BPU, 0, 0, 0, 0, 0, // PC_VAVGUW
+ BPU, 0, 0, 0, 0, 0, // PC_VCFSX
+ BPU, 0, 0, 0, 0, 0, // PC_VCFUX
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPBFP
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPEQFP
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPEQUB
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPEQUH
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPEQUW
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGEFP
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTFP
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTSB
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTSH
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTSW
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTUB
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTUH
+ BPU, 0, 0, 0, 0, 0, // PC_VCMPGTUW
+ BPU, 0, 0, 0, 0, 0, // PC_VCTSXS
+ BPU, 0, 0, 0, 0, 0, // PC_VCTUXS
+ BPU, 0, 0, 0, 0, 0, // PC_VEXPTEFP
+ BPU, 0, 0, 0, 0, 0, // PC_VLOGEFP
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXFP
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXSB
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXSH
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXSW
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXUB
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXUH
+ BPU, 0, 0, 0, 0, 0, // PC_VMAXUW
+ BPU, 0, 0, 0, 0, 0, // PC_VMINFP
+ BPU, 0, 0, 0, 0, 0, // PC_VMINSB
+ BPU, 0, 0, 0, 0, 0, // PC_VMINSH
+ BPU, 0, 0, 0, 0, 0, // PC_VMINSW
+ BPU, 0, 0, 0, 0, 0, // PC_VMINUB
+ BPU, 0, 0, 0, 0, 0, // PC_VMINUH
+ BPU, 0, 0, 0, 0, 0, // PC_VMINUW
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGHB
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGHH
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGHW
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGLB
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGLH
+ BPU, 0, 0, 0, 0, 0, // PC_VMRGLW
+ BPU, 0, 0, 0, 0, 0, // PC_VMULESB
+ BPU, 0, 0, 0, 0, 0, // PC_VMULESH
+ BPU, 0, 0, 0, 0, 0, // PC_VMULEUB
+ BPU, 0, 0, 0, 0, 0, // PC_VMULEUH
+ BPU, 0, 0, 0, 0, 0, // PC_VMULOSB
+ BPU, 0, 0, 0, 0, 0, // PC_VMULOSH
+ BPU, 0, 0, 0, 0, 0, // PC_VMULOUB
+ BPU, 0, 0, 0, 0, 0, // PC_VMULOUH
+ BPU, 0, 0, 0, 0, 0, // PC_VNOR
+ BPU, 0, 0, 0, 0, 0, // PC_VOR
+ BPU, 0, 0, 0, 0, 0, // PC_VPKPX
+ BPU, 0, 0, 0, 0, 0, // PC_VPKSHSS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKSHUS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKSWSS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKSWUS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKUHUM
+ BPU, 0, 0, 0, 0, 0, // PC_VPKUHUS
+ BPU, 0, 0, 0, 0, 0, // PC_VPKUWUM
+ BPU, 0, 0, 0, 0, 0, // PC_VPKUWUS
+ BPU, 0, 0, 0, 0, 0, // PC_VREFP
+ BPU, 0, 0, 0, 0, 0, // PC_VRFIM
+ BPU, 0, 0, 0, 0, 0, // PC_VRFIN
+ BPU, 0, 0, 0, 0, 0, // PC_VRFIP
+ BPU, 0, 0, 0, 0, 0, // PC_VRFIZ
+ BPU, 0, 0, 0, 0, 0, // PC_VRLB
+ BPU, 0, 0, 0, 0, 0, // PC_VRLH
+ BPU, 0, 0, 0, 0, 0, // PC_VRLW
+ BPU, 0, 0, 0, 0, 0, // PC_VRSQRTEFP
+ BPU, 0, 0, 0, 0, 0, // PC_VSL
+ BPU, 0, 0, 0, 0, 0, // PC_VSLB
+ BPU, 0, 0, 0, 0, 0, // PC_VSLH
+ BPU, 0, 0, 0, 0, 0, // PC_VSLO
+ BPU, 0, 0, 0, 0, 0, // PC_VSLW
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTB
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTH
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTW
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTISB
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTISH
+ BPU, 0, 0, 0, 0, 0, // PC_VSPLTISW
+ BPU, 0, 0, 0, 0, 0, // PC_VSR
+ BPU, 0, 0, 0, 0, 0, // PC_VSRAB
+ BPU, 0, 0, 0, 0, 0, // PC_VSRAH
+ BPU, 0, 0, 0, 0, 0, // PC_VSRAW
+ BPU, 0, 0, 0, 0, 0, // PC_VSRB
+ BPU, 0, 0, 0, 0, 0, // PC_VSRH
+ BPU, 0, 0, 0, 0, 0, // PC_VSRO
+ BPU, 0, 0, 0, 0, 0, // PC_VSRW
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBCUW
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBFP
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBSBS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBSWS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUBM
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUBS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUHM
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUHS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUWM
+ BPU, 0, 0, 0, 0, 0, // PC_VSUBUWS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUMSWS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUM2SWS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUM4SBS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUM4SHS
+ BPU, 0, 0, 0, 0, 0, // PC_VSUM4UBS
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKHPX
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKHSB
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKHSH
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKLPX
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKLSB
+ BPU, 0, 0, 0, 0, 0, // PC_VUPKLSH
+ BPU, 0, 0, 0, 0, 0, // PC_VXOR
+ BPU, 0, 0, 0, 0, 0, // PC_VMADDFP
+ BPU, 0, 0, 0, 0, 0, // PC_VMHADDSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VMHRADDSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VMLADDUHM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMMBM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMSHM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMSHS
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMUBM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMUHM
+ BPU, 0, 0, 0, 0, 0, // PC_VMSUMUHS
+ BPU, 0, 0, 0, 0, 0, // PC_VNMSUBFP
+ BPU, 0, 0, 0, 0, 0, // PC_VPERM
+ BPU, 0, 0, 0, 0, 0, // PC_VSEL
+ BPU, 0, 0, 0, 0, 0, // PC_VSLDOI
+ BPU, 0, 0, 0, 0, 0, // PC_VMR
+ BPU, 0, 0, 0, 0, 0, // PC_VMRP
+ BPU, 0, 0, 0, 0, 0, // PC_SLE
+ BPU, 0, 0, 0, 0, 0, // PC_SLEQ
+ BPU, 0, 0, 0, 0, 0, // PC_SLIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SLLIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SLLQ
+ BPU, 0, 0, 0, 0, 0, // PC_SLQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRAIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRAQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRE
+ BPU, 0, 0, 0, 0, 0, // PC_SREA
+ BPU, 0, 0, 0, 0, 0, // PC_SREQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRLIQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRLQ
+ BPU, 0, 0, 0, 0, 0, // PC_SRQ
+ BPU, 0, 0, 0, 0, 0, // PC_MASKG
+ BPU, 0, 0, 0, 0, 0, // PC_MASKIR
+ BPU, 0, 0, 0, 0, 0, // PC_LSCBX
+ BPU, 0, 0, 0, 0, 0, // PC_DIV
+ BPU, 0, 0, 0, 0, 0, // PC_DIVS
+ BPU, 0, 0, 0, 0, 0, // PC_DOZ
+ BPU, 0, 0, 0, 0, 0, // PC_MUL
+ BPU, 0, 0, 0, 0, 0, // PC_NABS
+ BPU, 0, 0, 0, 0, 0, // PC_ABS
+ BPU, 0, 0, 0, 0, 0, // PC_CLCS
+ BPU, 0, 0, 0, 0, 0, // PC_DOZI
+ BPU, 0, 0, 0, 0, 0, // PC_RLMI
+ BPU, 0, 0, 0, 0, 0, // PC_RRIB
+};
+
+static void advance(int firstStage, int oldStage, int newStage) {
+ PCode *instr = pipeline[oldStage].instr;
+ int cycles = instruction_timing[instr->op].cycles[newStage - firstStage];
+ pipeline[newStage].instr = instr;
+ pipeline[newStage].remaining = cycles;
+ pipeline[oldStage].instr = NULL;
+}
+
+static void assign_completion_buffer(PCode *instr) {
+ completionbuffers.used++;
+ completionbuffers.free--;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].instr = instr;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].completed = 0;
+ completionbuffers.nextFreeSlot = (completionbuffers.nextFreeSlot + 1) % MaxEntries;
+}
+
+static void complete_instruction(int stage) {
+ PCode *instr = pipeline[stage].instr;
+ int buf = 0;
+ while (buf < MaxEntries && completionbuffers.entries[buf].instr != instr)
+ buf++;
+
+ completionbuffers.entries[buf].completed = 1;
+ pipeline[stage].instr = NULL;
+
+ if (stage == IU1)
+ iu1_completed_instruction = instr;
+ else if (stage == IU2)
+ iu2_completed_instruction = instr;
+}
+
+static void retire_instruction(void) {
+ completionbuffers.entries[completionbuffers.nextToRetire].instr = NULL;
+ completionbuffers.used--;
+ completionbuffers.free++;
+ completionbuffers.nextToRetire = (completionbuffers.nextToRetire + 1) % MaxEntries;
+}
+
+static int latency(PCode *instr) {
+ int cycles = instruction_timing[instr->op].latency;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ cycles += 2;
+ if (instr->op == PC_LMW || instr->op == PC_STMW)
+ cycles += instr->argCount - 2;
+ return cycles;
+}
+
+static void initialize(void) {
+ int stage;
+ int i;
+
+ for (stage = 0; stage < NumStages; stage++)
+ pipeline[stage].instr = NULL;
+
+ completionbuffers.free = MaxEntries;
+ completionbuffers.used = 0;
+ completionbuffers.nextToRetire = 0;
+ completionbuffers.nextFreeSlot = 0;
+ for (i = 0; i < MaxEntries; i++)
+ completionbuffers.entries[i].instr = NULL;
+
+ iu1_completed_instruction = NULL;
+ iu2_completed_instruction = NULL;
+}
+
+static int can_issue(PCode *instr) {
+ int stage;
+
+ if (completionbuffers.free == 0)
+ return 0;
+
+ stage = instruction_timing[instr->op].stage;
+
+ if (stage == IU2) {
+ PCode *check;
+ int isClear1 = !pipeline[IU1].instr;
+ int isClear2 = !pipeline[IU2].instr;
+ if (!isClear1 && !isClear2)
+ return 0;
+ if (isClear1 && isClear2)
+ return 1;
+
+ if (isClear1)
+ check = pipeline[IU2].instr;
+ else
+ check = pipeline[IU1].instr;
+
+ if (is_dependent(instr, check, RegClass_GPR))
+ return 0;
+ if (is_dependent(instr, iu1_completed_instruction, RegClass_GPR))
+ return 0;
+ if (is_dependent(instr, iu2_completed_instruction, RegClass_GPR))
+ return 0;
+ } else {
+ if (pipeline[stage].instr)
+ return 0;
+ }
+
+ if ((instr->flags & fIsWrite) && pipeline[LSU2].instr && (pipeline[LSU2].instr->flags & fIsWrite))
+ return 0;
+
+ return 1;
+}
+
+static void issue(PCode *instr) {
+ int stage = instruction_timing[instr->op].stage;
+ int cycles = instruction_timing[instr->op].cycles[0];
+ assign_completion_buffer(instr);
+ if (stage == IU2 && !pipeline[IU1].instr)
+ stage = IU1;
+ pipeline[stage].instr = instr;
+ pipeline[stage].remaining = cycles;
+}
+
+static void advance_clock(void) {
+ int stage;
+
+ iu1_completed_instruction = NULL;
+ iu2_completed_instruction = NULL;
+
+ for (stage = 0; stage < NumStages; stage++) {
+ if (pipeline[stage].instr && pipeline[stage].remaining)
+ --pipeline[stage].remaining;
+ }
+
+ if (completionbuffers.used && completionbuffers.entries[completionbuffers.nextToRetire].completed) {
+ retire_instruction();
+ if (completionbuffers.used && completionbuffers.entries[completionbuffers.nextToRetire].completed) {
+ retire_instruction();
+ }
+ }
+
+ if (pipeline[IU1].instr && pipeline[IU1].remaining == 0)
+ complete_instruction(IU1);
+ if (pipeline[LSU2].instr && pipeline[LSU2].remaining == 0)
+ complete_instruction(LSU2);
+ if (pipeline[FPU3].instr && pipeline[FPU3].remaining == 0)
+ complete_instruction(FPU3);
+ if (pipeline[SRU].instr && pipeline[SRU].remaining == 0)
+ complete_instruction(SRU);
+ if (pipeline[BPU].instr && pipeline[BPU].remaining == 0)
+ complete_instruction(BPU);
+ if (pipeline[IU2].instr && pipeline[IU2].remaining == 0)
+ complete_instruction(IU2);
+
+ if (
+ pipeline[FPU1].instr &&
+ pipeline[FPU1].remaining == 0 &&
+ (pipeline[FPU1].instr->op == PC_FDIV || pipeline[FPU1].instr->op == PC_FDIVS)
+ )
+ complete_instruction(FPU1);
+
+ if (pipeline[FPU2].instr && pipeline[FPU2].remaining == 0 && !pipeline[FPU3].instr)
+ advance(FPU1, FPU2, FPU3);
+ if (pipeline[FPU1].instr && pipeline[FPU1].remaining == 0 && !pipeline[FPU2].instr)
+ advance(FPU1, FPU1, FPU2);
+
+ if (pipeline[LSU1].instr && pipeline[LSU1].remaining == 0 && !pipeline[LSU2].instr)
+ advance(LSU1, LSU1, LSU2);
+}
+
+static int serializes(PCode *instr) {
+ return instruction_timing[instr->op].serializes;
+}
+
+MachineInfo machine750 = {
+ 2,
+ 1,
+ 0,
+ &latency,
+ &initialize,
+ &can_issue,
+ &issue,
+ &advance_clock,
+ &serializes,
+ &default_uses_vpermute_unit
+};
diff --git a/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation821.c b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation821.c
new file mode 100644
index 0000000..bbf0509
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulation821.c
@@ -0,0 +1,615 @@
+#include "compiler/Scheduler.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+
+// https://www.nxp.com/docs/en/user-guide/MPC821UM.pdf
+
+typedef enum Stage {
+ BranchUnit,
+ Stage1,
+ Stage2,
+ LSU1,
+ LSU2,
+ CRUnit,
+ NumStages,
+ Stage7
+} Stage;
+
+static struct {
+ // the instruction currently in this pipeline stage
+ PCode *instr;
+
+ // how many cycles are left for this instruction to finish
+ int remaining;
+} pipeline[NumStages];
+
+enum {
+ MaxEntries = 6
+};
+
+static struct {
+ // how many entries remain unused in the queue
+ unsigned int free;
+
+ // how many entries are currently used in the queue
+ unsigned int used;
+
+ // the index of the next instruction that will be retired
+ unsigned int nextToRetire;
+
+ // the index of the next free slot that will be used when an instruction is dispatched
+ unsigned int nextFreeSlot;
+
+ // circular array of entries in the completion queue
+ struct {
+ PCode *instr;
+ int completed;
+ } entries[MaxEntries];
+} completionbuffers;
+
+static struct {
+ // the initial stage for this instruction
+ Stage stage;
+
+ // the total amount of cycles required by this instruction
+ char latency;
+
+ // how long it takes to finish each stage
+ char cycles[3];
+
+ // does this instruction serialise?
+ char serializes;
+} instruction_timing[OPCODE_MAX] = {
+ BranchUnit, 0, 0, 0, 0, 0, // PC_B
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BL
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BC
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BCLR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BCCTR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BT
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BTLR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BTCTR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BF
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BFLR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BFCTR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BDNZ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BDNZT
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BDNZF
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BDZ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BDZT
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BDZF
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BLR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BCTR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BCTRL
+ BranchUnit, 0, 0, 0, 0, 0, // PC_BLRL
+ BranchUnit, 0, 0, 0, 0, 0, // PC_LBZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LBZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHA
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAU
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHAUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LHBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZ
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZU
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWZUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LWBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_LMW
+ LSU1, 2, 1, 1, 0, 0, // PC_STB
+ LSU1, 2, 1, 1, 0, 0, // PC_STBU
+ LSU1, 2, 1, 1, 0, 0, // PC_STBX
+ LSU1, 2, 1, 1, 0, 0, // PC_STBUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STH
+ LSU1, 2, 1, 1, 0, 0, // PC_STHU
+ LSU1, 2, 1, 1, 0, 0, // PC_STHX
+ LSU1, 2, 1, 1, 0, 0, // PC_STHUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STHBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_STW
+ LSU1, 2, 1, 1, 0, 0, // PC_STWU
+ LSU1, 2, 1, 1, 0, 0, // PC_STWX
+ LSU1, 2, 1, 1, 0, 0, // PC_STWUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STWBRX
+ LSU1, 2, 1, 1, 0, 0, // PC_STMW
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBF
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBST
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBT
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBTST
+ LSU1, 2, 1, 1, 0, 0, // PC_DCBZ
+ LSU1, 2, 1, 1, 0, 0, // PC_ADD
+ Stage1, 1, 1, 0, 0, 0, // PC_ADDC
+ Stage1, 1, 1, 0, 0, 0, // PC_ADDE
+ Stage1, 1, 1, 0, 0, 0, // PC_ADDI
+ Stage1, 1, 1, 0, 0, 0, // PC_ADDIC
+ Stage1, 1, 1, 0, 0, 0, // PC_ADDICR
+ Stage1, 1, 1, 0, 0, 0, // PC_ADDIS
+ Stage1, 1, 1, 0, 0, 0, // PC_ADDME
+ Stage1, 1, 1, 0, 0, 0, // PC_ADDZE
+ Stage1, 1, 1, 0, 0, 0, // PC_DIVW
+ Stage1, 37, 37, 0, 0, 0, // PC_DIVWU
+ Stage1, 37, 37, 0, 0, 0, // PC_MULHW
+ Stage1, 5, 5, 0, 0, 0, // PC_MULHWU
+ Stage1, 5, 5, 0, 0, 0, // PC_MULLI
+ Stage1, 3, 3, 0, 0, 0, // PC_MULLW
+ Stage1, 5, 5, 0, 0, 0, // PC_NEG
+ Stage1, 1, 1, 0, 0, 0, // PC_SUBF
+ Stage1, 1, 1, 0, 0, 0, // PC_SUBFC
+ Stage1, 1, 1, 0, 0, 0, // PC_SUBFE
+ Stage1, 1, 1, 0, 0, 0, // PC_SUBFIC
+ Stage1, 1, 1, 0, 0, 0, // PC_SUBFME
+ Stage1, 1, 1, 0, 0, 0, // PC_SUBFZE
+ Stage1, 1, 1, 0, 0, 0, // PC_CMPI
+ Stage1, 3, 1, 0, 0, 0, // PC_CMP
+ Stage1, 3, 1, 0, 0, 0, // PC_CMPLI
+ Stage1, 3, 1, 0, 0, 0, // PC_CMPL
+ Stage1, 3, 1, 0, 0, 0, // PC_ANDI
+ Stage1, 1, 1, 0, 0, 0, // PC_ANDIS
+ Stage1, 1, 1, 0, 0, 0, // PC_ORI
+ Stage1, 1, 1, 0, 0, 0, // PC_ORIS
+ Stage1, 1, 1, 0, 0, 0, // PC_XORI
+ Stage1, 1, 1, 0, 0, 0, // PC_XORIS
+ Stage1, 1, 1, 0, 0, 0, // PC_AND
+ Stage1, 1, 1, 0, 0, 0, // PC_OR
+ Stage1, 1, 1, 0, 0, 0, // PC_XOR
+ Stage1, 1, 1, 0, 0, 0, // PC_NAND
+ Stage1, 1, 1, 0, 0, 0, // PC_NOR
+ Stage1, 1, 1, 0, 0, 0, // PC_EQV
+ Stage1, 1, 1, 0, 0, 0, // PC_ANDC
+ Stage1, 1, 1, 0, 0, 0, // PC_ORC
+ Stage1, 1, 1, 0, 0, 0, // PC_EXTSB
+ Stage1, 1, 1, 0, 0, 0, // PC_EXTSH
+ Stage1, 1, 1, 0, 0, 0, // PC_CNTLZW
+ Stage1, 1, 1, 0, 0, 0, // PC_RLWINM
+ Stage1, 1, 1, 0, 0, 0, // PC_RLWNM
+ Stage1, 1, 1, 0, 0, 0, // PC_RLWIMI
+ Stage1, 1, 1, 0, 0, 0, // PC_SLW
+ Stage1, 1, 1, 0, 0, 0, // PC_SRW
+ Stage1, 1, 1, 0, 0, 0, // PC_SRAWI
+ Stage1, 1, 1, 0, 0, 0, // PC_SRAW
+ Stage1, 1, 1, 0, 0, 0, // PC_CRAND
+ CRUnit, 1, 1, 0, 0, 0, // PC_CRANDC
+ CRUnit, 1, 1, 0, 0, 0, // PC_CREQV
+ CRUnit, 1, 1, 0, 0, 0, // PC_CRNAND
+ CRUnit, 1, 1, 0, 0, 0, // PC_CRNOR
+ CRUnit, 1, 1, 0, 0, 0, // PC_CROR
+ CRUnit, 1, 1, 0, 0, 0, // PC_CRORC
+ CRUnit, 1, 1, 0, 0, 0, // PC_CRXOR
+ CRUnit, 1, 1, 0, 0, 0, // PC_MCRF
+ CRUnit, 1, 1, 0, 0, 0, // PC_MTXER
+ Stage1, 1, 1, 0, 0, 0, // PC_MTCTR
+ BranchUnit, 2, 2, 0, 0, 0, // PC_MTLR
+ BranchUnit, 2, 2, 0, 0, 0, // PC_MTCRF
+ Stage1, 1, 1, 0, 0, 0, // PC_MTMSR
+ Stage1, 1, 1, 0, 0, 0, // PC_MTSPR
+ Stage1, 1, 1, 0, 0, 0, // PC_MFMSR
+ Stage1, 1, 1, 0, 0, 0, // PC_MFSPR
+ Stage1, 1, 1, 0, 0, 0, // PC_MFXER
+ Stage7, 3, 1, 1, 1, 0, // PC_MFCTR
+ Stage7, 3, 1, 1, 1, 0, // PC_MFLR
+ Stage1, 1, 1, 0, 0, 0, // PC_MFCR
+ Stage1, 1, 1, 0, 0, 0, // PC_MFFS
+ Stage1, 1, 1, 0, 0, 0, // PC_MTFSF
+ Stage1, 1, 1, 0, 0, 0, // PC_EIEIO
+ Stage1, 1, 1, 0, 0, 0, // PC_ISYNC
+ Stage1, 1, 1, 0, 0, 0, // PC_SYNC
+ Stage1, 1, 1, 0, 0, 0, // PC_RFI
+ Stage1, 1, 1, 0, 0, 0, // PC_LI
+ LSU1, 2, 1, 1, 0, 0, // PC_LIS
+ LSU1, 2, 1, 1, 0, 0, // PC_MR
+ LSU1, 2, 1, 1, 0, 0, // PC_NOP
+ LSU1, 2, 1, 1, 0, 0, // PC_NOT
+ LSU1, 2, 1, 1, 0, 0, // PC_LFS
+ LSU1, 2, 1, 1, 0, 0, // PC_LFSU
+ LSU1, 2, 1, 1, 0, 0, // PC_LFSX
+ LSU1, 2, 1, 1, 0, 0, // PC_LFSUX
+ LSU1, 2, 1, 1, 0, 0, // PC_LFD
+ LSU1, 2, 1, 1, 0, 0, // PC_LFDU
+ LSU1, 2, 1, 1, 0, 0, // PC_LFDX
+ LSU1, 2, 1, 1, 0, 0, // PC_LFDUX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFS
+ LSU1, 2, 1, 1, 0, 0, // PC_STFSU
+ LSU1, 2, 1, 1, 0, 0, // PC_STFSX
+ LSU1, 2, 1, 1, 0, 0, // PC_STFSUX
+ Stage7, 3, 1, 1, 1, 0, // PC_STFD
+ Stage7, 3, 1, 1, 1, 0, // PC_STFDU
+ Stage7, 3, 1, 1, 1, 0, // PC_STFDX
+ Stage7, 3, 1, 1, 1, 0, // PC_STFDUX
+ Stage7, 3, 1, 1, 1, 0, // PC_FMR
+ Stage7, 3, 1, 1, 1, 0, // PC_FABS
+ Stage7, 3, 1, 1, 1, 0, // PC_FNEG
+ Stage7, 3, 1, 1, 1, 0, // PC_FNABS
+ Stage7, 4, 2, 1, 1, 0, // PC_FADD
+ Stage7, 3, 1, 1, 1, 0, // PC_FADDS
+ Stage7, 33, 33, 0, 0, 0, // PC_FSUB
+ Stage7, 18, 18, 0, 0, 0, // PC_FSUBS
+ Stage7, 4, 2, 1, 1, 0, // PC_FMUL
+ Stage7, 3, 1, 1, 1, 0, // PC_FMULS
+ Stage7, 4, 2, 1, 1, 0, // PC_FDIV
+ Stage7, 3, 1, 1, 1, 0, // PC_FDIVS
+ Stage7, 4, 2, 1, 1, 0, // PC_FMADD
+ Stage7, 3, 1, 1, 1, 0, // PC_FMADDS
+ Stage7, 4, 2, 1, 1, 0, // PC_FMSUB
+ Stage7, 3, 1, 1, 1, 0, // PC_FMSUBS
+ Stage7, 18, 18, 0, 0, 0, // PC_FNMADD
+ Stage7, 3, 1, 1, 1, 0, // PC_FNMADDS
+ Stage7, 3, 1, 1, 1, 0, // PC_FNMSUB
+ Stage7, 3, 1, 1, 1, 0, // PC_FNMSUBS
+ Stage7, 3, 1, 1, 1, 0, // PC_FRES
+ Stage7, 3, 1, 1, 1, 0, // PC_FRSQRTE
+ Stage7, 5, 1, 1, 1, 0, // PC_FSEL
+ Stage7, 5, 1, 1, 1, 0, // PC_FRSP
+ LSU1, 1, 0, 0, 0, 0, // PC_FCTIW
+ LSU1, 1, 0, 0, 0, 0, // PC_FCTIWZ
+ LSU1, 1, 0, 0, 0, 0, // PC_FCMPU
+ LSU1, 1, 0, 0, 0, 0, // PC_FCMPO
+ LSU1, 1, 0, 0, 0, 0, // PC_LWARX
+ LSU1, 1, 0, 0, 0, 0, // PC_LSWI
+ LSU1, 1, 0, 0, 0, 0, // PC_LSWX
+ Stage1, 1, 0, 0, 0, 0, // PC_STFIWX
+ Stage1, 1, 0, 0, 0, 0, // PC_STSWI
+ Stage1, 1, 0, 0, 0, 0, // PC_STSWX
+ Stage1, 1, 0, 0, 0, 0, // PC_STWCX
+ Stage1, 1, 0, 0, 0, 0, // PC_ECIWX
+ Stage1, 1, 0, 0, 0, 0, // PC_ECOWX
+ Stage1, 1, 0, 0, 0, 0, // PC_DCBI
+ Stage1, 1, 0, 0, 0, 0, // PC_ICBI
+ Stage1, 1, 0, 0, 0, 0, // PC_MCRFS
+ Stage1, 1, 0, 0, 0, 0, // PC_MCRXR
+ Stage1, 1, 0, 0, 0, 0, // PC_MFTB
+ Stage1, 1, 0, 0, 0, 0, // PC_MFSR
+ Stage1, 1, 0, 0, 0, 0, // PC_MTSR
+ Stage1, 1, 0, 0, 0, 0, // PC_MFSRIN
+ Stage1, 1, 0, 0, 0, 0, // PC_MTSRIN
+ Stage1, 1, 0, 0, 0, 0, // PC_MTFSB0
+ Stage1, 1, 0, 0, 0, 0, // PC_MTFSB1
+ Stage1, 1, 0, 0, 0, 0, // PC_MTFSFI
+ Stage1, 1, 0, 0, 0, 1, // PC_SC
+ Stage1, 1, 0, 0, 0, 1, // PC_FSQRT
+ Stage1, 1, 0, 0, 0, 0, // PC_FSQRTS
+ Stage1, 1, 0, 0, 0, 0, // PC_TLBIA
+ Stage1, 1, 0, 0, 0, 0, // PC_TLBIE
+ Stage1, 1, 0, 0, 0, 0, // PC_TLBLD
+ Stage1, 1, 0, 0, 0, 0, // PC_TLBLI
+ Stage1, 1, 0, 0, 0, 0, // PC_TLBSYNC
+ Stage1, 1, 0, 0, 0, 0, // PC_TW
+ Stage1, 1, 0, 0, 0, 1, // PC_TRAP
+ Stage1, 1, 0, 0, 0, 1, // PC_TWI
+ Stage1, 1, 0, 0, 0, 1, // PC_OPWORD
+ Stage1, 1, 0, 0, 0, 1, // PC_MFROM
+ Stage1, 1, 0, 0, 0, 0, // PC_DSA
+ Stage1, 1, 0, 0, 0, 0, // PC_ESA
+ Stage1, 1, 0, 0, 0, 0, // PC_DCCCI
+ Stage1, 0, 0, 0, 0, 0, // PC_DCREAD
+ Stage1, 0, 0, 0, 0, 0, // PC_ICBT
+ Stage1, 0, 0, 0, 0, 0, // PC_ICCCI
+ Stage1, 0, 0, 0, 0, 0, // PC_ICREAD
+ Stage1, 0, 0, 0, 0, 0, // PC_RFCI
+ Stage1, 0, 0, 0, 0, 0, // PC_TLBRE
+ Stage1, 0, 0, 0, 0, 0, // PC_TLBSX
+ Stage1, 0, 0, 0, 0, 0, // PC_TLBWE
+ Stage1, 0, 0, 0, 0, 0, // PC_WRTEE
+ Stage1, 0, 0, 0, 0, 0, // PC_WRTEEI
+ Stage1, 0, 0, 0, 0, 0, // PC_MFDCR
+ Stage1, 0, 0, 0, 0, 0, // PC_MTDCR
+ Stage1, 0, 0, 0, 0, 0, // PC_DCBA
+ Stage1, 0, 0, 0, 0, 0, // PC_DSS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_DSSALL
+ BranchUnit, 0, 0, 0, 0, 0, // PC_DST
+ BranchUnit, 0, 0, 0, 0, 0, // PC_DSTT
+ BranchUnit, 0, 0, 0, 0, 0, // PC_DSTST
+ BranchUnit, 0, 0, 0, 0, 0, // PC_DSTSTT
+ BranchUnit, 0, 0, 0, 0, 0, // PC_LVEBX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_LVEHX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_LVEWX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_LVSL
+ BranchUnit, 0, 0, 0, 0, 0, // PC_LVSR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_LVX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_LVXL
+ BranchUnit, 0, 0, 0, 0, 0, // PC_STVEBX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_STVEHX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_STVEWX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_STVX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_STVXL
+ BranchUnit, 0, 0, 0, 0, 0, // PC_MFVSCR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_MTVSCR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VADDCUW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VADDFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VADDSBS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VADDSHS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VADDSWS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VADDUBM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VADDUBS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VADDUHM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VADDUHS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VADDUWM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VADDUWS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VAND
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VANDC
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VAVGSB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VAVGSH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VAVGSW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VAVGUB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VAVGUH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VAVGUW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCFSX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCFUX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCMPBFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCMPEQFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCMPEQUB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCMPEQUH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCMPEQUW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCMPGEFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCMPGTFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCMPGTSB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCMPGTSH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCMPGTSW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCMPGTUB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCMPGTUH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCMPGTUW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCTSXS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VCTUXS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VEXPTEFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VLOGEFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMAXFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMAXSB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMAXSH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMAXSW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMAXUB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMAXUH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMAXUW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMINFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMINSB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMINSH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMINSW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMINUB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMINUH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMINUW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMRGHB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMRGHH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMRGHW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMRGLB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMRGLH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMRGLW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMULESB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMULESH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMULEUB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMULEUH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMULOSB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMULOSH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMULOUB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMULOUH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VNOR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VOR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VPKPX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VPKSHSS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VPKSHUS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VPKSWSS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VPKSWUS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VPKUHUM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VPKUHUS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VPKUWUM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VPKUWUS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VREFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VRFIM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VRFIN
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VRFIP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VRFIZ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VRLB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VRLH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VRLW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VRSQRTEFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSL
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSLB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSLH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSLO
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSLW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSPLTB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSPLTH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSPLTW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSPLTISB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSPLTISH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSPLTISW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSRAB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSRAH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSRAW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSRB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSRH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSRO
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSRW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUBCUW
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUBFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUBSBS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUBSHS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUBSWS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUBUBM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUBUBS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUBUHM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUBUHS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUBUWM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUBUWS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUMSWS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUM2SWS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUM4SBS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUM4SHS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSUM4UBS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VUPKHPX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VUPKHSB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VUPKHSH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VUPKLPX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VUPKLSB
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VUPKLSH
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VXOR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMADDFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMHADDSHS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMHRADDSHS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMLADDUHM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMSUMMBM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMSUMSHM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMSUMSHS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMSUMUBM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMSUMUHM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMSUMUHS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VNMSUBFP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VPERM
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSEL
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VSLDOI
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_VMRP
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SLE
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SLEQ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SLIQ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SLLIQ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SLLQ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SLQ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SRAIQ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SRAQ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SRE
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SREA
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SREQ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SRIQ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SRLIQ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SRLQ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_SRQ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_MASKG
+ BranchUnit, 0, 0, 0, 0, 0, // PC_MASKIR
+ BranchUnit, 0, 0, 0, 0, 0, // PC_LSCBX
+ BranchUnit, 0, 0, 0, 0, 0, // PC_DIV
+ BranchUnit, 0, 0, 0, 0, 0, // PC_DIVS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_DOZ
+ BranchUnit, 0, 0, 0, 0, 0, // PC_MUL
+ BranchUnit, 0, 0, 0, 0, 0, // PC_NABS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_ABS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_CLCS
+ BranchUnit, 0, 0, 0, 0, 0, // PC_DOZI
+ BranchUnit, 0, 0, 0, 0, 0, // PC_RLMI
+ BranchUnit, 0, 0, 0, 0, 0, // PC_RRIB
+};
+
+static void advance(int firstStage, int oldStage, int newStage) {
+ PCode *instr = pipeline[oldStage].instr;
+ int cycles = instruction_timing[instr->op].cycles[newStage - firstStage];
+ pipeline[newStage].instr = instr;
+ pipeline[newStage].remaining = cycles;
+ pipeline[oldStage].instr = NULL;
+}
+
+static void assign_completion_buffer(PCode *instr) {
+ completionbuffers.used++;
+ completionbuffers.free--;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].instr = instr;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].completed = 0;
+ completionbuffers.nextFreeSlot = (completionbuffers.nextFreeSlot + 1) % MaxEntries;
+}
+
+static void complete_instruction(int stage) {
+ PCode *instr = pipeline[stage].instr;
+ int buf = 0;
+ while (buf < MaxEntries && completionbuffers.entries[buf].instr != instr)
+ buf++;
+
+ completionbuffers.entries[buf].completed = 1;
+ pipeline[stage].instr = NULL;
+}
+
+static void retire_instruction(void) {
+ completionbuffers.entries[completionbuffers.nextToRetire].instr = NULL;
+ completionbuffers.used--;
+ completionbuffers.free++;
+ completionbuffers.nextToRetire = (completionbuffers.nextToRetire + 1) % MaxEntries;
+}
+
+static int latency(PCode *instr) {
+ int cycles = instruction_timing[instr->op].latency;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ cycles += 2;
+ if (instr->op == PC_LMW || instr->op == PC_STMW)
+ cycles += instr->argCount - 2;
+ return cycles;
+}
+
+static void initialize(void) {
+ int stage;
+ int i;
+
+ for (stage = 0; stage < NumStages; stage++)
+ pipeline[stage].instr = NULL;
+
+ completionbuffers.free = MaxEntries;
+ completionbuffers.used = 0;
+ completionbuffers.nextToRetire = 0;
+ completionbuffers.nextFreeSlot = 0;
+ for (i = 0; i < MaxEntries; i++)
+ completionbuffers.entries[i].instr = NULL;
+}
+
+static int can_issue(PCode *instr) {
+ int stage;
+
+ if (completionbuffers.free == 0)
+ return 0;
+
+ stage = instruction_timing[instr->op].stage;
+ if (pipeline[stage].instr)
+ return 0;
+
+ if ((instr->flags & fIsWrite) && pipeline[LSU2].instr && (pipeline[LSU2].instr->flags & fIsWrite))
+ return 0;
+
+ return 1;
+}
+
+static void issue(PCode *instr) {
+ int stage = instruction_timing[instr->op].stage;
+ int cycles = instruction_timing[instr->op].cycles[0];
+ assign_completion_buffer(instr);
+ pipeline[stage].instr = instr;
+ pipeline[stage].remaining = cycles;
+}
+
+static void advance_clock(void) {
+ int stage;
+
+ for (stage = 0; stage < NumStages; stage++) {
+ if (pipeline[stage].instr && pipeline[stage].remaining)
+ --pipeline[stage].remaining;
+ }
+
+ if (completionbuffers.used && completionbuffers.entries[completionbuffers.nextToRetire].completed) {
+ retire_instruction();
+ if (completionbuffers.used && completionbuffers.entries[completionbuffers.nextToRetire].completed) {
+ retire_instruction();
+ }
+ }
+
+ if (pipeline[Stage1].instr && pipeline[Stage1].remaining == 0)
+ complete_instruction(Stage1);
+ if (pipeline[LSU2].instr && pipeline[LSU2].remaining == 0)
+ complete_instruction(LSU2);
+ if (pipeline[BranchUnit].instr && pipeline[BranchUnit].remaining == 0)
+ complete_instruction(BranchUnit);
+
+ if (pipeline[LSU1].instr && pipeline[LSU1].remaining == 0 && !pipeline[LSU2].instr)
+ advance(LSU1, LSU1, LSU2);
+}
+
+static int serializes(PCode *instr) {
+ return instruction_timing[instr->op].serializes;
+}
+
+MachineInfo machine821 = {
+ 1,
+ 0,
+ 0,
+ &latency,
+ &initialize,
+ &can_issue,
+ &issue,
+ &advance_clock,
+ &serializes,
+ &default_uses_vpermute_unit
+};
diff --git a/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulationAltiVec.c b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulationAltiVec.c
new file mode 100644
index 0000000..d261ee9
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/Scheduler/MachineSimulationAltiVec.c
@@ -0,0 +1,752 @@
+#include "compiler/Scheduler.h"
+#include "compiler/CError.h"
+#include "compiler/PCode.h"
+#include "compiler/PCodeInfo.h"
+
+// https://www.nxp.com/docs/en/reference-manual/MPC7450UM.pdf
+
+typedef enum Stage {
+ BPU, // Branch Prediction Unit
+
+ IU2_1, // Multiple-Cycle Integer Unit
+ IU2_2,
+ IU2_3,
+
+ IU1a, // Single-Cycle Integer Unit
+ IU1b, // Single-Cycle Integer Unit
+ IU1c, // Single-Cycle Integer Unit
+
+ LSU_1, // Load/Store Unit
+ LSU_2,
+ LSU_3,
+ LSU_4,
+
+ FPU_1, // Floating-Point Unit
+ FPU_2,
+ FPU_3,
+ FPU_4,
+
+ VIU1, // Vector Simple Integer Unit
+
+ VPU_1, // Vector Permute Unit
+ VPU_2,
+
+ VIU2_1, // Vector Complex Integer Unit
+ VIU2_2,
+ VIU2_3,
+ VIU2_4,
+
+ VFPU_1, // Vector Floating-Point Unit
+ VFPU_2,
+ VFPU_3,
+ VFPU_4,
+
+ NumStages
+} Stage;
+
+static struct {
+ // the instruction currently in this pipeline stage
+ PCode *instr;
+
+ // how many cycles are left for this instruction to finish
+ int remaining;
+} pipeline_altivec[NumStages];
+
+enum {
+ Queue0,
+ Queue1,
+ Queue2,
+ Queue3,
+ Queue4,
+ Queue5,
+ Queue6,
+ Queue7,
+ NumQueues
+};
+
+static int fetchqueues[NumQueues];
+
+enum {
+ MaxEntries = 16
+};
+
+static struct {
+ // how many entries remain unused in the queue
+ unsigned int free;
+
+ // how many entries are currently used in the queue
+ unsigned int used;
+
+ // the index of the next instruction that will be retired
+ unsigned int nextToRetire;
+
+ // the index of the next free slot that will be used when an instruction is dispatched
+ unsigned int nextFreeSlot;
+
+ // circular array of entries in the completion queue
+ struct {
+ PCode *instr;
+ int completed;
+ } entries[MaxEntries];
+} completionbuffers;
+
+static struct {
+ short index;
+
+ // the initial stage for this instruction
+ Stage stage;
+
+ // the total amount of cycles required by this instruction
+ char latency;
+
+ // how long it takes to finish each stage
+ char cycles[4];
+
+ // does this instruction serialise?
+ char serializes;
+
+ char unused;
+} instruction_timing[] = {
+ 0, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_B
+ 1, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BL
+ 2, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BC
+ 3, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BCLR
+ 4, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BCCTR
+ 5, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BT
+ 6, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BTLR
+ 7, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BTCTR
+ 8, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BF
+ 9, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BFLR
+ 10, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BFCTR
+ 11, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BDNZ
+ 12, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BDNZT
+ 13, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BDNZF
+ 14, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BDZ
+ 15, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BDZT
+ 16, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BDZF
+ 17, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BLR
+ 18, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BCTR
+ 19, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BCTRL
+ 20, BPU, 0, 0, 0, 0, 0, 0, 0, // PC_BLRL
+ 21, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LBZ
+ 22, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LBZU
+ 23, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LBZX
+ 24, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LBZUX
+ 25, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LHZ
+ 26, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LHZU
+ 27, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LHZX
+ 28, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LHZUX
+ 29, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LHA
+ 30, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LHAU
+ 31, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LHAX
+ 32, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LHAUX
+ 33, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LHBRX
+ 34, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LWZ
+ 35, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LWZU
+ 36, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LWZX
+ 37, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LWZUX
+ 38, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LWBRX
+ 39, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_LMW
+ 40, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STB
+ 41, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STBU
+ 42, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STBX
+ 43, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STBUX
+ 44, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STH
+ 45, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STHU
+ 46, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STHX
+ 47, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STHUX
+ 48, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STHBRX
+ 49, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STW
+ 50, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STWU
+ 51, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STWX
+ 52, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STWUX
+ 53, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STWBRX
+ 54, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_STMW
+ 55, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_DCBF
+ 56, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_DCBST
+ 57, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_DCBT
+ 58, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_DCBTST
+ 59, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_DCBZ
+ 60, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ADD
+ 61, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ADDC
+ 62, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ADDE
+ 63, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ADDI
+ 64, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ADDIC
+ 65, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ADDICR
+ 66, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ADDIS
+ 67, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ADDME
+ 68, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ADDZE
+ 69, IU2_1, 23, 23, 0, 0, 0, 0, 0, // PC_DIVW
+ 70, IU2_1, 23, 23, 0, 0, 0, 0, 0, // PC_DIVWU
+ 71, IU2_1, 4, 2, 2, 0, 0, 0, 0, // PC_MULHW
+ 72, IU2_1, 4, 2, 2, 0, 0, 0, 0, // PC_MULHWU
+ 73, IU2_1, 3, 1, 1, 1, 0, 0, 0, // PC_MULLI
+ 74, IU2_1, 4, 2, 2, 0, 0, 0, 0, // PC_MULLW
+ 75, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_NEG
+ 76, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_SUBF
+ 77, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_SUBFC
+ 78, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_SUBFE
+ 79, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_SUBFIC
+ 80, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_SUBFME
+ 81, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_SUBFZE
+ 82, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_CMPI
+ 83, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_CMP
+ 84, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_CMPLI
+ 85, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_CMPL
+ 86, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ANDI
+ 87, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ANDIS
+ 88, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ORI
+ 89, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ORIS
+ 90, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_XORI
+ 91, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_XORIS
+ 92, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_AND
+ 93, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_OR
+ 94, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_XOR
+ 95, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_NAND
+ 96, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_NOR
+ 97, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_EQV
+ 98, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ANDC
+ 99, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ORC
+ 100, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_EXTSB
+ 101, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_EXTSH
+ 102, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_CNTLZW
+ 103, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_RLWINM
+ 104, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_RLWNM
+ 105, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_RLWIMI
+ 106, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_SLW
+ 107, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_SRW
+ 108, IU1a, 2, 2, 0, 0, 0, 0, 0, // PC_SRAWI
+ 109, IU1a, 2, 2, 0, 0, 0, 0, 0, // PC_SRAW
+ 110, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_CRAND
+ 111, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_CRANDC
+ 112, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_CREQV
+ 113, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_CRNAND
+ 114, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_CRNOR
+ 115, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_CROR
+ 116, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_CRORC
+ 117, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_CRXOR
+ 118, IU2_1, 1, 1, 0, 0, 0, 1, 0, // PC_MCRF
+ 119, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_MTXER
+ 120, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_MTCTR
+ 121, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_MTLR
+ 122, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_MTCRF
+ 123, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_MTMSR
+ 124, IU2_1, 3, 3, 0, 0, 0, 1, 0, // PC_MTSPR
+ 125, IU2_1, 3, 2, 1, 0, 0, 0, 0, // PC_MFMSR
+ 126, IU2_1, 3, 3, 0, 0, 0, 1, 0, // PC_MFSPR
+ 127, IU2_1, 1, 1, 0, 0, 0, 1, 0, // PC_MFXER
+ 128, IU2_1, 1, 1, 0, 0, 0, 1, 0, // PC_MFCTR
+ 129, IU2_1, 1, 1, 0, 0, 0, 1, 0, // PC_MFLR
+ 130, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_MFCR
+ 131, FPU_1, 5, 5, 0, 0, 0, 1, 0, // PC_MFFS
+ 132, FPU_1, 5, 5, 0, 0, 0, 1, 0, // PC_MTFSF
+ 133, LSU_1, 3, 3, 0, 0, 0, 1, 0, // PC_EIEIO
+ 134, IU2_1, 1, 1, 0, 0, 0, 1, 0, // PC_ISYNC
+ 135, LSU_1, 35, 35, 0, 0, 0, 1, 0, // PC_SYNC
+ 136, IU2_1, 1, 1, 0, 0, 0, 1, 0, // PC_RFI
+ 137, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_LI
+ 138, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_LIS
+ 139, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_MR
+ 140, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_NOP
+ 141, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_NOT
+ 142, LSU_1, 4, 1, 1, 1, 1, 0, 0, // PC_LFS
+ 143, LSU_1, 4, 1, 1, 1, 1, 0, 0, // PC_LFSU
+ 144, LSU_1, 4, 1, 1, 1, 1, 0, 0, // PC_LFSX
+ 145, LSU_1, 4, 1, 1, 1, 1, 0, 0, // PC_LFSUX
+ 146, LSU_1, 4, 1, 1, 1, 1, 0, 0, // PC_LFD
+ 147, LSU_1, 4, 1, 1, 1, 1, 0, 0, // PC_LFDU
+ 148, LSU_1, 4, 1, 1, 1, 1, 0, 0, // PC_LFDX
+ 149, LSU_1, 4, 1, 1, 1, 1, 0, 0, // PC_LFDUX
+ 150, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_STFS
+ 151, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_STFSU
+ 152, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_STFSX
+ 153, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_STFSUX
+ 154, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_STFD
+ 155, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_STFDU
+ 156, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_STFDX
+ 157, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_STFDUX
+ 158, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FMR
+ 159, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FABS
+ 160, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FNEG
+ 161, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FNABS
+ 162, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FADD
+ 163, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FADDS
+ 164, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FSUB
+ 165, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FSUBS
+ 166, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FMUL
+ 167, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FMULS
+ 168, FPU_1, 35, 35, 0, 0, 0, 0, 0, // PC_FDIV
+ 169, FPU_1, 21, 21, 0, 0, 0, 0, 0, // PC_FDIVS
+ 170, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FMADD
+ 171, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FMADDS
+ 172, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FMSUB
+ 173, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FMSUBS
+ 174, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FNMADD
+ 175, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FNMADDS
+ 176, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FNMSUB
+ 177, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FNMSUBS
+ 178, FPU_1, 14, 14, 0, 0, 0, 0, 0, // PC_FRES
+ 179, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FRSQRTE
+ 180, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FSEL
+ 181, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FRSP
+ 182, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FCTIW
+ 183, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FCTIWZ
+ 184, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FCMPU
+ 185, FPU_1, 5, 1, 1, 1, 2, 0, 0, // PC_FCMPO
+ 186, LSU_1, 3, 3, 0, 0, 0, 1, 0, // PC_LWARX
+ 187, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LSWI
+ 188, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_LSWX
+ 189, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STFIWX
+ 190, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_STSWI
+ 191, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_STSWX
+ 192, LSU_1, 3, 1, 1, 1, 0, 1, 0, // PC_STWCX
+ 193, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_ECIWX
+ 194, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_ECOWX
+ 195, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_DCBI
+ 196, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_ICBI
+ 197, IU2_1, 5, 5, 0, 0, 0, 1, 0, // PC_MCRFS
+ 198, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_MCRXR
+ 199, IU2_1, 5, 5, 0, 0, 0, 0, 0, // PC_MFTB
+ 200, IU2_1, 4, 1, 3, 0, 0, 0, 0, // PC_MFSR
+ 201, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_MTSR
+ 202, IU2_1, 4, 1, 3, 0, 0, 0, 0, // PC_MFSRIN
+ 203, IU2_1, 2, 2, 0, 0, 0, 1, 0, // PC_MTSRIN
+ 204, FPU_1, 5, 5, 0, 0, 0, 1, 0, // PC_MTFSB0
+ 205, FPU_1, 5, 5, 0, 0, 0, 1, 0, // PC_MTFSB1
+ 206, FPU_1, 5, 5, 0, 0, 0, 0, 0, // PC_MTFSFI
+ 207, IU2_1, 1, 1, 0, 0, 0, 1, 0, // PC_SC
+ 208, FPU_1, 1, 1, 0, 0, 0, 0, 0, // PC_FSQRT
+ 209, FPU_1, 1, 1, 0, 0, 0, 0, 0, // PC_FSQRTS
+ 210, LSU_1, 1, 1, 0, 0, 0, 0, 0, // PC_TLBIA
+ 211, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_TLBIE
+ 212, LSU_1, 3, 3, 0, 0, 0, 0, 0, // PC_TLBLD
+ 213, LSU_1, 3, 3, 0, 0, 0, 1, 0, // PC_TLBLI
+ 214, LSU_1, 3, 3, 0, 0, 0, 1, 0, // PC_TLBSYNC
+ 215, IU1a, 2, 2, 0, 0, 0, 0, 0, // PC_TW
+ 216, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_TRAP
+ 217, IU1a, 2, 2, 0, 0, 0, 0, 0, // PC_TWI
+ 218, IU1a, 1, 1, 0, 0, 0, 1, 0, // PC_OPWORD
+ 219, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_MFROM
+ 220, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_DSA
+ 221, IU1a, 1, 1, 0, 0, 0, 0, 0, // PC_ESA
+ 222, IU1a, 1, 0, 0, 0, 0, 0, 0, // PC_DCCCI
+ 223, IU1a, 1, 0, 0, 0, 0, 0, 0, // PC_DCREAD
+ 224, IU1a, 1, 0, 0, 0, 0, 0, 0, // PC_ICBT
+ 225, IU1a, 1, 0, 0, 0, 0, 0, 0, // PC_ICCCI
+ 226, IU1a, 1, 0, 0, 0, 0, 0, 0, // PC_ICREAD
+ 227, IU1a, 1, 0, 0, 0, 0, 0, 0, // PC_RFCI
+ 228, IU1a, 1, 0, 0, 0, 0, 0, 0, // PC_TLBRE
+ 229, IU1a, 1, 0, 0, 0, 0, 0, 0, // PC_TLBSX
+ 230, IU1a, 1, 0, 0, 0, 0, 0, 0, // PC_TLBWE
+ 231, IU1a, 1, 0, 0, 0, 0, 0, 0, // PC_WRTEE
+ 232, IU1a, 1, 0, 0, 0, 0, 0, 0, // PC_WRTEEI
+ 233, IU1a, 1, 0, 0, 0, 0, 0, 0, // PC_MFDCR
+ 234, IU1a, 1, 0, 0, 0, 0, 0, 0, // PC_MTDCR
+ 235, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_DCBA
+ 236, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_DSS
+ 237, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_DSSALL
+ 238, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_DST
+ 239, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_DSTT
+ 240, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_DSTST
+ 241, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_DSTSTT
+ 242, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LVEBX
+ 243, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LVEHX
+ 244, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LVEWX
+ 245, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LVSL
+ 246, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LVSR
+ 247, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LVX
+ 248, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_LVXL
+ 249, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STVEBX
+ 250, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STVEHX
+ 251, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STVEWX
+ 252, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STVX
+ 253, LSU_1, 3, 1, 1, 1, 0, 0, 0, // PC_STVXL
+ 254, VFPU_1, 2, 2, 0, 0, 0, 1, 0, // PC_MFVSCR
+ 255, VFPU_1, 2, 2, 0, 0, 0, 1, 0, // PC_MTVSCR
+ 256, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VADDCUW
+ 257, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VADDFP
+ 258, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VADDSBS
+ 259, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VADDSHS
+ 260, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VADDSWS
+ 261, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VADDUBM
+ 262, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VADDUBS
+ 263, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VADDUHM
+ 264, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VADDUHS
+ 265, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VADDUWM
+ 266, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VADDUWS
+ 267, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VAND
+ 268, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VANDC
+ 269, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VAVGSB
+ 270, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VAVGSH
+ 271, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VAVGSW
+ 272, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VAVGUB
+ 273, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VAVGUH
+ 274, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VAVGUW
+ 275, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VCFSX
+ 276, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VCFUX
+ 277, VFPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VCMPBFP
+ 278, VFPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VCMPEQFP
+ 279, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPEQUB
+ 280, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPEQUH
+ 281, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPEQUW
+ 282, VFPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VCMPGEFP
+ 283, VFPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VCMPGTFP
+ 284, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPGTSB
+ 285, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPGTSH
+ 286, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPGTSW
+ 287, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPGTUB
+ 288, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPGTUH
+ 289, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VCMPGTUW
+ 290, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VCTSXS
+ 291, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VCTUXS
+ 292, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VEXPTEFP
+ 293, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VLOGEFP
+ 294, VFPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VMAXFP
+ 295, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VMAXSB
+ 296, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VMAXSH
+ 297, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VMAXSW
+ 298, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VMAXUB
+ 299, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VMAXUH
+ 300, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VMAXUW
+ 301, VFPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VMINFP
+ 302, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VMINSB
+ 303, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VMINSH
+ 304, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VMINSW
+ 305, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VMINUB
+ 306, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VMINUH
+ 307, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VMINUW
+ 308, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VMRGHB
+ 309, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VMRGHH
+ 310, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VMRGHW
+ 311, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VMRGLB
+ 312, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VMRGLH
+ 313, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VMRGLW
+ 314, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMULESB
+ 315, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMULESH
+ 316, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMULEUB
+ 317, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMULEUH
+ 318, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMULOSB
+ 319, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMULOSH
+ 320, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMULOUB
+ 321, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMULOUH
+ 322, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VNOR
+ 323, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VOR
+ 324, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VPKPX
+ 325, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VPKSHSS
+ 326, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VPKSHUS
+ 327, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VPKSWSS
+ 328, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VPKSWUS
+ 329, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VPKUHUM
+ 330, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VPKUHUS
+ 331, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VPKUWUM
+ 332, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VPKUWUS
+ 333, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VREFP
+ 334, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VRFIM
+ 335, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VRFIN
+ 336, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VRFIP
+ 337, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VRFIZ
+ 338, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VRLB
+ 339, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VRLH
+ 340, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VRLW
+ 341, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VRSQRTEFP
+ 342, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VSL
+ 343, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSLB
+ 344, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSLH
+ 345, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VSLO
+ 346, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSLW
+ 347, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VSPLTB
+ 348, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VSPLTH
+ 349, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VSPLTW
+ 350, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VSPLTISB
+ 351, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VSPLTISH
+ 352, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VSPLTISW
+ 353, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VSR
+ 354, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSRAB
+ 355, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSRAH
+ 356, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSRAW
+ 357, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSRB
+ 358, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSRH
+ 359, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VSRO
+ 360, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSRW
+ 361, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBCUW
+ 362, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VSUBFP
+ 363, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBSBS
+ 364, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBSHS
+ 365, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBSWS
+ 366, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBUBM
+ 367, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBUBS
+ 368, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBUHM
+ 369, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBUHS
+ 370, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBUWM
+ 371, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSUBUWS
+ 372, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VSUMSWS
+ 373, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VSUM2SWS
+ 374, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VSUM4SBS
+ 375, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VSUM4SHS
+ 376, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VSUM4UBS
+ 377, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VUPKHPX
+ 378, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VUPKHSB
+ 379, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VUPKHSH
+ 380, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VUPKLPX
+ 381, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VUPKLSB
+ 382, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VUPKLSH
+ 383, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VXOR
+ 384, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMADDFP
+ 385, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMHADDSHS
+ 386, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMHRADDSHS
+ 387, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMLADDUHM
+ 388, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMSUMMBM
+ 389, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMSUMSHM
+ 390, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMSUMSHS
+ 391, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMSUMUBM
+ 392, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMSUMUHM
+ 393, VIU2_1, 4, 1, 1, 1, 1, 0, 0, // PC_VMSUMUHS
+ 394, VFPU_1, 4, 1, 1, 1, 1, 0, 0, // PC_VNMSUBFP
+ 395, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VPERM
+ 396, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VSEL
+ 397, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VSLDOI
+ 398, VIU1, 1, 1, 0, 0, 0, 0, 0, // PC_VMR
+ 399, VPU_1, 2, 1, 1, 0, 0, 0, 0, // PC_VMRP
+ -1, IU2_1, 1, 1, 0, 0, 0, 1, 0
+};
+
+enum { NumPipelineUnits = 6 };
+static struct {
+ Stage start, end;
+} pipeline_units[8] = {
+ IU2_1, IU2_3,
+ LSU_1, LSU_4,
+ FPU_1, FPU_4,
+ VPU_1, VPU_2,
+ VIU2_1, VIU2_4,
+ VFPU_1, VFPU_4
+};
+
+enum { NumFinalStages = 11 };
+static Stage finalstages[16] = {
+ BPU, IU2_3, IU1a, IU1b,
+ IU1c, LSU_4, FPU_4, VIU1,
+ VPU_2, VIU2_4, VFPU_4
+};
+
+// forward decl
+static void complete_instruction(int stage);
+
+static void advance(int firstStage, int oldStage, int newStage) {
+ PCode *instr = pipeline_altivec[oldStage].instr;
+ int cycles = instruction_timing[instr->op].cycles[newStage - firstStage];
+ pipeline_altivec[newStage].instr = instr;
+ pipeline_altivec[newStage].remaining = cycles;
+ pipeline_altivec[oldStage].instr = NULL;
+ pipeline_altivec[oldStage].remaining = 0;
+ if (cycles == 0)
+ complete_instruction(newStage);
+}
+
+static void assign_completion_buffer(PCode *instr) {
+ completionbuffers.used++;
+ completionbuffers.free--;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].instr = instr;
+ completionbuffers.entries[completionbuffers.nextFreeSlot].completed = 0;
+ completionbuffers.nextFreeSlot = (completionbuffers.nextFreeSlot + 1) % MaxEntries;
+}
+
+static void complete_instruction(int stage) {
+ PCode *instr = pipeline_altivec[stage].instr;
+ int buf = 0;
+ while (buf < MaxEntries && completionbuffers.entries[buf].instr != instr)
+ buf++;
+
+ completionbuffers.entries[buf].completed = 1;
+ pipeline_altivec[stage].instr = NULL;
+}
+
+static void retire_instruction(void) {
+ completionbuffers.entries[completionbuffers.nextToRetire].instr = NULL;
+ completionbuffers.entries[completionbuffers.nextToRetire].completed = 0;
+ completionbuffers.used--;
+ completionbuffers.free++;
+ completionbuffers.nextToRetire = (completionbuffers.nextToRetire + 1) % MaxEntries;
+}
+
+static int latency(PCode *instr) {
+ int cycles = instruction_timing[instr->op].latency;
+ if (PCODE_FLAG_SET_F(instr) & fRecordBit)
+ cycles += 1;
+ if (instr->op == PC_LMW || instr->op == PC_STMW)
+ cycles += instr->argCount - 2;
+ return cycles;
+}
+
+static void initialize(void) {
+ int stage;
+ int i;
+
+ fetchqueues[Queue0] = 1;
+ for (i = 1; i < NumQueues; i++)
+ fetchqueues[i] = 0;
+
+ for (stage = 0; stage < NumStages; stage++)
+ pipeline_altivec[stage].instr = NULL;
+
+ completionbuffers.free = MaxEntries;
+ completionbuffers.used = 0;
+ completionbuffers.nextToRetire = 0;
+ completionbuffers.nextFreeSlot = 0;
+ for (i = 0; i < MaxEntries; i++) {
+ completionbuffers.entries[i].instr = NULL;
+ completionbuffers.entries[i].completed = 0;
+ }
+}
+
+static int can_issue(PCode *instr) {
+ int stage;
+
+ if (completionbuffers.free == 0)
+ return 0;
+
+ stage = instruction_timing[instr->op].stage;
+
+ if (stage == IU1a) {
+ int isClear1 = !pipeline_altivec[IU1a].instr;
+ int isClear2 = !pipeline_altivec[IU1b].instr;
+ if (!isClear1 && !isClear2)
+ return 0;
+ } else {
+ if (pipeline_altivec[stage].instr)
+ return 0;
+ }
+
+ if (fetchqueues[Queue1] <= 0)
+ return 0;
+
+ if (stage == FPU_1) {
+ if (fetchqueues[Queue2] < 1 || fetchqueues[Queue5] >= 1)
+ return 0;
+ } else if (stage >= VIU1 && stage <= VFPU_1) {
+ if (fetchqueues[Queue4] < 1 || fetchqueues[Queue7] >= 2)
+ return 0;
+ } else if (stage != BPU) {
+ if (fetchqueues[Queue3] < 1 || fetchqueues[Queue6] >= 3)
+ return 0;
+ }
+
+ return 1;
+}
+
+static void issue(PCode *instr) {
+ int stage = instruction_timing[instr->op].stage;
+ int cycles = instruction_timing[instr->op].cycles[0];
+ assign_completion_buffer(instr);
+
+ CError_ASSERT(879, --fetchqueues[Queue1] >= 0);
+
+ if (stage == FPU_1) {
+ fetchqueues[Queue2]--;
+ fetchqueues[Queue5]++;
+ } else if (stage >= VIU1 && stage <= VFPU_1) {
+ fetchqueues[Queue4]--;
+ fetchqueues[Queue7]++;
+ } else if (stage != BPU) {
+ fetchqueues[Queue3]--;
+ fetchqueues[Queue6]++;
+ }
+
+ fetchqueues[Queue2] = (fetchqueues[Queue1] < fetchqueues[Queue2]) ? fetchqueues[Queue1] : fetchqueues[Queue2];
+ fetchqueues[Queue3] = (fetchqueues[Queue1] < fetchqueues[Queue3]) ? fetchqueues[Queue1] : fetchqueues[Queue3];
+ fetchqueues[Queue4] = (fetchqueues[Queue1] < fetchqueues[Queue4]) ? fetchqueues[Queue1] : fetchqueues[Queue4];
+
+ if (stage == IU1a) {
+ if (!pipeline_altivec[IU1a].instr)
+ stage = IU1a;
+ else if (!pipeline_altivec[IU1b].instr)
+ stage = IU1b;
+ else if (!pipeline_altivec[IU1c].instr)
+ stage = IU1c;
+ }
+
+ pipeline_altivec[stage].instr = instr;
+ pipeline_altivec[stage].remaining = cycles;
+}
+
+static void advance_clock(void) {
+ int num;
+ int i;
+ unsigned int unit;
+
+ for (i = 0; i < NumStages; i++) {
+ if (pipeline_altivec[i].instr && pipeline_altivec[i].remaining)
+ --pipeline_altivec[i].remaining;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (completionbuffers.used == 0)
+ break;
+ if (completionbuffers.entries[completionbuffers.nextToRetire].completed == 0)
+ break;
+ retire_instruction();
+ }
+
+ unit = 0;
+ do {
+ if (pipeline_altivec[finalstages[unit]].instr && pipeline_altivec[finalstages[unit]].remaining == 0)
+ complete_instruction(finalstages[unit]);
+ } while (++unit < NumFinalStages);
+
+ unit = 0;
+ do {
+ Stage first;
+ Stage current;
+ first = pipeline_units[unit].start;
+ for (current = first; current < pipeline_units[unit].end; current++) {
+ if (pipeline_altivec[current].instr && pipeline_altivec[current].remaining == 0 && !pipeline_altivec[current + 1].instr)
+ advance(first, current, current + 1);
+ }
+ } while (++unit < NumPipelineUnits);
+
+ fetchqueues[Queue5] = 0;
+ fetchqueues[Queue6] = 0;
+ fetchqueues[Queue7] = 0;
+
+#define CHEAP_MIN(a, b) ( ((a) < (b)) ? (a) : (b) )
+ num = 2 - fetchqueues[Queue2];
+ num += 6 - fetchqueues[Queue3];
+ num += 4 - fetchqueues[Queue4];
+ num = (num > 3) ? 3 : num;
+ num = (completionbuffers.free < num) ? completionbuffers.free : num;
+ if (fetchqueues[Queue0] < num)
+ num = fetchqueues[Queue0];
+
+ fetchqueues[Queue1] += num;
+ fetchqueues[Queue0] -= num;
+
+ fetchqueues[Queue2] = CHEAP_MIN(fetchqueues[Queue1], CHEAP_MIN(2, fetchqueues[Queue2] + num));
+ fetchqueues[Queue3] = CHEAP_MIN(fetchqueues[Queue1], CHEAP_MIN(6, fetchqueues[Queue3] + num));
+ fetchqueues[Queue4] = CHEAP_MIN(fetchqueues[Queue1], CHEAP_MIN(4, fetchqueues[Queue4] + num));
+
+ CError_ASSERT(991, fetchqueues[Queue1] <= (fetchqueues[Queue2] + fetchqueues[Queue3] + fetchqueues[Queue4]));
+
+ if (fetchqueues[Queue0] <= 8)
+ fetchqueues[Queue0] += 4;
+}
+
+static int serializes(PCode *instr) {
+ return instruction_timing[instr->op].serializes;
+}
+
+static int uses_vpermute_unit_altivec(PCode *instr) {
+ return instruction_timing[instr->op].stage == VPU_1;
+}
+
+MachineInfo machine7450 = {
+ 6,
+ 1,
+ 4,
+ &latency,
+ &initialize,
+ &can_issue,
+ &issue,
+ &advance_clock,
+ &serializes,
+ &uses_vpermute_unit_altivec
+};
diff --git a/compiler_and_linker/BackEnd/PowerPC/Scheduler/Scheduler.c b/compiler_and_linker/BackEnd/PowerPC/Scheduler/Scheduler.c
new file mode 100644
index 0000000..23b580f
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/Scheduler/Scheduler.c
@@ -0,0 +1,547 @@
+#include "compiler/Scheduler.h"
+#include "compiler/CError.h"
+#include "compiler/CParser.h"
+#include "compiler/Alias.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/PCode.h"
+#include "compiler/Registers.h"
+
+#ifdef __MWERKS__
+#pragma options align=mac68k
+#endif
+typedef struct DGNode {
+ struct DGNode *x0;
+ struct DGNode *x4;
+ struct DGSuccessor *successors;
+ PCode *instr;
+ UInt16 x10;
+ UInt16 x12;
+ UInt16 x14;
+ UInt16 x16;
+ short predCount;
+} DGNode;
+
+typedef struct DGSuccessor {
+ struct DGSuccessor *next;
+ DGNode *node;
+ UInt16 x8;
+} DGSuccessor;
+
+typedef struct DGNodeList {
+ struct DGNodeList *next;
+ DGNode *node;
+} DGNodeList;
+#ifdef __MWERKS__
+#pragma options align=reset
+#endif
+
+static DGNodeList **register_uses[RegClassMax];
+static DGNodeList **register_defs[RegClassMax];
+static DGNodeList *memory_uses;
+static DGNodeList *memory_defs;
+static DGNodeList *side_effects;
+static DGNodeList *volatile_refs;
+static DGNode *defaultsuccessor;
+static UInt16 criticalpath;
+static MachineInfo *MI;
+
+static void initresources(void) {
+ int rclass;
+ int i;
+
+ for (rclass = 0; (char) rclass < RegClassMax; rclass++) {
+ register_uses[(char) rclass] = oalloc(sizeof(DGNodeList *) * used_virtual_registers[(char) rclass]);
+ register_defs[(char) rclass] = oalloc(sizeof(DGNodeList *) * used_virtual_registers[(char) rclass]);
+ for (i = 0; i < used_virtual_registers[(char) rclass]; i++) {
+ register_uses[(char) rclass][i] = register_defs[(char) rclass][i] = NULL;
+ }
+ }
+
+ memory_uses = memory_defs = NULL;
+ side_effects = NULL;
+ volatile_refs = NULL;
+ criticalpath = 0;
+}
+
+static DGNode *makedgnode(PCode *instr) {
+ DGNode *node;
+
+ node = oalloc(sizeof(DGNode));
+ node->x0 = NULL;
+ node->x4 = NULL;
+ node->successors = NULL;
+ node->instr = instr;
+ node->x10 = node->x16 = MI->latency(instr);
+ node->x12 = 0;
+ node->x14 = 0;
+ node->predCount = 0;
+ return node;
+}
+
+static DGNode *adddgnode(DGNode *head, DGNode *node) {
+ if (head)
+ head->x4 = node;
+ node->x0 = head;
+ return node;
+}
+
+static DGNode *removedgnode(DGNode *head, DGNode *node) {
+ if (node->x4)
+ node->x4->x0 = node->x0;
+ else
+ head = node->x0;
+
+ if (node->x0)
+ node->x0->x4 = node->x4;
+
+ return head;
+}
+
+static void addtolist(DGNodeList **list, DGNode *node) {
+ DGNodeList *entry = oalloc(sizeof(DGNodeList));
+ entry->node = node;
+ entry->next = *list;
+ *list = entry;
+}
+
+static DGNodeList *makedglistnode(DGNode *node) {
+ DGNodeList *list = oalloc(sizeof(DGNodeList));
+ list->next = NULL;
+ list->node = node;
+ return list;
+}
+
+int is_same_operand(PCodeArg *a, PCodeArg *b) {
+ if (a->kind != b->kind)
+ return 0;
+
+ switch (a->kind) {
+ case PCOp_IMMEDIATE:
+ if (a->data.imm.value != b->data.imm.value)
+ return 0;
+ break;
+ case PCOp_REGISTER:
+ if ((char) a->arg != (char) b->arg)
+ return 0;
+ if (a->data.reg.reg != b->data.reg.reg)
+ return 0;
+ break;
+ case PCOp_MEMORY:
+ if (a->data.mem.offset != b->data.mem.offset)
+ return 0;
+ if (a->data.mem.obj != b->data.mem.obj)
+ return 0;
+ break;
+ case PCOp_LABEL:
+ if (a->data.label.label != b->data.label.label)
+ return 0;
+ break;
+ }
+
+ return 1;
+}
+
+static void addsuccessor(DGNode *a, DGNode *b, Boolean flag) {
+ int v6;
+ int r29;
+ DGSuccessor *succ;
+
+ if (flag)
+ v6 = a->x10;
+ else
+ v6 = 0;
+
+ if (a != b) {
+ r29 = (v6 > 0) ? v6 : 0;
+ for (succ = a->successors; succ; succ = succ->next) {
+ if (succ->node == b) {
+ if (succ->x8 < r29) {
+ succ->x8 = r29;
+ if (b->x16 + succ->x8 > a->x16)
+ a->x16 = b->x16 + succ->x8;
+ }
+ return;
+ }
+ }
+
+ succ = oalloc(sizeof(DGSuccessor));
+ succ->node = b;
+ succ->next = a->successors;
+ a->successors = succ;
+ succ->x8 = r29;
+
+ if (flag && (succ->node->instr->flags & fIsBranch))
+ succ->x8 += MI->x8;
+
+ b->predCount++;
+
+ if (b->x16 + succ->x8 > a->x16)
+ a->x16 = b->x16 + succ->x8;
+ }
+}
+
+static void serializeall(DGNode *nodes, DGNode *node) {
+ DGNode *scan;
+
+ for (scan = nodes; scan; scan = scan->x0)
+ addsuccessor(node, scan, 0);
+}
+
+static void serializelist(DGNode *node, DGNodeList *list) {
+ while (list) {
+ if (list->node != node)
+ addsuccessor(node, list->node, 0);
+ list = list->next;
+ }
+}
+
+static void serializeregister(int rclass, DGNode *node, DGNodeList **defs, DGNodeList **uses, int isWrite) {
+ DGNodeList *list;
+
+ if (isWrite) {
+ for (list = *uses; list; list = list->next) {
+ if (list->node != node)
+ addsuccessor(node, list->node, 1);
+ }
+ for (list = *defs; list; list = list->next) {
+ if (list->node != node)
+ addsuccessor(node, list->node, ((char) rclass == RegClass_SPR) || (MI->x4 == 0));
+ }
+
+ list = makedglistnode(node);
+ list->next = *defs;
+ *defs = list;
+ } else {
+ for (list = *defs; list; list = list->next) {
+ if (list->node != node)
+ addsuccessor(node, list->node, ((char) rclass == RegClass_SPR) || (MI->x4 == 0));
+ }
+
+ list = makedglistnode(node);
+ list->next = *uses;
+ *uses = list;
+ }
+}
+
+static void serialize_load(DGNode *node) {
+ DGNodeList *list;
+
+ for (list = memory_defs; list; list = list->next) {
+ if (may_alias(node->instr, list->node->instr))
+ addsuccessor(node, list->node, 1);
+ }
+
+ addtolist(&memory_uses, node);
+}
+
+static void serialize_store(DGNode *node) {
+ DGNodeList *list;
+
+ for (list = memory_uses; list; list = list->next) {
+ if (may_alias(node->instr, list->node->instr))
+ addsuccessor(node, list->node, 1);
+ }
+ for (list = memory_defs; list; list = list->next) {
+ if (may_alias(node->instr, list->node->instr))
+ addsuccessor(node, list->node, 1);
+ }
+
+ addtolist(&memory_defs, node);
+ if (node->instr->flags & fPCodeFlag40000)
+ addtolist(&memory_uses, node);
+}
+
+static void findsuccessors(DGNode *nodes, DGNode *node) {
+ PCode *instr;
+ PCodeArg *op;
+ int i;
+
+ instr = node->instr;
+ for (i = 0, op = instr->args; i < instr->argCount; i++, op++) {
+ switch (op->kind) {
+ case PCOp_IMMEDIATE:
+ case PCOp_MEMORY:
+ break;
+ case PCOp_REGISTER:
+ if (
+ op->data.reg.reg < 0 ||
+ op->data.reg.reg > used_virtual_registers[(char) op->arg]
+ )
+ {
+ CError_FATAL(491);
+ }
+
+ if (op->kind == PCOp_REGISTER && op->arg == RegClass_GPR) {
+ if (op->data.reg.reg == Register2)
+ break;
+ if (op->data.reg.reg == Register0 && !(op->data.reg.effect & (EffectRead | EffectWrite)))
+ break;
+ }
+
+ serializeregister(
+ op->arg,
+ node,
+ &register_defs[(char) op->arg][op->data.reg.reg],
+ &register_uses[(char) op->arg][op->data.reg.reg],
+ op->data.reg.effect & EffectWrite
+ );
+
+ break;
+ }
+ }
+
+ if (instr->flags & (fIsRead | fPCodeFlag20000))
+ serialize_load(node);
+ else if (instr->flags & (fIsWrite | fPCodeFlag40000))
+ serialize_store(node);
+
+ if (instr->flags & fIsVolatile) {
+ serializelist(node, volatile_refs);
+ addtolist(&volatile_refs, node);
+ }
+
+ if (
+ ((instr->flags & fIsCall | fIsBranch) && (instr->flags & fLink)) ||
+ (instr->flags & fSideEffects) ||
+ MI->serializes(instr)
+ )
+ {
+ serializeall(nodes, node);
+ addtolist(&side_effects, node);
+ }
+
+ if (side_effects)
+ serializelist(node, side_effects);
+
+ if (!node->successors && defaultsuccessor)
+ addsuccessor(node, defaultsuccessor, 0);
+
+ if (node->x16 > criticalpath)
+ criticalpath = node->x16;
+}
+
+static void computedeadlines(DGNode *nodes) {
+ while (nodes) {
+ nodes->x14 = criticalpath - nodes->x16;
+ nodes = nodes->x0;
+ }
+}
+
+static int uncovering(DGNode *node) {
+ int counter;
+ DGSuccessor *succ;
+
+ counter = 0;
+ for (succ = node->successors; succ; succ = succ->next) {
+ if (succ->node->predCount == 1)
+ counter++;
+ }
+
+ return counter;
+}
+
+static DGNode *selectinstruction(DGNode *nodes, UInt16 counter) {
+ DGNode *node;
+ DGNode *node2;
+ int a;
+ int b;
+
+ node = nodes;
+ while (node) {
+ if (node->predCount == 0 && node->x12 <= counter && MI->can_issue(node->instr))
+ break;
+ node = node->x0;
+ }
+
+ if (!node)
+ return NULL;
+
+ for (node2 = node->x0; node2; node2 = node2->x0) {
+ if (
+ node2->predCount == 0 &&
+ node2->x12 <= counter &&
+ MI->can_issue(node2->instr) &&
+ (node->x14 > counter || node2->x14 <= counter)
+ )
+ {
+ if (node->x14 > counter && node2->x14 <= counter) {
+ node = node2;
+ continue;
+ }
+
+ if ((a = uncovering(node)) > (b = uncovering(node2)))
+ continue;
+
+ if (a < b) {
+ node = node2;
+ continue;
+ }
+
+ if (node->x16 > node2->x16)
+ continue;
+
+ if (node->x16 < node2->x16) {
+ node = node2;
+ continue;
+ }
+
+ if (coloring) {
+ if (opcodeinfo[node->instr->op].x9 < opcodeinfo[node2->instr->op].x9)
+ continue;
+
+ if (opcodeinfo[node->instr->op].x9 > opcodeinfo[node2->instr->op].x9)
+ node = node2;
+ }
+ }
+ }
+
+ return node;
+}
+
+static void holdoffsuccessors(DGNode *node, UInt16 counter) {
+ DGSuccessor *succ;
+ DGNode *n;
+
+ for (succ = node->successors; succ; succ = succ->next) {
+ n = succ->node;
+ n->predCount--;
+ if (n->x12 < counter + succ->x8)
+ n->x12 = counter + succ->x8;
+ }
+}
+
+static void scheduleblock(PCodeBlock *block) {
+ DGNode *node;
+ UInt16 counter;
+ PCode *instr;
+ UInt16 i;
+ DGNode *head;
+
+ initresources();
+ defaultsuccessor = NULL;
+ head = NULL;
+
+ for (instr = block->lastPCode; instr; instr = instr->prevPCode) {
+ DGNode *n = makedgnode(instr);
+ findsuccessors(head, n);
+ if (instr->flags & fIsBranch)
+ defaultsuccessor = n;
+ head = adddgnode(head, n);
+ }
+
+ computedeadlines(head);
+ block->firstPCode = block->lastPCode = NULL;
+ block->pcodeCount = 0;
+
+ MI->initialize();
+ counter = 0;
+ while (head != NULL) {
+ for (i = 0; i < MI->x0; i++) {
+ if (head == NULL)
+ break;
+
+ node = selectinstruction(head, counter);
+ if (!node)
+ break;
+
+ instr = node->instr;
+ if (node->successors)
+ holdoffsuccessors(node, counter);
+
+ appendpcode(block, instr);
+ MI->issue(instr);
+ head = removedgnode(head, node);
+ }
+
+ MI->advance_clock();
+ counter++;
+ }
+
+ freeoheap();
+}
+
+void scheduleinstructions(Boolean flag) {
+ PCodeBlock *block;
+ int cpu;
+
+ cpu = copts.scheduling;
+ if (cpu == 10) {
+ MI = &machine7450;
+ } else if (copts.altivec_model != 0 || cpu == 7) {
+ MI = &machine7400;
+ } else if (cpu == 2) {
+ MI = &machine603;
+ } else if (cpu == 5) {
+ MI = &machine603e;
+ } else if (cpu == 3) {
+ MI = &machine604;
+ } else if (cpu == 6) {
+ MI = &machine604;
+ } else if (cpu == 4) {
+ MI = &machine750;
+ } else if (cpu == 1) {
+ MI = &machine601;
+ } else if (cpu == 9) {
+ MI = &machine821;
+ } else {
+ MI = &machine603;
+ }
+
+ gather_alias_info();
+
+ for (block = pcbasicblocks; block; block = block->nextBlock) {
+ if (
+ block->pcodeCount > 2 &&
+ (flag || !(block->flags & (fIsProlog | fIsEpilogue))) &&
+ !(block->flags & fScheduled)
+ )
+ {
+ scheduleblock(block);
+ block->flags |= fScheduled;
+ }
+ }
+}
+
+int is_dependent(PCode *a, PCode *b, char rclass) {
+ int i;
+ int reg;
+ PCodeArg *op;
+
+ if (
+ b &&
+ b->argCount >= 1 &&
+ b->args[0].kind == PCOp_REGISTER &&
+ (char) b->args[0].arg == rclass &&
+ (b->args[0].data.reg.effect & EffectWrite)
+ )
+ {
+ reg = b->args[0].data.reg.reg;
+ for (i = 0; i < a->argCount; i++) {
+ op = &a->args[i];
+ if (
+ op->kind == PCOp_REGISTER &&
+ (char) op->arg == rclass &&
+ (op->data.reg.effect & (EffectRead | EffectWrite)) &&
+ op->data.reg.reg == reg
+ )
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int uses_vpermute_unit(PCode *instr) {
+ int cpu;
+
+ cpu = copts.scheduling;
+ if (cpu == 10)
+ return machine7450.uses_vpermute_unit(instr);
+ if (copts.altivec_model != 0 || cpu == 7)
+ return machine7400.uses_vpermute_unit(instr);
+ return 0;
+}
+
+int default_uses_vpermute_unit(PCode *instr) {
+ return 0;
+}