diff options
author | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
---|---|---|
committer | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
commit | 094b96ca1df4a035b5f93c351f773306c0241f3f (patch) | |
tree | 95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/BackEnd/PowerPC/PCode | |
parent | fc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff) | |
download | MWCC-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/PowerPC/PCode')
-rw-r--r-- | compiler_and_linker/BackEnd/PowerPC/PCode/PCodeInfo.c | 1354 |
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; +} |