2022-11-07 03:06:21 +00:00
|
|
|
#include "compiler/PCodeInfo.h"
|
|
|
|
#include "compiler/CError.h"
|
2022-12-29 12:32:55 +00:00
|
|
|
#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"
|
2022-11-07 03:06:21 +00:00
|
|
|
|
|
|
|
#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 {
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_FATAL(65);
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_FATAL(110);
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-11-20 05:07:22 +00:00
|
|
|
int pcode_const_from_format(const char *format, SInt32 *pResult) {
|
2022-11-07 03:06:21 +00:00
|
|
|
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;
|
2023-01-11 22:29:53 +00:00
|
|
|
SInt32 thing;
|
|
|
|
SInt32 thing2;
|
|
|
|
SInt32 thing3;
|
|
|
|
SInt32 thing4;
|
2022-11-07 03:06:21 +00:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
|
2023-01-11 22:29:53 +00:00
|
|
|
if (info->flags & fCanSetRecordBit)
|
2022-11-07 03:06:21 +00:00
|
|
|
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) {
|
2022-12-29 12:32:55 +00:00
|
|
|
if (arg >= lastArg)
|
|
|
|
CError_FATAL(189);
|
2022-11-07 03:06:21 +00:00
|
|
|
|
|
|
|
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':
|
2022-12-29 12:32:55 +00:00
|
|
|
if (isdigit(format[1]))
|
2022-11-07 03:06:21 +00:00
|
|
|
format += pcode_const_from_format(format + 1, &thing);
|
2022-12-29 12:32:55 +00:00
|
|
|
else
|
|
|
|
CError_FATAL(319);
|
2023-01-13 13:40:30 +00:00
|
|
|
case 's':
|
2022-11-07 03:06:21 +00:00
|
|
|
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 {
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_FATAL(353);
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
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;
|
2022-12-29 12:32:55 +00:00
|
|
|
if (isdigit(format[1]))
|
2022-11-07 03:06:21 +00:00
|
|
|
format += pcode_const_from_format(format + 1, &thing2);
|
2022-12-29 12:32:55 +00:00
|
|
|
else
|
|
|
|
CError_FATAL(371);
|
2022-11-07 03:06:21 +00:00
|
|
|
|
|
|
|
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') {
|
2022-12-29 12:32:55 +00:00
|
|
|
if (isdigit(format[1]))
|
2022-11-07 03:06:21 +00:00
|
|
|
tmp2 = (unsigned char) *(++format);
|
2022-12-29 12:32:55 +00:00
|
|
|
else
|
|
|
|
CError_FATAL(408);
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
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;
|
2022-12-29 12:32:55 +00:00
|
|
|
if (pcode_check_imm_bits(arg->data.imm.value, thing3, tmp2))
|
|
|
|
CError_FATAL(419);
|
2022-11-07 03:06:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'N':
|
|
|
|
arg->kind = PCOp_IMMEDIATE;
|
|
|
|
arg->data.imm.value = va_arg(argList, int);
|
|
|
|
arg->data.imm.obj = NULL;
|
2022-12-29 12:32:55 +00:00
|
|
|
if (pcode_check_imm_bits(arg->data.imm.value, 6, 'u'))
|
|
|
|
CError_FATAL(429);
|
2022-11-07 03:06:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'D':
|
|
|
|
arg->kind = PCOp_IMMEDIATE;
|
|
|
|
arg->data.imm.value = va_arg(argList, int);
|
|
|
|
arg->data.imm.obj = NULL;
|
2022-12-29 12:32:55 +00:00
|
|
|
if (pcode_check_imm_bits(arg->data.imm.value, 10, 'u'))
|
|
|
|
CError_FATAL(438);
|
2022-11-07 03:06:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'B':
|
|
|
|
case 't':
|
|
|
|
arg->kind = PCOp_IMMEDIATE;
|
|
|
|
arg->data.imm.value = va_arg(argList, int);
|
|
|
|
arg->data.imm.obj = NULL;
|
2022-12-29 12:32:55 +00:00
|
|
|
if (pcode_check_imm_bits(arg->data.imm.value, 5, 'u'))
|
|
|
|
CError_FATAL(448);
|
2022-11-07 03:06:21 +00:00
|
|
|
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;
|
2022-12-29 12:32:55 +00:00
|
|
|
if (pcode_check_imm_bits(arg->data.imm.value, 4, 'u'))
|
|
|
|
CError_FATAL(463);
|
2022-11-07 03:06:21 +00:00
|
|
|
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 *);
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(476, obj->otype == OT_OBJECT);
|
2022-11-07 03:06:21 +00:00
|
|
|
arg->data.mem.obj = obj;
|
|
|
|
arg->data.mem.offset = 0;
|
2023-01-13 01:36:56 +00:00
|
|
|
arg->arg = RefType_4;
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'd':
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(490, format[1] == '(');
|
2022-11-07 03:06:21 +00:00
|
|
|
effect = EffectRead;
|
|
|
|
format += 2;
|
|
|
|
if (*format == '=') {
|
|
|
|
effect = EffectWrite;
|
|
|
|
format++;
|
|
|
|
} else if (*format == '+') {
|
|
|
|
effect = EffectRead | EffectWrite;
|
|
|
|
format++;
|
|
|
|
}
|
|
|
|
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(502, format[0] == 'b');
|
2022-11-07 03:06:21 +00:00
|
|
|
|
|
|
|
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) {
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(515, obj->otype == OT_OBJECT);
|
2022-11-07 03:06:21 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2023-01-11 22:29:53 +00:00
|
|
|
if (pcode->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000)) {
|
2022-12-29 12:32:55 +00:00
|
|
|
pcode->alias = make_alias(obj, arg->data.mem.offset, nbytes_loaded_or_stored_by(pcode));
|
2022-11-07 03:06:21 +00:00
|
|
|
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)
|
2022-12-29 12:32:55 +00:00
|
|
|
pcode->alias = make_alias(obj, arg->data.mem.offset, 1);
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(536, obj->datatype == DLOCAL || arg->data.mem.offset == 0);
|
2023-01-11 22:29:53 +00:00
|
|
|
if (pcode->flags & (fIsRead | fIsWrite)) {
|
2022-11-07 03:06:21 +00:00
|
|
|
//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;
|
|
|
|
}
|
|
|
|
|
2023-01-11 22:29:53 +00:00
|
|
|
if (pcode->flags & (fIsBranch | fIsCall)) {
|
2022-11-07 03:06:21 +00:00
|
|
|
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;
|
2023-01-11 22:29:53 +00:00
|
|
|
if (pcode->flags & (fIsRead | fIsWrite))
|
|
|
|
pcode->flags |= fIsPtrOp;
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'M':
|
|
|
|
obj = va_arg(argList, Object *);
|
|
|
|
if (obj) {
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(578, obj->otype == OT_OBJECT);
|
2022-11-07 03:06:21 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(590, obj->datatype == DLOCAL || arg->data.mem.offset == 0);
|
2023-01-11 22:29:53 +00:00
|
|
|
if (pcode->flags & (fIsRead | fIsWrite)) {
|
2022-11-07 03:06:21 +00:00
|
|
|
//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;
|
2023-01-11 22:29:53 +00:00
|
|
|
if (pcode->flags & (fIsRead | fIsWrite))
|
|
|
|
pcode->flags |= fIsPtrOp;
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'p':
|
|
|
|
arg->kind = PCOp_PLACEHOLDEROPERAND;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'O':
|
|
|
|
arg--;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_FATAL(629);
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
while (format[1] && strchr("/<>|*", format[1])) {
|
|
|
|
switch (*(++format)) {
|
|
|
|
case '/':
|
|
|
|
if (format[1] == '2')
|
|
|
|
format++;
|
|
|
|
break;
|
|
|
|
case '<':
|
|
|
|
case '*':
|
|
|
|
case '|':
|
|
|
|
case '>':
|
2022-12-29 12:32:55 +00:00
|
|
|
if (format[1] == 'p')
|
2022-11-07 03:06:21 +00:00
|
|
|
format++;
|
2022-12-29 12:32:55 +00:00
|
|
|
else if (isdigit(format[1]))
|
2022-11-07 03:06:21 +00:00
|
|
|
format += pcode_const_from_format(format + 1, &thing4);
|
2022-12-29 12:32:55 +00:00
|
|
|
else
|
|
|
|
CError_FATAL(659);
|
|
|
|
break;
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2022-12-29 12:32:55 +00:00
|
|
|
if (strlen(name) == 0 || strlen(name) > 3200 || name[0] < 0)
|
|
|
|
CError_FATAL(849);
|
2022-11-07 03:06:21 +00:00
|
|
|
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)
|
2023-01-13 01:36:56 +00:00
|
|
|
tmp = sprintf(buf, "%sB%ld-B<unknown>+%ld", refis1 ? "-" : "", operand->data.labeldiff.labelA->block->blockIndex, operand->data.labeldiff.offset);
|
2022-11-07 03:06:21 +00:00
|
|
|
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) {
|
2023-01-13 01:36:56 +00:00
|
|
|
return expectandformatoperand(
|
|
|
|
operand,
|
|
|
|
operand->kind,
|
|
|
|
(operand->kind == PCOp_REGISTER) ? operand->arg : 'x',
|
|
|
|
-1,
|
|
|
|
buf);
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2023-01-11 22:29:53 +00:00
|
|
|
SInt32 thing;
|
|
|
|
SInt32 thing2;
|
|
|
|
SInt32 thing4;
|
2022-11-07 03:06:21 +00:00
|
|
|
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");
|
2023-01-13 13:40:30 +00:00
|
|
|
break;
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
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':
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(1124, pa->data.reg.reg == 0);
|
2022-11-07 03:06:21 +00:00
|
|
|
buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_SPR, -1, buf);
|
|
|
|
break;
|
|
|
|
case 'C':
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(1129, pa->data.reg.reg == 2);
|
2022-11-07 03:06:21 +00:00
|
|
|
buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_SPR, -1, buf);
|
|
|
|
break;
|
|
|
|
case 'L':
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(1134, pa->data.reg.reg == 1);
|
2022-11-07 03:06:21 +00:00
|
|
|
buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_SPR, -1, buf);
|
|
|
|
break;
|
|
|
|
case 'Z':
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(1139, pa->data.reg.reg == 0);
|
2022-11-07 03:06:21 +00:00
|
|
|
buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_SPR, -1, buf);
|
|
|
|
break;
|
|
|
|
case 'P':
|
2022-12-29 12:32:55 +00:00
|
|
|
if (isdigit(format[1]))
|
2022-11-07 03:06:21 +00:00
|
|
|
format += pcode_const_from_format(format + 1, &thing);
|
2022-12-29 12:32:55 +00:00
|
|
|
else
|
|
|
|
CError_FATAL(1149);
|
2022-11-07 03:06:21 +00:00
|
|
|
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]) {
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_FATAL(1161);
|
2022-11-07 03:06:21 +00:00
|
|
|
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':
|
2023-01-13 13:40:30 +00:00
|
|
|
buf += expectandformatoperand(pa, PCOp_REGISTER, RegClass_CRFIELD, -1, buf);
|
2022-11-07 03:06:21 +00:00
|
|
|
*(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 {
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_FATAL(1227);
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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);
|
2023-01-13 13:40:30 +00:00
|
|
|
break;
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
2023-01-13 13:40:30 +00:00
|
|
|
|
|
|
|
case 'B':
|
|
|
|
buf += expectandformatoperand(pa, PCOp_IMMEDIATE, 'x', 5, buf);
|
2022-11-07 03:06:21 +00:00
|
|
|
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);
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(1283, format[1] == '(');
|
2022-11-07 03:06:21 +00:00
|
|
|
format++;
|
|
|
|
*(buf++) = *(format++);
|
|
|
|
if (*format == '+')
|
|
|
|
format++;
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(1291, format[0] == 'b');
|
2022-11-07 03:06:21 +00:00
|
|
|
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);
|
2023-01-11 22:29:53 +00:00
|
|
|
else if ((pcode->flags & (fIsBranch | fIsCall)) && (pa->kind == PCOp_LABEL))
|
2022-11-07 03:06:21 +00:00
|
|
|
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) {
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_ASSERT(1335, pa->arg == RefType_8 || pa->arg == RefType_B || pa->arg == RefType_C);
|
2022-11-07 03:06:21 +00:00
|
|
|
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:
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_FATAL(1465);
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
while (format[1] && strchr("/<>|*", format[1])) {
|
|
|
|
switch (*(++format)) {
|
|
|
|
case '/':
|
|
|
|
if (format[1] == '2')
|
|
|
|
format++;
|
|
|
|
break;
|
|
|
|
case '<':
|
|
|
|
case '*':
|
|
|
|
case '|':
|
|
|
|
case '>':
|
2022-12-29 12:32:55 +00:00
|
|
|
if (format[1] == 'p')
|
2022-11-07 03:06:21 +00:00
|
|
|
format++;
|
2022-12-29 12:32:55 +00:00
|
|
|
else if (isdigit(format[1]))
|
2022-11-07 03:06:21 +00:00
|
|
|
format += pcode_const_from_format(format + 1, &thing4);
|
2022-12-29 12:32:55 +00:00
|
|
|
else
|
|
|
|
CError_FATAL(1495);
|
|
|
|
break;
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
2023-01-13 20:22:51 +00:00
|
|
|
if (flagSetF & fIsPtrOp)
|
2022-11-07 03:06:21 +00:00
|
|
|
buf += sprintf(buf, "; fIsPtrOp");
|
|
|
|
|
2023-01-13 20:22:51 +00:00
|
|
|
if (flagSetT) {
|
|
|
|
if (flagSetT & fLink)
|
2022-11-07 03:06:21 +00:00
|
|
|
buf += sprintf(buf, "; fLink");
|
2023-01-13 20:22:51 +00:00
|
|
|
if (flagSetT & fAbsolute)
|
2022-11-07 03:06:21 +00:00
|
|
|
buf += sprintf(buf, "; fAbsolute");
|
2023-01-13 20:22:51 +00:00
|
|
|
if (flagSetT & fBranchTaken)
|
2022-11-07 03:06:21 +00:00
|
|
|
buf += sprintf(buf, "; fBranchTaken");
|
2023-01-13 20:22:51 +00:00
|
|
|
if (flagSetT & fBranchNotTaken)
|
2022-11-07 03:06:21 +00:00
|
|
|
buf += sprintf(buf, "; fBranchNotTaken");
|
2023-01-13 20:22:51 +00:00
|
|
|
} else if (flagSetF) {
|
|
|
|
if (flagSetF & fSetsCarry)
|
2022-11-07 03:06:21 +00:00
|
|
|
buf += sprintf(buf, "; fSetsCarry");
|
2023-01-13 20:22:51 +00:00
|
|
|
if (flagSetF & fOverflow)
|
2022-11-07 03:06:21 +00:00
|
|
|
buf += sprintf(buf, "; fOverflow");
|
|
|
|
}
|
|
|
|
|
|
|
|
*buf = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
PCode *makecopyinstruction(PCodeArg *a, PCodeArg *b) {
|
2023-01-13 01:36:56 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2022-11-07 03:06:21 +00:00
|
|
|
|
2023-01-13 01:36:56 +00:00
|
|
|
CError_FATAL(1622);
|
|
|
|
return NULL;
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int is_location_independent(PCode *pcode) {
|
2023-01-13 01:36:56 +00:00
|
|
|
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;
|
|
|
|
}
|
2022-11-07 03:06:21 +00:00
|
|
|
|
2023-01-13 01:36:56 +00:00
|
|
|
return 0;
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int can_reuse_stored_value(PCode *a, PCode *b) {
|
2023-01-13 01:36:56 +00:00
|
|
|
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;
|
|
|
|
}
|
2022-11-07 03:06:21 +00:00
|
|
|
|
2023-01-13 01:36:56 +00:00
|
|
|
return 0;
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int nbytes_loaded_or_stored_by(PCode *pcode) {
|
|
|
|
OpcodeInfo *oinfo = opcodeinfo + pcode->op;
|
2023-01-11 22:29:53 +00:00
|
|
|
if (oinfo->flags & (fIsRead | fIsWrite)) {
|
2022-11-07 03:06:21 +00:00
|
|
|
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:
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_FATAL(2011);
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-29 12:32:55 +00:00
|
|
|
CError_FATAL(2014);
|
2022-11-07 03:06:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void change_num_operands(PCode *pcode, int newNum) {
|
2023-01-13 01:36:56 +00:00
|
|
|
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;
|
2022-11-07 03:06:21 +00:00
|
|
|
|
2023-01-13 01:36:56 +00:00
|
|
|
pcode->argCount = newNum;
|
2022-11-07 03:06:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void change_opcode(PCode *pcode, short opcode) {
|
|
|
|
pcode->flags = (pcode->flags & ~(opcodeinfo[pcode->op].flags & ~fIsPtrOp)) | opcodeinfo[opcode].flags;
|
2023-01-11 22:29:53 +00:00
|
|
|
if ((pcode->flags & fIsMove) && (PCODE_FLAG_SET_F(pcode) & fRecordBit))
|
|
|
|
pcode->flags &= ~fIsMove;
|
2022-11-07 03:06:21 +00:00
|
|
|
pcode->op = opcode;
|
|
|
|
}
|