MWCC/compiler_and_linker/unsorted/PCodeInfo.c

1356 lines
45 KiB
C

#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, "%ld", 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%ld", operand->data.label.label->block->blockIndex);
} else {
tmp = sprintf(buf, "%.8lX", 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>+%ld", refis1 ? "-" : "", operand->data.labeldiff.offset);
else
tmp = sprintf(buf, "%sB<unknown>-B%ld+%ld", refis1 ? "-" : "", operand->data.labeldiff.labelB->block->blockIndex, operand->data.labeldiff.offset);
} else {
if (b_null)
tmp = sprintf(buf, "%sB%ld-B<unknown>+%ld", refis1 ? "-" : "", operand->data.labeldiff.labelA->block->blockIndex, operand->data.labeldiff.offset);
else
tmp = sprintf(buf, "%sB%ld-B%ld+%ld", 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%ld", (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");
// i think these are the wrong way round lol
if (flagSetT & fIsPtrOp)
buf += sprintf(buf, "; fIsPtrOp");
if (flagSetF) {
if (flagSetF & fLink)
buf += sprintf(buf, "; fLink");
if (flagSetF & fAbsolute)
buf += sprintf(buf, "; fAbsolute");
if (flagSetF & fBranchTaken)
buf += sprintf(buf, "; fBranchTaken");
if (flagSetF & fBranchNotTaken)
buf += sprintf(buf, "; fBranchNotTaken");
} else if (flagSetT) {
if (flagSetT & fSetsCarry)
buf += sprintf(buf, "; fSetsCarry");
if (flagSetT & 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;
}