summaryrefslogtreecommitdiff
path: root/compiler_and_linker/BackEnd/PowerPC/PCode/PCodeInfo.c
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/PowerPC/PCode/PCodeInfo.c
parentfc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff)
downloadMWCC-094b96ca1df4a035b5f93c351f773306c0241f3f.tar.gz
MWCC-094b96ca1df4a035b5f93c351f773306c0241f3f.zip
move lots of source files around to match their actual placement in the original treemain
Diffstat (limited to 'compiler_and_linker/BackEnd/PowerPC/PCode/PCodeInfo.c')
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/PCode/PCodeInfo.c1354
1 files changed, 1354 insertions, 0 deletions
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;
+}