#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"); 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-B+%" PRId32, refis1 ? "-" : "", operand->data.labeldiff.offset); else tmp = sprintf(buf, "%sB-B%" PRId32 "+%" PRId32, refis1 ? "-" : "", operand->data.labeldiff.labelB->block->blockIndex, operand->data.labeldiff.offset); } else { if (b_null) tmp = sprintf(buf, "%sB%" PRId32 "-B+%" 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; }