move lots of source files around to match their actual placement in the original tree

This commit is contained in:
Ash Wolf
2023-01-26 11:30:47 +00:00
parent fc0c4c0df7
commit 094b96ca1d
120 changed files with 400 additions and 392 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,857 @@
#include "compiler/Exceptions.h"
#include "compiler/CError.h"
#include "compiler/CException.h"
#include "compiler/CInit.h"
#include "compiler/CFunc.h"
#include "compiler/CParser.h"
#include "compiler/CompilerTools.h"
#include "compiler/ObjGenMachO.h"
#include "compiler/PCode.h"
#include "compiler/PCodeUtilities.h"
#include "compiler/RegisterInfo.h"
#include "compiler/StackFrame.h"
#include "compiler/objects.h"
static PCAction *pc_actions;
static PCAction *last_pc_action;
EANode *DAG[EAT_NACTIONS];
static GList exceptmodule;
static OLinkList *except_refs;
static OLinkList *last_except_ref;
static EANode *makeEAnode(ExceptionAction *ea) {
EANode *prev;
EANode *node;
for (node = DAG[ea->type]; node; node = node->dagListNext) {
if (node->action == ea)
return node;
}
if (ea->prev)
prev = makeEAnode(ea->prev);
else
prev = NULL;
for (node = DAG[ea->type]; node; node = node->dagListNext) {
if (node->prev == prev && CExcept_ActionCompare(node->action, ea))
return node;
}
node = lalloc(sizeof(EANode));
node->prev = prev;
node->action = ea;
node->count = 0;
node->xE = 0;
node->dagListNext = DAG[ea->type];
DAG[ea->type] = node;
if (prev)
prev->count++;
return node;
}
static void addrelocation(Object *obj, SInt32 offset) {
OLinkList *ref;
ref = lalloc(sizeof(OLinkList));
ref->next = NULL;
ref->obj = obj;
ref->offset = offset;
ref->somevalue = 0;
if (except_refs)
last_except_ref->next = ref;
else
except_refs = ref;
last_except_ref = ref;
}
#ifdef __MWERKS__
#pragma options align=mac68k
#endif
typedef struct AABC {
UInt8 a;
UInt8 b;
UInt16 c;
UInt32 d;
} AABC;
typedef struct AACC {
UInt8 a;
UInt8 b;
UInt32 c;
UInt32 d;
} AACC;
typedef struct AABBC {
UInt8 a;
UInt8 b;
UInt16 c;
UInt16 d;
UInt32 e;
} AABBC;
typedef struct AABCC {
UInt8 a;
UInt8 b;
UInt16 c;
UInt32 d;
UInt32 e;
} AABCC;
typedef struct AACCC {
UInt8 a;
UInt8 b;
UInt32 c;
UInt32 d;
UInt32 e;
} AACCC;
typedef struct AABBBC {
UInt8 a;
UInt8 b;
UInt16 c;
UInt16 d;
UInt16 e;
UInt32 f;
} AABBBC;
typedef struct AABBCC {
UInt8 a;
UInt8 b;
UInt16 c;
UInt16 d;
UInt32 e;
UInt32 f;
} AABBCC;
typedef struct AACCCC {
UInt8 a;
UInt8 b;
UInt32 c;
UInt32 d;
UInt32 e;
UInt32 f;
} AACCCC;
typedef struct AABCCCC {
UInt8 a;
UInt8 b;
UInt16 c;
UInt32 d;
UInt32 e;
UInt32 f;
UInt32 g;
} AABCCCC;
typedef struct AACCCCC {
UInt8 a;
UInt8 b;
UInt32 c;
UInt32 d;
UInt32 e;
UInt32 f;
UInt32 g;
} AACCCCC;
typedef struct AAB {
UInt8 a;
UInt8 b;
UInt16 c;
} AAB;
typedef struct AAC {
UInt8 a;
UInt8 b;
UInt32 c;
} AAC;
typedef struct AA {
UInt8 a;
UInt8 b;
} AA;
#ifdef __MWERKS__
#pragma options align=reset
#endif
static void allocateactioninfo(EANode *node) {
ExceptionAction *ea;
SInt32 offset;
UInt32 flag26;
int reg;
int reg2;
while (node && (node->xE == 0 || node->prev == NULL)) {
offset = exceptmodule.size;
if (node->xE == 0)
node->xE = offset;
flag26 = node->prev ? 0 : 0x80;
ea = node->action;
switch (ea->type) {
case EAT_NOP:
CError_FATAL(146);
break;
case EAT_DESTROYLOCAL: {
if (local_is_16bit_offset(ea->data.destroy_local.local)) {
AABC e;
e.a = flag26 | 2;
e.b = 0;
e.c = CTool_EndianConvertWord16(local_offset_16(ea->data.destroy_local.local));
e.d = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_local.dtor, offset + 4);
} else {
AACC e;
e.a = flag26 | 0x11;
e.b = 0;
e.c = CTool_EndianConvertWord32(local_offset_32(ea->data.destroy_local.local));
e.d = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_local.dtor, offset + 6);
}
break;
}
case EAT_DESTROYLOCALCOND: {
reg = OBJECT_REG(ea->data.destroy_local_cond.cond);
if (
(reg || local_is_16bit_offset(ea->data.destroy_local_cond.cond)) &&
local_is_16bit_offset(ea->data.destroy_local_cond.local)
)
{
AABBC e;
e.a = flag26 | 3;
e.b = (reg != 0) << 7;
e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_local_cond.cond));
e.d = CTool_EndianConvertWord16(local_offset_16(ea->data.destroy_local_cond.local));
e.e = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_local_cond.dtor, offset + 6);
} else {
AACCC e;
e.a = flag26 | 0x12;
e.b = (reg != 0) << 7;
e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_local_cond.cond));
e.d = CTool_EndianConvertWord32(local_offset_32(ea->data.destroy_local_cond.local));
e.e = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_local_cond.dtor, offset + 10);
}
break;
}
case EAT_DESTROYLOCALOFFSET: {
if (local_is_16bit_offset(ea->data.destroy_local_offset.local)) {
AABC e;
e.a = flag26 | 2;
e.b = 0;
e.c = CTool_EndianConvertWord16(ea->data.destroy_local_offset.offset + local_offset_16(ea->data.destroy_local_offset.local));
e.d = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_local_offset.dtor, offset + 4);
} else {
AACC e;
e.a = flag26 | 0x11;
e.b = 0;
e.c = CTool_EndianConvertWord32(ea->data.destroy_local_offset.offset + local_offset_32(ea->data.destroy_local_offset.local));
e.d = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_local_offset.dtor, offset + 6);
}
break;
}
case EAT_DESTROYLOCALPOINTER: {
reg = OBJECT_REG(ea->data.destroy_local_pointer.pointer);
if (reg || local_is_16bit_offset(ea->data.destroy_local_pointer.pointer)) {
AABC e;
e.a = flag26 | 4;
e.b = (reg != 0) << 7;
e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_local_pointer.pointer));
e.d = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_local_pointer.dtor, offset + 4);
} else {
AACC e;
e.a = flag26 | 0x13;
e.b = (reg != 0) << 7;
e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_local_pointer.pointer));
e.d = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_local_pointer.dtor, offset + 6);
}
break;
}
case EAT_DESTROYLOCALARRAY: {
if (local_is_16bit_offset(ea->data.destroy_local_array.localarray)) {
AABBBC e;
e.a = flag26 | 5;
e.b = 0;
e.c = CTool_EndianConvertWord16(local_offset_16(ea->data.destroy_local_array.localarray));
e.d = CTool_EndianConvertWord16(ea->data.destroy_local_array.elements);
e.e = CTool_EndianConvertWord16(ea->data.destroy_local_array.element_size);
e.f = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_local_array.dtor, offset + 8);
} else {
AACCCC e;
e.a = flag26 | 0x14;
e.b = 0;
e.c = CTool_EndianConvertWord32(local_offset_32(ea->data.destroy_local_array.localarray));
e.d = CTool_EndianConvertWord32(ea->data.destroy_local_array.elements);
e.e = CTool_EndianConvertWord32(ea->data.destroy_local_array.element_size);
e.f = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_local_array.dtor, offset + 14);
}
break;
}
case EAT_DESTROYMEMBER: {
reg = OBJECT_REG(ea->data.destroy_member.objectptr);
if (reg || local_is_16bit_offset(ea->data.destroy_member.objectptr)) {
AABCC e;
e.a = flag26 | 7;
e.b = (reg != 0) << 7;
e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_member.objectptr));
e.d = CTool_EndianConvertWord32(ea->data.destroy_member.offset);
e.e = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_member.dtor, offset + 8);
} else {
AACCC e;
e.a = flag26 | 0x16;
e.b = (reg != 0) << 7;
e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_member.objectptr));
e.d = CTool_EndianConvertWord32(ea->data.destroy_member.offset);
e.e = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_member.dtor, offset + 10);
}
break;
}
case EAT_DESTROYBASE: {
reg = OBJECT_REG(ea->data.destroy_member.objectptr);
if (reg || local_is_16bit_offset(ea->data.destroy_member.objectptr)) {
AABCC e;
e.a = flag26 | 6;
e.b = (reg != 0) << 7;
e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_member.objectptr));
e.d = CTool_EndianConvertWord32(ea->data.destroy_member.offset);
e.e = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_member.dtor, offset + 8);
} else {
AACCC e;
e.a = flag26 | 0x15;
e.b = (reg != 0) << 7;
e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_member.objectptr));
e.d = CTool_EndianConvertWord32(ea->data.destroy_member.offset);
e.e = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_member.dtor, offset + 10);
}
break;
}
case EAT_DESTROYMEMBERCOND: {
reg = OBJECT_REG(ea->data.destroy_member_cond.cond);
reg2 = OBJECT_REG(ea->data.destroy_member_cond.objectptr);
if (
(reg || local_is_16bit_offset(ea->data.destroy_member_cond.cond)) &&
(reg2 || local_is_16bit_offset(ea->data.destroy_member_cond.objectptr))
)
{
AABBCC e;
e.a = flag26 | 8;
e.b = ((reg ? 1 : 0) << 7) | ((reg2 ? 1 : 0) << 6);
e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_member_cond.cond));
e.d = CTool_EndianConvertWord16(reg2 ? reg2 : local_offset_16(ea->data.destroy_member_cond.objectptr));
e.e = CTool_EndianConvertWord32(ea->data.destroy_member_cond.offset);
e.f = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_member_cond.dtor, offset + 10);
} else {
AACCCC e;
e.a = flag26 | 0x17;
e.b = ((reg ? 1 : 0) << 7) | ((reg2 ? 1 : 0) << 6);
e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_member_cond.cond));
e.d = CTool_EndianConvertWord32(reg2 ? reg2 : local_offset_32(ea->data.destroy_member_cond.objectptr));
e.e = CTool_EndianConvertWord32(ea->data.destroy_member_cond.offset);
e.f = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_member_cond.dtor, offset + 14);
}
break;
}
case EAT_DESTROYMEMBERARRAY: {
reg = OBJECT_REG(ea->data.destroy_member_array.objectptr);
if (reg || local_is_16bit_offset(ea->data.destroy_member_array.objectptr)) {
AABCCCC e;
e.a = flag26 | 9;
e.b = (reg != 0) << 7;
e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.destroy_member_array.objectptr));
e.d = CTool_EndianConvertWord32(ea->data.destroy_member_array.offset);
e.e = CTool_EndianConvertWord32(ea->data.destroy_member_array.elements);
e.f = CTool_EndianConvertWord32(ea->data.destroy_member_array.element_size);
e.g = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_member_array.dtor, offset + 16);
} else {
AACCCCC e;
e.a = flag26 | 0x18;
e.b = (reg != 0) << 7;
e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.destroy_member_array.objectptr));
e.d = CTool_EndianConvertWord32(ea->data.destroy_member_array.offset);
e.e = CTool_EndianConvertWord32(ea->data.destroy_member_array.elements);
e.f = CTool_EndianConvertWord32(ea->data.destroy_member_array.element_size);
e.g = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.destroy_member_array.dtor, offset + 18);
}
break;
}
case EAT_DELETEPOINTER:
case EAT_DELETELOCALPOINTER: {
reg = OBJECT_REG(ea->data.delete_pointer.pointerobject);
if (reg || local_is_16bit_offset(ea->data.delete_pointer.pointerobject)) {
AABC e;
e.a = flag26 | 0xA;
e.b = (reg != 0) << 7;
e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.delete_pointer.pointerobject));
e.d = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.delete_pointer.deletefunc, offset + 4);
} else {
AACC e;
e.a = flag26 | 0x19;
e.b = (reg != 0) << 7;
e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.delete_pointer.pointerobject));
e.d = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.delete_pointer.deletefunc, offset + 6);
}
break;
}
case EAT_DELETEPOINTERCOND: {
reg = OBJECT_REG(ea->data.delete_pointer_cond.cond);
reg2 = OBJECT_REG(ea->data.delete_pointer_cond.pointerobject);
if (
(reg || local_is_16bit_offset(ea->data.delete_pointer_cond.cond)) &&
(reg2 || local_is_16bit_offset(ea->data.delete_pointer_cond.pointerobject))
)
{
AABBC e;
e.a = flag26 | 0xB;
e.b = ((reg ? 1 : 0) << 7) | ((reg2 ? 1 : 0) << 6);
e.c = CTool_EndianConvertWord16(reg ? reg : local_offset_16(ea->data.delete_pointer_cond.cond));
e.d = CTool_EndianConvertWord16(reg2 ? reg2 : local_offset_16(ea->data.delete_pointer_cond.pointerobject));
e.e = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.delete_pointer_cond.deletefunc, offset + 6);
} else {
AACCC e;
e.a = flag26 | 0x1A;
e.b = ((reg ? 1 : 0) << 7) | ((reg2 ? 1 : 0) << 6);
e.c = CTool_EndianConvertWord32(reg ? reg : local_offset_32(ea->data.delete_pointer_cond.cond));
e.d = CTool_EndianConvertWord32(reg2 ? reg2 : local_offset_32(ea->data.delete_pointer_cond.pointerobject));
e.e = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
addrelocation(ea->data.delete_pointer_cond.deletefunc, offset + 10);
}
break;
}
case EAT_CATCHBLOCK: {
AACCC e;
e.a = flag26 | 0x10;
e.b = 0;
e.c = 0;
if (ea->data.catch_block.catch_label->pclabel)
e.d = CTool_EndianConvertWord32(ea->data.catch_block.catch_label->pclabel->block->codeOffset);
else
e.d = 0;
e.e = CTool_EndianConvertWord32(local_offset_16(ea->data.catch_block.catch_info_object));
AppendGListData(&exceptmodule, &e, sizeof(e));
if (ea->data.catch_block.catch_typeid)
addrelocation(ea->data.catch_block.catch_typeid, offset + 2);
break;
}
case EAT_ACTIVECATCHBLOCK: {
if (local_is_16bit_offset(ea->data.active_catch_block.catch_info_object)) {
AAB e;
e.a = flag26 | 0xD;
e.b = 0;
e.c = CTool_EndianConvertWord16(local_offset_16(ea->data.active_catch_block.catch_info_object));
AppendGListData(&exceptmodule, &e, sizeof(e));
} else {
AAC e;
e.a = flag26 | 0x1B;
e.b = 0;
e.c = CTool_EndianConvertWord32(local_offset_32(ea->data.active_catch_block.catch_info_object));
AppendGListData(&exceptmodule, &e, sizeof(e));
}
break;
}
case EAT_SPECIFICATION: {
AABCC e;
int i;
e.a = flag26 | 0xF;
e.b = 0;
e.c = CTool_EndianConvertWord16(ea->data.specification.unexp_ids);
if (ea->data.specification.unexp_label->pclabel)
e.d = CTool_EndianConvertWord32(ea->data.specification.unexp_label->pclabel->block->codeOffset);
e.e = CTool_EndianConvertWord32(local_offset_16(ea->data.specification.unexp_info_object));
AppendGListData(&exceptmodule, &e, sizeof(e));
for (i = 0; i < ea->data.specification.unexp_ids; i++) {
addrelocation(ea->data.specification.unexp_id[i], 12 + i * 4 + offset);
AppendGListLong(&exceptmodule, 0);
}
break;
}
case EAT_TERMINATE: {
AA e;
e.a = flag26 | 0xE;
e.b = 0;
AppendGListData(&exceptmodule, &e, sizeof(e));
break;
}
default:
CError_FATAL(671);
}
node = node->prev;
}
if (node) {
AAB e;
e.a = 1;
e.b = 0;
e.c = CTool_EndianConvertWord16(node->xE);
AppendGListData(&exceptmodule, &e, sizeof(e));
}
}
static UInt32 findPC(PCode *instr) {
UInt32 pc = instr->block->codeOffset;
instr = instr->prevPCode;
while (instr) {
instr = instr->prevPCode;
pc += 4;
}
CError_ASSERT(704, FITS_IN_USHORT(pc));
return pc;
}
static UInt32 findPC_long(PCode *instr) {
UInt32 pc = instr->block->codeOffset;
instr = instr->prevPCode;
while (instr) {
instr = instr->prevPCode;
pc += 4;
}
return pc;
}
void initializeexceptiontables(void) {
int i;
for (i = 0; i < EAT_NACTIONS; i++)
DAG[i] = NULL;
pc_actions = last_pc_action = NULL;
except_refs = last_except_ref = NULL;
}
int countexceptionactionregisters(ExceptionAction *actions) {
int count = 0;
while (actions) {
switch (actions->type) {
case EAT_DESTROYLOCALCOND:
if (OBJECT_REG(actions->data.destroy_local_cond.cond))
count++;
break;
case EAT_DESTROYLOCALPOINTER:
if (OBJECT_REG(actions->data.destroy_local_pointer.pointer))
count++;
break;
case EAT_DESTROYMEMBER:
if (OBJECT_REG(actions->data.destroy_member.objectptr))
count++;
break;
case EAT_DESTROYBASE:
if (OBJECT_REG(actions->data.destroy_base.objectptr))
count++;
break;
case EAT_DESTROYMEMBERCOND:
if (OBJECT_REG(actions->data.destroy_member_cond.cond))
count++;
if (OBJECT_REG(actions->data.destroy_member_cond.objectptr))
count++;
break;
case EAT_DESTROYMEMBERARRAY:
if (OBJECT_REG(actions->data.destroy_member_array.objectptr))
count++;
break;
case EAT_DELETEPOINTER:
case EAT_DELETELOCALPOINTER:
if (OBJECT_REG(actions->data.delete_pointer.pointerobject))
count++;
break;
case EAT_DELETEPOINTERCOND:
if (OBJECT_REG(actions->data.delete_pointer_cond.cond))
count++;
if (OBJECT_REG(actions->data.delete_pointer_cond.pointerobject))
count++;
break;
}
actions = actions->prev;
}
return count;
}
void noteexceptionactionregisters(ExceptionAction *actions, PCodeArg *ops) {
Object *obj;
int reg;
while (actions) {
switch (actions->type) {
case EAT_DESTROYLOCALCOND:
if ((reg = OBJECT_REG(obj = actions->data.destroy_local_cond.cond))) {
ops->kind = PCOp_REGISTER;
ops->arg = obj->u.var.info->rclass;
ops->data.reg.reg = reg;
ops->data.reg.effect = EffectRead | Effect8;
ops++;
}
break;
case EAT_DESTROYLOCALPOINTER:
if ((reg = OBJECT_REG(obj = actions->data.destroy_local_pointer.pointer))) {
ops->kind = PCOp_REGISTER;
ops->arg = obj->u.var.info->rclass;
ops->data.reg.reg = reg;
ops->data.reg.effect = EffectRead | Effect8;
ops++;
}
break;
case EAT_DESTROYMEMBER:
if ((reg = OBJECT_REG(obj = actions->data.destroy_member.objectptr))) {
ops->kind = PCOp_REGISTER;
ops->arg = obj->u.var.info->rclass;
ops->data.reg.reg = reg;
ops->data.reg.effect = EffectRead | Effect8;
ops++;
}
break;
case EAT_DESTROYBASE:
if ((reg = OBJECT_REG(obj = actions->data.destroy_base.objectptr))) {
ops->kind = PCOp_REGISTER;
ops->arg = obj->u.var.info->rclass;
ops->data.reg.reg = reg;
ops->data.reg.effect = EffectRead | Effect8;
ops++;
}
break;
case EAT_DESTROYMEMBERCOND:
if ((reg = OBJECT_REG(obj = actions->data.destroy_member_cond.cond))) {
ops->kind = PCOp_REGISTER;
ops->arg = obj->u.var.info->rclass;
ops->data.reg.reg = reg;
ops->data.reg.effect = EffectRead | Effect8;
ops++;
}
if ((reg = OBJECT_REG(obj = actions->data.destroy_member_cond.objectptr))) {
ops->kind = PCOp_REGISTER;
ops->arg = obj->u.var.info->rclass;
ops->data.reg.reg = reg;
ops->data.reg.effect = EffectRead | Effect8;
ops++;
}
break;
case EAT_DESTROYMEMBERARRAY:
if ((reg = OBJECT_REG(obj = actions->data.destroy_member_array.objectptr))) {
ops->kind = PCOp_REGISTER;
ops->arg = obj->u.var.info->rclass;
ops->data.reg.reg = reg;
ops->data.reg.effect = EffectRead | Effect8;
ops++;
}
break;
case EAT_DELETEPOINTER:
case EAT_DELETELOCALPOINTER:
if ((reg = OBJECT_REG(obj = actions->data.delete_pointer.pointerobject))) {
ops->kind = PCOp_REGISTER;
ops->arg = obj->u.var.info->rclass;
ops->data.reg.reg = reg;
ops->data.reg.effect = EffectRead | Effect8;
ops++;
}
break;
case EAT_DELETEPOINTERCOND:
if ((reg = OBJECT_REG(obj = actions->data.delete_pointer_cond.cond))) {
ops->kind = PCOp_REGISTER;
ops->arg = obj->u.var.info->rclass;
ops->data.reg.reg = reg;
ops->data.reg.effect = EffectRead | Effect8;
ops++;
}
if ((reg = OBJECT_REG(obj = actions->data.delete_pointer_cond.pointerobject))) {
ops->kind = PCOp_REGISTER;
ops->arg = obj->u.var.info->rclass;
ops->data.reg.reg = reg;
ops->data.reg.effect = EffectRead | Effect8;
ops++;
}
break;
}
actions = actions->prev;
}
}
void recordexceptionactions(PCode *instr, ExceptionAction *actions) {
PCAction *pca;
if (!actions && (!last_pc_action || !last_pc_action->actions))
return;
pca = lalloc(sizeof(PCAction));
pca->next = NULL;
pca->firstInstr = pca->lastInstr = instr;
pca->actions = actions;
pca->prev = last_pc_action;
if (last_pc_action)
last_pc_action->next = pca;
else
pc_actions = pca;
last_pc_action = pca;
branch_label(makepclabel());
while (actions) {
if (actions->type == EAT_CATCHBLOCK && actions->data.catch_block.catch_label->pclabel)
pcbranch(instr->block, actions->data.catch_block.catch_label->pclabel);
else if (actions->type == EAT_SPECIFICATION && actions->data.specification.unexp_label->pclabel)
pcbranch(instr->block, actions->data.specification.unexp_label->pclabel);
actions = actions->prev;
}
}
static void deleteexceptionaction(PCAction *pca) {
if (pca->prev)
pca->prev->next = pca->next;
else
pc_actions = pca->next;
if (pca->next)
pca->next->prev = pca->prev;
}
static int mergeexceptionactions(void) {
int count;
PCAction *pca;
PCAction *prev;
if (!pc_actions)
return 0;
for (pca = pc_actions; pca; pca = pca->next) {
if (pca->firstInstr->block->flags & fDeleted)
deleteexceptionaction(pca);
}
if (!(pca = pc_actions))
return 0;
while (pca) {
pca->node = pca->actions ? makeEAnode(pca->actions) : NULL;
pca = pca->next;
}
prev = pc_actions;
for (pca = pc_actions->next; pca; pca = pca->next) {
if (pca->node == prev->node) {
prev->lastInstr = pca->lastInstr;
deleteexceptionaction(pca);
} else {
prev = pca;
}
}
count = 0;
for (pca = pc_actions; pca; pca = pca->next) {
if (!pca->actions)
deleteexceptionaction(pca);
else
count++;
}
return count;
}
typedef struct ExceptionThing {
UInt32 x0;
UInt16 x4;
UInt16 x6;
} ExceptionThing;
void dumpexceptiontables(Object *function, SInt32 codesize) {
PCAction *pca;
UInt32 insn_start;
UInt32 insn_count;
UInt16 *sh;
ExceptionThing *thing;
int count;
count = mergeexceptionactions();
InitGList(&exceptmodule, 256);
AppendGListNoData(&exceptmodule, 8 * count + 4);
AppendGListLong(&exceptmodule, 0);
for (pca = pc_actions; pca; pca = pca->next) {
if (pca->node->count == 0 && pca->node->xE == 0)
allocateactioninfo(pca->node);
}
sh = (UInt16 *) *exceptmodule.data;
if (copts.altivec_model && used_nonvolatile_registers[RegClass_VR]) {
sh[0] =
CTool_EndianConvertWord16(
(used_nonvolatile_registers[RegClass_GPR] << 11) |
((used_nonvolatile_registers[RegClass_FPR] & 0x1F) << 6) |
(((used_nonvolatile_registers[RegClass_CRFIELD] != 0) & 1) << 5) |
((dynamic_stack & 1) << 4) |
8);
sh[0] |= 4;
if (copts.altivec_vrsave)
sh[1] = CTool_EndianConvertWord16((used_nonvolatile_registers[RegClass_VR] << 11) | 0x400);
else
sh[1] = CTool_EndianConvertWord16((used_nonvolatile_registers[RegClass_VR] & 0x1F) << 11);
} else {
sh[0] =
CTool_EndianConvertWord16(
(used_nonvolatile_registers[RegClass_GPR] << 11) |
((used_nonvolatile_registers[RegClass_FPR] & 0x1F) << 6) |
(((used_nonvolatile_registers[RegClass_CRFIELD] != 0) & 1) << 5) |
((dynamic_stack & 1) << 4) |
8);
sh[1] = 0;
}
thing = (ExceptionThing *) (sh + 2);
pca = pc_actions;
while (pca) {
insn_start = findPC_long(pca->firstInstr);
insn_count = (findPC_long(pca->lastInstr) - insn_start) / 4;
CError_ASSERT(1203, (insn_count & 0xFFFF0000) == 0);
thing->x0 = CTool_EndianConvertWord32(insn_start + 4);
thing->x4 = CTool_EndianConvertWord16(insn_count);
thing->x6 = CTool_EndianConvertWord16(pca->node->xE);
pca = pca->next;
thing++;
}
LockGList(&exceptmodule);
ObjGen_DeclareExceptionTables(function, codesize, *exceptmodule.data, exceptmodule.size, except_refs);
FreeGList(&exceptmodule);
}

View File

@@ -0,0 +1,642 @@
#include "compiler/FunctionCalls.h"
#include "compiler/CError.h"
#include "compiler/CFunc.h"
#include "compiler/CMachine.h"
#include "compiler/CParser.h"
#include "compiler/CodeGen.h"
#include "compiler/CompilerTools.h"
#include "compiler/InstrSelection.h"
#include "compiler/Operands.h"
#include "compiler/PCode.h"
#include "compiler/PCodeUtilities.h"
#include "compiler/Registers.h"
#include "compiler/StackFrame.h"
#include "compiler/StructMoves.h"
#include "compiler/types.h"
enum {
AIF_PassInGPR = 1,
AIF_PassInFPR = 2,
AIF_PassOnStack = 4,
AIF_ExtendTo32Bits = 8,
AIF_ForceDoublePrecision = 0x10,
AIF_PassInVR = 0x20,
AIF_PassMask = AIF_PassInGPR | AIF_PassInFPR | AIF_PassOnStack | AIF_PassInVR
};
#ifdef __MWERKS__
#pragma options align=mac68k
#endif
typedef struct ArgInfo {
struct ArgInfo *next;
ENode *expr;
Operand opnd;
SInt32 offset;
short gpr;
short gprHi;
short fpr;
short vr;
short evaluated;
short flags;
} ArgInfo;
#ifdef __MWERKS__
#pragma options align=reset
#endif
// forward decls
static void branch_subroutine_indirect_ctr(Operand *addrOpnd, UInt32 *used_regs);
static ArgInfo *make_arginfo(ENode *expr) {
ArgInfo *info = lalloc(sizeof(ArgInfo));
memclrw(info, sizeof(ArgInfo));
info->next = NULL;
info->expr = expr;
info->offset = -1;
info->gpr = -1;
info->gprHi = -1;
info->fpr = -1;
info->vr = -1;
info->evaluated = 0;
info->flags = 0;
return info;
}
static ArgInfo *analyze_arguments(ENode *funcref, ENodeList *arg_expr, FuncArg *arg, UInt32 *used_regs, Boolean *resultHasFloats, char has_varargs) {
ArgInfo *infos;
ArgInfo *info;
SInt32 displ;
SInt32 arg_size;
int gpr_counter;
int fpr_counter;
int vr_counter;
Type *type;
RegClass rclass;
Boolean spilledVectorFlag;
infos = NULL;
displ = 0;
gpr_counter = 3;
fpr_counter = 1;
vr_counter = 2;
for (rclass = 0; rclass < RegClassMax; rclass++)
used_regs[rclass] = 0;
*resultHasFloats = 0;
while (arg_expr) {
if (arg_expr->node == funcref) {
arg_expr = arg_expr->next;
arg = arg->next;
continue;
}
type = arg_expr->node->rtype;
if (infos) {
info->next = make_arginfo(arg_expr->node);
info = info->next;
} else {
infos = info = make_arginfo(arg_expr->node);
}
arg_size = 0;
if (IS_TYPE_VECTOR(type)) {
if (arg == &elipsis) {
spilledVectorFlag = 1;
info->flags |= AIF_PassOnStack;
} else {
spilledVectorFlag = 0;
if (vr_counter <= 13) {
info->flags |= AIF_PassInVR;
info->vr = vr_counter;
used_regs[RegClass_VR] |= 1 << vr_counter;
} else {
spilledVectorFlag = 1;
info->flags |= AIF_PassOnStack;
}
}
if (has_varargs) {
if (gpr_counter < 10) {
gpr_counter = ((gpr_counter - 2) & ~3) + 5;
if (arg == &elipsis && gpr_counter < 10) {
info->flags |= AIF_PassInGPR;
info->gpr = gpr_counter;
used_regs[RegClass_GPR] |= (15 << gpr_counter) & 0x7E0;
}
gpr_counter += 4;
}
spilledVectorFlag = 1;
}
if (spilledVectorFlag)
arg_size = 16;
vr_counter++;
} else if (IS_TYPE_FLOAT(type)) {
*resultHasFloats = 1;
if (!arg || arg == &oldstyle) {
if (fpr_counter <= 13) {
info->flags |= AIF_PassInFPR;
info->fpr = fpr_counter;
used_regs[RegClass_FPR] |= 1 << fpr_counter;
} else {
info->flags |= AIF_PassOnStack | AIF_ForceDoublePrecision;
}
arg_size = 8;
fpr_counter++;
gpr_counter += 2;
} else if (arg == &elipsis) {
if (gpr_counter < 10) {
info->flags |= AIF_PassInGPR;
info->gpr = gpr_counter;
used_regs[RegClass_GPR] |= 3 << gpr_counter;
} else if (gpr_counter == 10) {
info->flags |= AIF_PassInGPR | AIF_PassOnStack | AIF_ForceDoublePrecision;
info->gpr = gpr_counter;
used_regs[RegClass_GPR] |= 3 << gpr_counter;
} else {
info->flags |= AIF_PassOnStack | AIF_ForceDoublePrecision;
}
arg_size = 8;
fpr_counter++;
gpr_counter += 2;
} else {
if (fpr_counter <= 13) {
info->flags |= AIF_PassInFPR;
info->fpr = fpr_counter;
used_regs[RegClass_FPR] |= 1 << fpr_counter;
} else {
info->flags |= AIF_PassOnStack;
}
if (type->size == 4) {
arg_size = 4;
gpr_counter++;
} else {
arg_size = 8;
gpr_counter += 2;
}
fpr_counter++;
}
} else if (TYPE_IS_8BYTES(type)) {
if (gpr_counter <= 10) {
info->flags |= AIF_PassInGPR;
if (copts.littleendian) {
info->gpr = gpr_counter;
info->gprHi = gpr_counter + 1;
} else {
info->gpr = gpr_counter + 1;
info->gprHi = gpr_counter;
}
used_regs[RegClass_GPR] |= 1 << gpr_counter;
if ((gpr_counter + 1) <= 10)
used_regs[RegClass_GPR] |= 1 << (gpr_counter + 1);
} else {
info->flags |= AIF_PassOnStack;
}
arg_size = 8;
gpr_counter += 2;
} else if (TYPE_FITS_IN_REGISTER(type)) {
if ((!arg || arg == &elipsis || arg == &oldstyle) && type->size < 4)
info->flags |= AIF_ExtendTo32Bits;
if (gpr_counter <= 10) {
info->flags |= AIF_PassInGPR;
info->gpr = gpr_counter;
used_regs[RegClass_GPR] |= 1 << gpr_counter;
} else {
info->flags |= AIF_PassOnStack;
}
arg_size = 4;
gpr_counter++;
} else if (IS_TYPE_ARRAY(type) || IS_TYPE_NONVECTOR_STRUCT(type) || IS_TYPE_CLASS(type) ||
IS_TYPE_12BYTES_MEMBERPOINTER(type)) {
SInt32 gprs_needed = (type->size >> 2) + ((type->size & 3) != 0);
if (gpr_counter <= 10) {
if ((gpr_counter + gprs_needed - 1) <= 10) {
info->flags |= AIF_PassInGPR;
info->gpr = gpr_counter;
used_regs[RegClass_GPR] |= ((1 << gprs_needed) - 1) << gpr_counter;
} else {
info->flags |= AIF_PassInGPR | AIF_PassOnStack;
info->gpr = gpr_counter;
used_regs[RegClass_GPR] |= ((1 << (11 - gpr_counter)) - 1) << gpr_counter;
}
} else {
info->flags |= AIF_PassOnStack;
}
gpr_counter += gprs_needed;
arg_size = type->size;
} else {
CError_FATAL(421);
}
displ = set_out_param_displ(displ, type, info->flags & AIF_PassOnStack, &info->offset, arg_size);
arg_expr = arg_expr->next;
if (arg && arg != &elipsis && arg != &oldstyle)
arg = arg->next;
}
update_out_param_size(displ);
return infos;
}
static void pass_in_memory(ArgInfo *info) {
Type *type;
Operand opnd;
type = info->expr->rtype;
memclrw(&opnd, sizeof(Operand));
if (TYPE_FITS_IN_REGISTER(type)) {
if (TYPE_IS_8BYTES(type)) {
if (!info->evaluated)
GEN_NODE(info->expr, &info->opnd);
coerce_to_register_pair(&info->opnd, type, 0, 0);
load_store_register(
PC_STW, info->opnd.reg, 1,
NULL, low_offset + out_param_displ_to_offset(info->offset));
load_store_register(
PC_STW, info->opnd.regHi, 1,
NULL, high_offset + out_param_displ_to_offset(info->offset));
} else {
if (!info->evaluated)
GEN_NODE(info->expr, &info->opnd);
if (info->flags & AIF_ExtendTo32Bits)
extend32(&info->opnd, type, 0);
ENSURE_GPR(&info->opnd, type, 0);
load_store_register(
PC_STW, info->opnd.reg, 1,
NULL, out_param_displ_to_offset(info->offset));
}
} else if (IS_TYPE_FLOAT(type)) {
if (!info->evaluated)
GEN_NODE(info->expr, &info->opnd);
ENSURE_FPR(&info->opnd, type, 0);
if (type->size == 4 && !(info->flags & AIF_ForceDoublePrecision)) {
load_store_register(
PC_STFS, info->opnd.reg, 1,
NULL, out_param_displ_to_offset(info->offset));
} else {
load_store_register(
PC_STFD, info->opnd.reg, 1,
NULL, out_param_displ_to_offset(info->offset));
}
} else if (IS_TYPE_VECTOR(type)) {
if (!info->evaluated)
GEN_NODE(info->expr, &info->opnd);
ENSURE_VR(&info->opnd, type, 0);
load_store_register(
PC_STVX, info->opnd.reg, 1,
NULL, out_param_displ_to_offset(info->offset));
} else {
opnd.optype = OpndType_IndirectGPR_ImmOffset;
opnd.reg = 1;
opnd.object = NULL;
opnd.immOffset = out_param_displ_to_offset(info->offset);
if (!info->evaluated)
GEN_NODE(info->expr, &info->opnd);
move_block(&opnd, &info->opnd, type->size, CMach_ArgumentAlignment(type));
}
}
static void pass_in_register(ArgInfo *info) {
Type *type;
type = info->expr->rtype;
if ((info->flags & AIF_PassMask) == AIF_PassInFPR) {
if (!info->evaluated)
GEN_NODE_TO_REG(info->expr, info->fpr, 0, &info->opnd);
ENSURE_FPR(&info->opnd, type, info->fpr);
if (info->opnd.reg != info->fpr)
emitpcode(PC_FMR, info->fpr, info->opnd.reg);
} else if ((info->flags & AIF_PassMask) == AIF_PassInVR) {
if (!info->evaluated)
GEN_NODE_TO_REG(info->expr, info->vr, 0, &info->opnd);
ENSURE_VR(&info->opnd, type, info->vr);
if (info->opnd.reg != info->vr)
emitpcode(PC_VMR, info->vr, info->opnd.reg);
} else if (TYPE_FITS_IN_REGISTER(type)) {
if (TYPE_IS_8BYTES(type)) {
if (!info->evaluated)
GEN_NODE_TO_REG(info->expr, info->gpr, info->gprHi, &info->opnd);
coerce_to_register_pair(&info->opnd, type, info->gpr, info->gprHi);
if (copts.littleendian) {
if (info->gprHi > 10) {
load_store_register(
PC_STW, info->opnd.regHi, 1,
NULL, high_offset + out_param_displ_to_offset(info->offset));
}
} else {
if (info->gpr > 10) {
load_store_register(
PC_STW, info->opnd.reg, 1,
NULL, low_offset + out_param_displ_to_offset(info->offset));
}
}
} else {
if (!info->evaluated)
GEN_NODE_TO_REG(info->expr, info->gpr, 0, &info->opnd);
if (info->flags & AIF_ExtendTo32Bits)
extend32(&info->opnd, type, info->gpr);
ENSURE_GPR(&info->opnd, type, info->gpr);
if (info->opnd.reg != info->gpr)
emitpcode(PC_MR, info->gpr, info->opnd.reg);
}
} else if (IS_TYPE_FLOAT(type)) {
if (!info->evaluated)
GEN_NODE(info->expr, &info->opnd);
if (type->size != 4 && info->opnd.optype == OpndType_IndirectGPR_ImmOffset) {
load_store_register(
PC_LWZ, info->gpr, info->opnd.reg,
info->opnd.object, info->opnd.immOffset);
load_store_register(
PC_LWZ, info->gpr + 1, info->opnd.reg,
info->opnd.object, info->opnd.immOffset + 4);
} else {
ENSURE_FPR(&info->opnd, type, 0);
load_store_register(
PC_STFD, info->opnd.reg, 1,
NULL, out_param_displ_to_offset(info->offset));
load_store_register(
PC_LWZ, info->gpr, 1,
NULL, out_param_displ_to_offset(info->offset));
load_store_register(
PC_LWZ, info->gpr + 1, 1,
NULL, out_param_displ_to_offset(info->offset) + 4);
}
} else if (IS_TYPE_VECTOR(type)) {
if (!info->evaluated)
GEN_NODE(info->expr, &info->opnd);
if (info->opnd.optype == OpndType_IndirectGPR_ImmOffset) {
load_store_register(
PC_LWZ, info->gpr, info->opnd.reg,
info->opnd.object, info->opnd.immOffset);
load_store_register(
PC_LWZ, info->gpr + 1, info->opnd.reg,
info->opnd.object, info->opnd.immOffset + 4);
if ((info->gpr + 2) < 10) {
load_store_register(
PC_LWZ, info->gpr + 2, info->opnd.reg,
info->opnd.object, info->opnd.immOffset + 8);
load_store_register(
PC_LWZ, info->gpr + 3, info->opnd.reg,
info->opnd.object, info->opnd.immOffset + 12);
}
} else {
ENSURE_VR(&info->opnd, type, 0);
load_store_register(
PC_STVX, info->opnd.reg, 1,
NULL, out_param_displ_to_offset(info->offset));
load_store_register(
PC_LWZ, info->gpr, 1,
NULL, out_param_displ_to_offset(info->offset));
load_store_register(
PC_LWZ, info->gpr + 1, 1,
NULL, out_param_displ_to_offset(info->offset) + 4);
if ((info->gpr + 2) < 10) {
load_store_register(
PC_LWZ, info->gpr + 2, 1,
NULL, out_param_displ_to_offset(info->offset) + 8);
load_store_register(
PC_LWZ, info->gpr + 3, 1,
NULL, out_param_displ_to_offset(info->offset) + 12);
}
}
} else {
if (!info->evaluated)
GEN_NODE(info->expr, &info->opnd);
if (type->size <= 4) {
if (info->opnd.optype == OpndType_IndirectSymbol)
coerce_to_addressable(&info->opnd);
if (info->opnd.optype == OpndType_IndirectGPR_ImmOffset) {
load_store_register(
PC_LWZ, info->gpr, info->opnd.reg,
info->opnd.object, info->opnd.immOffset);
} else if (info->opnd.optype == OpndType_IndirectGPR_Indexed) {
emitpcode(
PC_LWZX, info->gpr, info->opnd.reg,
info->opnd.regOffset);
}
} else {
SInt32 gprs_needed = (type->size >> 2) + ((type->size & 3) != 0);
SInt32 i;
make_addressable(&info->opnd, gprs_needed * 4, 12);
for (i = 0; i < gprs_needed; i++) {
if (info->opnd.reg != (info->gpr + i)) {
load_store_register(
PC_LWZ, info->gpr + i, info->opnd.reg,
info->opnd.object, info->opnd.immOffset + i * 4);
}
}
if (info->opnd.reg >= info->gpr && info->opnd.reg < (info->gpr + gprs_needed)) {
load_store_register(
PC_LWZ, info->opnd.reg, info->opnd.reg,
info->opnd.object, info->opnd.immOffset + (info->opnd.reg - info->gpr) * 4);
}
}
}
}
static void pass_in_register_and_memory(ArgInfo *info) {
Type *type;
int gpr;
SInt32 offset;
type = info->expr->rtype;
gpr = info->gpr;
offset = 0;
while (offset < type->size && gpr <= 10) {
load_store_register(
PC_LWZ, gpr, 1,
NULL, offset + out_param_displ_to_offset(info->offset));
gpr++;
offset += 4;
}
}
static Boolean needs_TOC_reload(Object *func) {
return 0;
}
static void load_virtual_function(TypeClass *tclass, SInt32 offset, int reg, Operand *opnd) {
if (tclass->flags & CLASS_HANDLEOBJECT) {
load_store_register(PC_LWZ, 12, reg, NULL, 0);
load_store_register(PC_LWZ, 12, 12, NULL, tclass->vtable->offset);
} else {
load_store_register(PC_LWZ, 12, reg, NULL, tclass->vtable->offset);
}
load_store_register(PC_LWZ, 12, 12, NULL, offset);
opnd->optype = OpndType_GPR;
opnd->reg = 12;
}
static void branch_subroutine_indirect(Object *func, Operand *addrOpnd, UInt32 *used_regs) {
if (addrOpnd->reg != 12)
emitpcode(PC_MR, 12, addrOpnd->reg);
used_regs[RegClass_GPR] |= 1 << 12;
branch_subroutine(func, 1, used_regs);
}
static void evaluate_nested_function_calls(ArgInfo *info) {
ArgInfo *scan;
scan = info->next;
while (scan && !scan->expr->hascall)
scan = scan->next;
if (scan)
evaluate_nested_function_calls(scan);
if (info->expr->hascall) {
GEN_NODE(info->expr, &info->opnd);
info->evaluated = 1;
}
}
void call_function(ENode *expr, Operand *output) {
ArgInfo *infos; // r31
ENode *funcref = expr->data.funccall.funcref; // r27
Type *resultType = expr->data.funccall.functype->functype; // r26
ENode *node = NULL; // r25
char has_varargs; // r24
ArgInfo *info; // r22
Operand opnd;
UInt32 used_regs[RegClassMax] = {0};
Boolean has_floats;
FuncArg *arg;
memclrw(&opnd, sizeof(Operand));
has_varargs = 0;
for (arg = expr->data.funccall.functype->args; arg; arg = arg->next) {
if (arg == &elipsis) {
has_varargs = 1;
break;
}
}
if (expr->data.funccall.functype->flags & FUNC_FLAGS_80) {
if (CMach_PassResultInHiddenArg(resultType))
node = expr->data.funccall.args->next->node;
else
node = expr->data.funccall.args->node;
}
infos = analyze_arguments(
node,
expr->data.funccall.args,
expr->data.funccall.functype->args,
used_regs,
&has_floats,
has_varargs);
if (infos)
evaluate_nested_function_calls(infos);
if (funcref->hascall) {
GEN_NODE_TO_GPR(funcref, &opnd, TYPE(&void_ptr), 0);
} else if (node && node->hascall) {
GEN_NODE_TO_GPR(node, &opnd, TYPE(&void_ptr), 0);
}
for (info = infos; info; info = info->next) {
if (info->flags & AIF_PassOnStack)
pass_in_memory(info);
}
for (info = infos; info; info = info->next) {
if ((info->flags & AIF_PassMask) == (AIF_PassInGPR | AIF_PassOnStack))
pass_in_register_and_memory(info);
}
for (info = infos; info; info = info->next) {
int flag = info->flags & AIF_PassMask;
if (
flag == AIF_PassInGPR ||
flag == AIF_PassInFPR ||
flag == AIF_PassInVR
)
pass_in_register(info);
}
if (funcref->type == EOBJREF) {
TypeClass *tclass;
SInt32 vfOffset;
if (CParser_IsVirtualFunction(funcref->data.objref, &tclass, &vfOffset)) {
load_virtual_function(
tclass,
vfOffset,
CMach_PassResultInHiddenArg(resultType) ? Register4 : Register3,
&opnd
);
branch_subroutine_indirect_ctr(&opnd, used_regs);
} else if (node) {
if (!node->hascall) {
GEN_NODE_TO_REG(node, 12, 0, &opnd);
ENSURE_GPR(&opnd, TYPE(&void_ptr), 12);
}
branch_subroutine_indirect(funcref->data.objref, &opnd, used_regs);
} else {
branch_subroutine(funcref->data.objref, needs_TOC_reload(funcref->data.objref), used_regs);
}
} else {
if (!funcref->hascall)
GEN_NODE_TO_REG(funcref, 12, 0, &opnd);
ENSURE_GPR(&opnd, TYPE(&void_ptr), 12);
branch_subroutine_indirect_ctr(&opnd, used_regs);
}
if (IS_TYPE_FLOAT(resultType)) {
output->optype = OpndType_FPR;
output->reg = used_virtual_registers[RegClass_FPR]++;
emitpcode(PC_FMR, output->reg, 1);
} else if (IS_TYPE_VECTOR(resultType)) {
output->optype = OpndType_VR;
output->reg = used_virtual_registers[RegClass_VR]++;
emitpcode(PC_VMR, output->reg, 2);
} else if (TYPE_FITS_IN_REGISTER(resultType)) {
if (resultType->size > 4) {
output->optype = OpndType_GPRPair;
output->reg = used_virtual_registers[RegClass_GPR]++;
output->regHi = used_virtual_registers[RegClass_GPR]++;
emitpcode(PC_MR, output->reg, low_reg);
emitpcode(PC_MR, output->regHi, high_reg);
} else {
output->optype = OpndType_GPR;
output->reg = used_virtual_registers[RegClass_GPR]++;
emitpcode(PC_MR, output->reg, 3);
}
} else {
output->optype = OpndType_Absolute;
output->immediate = 0;
}
}
static void branch_subroutine_indirect_ctr(Operand *addrOpnd, UInt32 *used_regs) {
if (addrOpnd->reg != 12)
emitpcode(PC_MR, 12, addrOpnd->reg);
emitpcode(PC_MTCTR, 12);
used_regs[RegClass_GPR] |= 1 << 12;
branch_subroutine_ctr(used_regs);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,536 @@
#include "compiler/PCodeListing.h"
#include "compiler/CError.h"
#include "compiler/CMangler.h"
#include "compiler/CParser.h"
#include "compiler/Alias.h"
#include "compiler/BitVectors.h"
#include "compiler/CompilerTools.h"
#include "compiler/InterferenceGraph.h"
#include "compiler/LiveInfo.h"
#include "compiler/PCode.h"
#include "compiler/PCodeAssembly.h"
#include "compiler/Registers.h"
#include "compiler/Scheduler.h"
#include "compiler/objects.h"
static FILE *pcfile;
static int ptime;
static int sourcetext;
static int sourcetext_is_main;
static int sourcelength;
int pclist_bad_operand;
static void formatdataflowset(char *name, UInt32 *vec, UInt32 size, char *format) {
UInt32 i;
UInt32 counter;
char *separator;
separator = "";
fprintf(pcfile, "%s = {", name);
for (i = 0, counter = 0; i < size; i++) {
if (bitvectorgetbit(i, vec)) {
if (i)
fprintf(pcfile, separator);
if (counter++ == 10) {
fprintf(pcfile, "\n\t\t");
counter = 0;
}
fprintf(pcfile, format, i);
separator = ",";
}
}
fprintf(pcfile, "}\n");
}
static void pclistblock(PCodeBlock *block, char *format, UInt32 vecSize) {
PCLink *link;
PCodeLabel *label;
int cpu;
int chr;
PCode *instr;
int offset;
int latency;
UInt32 opcode;
MachineInfo *mi;
char buf[500];
WeirdOperand dummyArg;
fprintf(pcfile, ":{%4.4x}::::::::::::::::::::::::::::::::::::::::LOOPWEIGHT=%" PRId32 "\n", block->flags, block->loopWeight);
fprintf(pcfile, "B%" PRId32 ": ", block->blockIndex);
fprintf(pcfile, "Successors = { ");
for (link = block->successors; link; link = link->nextLink) {
if (link->block)
fprintf(pcfile, "B%" PRId32 " ", link->block->blockIndex);
}
fprintf(pcfile, "} ");
fprintf(pcfile, "Predecessors = { ");
for (link = block->predecessors; link; link = link->nextLink) {
if (link->block)
fprintf(pcfile, "B%" PRId32 " ", link->block->blockIndex);
}
if (block->labels) {
fprintf(pcfile, "} Labels = { ");
for (label = block->labels; label; label = label->nextLabel)
fprintf(pcfile, "L%" PRId32 " ", label->index);
}
fprintf(pcfile, "}\n\n");
cpu = copts.scheduling;
if (cpu == 10) {
mi = &machine7450;
} else if (copts.altivec_model != 0 || cpu == 7) {
mi = &machine7400;
} else if (cpu == 2) {
mi = &machine603;
} else if (cpu == 5) {
mi = &machine603e;
} else if (cpu == 3) {
mi = &machine604;
} else if (cpu == 6) {
mi = &machine604;
} else if (cpu == 4) {
mi = &machine750;
} else if (cpu == 1) {
mi = &machine601;
} else if (cpu == 9) {
mi = &machine821;
} else {
mi = &machine603;
}
for (offset = block->codeOffset, instr = block->firstPCode; instr; instr = instr->nextPCode, offset += 4) {
latency = mi->latency(instr);
formatoperands(instr, buf, 1);
chr = (PCODE_FLAG_SET_F(instr) & fRecordBit) ? '.' : ' ';
if (coloring)
opcode = 0;
else
opcode = assemblepcode(instr, offset, &dummyArg);
fprintf(
pcfile,
" %.8" PRIX32 " %.8" PRIX32 " %4" PRId32 " %-7s%c %s\n",
offset, CTool_EndianConvertWord32(opcode), latency,
opcodeinfo[instr->op].name, chr, buf
);
if (instr->alias)
dumpalias(instr->alias, 0, 1, 0);
}
if (vecSize) {
fprintf(pcfile, "............................................................\n");
formatdataflowset("use", liveinfo[block->blockIndex].use, vecSize, format);
formatdataflowset("def", liveinfo[block->blockIndex].def, vecSize, format);
formatdataflowset("in ", liveinfo[block->blockIndex].in, vecSize, format);
formatdataflowset("out", liveinfo[block->blockIndex].out, vecSize, format);
}
fflush(pcfile);
if (pclist_bad_operand)
CError_FATAL(252);
}
static void pclistonoff(int flag) {
if (flag)
fprintf(pcfile, "On\n");
else
fprintf(pcfile, "Off\n");
}
void pcinitlisting() {
// unknown args, etc
}
void pccleanuplisting(void) {
#ifdef CW_ENABLE_PCODE_DEBUG
// this code is not based on the original as we don't have it
if (pcfile) {
fclose(pcfile);
pcfile = NULL;
}
#endif
}
void pclistblocks(char *name1, char *name2) {
#ifdef CW_ENABLE_PCODE_DEBUG
// this code is not based on the original as we don't have it
PCodeBlock *block;
if (copts.debuglisting) {
if (!pcfile)
pcfile = fopen("pcdump.txt", "a");
fprintf(pcfile, "\n%s\n%s\n", name1, name2);
for (block = pcbasicblocks; block; block = block->nextBlock)
pclistblock(block, NULL, 0);
}
#endif
}
void pclistdataflow() {
// unknown args
}
void pclistinterferences(char *class_format, int regcount) {
}
void pclistspill() {
// unknown args
}
void pclistcopypropitem() {
// unknown args
}
void pclistcoalesce() {
// unknown args
}
void pclistusedefs() {
// unknown args
}
void pclistpropinfo() {
// unknown args
}
static void listloop() {
// unknown args
}
static void listloops() {
// unknown args
}
void pclistloops() {
// unknown args
}
static void listswitchtables() {
// unknown args
}
void pclistswitchtables() {
// unknown args
}
void pclistdominators() {
// unknown args
}
void pclistbackedge() {
// unknown args
}
static char *GetInterferenceFlags(IGNode *node) {
char *buf;
Boolean first;
first = 1;
buf = oalloc(512);
buf[0] = 0;
if (node->flags & fSpilled) {
strcat(buf, "fSpilled");
first = 0;
}
if (node->flags & fPushed) {
if (!first)
strcat(buf, "|");
strcat(buf, "fPushed");
first = 0;
}
if (node->flags & fCoalesced) {
if (!first)
strcat(buf, "|");
strcat(buf, "fCoalesced");
first = 0;
}
if (node->flags & fCoalescedInto) {
if (!first)
strcat(buf, "|");
strcat(buf, "fCoalescedInto");
first = 0;
}
if (node->flags & fPairHigh) {
if (!first)
strcat(buf, "|");
strcat(buf, "fPairHigh");
first = 0;
}
if (node->flags & fPairLow) {
if (!first)
strcat(buf, "|");
strcat(buf, "fPairLow");
first = 0;
}
if (!*buf)
strcat(buf, "no_flags");
return buf;
}
void pclistinterferencegraphnode() {
// unknown args
}
void pclistinterferencegraph() {
// unknown args
}
void pclistblock_scheduler() {
// unknown args
}
void pclistblocks_start_scheduler(char *str1, char *str2) {
}
void pclistblocks_end_scheduler(void) {
if (pclist_bad_operand)
CError_FATAL(1318);
}
static void printheapsize() {
// unknown args
}
void pctotalheap() {
// unknown args
}
void pctotalmemory() {
// unknown args
}
void pcmessage(char *probably_a_string, ...) {
}
int formatalias(Alias *alias, char *buf, int bufSize) {
char *name;
char *typestr;
int len;
int len2;
if (bufSize < 16)
return sprintf(buf, "...");
switch (alias->type) {
case AliasType0:
case AliasType1:
name = CMangler_GetLinkName(alias->object)->name;
if (!strlen(name) || name[0] < 0)
CError_FATAL(1458);
if (strlen(name) + 16 > bufSize)
return sprintf(buf, "...");
switch (alias->object->datatype) {
case DNONLAZYPTR:
typestr = "{NL}";
break;
case DDATA:
typestr = "{RW}";
break;
case DLOCAL:
typestr = "{SP}";
break;
default:
typestr = "";
}
len = sprintf(buf, "%0.*s%s", bufSize - 20, name, typestr, alias->size);
buf += len;
if (alias->type == AliasType0)
return len;
if (alias->offset == 0)
len2 = sprintf(buf, ":%d", alias->size);
else if (alias->offset > 0)
len2 = sprintf(buf, "+%d:%d", alias->offset, alias->size);
else
len2 = sprintf(buf, "-%d:%d", -alias->offset, alias->size);
return len + len2;
case AliasType2:
len = 0;
len2 = sprintf(buf, "{");
buf += len2;
len += len2;
len2 = sprintf(buf, "*");
buf += len2;
len += len2;
len2 = sprintf(buf, "}");
buf += len2;
len += len2;
return len;
default:
CError_FATAL(1543);
return 0;
}
}
int dumpalias(Alias *alias, int len, Boolean flag1, Boolean flag2) {
char *name;
char *typestr;
AliasMember *member;
Boolean notFirst;
if (!flag2 && alias == worst_case) {
fprintf(pcfile, " ALIAS = {worst_case}");
if (flag1)
fprintf(pcfile, "\n");
return 0;
}
if (flag1) {
if (alias == worst_case)
fprintf(pcfile, "ALIAS worst_case = ");
else
fprintf(pcfile, " ALIAS = ");
}
switch (alias->type) {
case AliasType0:
case AliasType1:
name = CMangler_GetLinkName(alias->object)->name;
if (!strlen(name) || name[0] < 0)
CError_FATAL(1581);
switch (alias->object->datatype) {
case DNONLAZYPTR:
typestr = "{NL}";
break;
case DDATA:
typestr = "{RW}";
break;
case DLOCAL:
typestr = "{SP}";
break;
default:
typestr = "";
}
len += fprintf(pcfile, "%0.80s%s", name, typestr);
if (alias->type == AliasType0) {
if (flag1)
fprintf(pcfile, "\n");
return len;
}
if (alias->offset == 0)
len += fprintf(pcfile, ":%d", alias->size);
else if (alias->offset > 0)
len += fprintf(pcfile, "+%d:%d", alias->offset, alias->size);
else
len += fprintf(pcfile, "-%d:%d", -alias->offset, alias->size);
if (flag1)
fprintf(pcfile, "\n");
return len;
case AliasType2:
len += fprintf(pcfile, "{");
notFirst = 0;
for (member = alias->parents; member; member = member->nextParent) {
if (member->child->type == AliasType0) {
if (notFirst)
len += fprintf(pcfile, ",");
if (len > 60) {
fprintf(pcfile, "\n ");
len = 0;
}
len = dumpalias(member->child, len, 0, 0);
notFirst = 1;
}
}
for (member = alias->parents; member; member = member->nextParent) {
if (member->child->type != AliasType0) {
if (notFirst)
len += fprintf(pcfile, ",");
if (len > 60) {
fprintf(pcfile, "\n ");
len = 0;
}
len = dumpalias(member->child, len, 0, 0);
notFirst = 1;
}
}
len += fprintf(pcfile, "}");
if (flag1)
fprintf(pcfile, "\n");
return len;
default:
CError_FATAL(1661);
return 0;
}
}
void pcformatset() {
// unknown args
}
int GetLineEndOffset(char *str, int lineNum, int len) {
int offset;
char *work;
offset = GetLineOffset(str, lineNum, len);
if (offset < 0)
return offset;
work = str + offset;
while (*work) {
if (*work == '\n')
return work - str - 1;
work++;
}
return -1;
}
int GetLineOffset(char *str, int lineNum, int len) {
char *work = str;
char *end;
if (lineNum < 0)
return -1;
end = str + len;
while (work < end) {
if (*work == '\n' && --lineNum <= 0)
return work - str;
work++;
}
return 0;
}
void DumpSourceCode() {
// unknown args
}
int DumpIR_SrcBreak() {
// unknown args
return 0;
}

View File

@@ -0,0 +1,345 @@
#include "compiler/PCodeUtilities.h"
#include "compiler/CError.h"
#include "compiler/CFunc.h"
#include "compiler/CParser.h"
#include "compiler/CodeGen.h"
#include "compiler/Exceptions.h"
#include "compiler/PCode.h"
#include "compiler/PCodeInfo.h"
#include "compiler/Registers.h"
#include "compiler/enode.h"
#include "compiler/objects.h"
void pcsetrecordbit(PCode *pc) {
int reg;
PCodeArg *arg;
short argCount;
int argIdx;
pc->flags &= ~(fIsMove | fCommutative | fIsCSE);
if ((pc->flags & fOpTypeMask) == fOpTypeFPR) {
reg = 1;
} else if ((pc->flags & fOpTypeMask) == fOpTypeVR) {
reg = 6;
} else {
reg = 0;
}
if (pc->op == PC_ANDI || pc->op == PC_ANDIS) {
pc->flags |= fRecordBit;
} else if (pc->op == PC_ADDI || pc->op == PC_ADDIC) {
pc->flags |= fSetsCarry;
pc->flags |= fRecordBit;
change_num_operands(pc, 5);
pc->op = PC_ADDICR;
CError_ASSERT(76, pc->args[3].kind == PCOp_PLACEHOLDEROPERAND);
pc->args[3].kind = PCOp_REGISTER;
pc->args[3].arg = RegClass_SPR;
pc->args[3].data.reg.reg = 0;
pc->args[3].data.reg.effect = EffectWrite;
CError_ASSERT(80, pc->args[4].kind == PCOp_PLACEHOLDEROPERAND);
pc->args[4].kind = PCOp_REGISTER;
pc->args[4].arg = RegClass_CRFIELD;
pc->args[4].data.reg.reg = reg;
pc->args[4].data.reg.effect = EffectWrite;
} else {
arg = pc->args;
argIdx = argCount = pc->argCount;
while (arg->kind != PCOp_PLACEHOLDEROPERAND && argIdx) {
if (arg->kind == PCOp_REGISTER && arg->arg == RegClass_CRFIELD && arg->data.reg.reg == reg) {
arg->data.reg.effect |= EffectWrite;
pc->flags |= fRecordBit;
return;
}
arg++;
argIdx--;
}
if (argIdx <= 0) {
arg = &pc->args[argCount];
pc->argCount++;
}
CError_ASSERT(105, arg->kind == PCOp_PLACEHOLDEROPERAND);
arg->kind = PCOp_REGISTER;
arg->arg = RegClass_CRFIELD;
arg->data.reg.reg = reg;
arg->data.reg.effect = EffectWrite;
if (pc->op != PC_ADDICR)
pc->flags |= fRecordBit;
}
}
void pcsetsideeffects(PCode *pc) {
pc->flags &= ~(fIsMove | fCommutative | fIsCSE);
pc->flags |= fSideEffects;
}
void pcsetlinkbit(PCode *pc) {
PCodeArg *arg;
int argIdx;
switch (pc->op) {
case PC_B:
pc->op = PC_BL;
break;
case PC_BCTR:
pc->op = PC_BCTRL;
break;
case PC_BLR:
pc->op = PC_BLRL;
break;
}
arg = pc->args;
argIdx = pc->argCount;
while (arg->kind != PCOp_PLACEHOLDEROPERAND && argIdx) {
if (arg->kind == PCOp_REGISTER && arg->arg == RegClass_SPR && arg->data.reg.reg == 1) {
arg->data.reg.effect |= EffectWrite;
pc->flags |= fLink;
return;
}
arg++;
argIdx--;
}
CError_ASSERT(169, arg->kind == PCOp_PLACEHOLDEROPERAND);
arg->kind = PCOp_REGISTER;
arg->arg = RegClass_SPR;
arg->data.reg.reg = 1;
arg->data.reg.effect = EffectWrite;
if (opcodeinfo[pc->op].flags & fIsCall) {
pc->flags &= ~fIsBranch;
pc->flags |= fIsCall;
}
pc->flags |= fLink;
}
void branch_label(PCodeLabel *label) {
if (pclastblock->pcodeCount) {
pcbranch(pclastblock, label);
makepcblock();
}
pclabel(pclastblock, label);
}
void branch_conditional(short a, short compareop, short c, PCodeLabel *label) {
PCodeBlock *tmpblock;
PCodeLabel *tmplabel;
int r28;
tmpblock = pclastblock;
tmplabel = makepclabel();
switch (compareop) {
case ENOTEQU:
c = !c;
case EEQU:
r28 = 2;
break;
case EGREATEREQU:
c = !c;
case ELESS:
r28 = 0;
break;
case ELESSEQU:
c = !c;
case EGREATER:
r28 = 1;
break;
}
emitpcode(c ? PC_BT : PC_BF, a, r28, label);
pcbranch(pclastblock, label);
pcbranch(pclastblock, tmplabel);
makepcblock();
pclabel(pclastblock, tmplabel);
}
void branch_always(PCodeLabel *label) {
emitpcode(PC_B, label);
pcbranch(pclastblock, label);
makepcblock();
}
void branch_decrement_always(Opcode opcode, PCodeLabel *label) {
PCodeLabel *tmplabel = makepclabel();
emitpcode(opcode, label);
pcbranch(pclastblock, label);
pcbranch(pclastblock, tmplabel);
makepcblock();
pclabel(pclastblock, tmplabel);
}
void branch_indirect(Object *obj) {
emitpcode(PC_BCTR, obj, 0);
makepcblock();
}
int branch_count_volatiles(void) {
int count = 0;
int i;
RegClass rclass;
for (rclass = 0; rclass < RegClassMax; rclass++) {
for (i = 0; i < n_scratch_registers[rclass]; i++) {
count++;
}
}
return count;
}
PCodeArg *branch_record_volatiles(PCodeArg *arglist, UInt32 *masks) {
int i;
RegClass rclass;
for (rclass = RegClassMax - 1; rclass >= 0; rclass--) {
for (i = 0; i < n_scratch_registers[rclass]; i++) {
arglist->kind = PCOp_REGISTER;
arglist->arg = rclass;
arglist->data.reg.reg = scratch_registers[rclass][i];
arglist->data.reg.effect = EffectWrite;
if (masks[rclass] & (1 << scratch_registers[rclass][i]))
arglist->data.reg.effect |= EffectRead;
arglist++;
}
}
return arglist;
}
void branch_subroutine(Object *obj, short add_nop, UInt32 *masks) {
int count;
PCode *pc;
PCodeArg *arg;
count = branch_count_volatiles();
if (copts.exceptions && current_statement)
count += countexceptionactionregisters(current_statement->dobjstack);
pc = makepcode(PC_BL, count, obj, 0);
arg = branch_record_volatiles(pc->args + 1, masks);
if (copts.exceptions && current_statement)
noteexceptionactionregisters(current_statement->dobjstack, arg);
appendpcode(pclastblock, pc);
if (add_nop)
emitpcode(PC_NOP);
branch_label(makepclabel());
if (copts.exceptions && current_statement)
recordexceptionactions(pc, current_statement->dobjstack);
}
void branch_subroutine_ctr(UInt32 *masks) {
int count;
PCode *pc;
PCodeArg *arg;
count = branch_count_volatiles();
if (copts.exceptions && current_statement)
count += countexceptionactionregisters(current_statement->dobjstack);
pc = makepcode(PC_BCTRL, count);
arg = branch_record_volatiles(pc->args + 1, masks);
if (copts.exceptions && current_statement)
noteexceptionactionregisters(current_statement->dobjstack, arg);
appendpcode(pclastblock, pc);
branch_label(makepclabel());
if (copts.exceptions && current_statement)
recordexceptionactions(pc, current_statement->dobjstack);
}
void add_immediate(short dest_reg, short base_reg, Object *obj, SInt16 offset) {
short tmp_reg = base_reg;
if (obj && offset && obj->datatype != DLOCAL) {
tmp_reg = used_virtual_registers[RegClass_GPR]++;
add_immediate_lo(tmp_reg, base_reg, obj, 0, 1);
obj = NULL;
}
if (!obj && !offset)
emitpcode(PC_MR, dest_reg, tmp_reg);
else
emitpcode(PC_ADDI, dest_reg, tmp_reg, obj, offset);
}
PCode *add_immediate_lo(short dest_reg, short base_reg, Object *obj, SInt16 offset, char add_to_block) {
PCode *pc;
CError_ASSERT(577, obj);
pc = makepcode(PC_ADDI, dest_reg, base_reg, obj, offset);
if (add_to_block)
appendpcode(pclastblock, pc);
return pc;
}
PCode *op_absolute_ha(short dest_reg, short base_reg, Object *obj, short offset, char add_to_block) {
PCode *pc;
int tmp_reg;
if (obj->datatype == DLOCAL) {
pc = makepcode(PC_ADDIS, dest_reg, base_reg, obj, offset);
} else if (copts.codegen_pic) {
tmp_reg = base_reg;
CError_ASSERT(601, tmp_reg);
pc = makepcode(PC_ADDIS, dest_reg, tmp_reg, obj, offset);
} else {
CError_ASSERT(606, base_reg == 0);
pc = makepcode(PC_LIS, dest_reg, obj, offset);
}
if (add_to_block)
appendpcode(pclastblock, pc);
return pc;
}
void load_store_register(Opcode opcode, short dest_reg, short base_reg, Object *obj, SInt32 offset) {
short addi_tmp;
short offset_reg1;
short offset_reg2;
offset_reg1 = base_reg;
if (obj && offset && obj->datatype != DLOCAL) {
offset_reg1 = used_virtual_registers[RegClass_GPR]++;
add_immediate_lo(offset_reg1, base_reg, obj, 0, 1);
obj = NULL;
}
if (offset != (short)offset) {
if (opcode == PC_LWZ && dest_reg == 12)
offset_reg2 = 12;
else if (opcode == PC_LWZ && dest_reg == 11)
offset_reg2 = 11;
else
offset_reg2 = used_virtual_registers[RegClass_GPR]++;
emitpcode(PC_ADDIS, offset_reg2, offset_reg1, 0, (short) ((offset >> 16) + ((offset & 0x8000) >> 15)));
offset = (short) offset;
offset_reg1 = offset_reg2;
}
if (opcode == PC_STVX || opcode == PC_LVX) {
offset_reg2 = 0;
if (obj) {
addi_tmp = used_virtual_registers[RegClass_GPR]++;
emitpcode(PC_ADDI, addi_tmp, offset_reg1, obj, offset);
offset_reg1 = addi_tmp;
} else if (offset) {
offset_reg2 = used_virtual_registers[RegClass_GPR]++;
emitpcode(PC_LI, offset_reg2, offset);
}
if (!offset_reg2)
emitpcode(opcode, dest_reg, 0, offset_reg1);
else
emitpcode(opcode, dest_reg, offset_reg1, offset_reg2);
} else {
emitpcode(opcode, dest_reg, offset_reg1, obj, offset);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,792 @@
#include "compiler/StructMoves.h"
#include "compiler/CError.h"
#include "compiler/CParser.h"
#include "compiler/CodeGen.h"
#include "compiler/Operands.h"
#include "compiler/PCode.h"
#include "compiler/PCodeUtilities.h"
#include "compiler/Registers.h"
void make_addressable(Operand *opnd, SInt32 offset, int unusedArg) {
int reg;
if (opnd->optype == OpndType_IndirectSymbol)
coerce_to_addressable(opnd);
if (opnd->optype != OpndType_IndirectGPR_ImmOffset || (opnd->immOffset + offset) > 0x7FFF) {
reg = used_virtual_registers[RegClass_GPR]++;
load_address(reg, opnd);
opnd->optype = OpndType_IndirectGPR_ImmOffset;
opnd->reg = reg;
opnd->object = NULL;
opnd->immOffset = 0;
}
}
static void load_displaced_address(Operand *opnd, SInt32 offset) {
int reg;
reg = used_virtual_registers[RegClass_GPR]++;
if (opnd->optype == OpndType_IndirectSymbol)
coerce_to_addressable(opnd);
if (opnd->optype == OpndType_IndirectGPR_ImmOffset) {
offset += opnd->immOffset;
if (!FITS_IN_SHORT(offset)) {
add_immediate(reg, opnd->reg, opnd->object, opnd->immOffset);
emitpcode(PC_ADDI, reg, reg, 0, offset - opnd->immOffset);
} else {
add_immediate(reg, opnd->reg, opnd->object, offset);
}
} else if (opnd->optype == OpndType_IndirectGPR_Indexed) {
emitpcode(PC_ADD, reg, opnd->reg, opnd->regOffset);
emitpcode(PC_ADDI, reg, reg, 0, offset);
} else {
CError_FATAL(80);
}
opnd->optype = OpndType_IndirectGPR_ImmOffset;
opnd->reg = reg;
opnd->object = NULL;
opnd->immOffset = 0;
}
static void move_block_via_load_store(Operand *dst, Operand *src, SInt32 len, SInt32 align) {
SInt32 step;
SInt32 pos;
int floatReg;
int reg;
if (src->optype == OpndType_IndirectSymbol)
coerce_to_addressable(src);
if (dst->optype == OpndType_IndirectSymbol)
coerce_to_addressable(dst);
if (len == 8) {
floatReg = used_virtual_registers[RegClass_FPR]++;
if (src->optype == OpndType_IndirectGPR_ImmOffset) {
load_store_register(PC_LFD, floatReg, src->reg, src->object, src->immOffset);
setpcodeflags(src->flags);
} else if (src->optype == OpndType_IndirectGPR_Indexed) {
emitpcode(PC_LFDX, floatReg, src->reg, src->regOffset);
setpcodeflags(src->flags);
} else {
CError_FATAL(145);
}
if (dst->optype == OpndType_IndirectGPR_ImmOffset) {
load_store_register(PC_STFD, floatReg, dst->reg, dst->object, dst->immOffset);
setpcodeflags(dst->flags);
} else if (dst->optype == OpndType_IndirectGPR_Indexed) {
emitpcode(PC_STFDX, floatReg, dst->reg, dst->regOffset);
setpcodeflags(dst->flags);
} else {
CError_FATAL(157);
}
return;
}
if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align;
step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2;
} else {
step = ((UInt32) len > 4) ? 4 : ((UInt32) len <= 2) ? len : 2;
}
if (step != len) {
if (dst->optype == OpndType_IndirectGPR_Indexed)
make_addressable(dst, len, 0);
if (src->optype == OpndType_IndirectGPR_Indexed)
make_addressable(src, len, 0);
}
for (pos = 0; len != 0; len -= step, pos += step) {
reg = used_virtual_registers[RegClass_GPR]++;
if (src->optype == OpndType_IndirectGPR_ImmOffset) {
load_store_register(
(step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
reg,
src->reg,
src->object,
src->immOffset + pos
);
setpcodeflags(src->flags);
} else if (src->optype == OpndType_IndirectGPR_Indexed) {
emitpcode(
(step == 1) ? PC_LBZX : (step == 2) ? PC_LHZX : PC_LWZX,
reg,
src->reg,
src->regOffset
);
setpcodeflags(src->flags);
} else {
CError_FATAL(183);
}
if (dst->optype == OpndType_IndirectGPR_ImmOffset) {
load_store_register(
(step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
reg,
dst->reg,
dst->object,
dst->immOffset + pos
);
setpcodeflags(dst->flags);
} else if (dst->optype == OpndType_IndirectGPR_Indexed) {
emitpcode(
(step == 1) ? PC_STBX : (step == 2) ? PC_STHX : PC_STWX,
reg,
dst->reg,
dst->regOffset
);
setpcodeflags(dst->flags);
} else {
CError_FATAL(195);
}
}
}
static void move_block_via_load_store_sequence(Operand *dst, Operand *src, SInt32 len, SInt32 align) {
SInt32 pos;
int i;
SInt32 step;
pos = 0;
make_addressable(dst, len, 0);
make_addressable(src, len, 0);
if ((align % 8) == 0) {
while (len >= 16) {
int reg1 = used_virtual_registers[RegClass_FPR]++;
int reg2 = used_virtual_registers[RegClass_FPR]++;
load_store_register(PC_LFD, reg1, src->reg, src->object, src->immOffset + pos);
setpcodeflags(src->flags);
load_store_register(PC_LFD, reg2, src->reg, src->object, src->immOffset + pos + 8);
setpcodeflags(src->flags);
load_store_register(PC_STFD, reg1, dst->reg, dst->object, dst->immOffset + pos);
setpcodeflags(dst->flags);
load_store_register(PC_STFD, reg2, dst->reg, dst->object, dst->immOffset + pos + 8);
setpcodeflags(dst->flags);
pos += 16;
len -= 16;
}
}
while (len >= 8) {
if ((align % 8) == 0) {
int reg = used_virtual_registers[RegClass_FPR]++;
load_store_register(PC_LFD, reg, src->reg, src->object, src->immOffset + pos);
setpcodeflags(src->flags);
load_store_register(PC_STFD, reg, dst->reg, dst->object, dst->immOffset + pos);
setpcodeflags(dst->flags);
pos += 8;
len -= 8;
} else {
if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align;
step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp > 2) ? 2 : 1;
} else {
step = 4;
}
for (i = 0; i < 8; i += (step * 2)) {
int reg1 = used_virtual_registers[RegClass_GPR]++;
int reg2 = used_virtual_registers[RegClass_GPR]++;
load_store_register(
(step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
reg1,
src->reg,
src->object,
src->immOffset + pos
);
setpcodeflags(src->flags);
load_store_register(
(step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
reg2,
src->reg,
src->object,
src->immOffset + pos + step
);
setpcodeflags(src->flags);
load_store_register(
(step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
reg1,
dst->reg,
dst->object,
dst->immOffset + pos
);
setpcodeflags(dst->flags);
load_store_register(
(step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
reg2,
dst->reg,
dst->object,
dst->immOffset + pos + step
);
setpcodeflags(dst->flags);
pos += (step * 2);
len -= (step * 2);
}
}
}
while (len) {
int reg;
if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align;
step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2;
} else {
step = ((UInt32) len > 4) ? 4 : ((UInt32) len <= 2) ? len : 2;
}
reg = used_virtual_registers[RegClass_GPR]++;
load_store_register(
(step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
reg,
src->reg,
src->object,
src->immOffset + pos
);
setpcodeflags(src->flags);
load_store_register(
(step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
reg,
dst->reg,
dst->object,
dst->immOffset + pos
);
setpcodeflags(dst->flags);
len -= step;
pos += step;
}
}
static void move_block_via_inline_loop(Operand *dst, Operand *src, SInt32 len, SInt32 align) {
PCodeLabel *label; // r25
SInt32 pos; // r25
SInt32 step; // r24
int reg1; // r22
int reg2; // r23
SInt32 remainder; // r23
label = makepclabel();
if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
SInt32 tmp = (align == 0) ? 1 : (align > len) ? len : align;
step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2;
} else {
step = 4;
}
load_displaced_address(dst, -step);
load_displaced_address(src, -step);
CError_ASSERT(377, (len / step) != 0);
reg1 = used_virtual_registers[RegClass_GPR]++;
load_immediate(reg1, len / (step * 2));
emitpcode(PC_MTCTR, reg1);
branch_label(label);
reg1 = used_virtual_registers[RegClass_GPR]++;
reg2 = used_virtual_registers[RegClass_GPR]++;
load_store_register(
(step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
reg1,
src->reg,
NULL,
step
);
setpcodeflags(src->flags);
load_store_register(
(step == 1) ? PC_LBZU : (step == 2) ? PC_LHZU : PC_LWZU,
reg2,
src->reg,
NULL,
step * 2
);
setpcodeflags(src->flags);
load_store_register(
(step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
reg1,
dst->reg,
NULL,
step
);
setpcodeflags(dst->flags);
load_store_register(
(step == 1) ? PC_STBU : (step == 2) ? PC_STHU : PC_STWU,
reg2,
dst->reg,
NULL,
step * 2
);
setpcodeflags(dst->flags);
branch_decrement_always(PC_BDNZ, label);
for (remainder = len & 7, pos = step; remainder != 0; remainder -= step, pos += step) {
int reg;
if (copts.misaligned_mem_access == 0 && (UInt32) align < 4) {
SInt32 tmp = (align == 0) ? 1 : (align > remainder) ? remainder : align;
step = ((UInt32) tmp > 4) ? 4 : ((UInt32) tmp <= 2) ? (UInt32) tmp : 2;
} else {
step = ((UInt32) remainder > 4) ? 4 : ((UInt32) remainder <= 2) ? remainder : 2;
}
reg = used_virtual_registers[RegClass_GPR]++;
load_store_register(
(step == 1) ? PC_LBZ : (step == 2) ? PC_LHZ : PC_LWZ,
reg,
src->reg,
NULL,
pos
);
setpcodeflags(src->flags);
load_store_register(
(step == 1) ? PC_STB : (step == 2) ? PC_STH : PC_STW,
reg,
dst->reg,
NULL,
pos
);
setpcodeflags(dst->flags);
}
}
void move_block(Operand *dst, Operand *src, SInt32 len, SInt32 align) {
Operand myDst;
myDst = *dst;
CError_ASSERT(447, myDst.optype >= OpndType_IndirectGPR_ImmOffset);
CError_ASSERT(449, src->optype >= OpndType_IndirectGPR_ImmOffset);
if (len == 1 || len == 2 || len == 4)
move_block_via_load_store(&myDst, src, len, align);
else if (len == 8 && align == 8)
move_block_via_load_store(&myDst, src, len, align);
else if (len <= 16 || (copts.optimizesize == 0 && len <= 64))
move_block_via_load_store_sequence(&myDst, src, len, align);
else
move_block_via_inline_loop(&myDst, src, len, align);
}
static void load_word_of_small_struct(short dstReg, short srcReg, Operand *opnd, SInt32 offset, SInt32 len, SInt32 align) {
short tmpReg;
short extra = 0;
switch (len) {
case 1:
tmpReg = used_virtual_registers[RegClass_GPR]++;
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset);
setpcodeflags(opnd->flags);
emitpcode(PC_RLWINM, dstReg, tmpReg, 24, 0, 7);
setpcodeflags(opnd->flags);
break;
case 2:
case 3:
if (align > 1) {
tmpReg = used_virtual_registers[RegClass_GPR]++;
load_store_register(PC_LHZ, tmpReg, srcReg, opnd->object, offset);
extra += 2;
setpcodeflags(opnd->flags);
emitpcode(PC_RLWINM, dstReg, tmpReg, 16, 0, 15);
setpcodeflags(opnd->flags);
} else {
tmpReg = used_virtual_registers[RegClass_GPR]++;
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset);
setpcodeflags(opnd->flags);
emitpcode(PC_RLWINM, dstReg, tmpReg, 24, 0, 7);
setpcodeflags(opnd->flags);
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 1);
extra += 2;
setpcodeflags(opnd->flags);
emitpcode(PC_RLWIMI, dstReg, tmpReg, 16, 8, 15);
setpcodeflags(opnd->flags);
}
if (len == 3) {
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + extra);
setpcodeflags(opnd->flags);
emitpcode(PC_RLWIMI, dstReg, tmpReg, 8, 16, 23);
setpcodeflags(opnd->flags);
}
break;
case 4:
if (align > 2) {
load_store_register(PC_LWZ, dstReg, srcReg, opnd->object, offset);
setpcodeflags(opnd->flags);
} else if (align > 1) {
tmpReg = used_virtual_registers[RegClass_GPR]++;
load_store_register(PC_LHZ, tmpReg, srcReg, opnd->object, offset);
setpcodeflags(opnd->flags);
emitpcode(PC_RLWINM, dstReg, tmpReg, 16, 0, 15);
setpcodeflags(opnd->flags);
load_store_register(PC_LHZ, tmpReg, srcReg, opnd->object, offset + 2);
setpcodeflags(opnd->flags);
emitpcode(PC_RLWIMI, dstReg, tmpReg, 0, 16, 31);
setpcodeflags(opnd->flags);
} else {
tmpReg = used_virtual_registers[RegClass_GPR]++;
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset);
setpcodeflags(opnd->flags);
emitpcode(PC_RLWINM, dstReg, tmpReg, 24, 0, 7);
setpcodeflags(opnd->flags);
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 1);
setpcodeflags(opnd->flags);
emitpcode(PC_RLWIMI, dstReg, tmpReg, 16, 8, 15);
setpcodeflags(opnd->flags);
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 2);
setpcodeflags(opnd->flags);
emitpcode(PC_RLWIMI, dstReg, tmpReg, 8, 16, 23);
setpcodeflags(opnd->flags);
load_store_register(PC_LBZ, tmpReg, srcReg, opnd->object, offset + 3);
setpcodeflags(opnd->flags);
emitpcode(PC_RLWIMI, dstReg, tmpReg, 0, 24, 31);
setpcodeflags(opnd->flags);
}
break;
}
}
void load_small_block_into_reg(short dstReg, Operand *srcOpnd, Type *type, SInt32 align) {
short finalReg;
short tmpReg;
SInt32 absAddress;
coerce_to_addressable(srcOpnd);
if (srcOpnd->optype == OpndType_IndirectGPR_Indexed) {
CError_FATAL(557);
tmpReg = used_virtual_registers[RegClass_GPR]++;
load_address(tmpReg, srcOpnd);
srcOpnd->optype = OpndType_IndirectGPR_ImmOffset;
srcOpnd->reg = tmpReg;
srcOpnd->object = NULL;
srcOpnd->immOffset = 0;
}
if (copts.misaligned_mem_access)
align = 4;
switch (srcOpnd->optype) {
case OpndType_GPRPair:
return;
case OpndType_GPR:
return;
case OpndType_GPR_ImmOffset:
finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++;
add_immediate(finalReg, srcOpnd->reg, srcOpnd->object, srcOpnd->immOffset);
break;
case OpndType_GPR_Indexed:
finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++;
emitpcode(PC_ADD, finalReg, srcOpnd->reg, srcOpnd->regOffset);
break;
case OpndType_Absolute:
finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++;
absAddress = srcOpnd->immediate;
if (FITS_IN_SHORT(absAddress)) {
emitpcode(PC_LI, finalReg, absAddress);
} else {
tmpReg = finalReg;
if (copts.optimizationlevel > 1 && absAddress)
tmpReg = used_virtual_registers[RegClass_GPR]++;
emitpcode(PC_LIS, tmpReg, 0, HIGH_PART(absAddress));
if (absAddress)
emitpcode(PC_ADDI, finalReg, tmpReg, 0, LOW_PART(absAddress));
}
break;
case OpndType_IndirectGPR_ImmOffset:
finalReg = dstReg ? dstReg : used_virtual_registers[RegClass_GPR]++;
load_word_of_small_struct(finalReg, srcOpnd->reg, srcOpnd, srcOpnd->immOffset, type->size, align);
break;
default:
CError_FATAL(606);
}
srcOpnd->optype = OpndType_GPR;
srcOpnd->reg = finalReg;
}
void load_small_block_into_reg_pair(short dstRegLo, short dstRegHi, Operand *srcOpnd, Type *type, SInt32 align) {
short finalRegLo;
short finalRegHi;
short tmpRegLo;
short tmpRegHi;
short tmpReg;
SInt32 absAddress;
finalRegHi = -1;
coerce_to_addressable(srcOpnd);
if (srcOpnd->optype == OpndType_IndirectGPR_Indexed) {
CError_FATAL(624);
tmpReg = used_virtual_registers[RegClass_GPR]++;
load_address(tmpReg, srcOpnd);
srcOpnd->optype = OpndType_IndirectGPR_ImmOffset;
srcOpnd->reg = tmpReg;
srcOpnd->object = NULL;
srcOpnd->immOffset = 0;
}
if (copts.misaligned_mem_access)
align = 4;
switch (srcOpnd->optype) {
case OpndType_GPRPair:
if (dstRegLo != 0 && dstRegHi == 0)
dstRegHi = used_virtual_registers[RegClass_GPR]++;
if (dstRegHi != 0 && dstRegLo == 0)
dstRegLo = used_virtual_registers[RegClass_GPR]++;
if (srcOpnd->reg != dstRegLo || srcOpnd->regHi != dstRegHi) {
tmpRegLo = dstRegLo ? dstRegLo : srcOpnd->reg;
tmpRegHi = dstRegHi ? dstRegHi : srcOpnd->regHi;
if (tmpRegLo != srcOpnd->reg) {
if (tmpRegLo == srcOpnd->regHi) {
CError_ASSERT(657, tmpRegLo != tmpRegHi);
emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi);
emitpcode(PC_MR, tmpRegLo, srcOpnd->reg);
} else {
emitpcode(PC_MR, tmpRegLo, srcOpnd->reg);
if (srcOpnd->regHi != tmpRegHi)
emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi);
}
} else if (tmpRegHi != srcOpnd->regHi) {
if (tmpRegHi == srcOpnd->reg) {
CError_ASSERT(671, tmpRegLo != tmpRegHi);
emitpcode(PC_MR, tmpRegLo, srcOpnd->reg);
emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi);
} else {
emitpcode(PC_MR, tmpRegHi, srcOpnd->regHi);
if (srcOpnd->reg != tmpRegLo)
emitpcode(PC_MR, tmpRegLo, srcOpnd->reg);
}
}
}
finalRegLo = srcOpnd->reg;
finalRegHi = srcOpnd->regHi;
break;
case OpndType_GPR:
CError_FATAL(688);
break;
case OpndType_GPR_ImmOffset:
CError_FATAL(691);
break;
case OpndType_GPR_Indexed:
CError_FATAL(694);
break;
case OpndType_Absolute:
finalRegLo = dstRegLo ? dstRegLo : used_virtual_registers[RegClass_GPR]++;
absAddress = srcOpnd->immediate;
if (FITS_IN_SHORT(absAddress)) {
emitpcode(PC_LI, finalRegLo, absAddress);
} else {
tmpReg = finalRegLo;
if (copts.optimizationlevel > 1 && absAddress)
tmpReg = used_virtual_registers[RegClass_GPR]++;
emitpcode(PC_LIS, tmpReg, 0, HIGH_PART(absAddress));
if (absAddress)
emitpcode(PC_ADDI, finalRegLo, tmpReg, 0, LOW_PART(absAddress));
}
finalRegHi = dstRegHi ? dstRegHi : used_virtual_registers[RegClass_GPR]++;
if (is_unsigned(type) || absAddress >= 0)
load_immediate(finalRegHi, 0);
else
load_immediate(finalRegHi, -1);
break;
case OpndType_IndirectGPR_ImmOffset:
finalRegLo = dstRegLo ? dstRegLo : used_virtual_registers[RegClass_GPR]++;
finalRegHi = dstRegHi ? dstRegHi : used_virtual_registers[RegClass_GPR]++;
if (srcOpnd->reg == finalRegHi) {
if (srcOpnd->reg == finalRegLo) {
CError_FATAL(726);
} else {
load_word_of_small_struct(
finalRegLo, srcOpnd->reg, srcOpnd,
srcOpnd->immOffset + low_offset, type->size - 4, align);
load_word_of_small_struct(
finalRegHi, srcOpnd->reg, srcOpnd,
srcOpnd->immOffset + high_offset, 4, align);
}
} else {
load_word_of_small_struct(
finalRegHi, srcOpnd->reg, srcOpnd,
srcOpnd->immOffset + high_offset, 4, align);
load_word_of_small_struct(
finalRegLo, srcOpnd->reg, srcOpnd,
srcOpnd->immOffset + low_offset, type->size - 4, align);
}
break;
default:
CError_FATAL(737);
}
if (finalRegHi == -1) {
CError_FATAL(741);
} else {
srcOpnd->optype = OpndType_GPRPair;
srcOpnd->reg = finalRegLo;
srcOpnd->regHi = finalRegHi;
}
}
static void store_word_of_small_struct(short srcReg, short dstReg, Operand *opnd, SInt32 offset, SInt32 len, SInt32 align) {
short tmpReg;
short extra = 0;
switch (len) {
case 1:
tmpReg = used_virtual_registers[RegClass_GPR]++;
emitpcode(PC_RLWINM, tmpReg, srcReg, 8, 24, 31);
setpcodeflags(opnd->flags);
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset);
setpcodeflags(opnd->flags);
break;
case 2:
case 3:
if (align > 1) {
tmpReg = used_virtual_registers[RegClass_GPR]++;
emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 16, 31);
setpcodeflags(opnd->flags);
load_store_register(PC_STH, tmpReg, dstReg, opnd->object, offset);
extra += 2;
setpcodeflags(opnd->flags);
} else {
tmpReg = used_virtual_registers[RegClass_GPR]++;
emitpcode(PC_RLWINM, tmpReg, srcReg, 8, 24, 31);
setpcodeflags(opnd->flags);
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset);
setpcodeflags(opnd->flags);
emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 24, 31);
setpcodeflags(opnd->flags);
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + 1);
extra += 2;
setpcodeflags(opnd->flags);
}
if (len == 3) {
emitpcode(PC_RLWINM, tmpReg, srcReg, 24, 24, 31);
setpcodeflags(opnd->flags);
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + extra);
setpcodeflags(opnd->flags);
}
break;
case 4:
if (align > 2) {
load_store_register(PC_STW, srcReg, dstReg, opnd->object, offset);
setpcodeflags(opnd->flags);
} else if (align > 1) {
tmpReg = used_virtual_registers[RegClass_GPR]++;
emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 16, 31);
setpcodeflags(opnd->flags);
load_store_register(PC_STH, tmpReg, dstReg, opnd->object, offset);
setpcodeflags(opnd->flags);
load_store_register(PC_STH, srcReg, dstReg, opnd->object, offset + 2);
setpcodeflags(opnd->flags);
} else {
tmpReg = used_virtual_registers[RegClass_GPR]++;
emitpcode(PC_RLWINM, tmpReg, srcReg, 8, 24, 31);
setpcodeflags(opnd->flags);
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset);
setpcodeflags(opnd->flags);
emitpcode(PC_RLWINM, tmpReg, srcReg, 16, 24, 31);
setpcodeflags(opnd->flags);
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + 1);
setpcodeflags(opnd->flags);
emitpcode(PC_RLWINM, tmpReg, srcReg, 24, 24, 31);
setpcodeflags(opnd->flags);
load_store_register(PC_STB, tmpReg, dstReg, opnd->object, offset + 2);
setpcodeflags(opnd->flags);
load_store_register(PC_STB, srcReg, dstReg, opnd->object, offset + 3);
setpcodeflags(opnd->flags);
}
break;
}
}
void store_small_block_from_reg(short srcReg, Operand *dstOpnd, Type *type, SInt32 align) {
short tmpReg;
coerce_to_addressable(dstOpnd);
if (dstOpnd->optype == OpndType_IndirectGPR_Indexed) {
CError_FATAL(839);
tmpReg = used_virtual_registers[RegClass_GPR]++;
load_address(tmpReg, dstOpnd);
dstOpnd->optype = OpndType_IndirectGPR_ImmOffset;
dstOpnd->reg = tmpReg;
dstOpnd->object = NULL;
dstOpnd->immOffset = 0;
}
if (copts.misaligned_mem_access)
align = 4;
store_word_of_small_struct(srcReg, dstOpnd->reg, dstOpnd, dstOpnd->immOffset, type->size, align);
}
void store_small_block_from_reg_pair(short srcRegLo, short srcRegHi, Operand *dstOpnd, Type *type, SInt32 align) {
short tmpReg;
coerce_to_addressable(dstOpnd);
if (dstOpnd->optype == OpndType_IndirectGPR_Indexed) {
CError_FATAL(860);
tmpReg = used_virtual_registers[RegClass_GPR]++;
load_address(tmpReg, dstOpnd);
dstOpnd->optype = OpndType_IndirectGPR_ImmOffset;
dstOpnd->reg = tmpReg;
dstOpnd->object = NULL;
dstOpnd->immOffset = 0;
}
if (copts.misaligned_mem_access)
align = 4;
store_word_of_small_struct(
srcRegLo, dstOpnd->reg, dstOpnd,
dstOpnd->immOffset + low_offset, type->size - 4, align);
store_word_of_small_struct(
srcRegHi, dstOpnd->reg, dstOpnd,
dstOpnd->immOffset + high_offset, 4, align);
}

View File

@@ -0,0 +1,518 @@
#include "compiler/Switch.h"
#include "compiler/CError.h"
#include "compiler/CFunc.h"
#include "compiler/CInt64.h"
#include "compiler/CParser.h"
#include "compiler/InstrSelection.h"
#include "compiler/ObjGenMachO.h"
#include "compiler/Operands.h"
#include "compiler/PCode.h"
#include "compiler/PCodeUtilities.h"
#include "compiler/RegisterInfo.h"
#include "compiler/TOC.h"
#include "compiler/CompilerTools.h"
#include "compiler/objects.h"
ObjectList *switchtables;
static SwitchCase **caselabels;
static CaseRange *caseranges;
static SInt32 ncases;
static SInt32 nranges_minus1;
static CInt64 min;
static CInt64 max;
static CInt64 first;
static short selector_gpr;
static short selector_gprHi;
static Type *selector_type;
static PCodeLabel *defaultlabel;
static CInt64 range;
static int compare_cases(const void *a, const void *b) {
const SwitchCase **casea = (const SwitchCase **) a;
const SwitchCase **caseb = (const SwitchCase **) b;
if (CInt64_Less((*casea)->min, (*caseb)->min))
return -1;
if (CInt64_Greater((*casea)->min, (*caseb)->min))
return 1;
return 0;
}
static void build_case_ranges(Type *type, SwitchCase *cases, CLabel *label) {
SwitchCase **caseptr;
SInt32 i;
SwitchCase *curcase;
CaseRange *currange;
if (type->size == 8) {
min.lo = 0;
min.hi = 0x80000000;
max.lo = 0xFFFFFFFF;
max.hi = 0x7FFFFFFF;
} else if (type->size == 4) {
CInt64_SetLong(&min, 0x80000000);
CInt64_SetLong(&max, 0x7FFFFFFF);
} else if (is_unsigned(type)) {
min.hi = 0;
min.lo = 0;
max.hi = 0;
max.lo = 0xFFFF;
} else {
CInt64_SetLong(&min, -0x8000);
CInt64_SetLong(&max, 0x7FFF);
}
caselabels = lalloc(sizeof(SwitchCase *) * ncases);
caseptr = caselabels;
while (cases) {
*caseptr = cases;
cases = cases->next;
++caseptr;
}
caseranges = lalloc(((ncases * 2) + 2) * sizeof(CaseRange));
if (type->size < 8) {
for (i = 0; i < ncases; i++)
CInt64_SetLong(&caselabels[i]->min, caselabels[i]->min.lo);
}
qsort(caselabels, ncases, sizeof(SwitchCase *), &compare_cases);
currange = caseranges;
currange->min = min;
currange->range = CInt64_Sub(max, min);
currange->label = label->pclabel;
for (i = 0; i < ncases; i++) {
curcase = caselabels[i];
if (CInt64_GreaterEqual(curcase->min, min) && CInt64_LessEqual(curcase->min, max)) {
if (CInt64_Equal(currange->min, min))
first = curcase->min;
range = CInt64_Sub(curcase->min, first);
if (CInt64_Greater(curcase->min, currange->min)) {
currange->range = CInt64_Sub(CInt64_Sub(curcase->min, currange->min), cint64_one);
(++currange)->min = curcase->min;
} else if (CInt64_Greater(currange->min, min) && curcase->label->pclabel == currange[-1].label) {
currange[-1].range = CInt64_Add(currange[-1].range, cint64_one);
if (CInt64_Equal(currange->range, cint64_zero)) {
currange--;
} else {
currange->min = CInt64_Add(currange->min, cint64_one);
currange->range = CInt64_Sub(currange->range, cint64_one);
}
continue;
}
currange->range = cint64_zero;
currange->label = curcase->label->pclabel;
if (CInt64_Less(curcase->min, max)) {
currange++;
currange->min = CInt64_Add(curcase->min, cint64_one);
currange->range = CInt64_Sub(max, currange->min);
currange->label = label->pclabel;
}
}
}
nranges_minus1 = currange - caseranges;
}
static void treecompare(SInt32 start, SInt32 end) {
SInt32 r30;
SInt32 r29;
CaseRange *currange;
int count;
count = end - start;
CError_ASSERT(175, selector_type->size <= 4);
r29 = start + (count >> 1) + 1;
currange = caseranges + r29;
if (CInt64_Equal(currange[-1].range, cint64_zero) && (!(count & 1) || (CInt64_NotEqual(currange->range, cint64_zero) && count > 1))) {
currange--;
r29--;
}
r30 = r29 - 1;
if (selector_type->size < 4 && is_unsigned(selector_type)) {
emitpcode(PC_CMPLI, 0, selector_gpr, CInt64_GetULong(&currange->min));
} else if (FITS_IN_SHORT((SInt32) CInt64_GetULong(&currange->min))) {
emitpcode(PC_CMPI, 0, selector_gpr, CInt64_GetULong(&currange->min));
} else {
SInt32 value = CInt64_GetULong(&currange->min);
int reg = ALLOC_GPR();
load_immediate(reg, value);
emitpcode(PC_CMP, 0, selector_gpr, reg);
}
if (CInt64_Equal(currange->range, cint64_zero) && r29 < end) {
branch_conditional(0, EEQU, 1, currange->label);
r29++;
}
if (r29 == end) {
if (start == r30) {
if (caseranges[start].label == caseranges[end].label) {
branch_always(caseranges[start].label);
} else {
branch_conditional(0, EGREATEREQU, 1, caseranges[end].label);
branch_always(caseranges[start].label);
}
} else {
branch_conditional(0, EGREATEREQU, 1, caseranges[end].label);
treecompare(start, r30);
}
} else {
if (start == r30) {
branch_conditional(0, ELESS, 1, caseranges[start].label);
treecompare(r29, end);
} else {
PCodeLabel *label = makepclabel();
branch_conditional(0, EGREATEREQU, 1, label);
treecompare(start, r30);
branch_label(label);
treecompare(r29, end);
}
}
}
static void I8_treecompare(SInt32 start, SInt32 end) {
SInt32 r30;
SInt32 r29;
CaseRange *currange;
int count;
count = end - start;
r29 = start + (count >> 1) + 1;
currange = caseranges + r29;
if (CInt64_Equal(currange[-1].range, cint64_zero) && (!(count & 1) || (CInt64_NotEqual(currange->range, cint64_zero) && count > 1))) {
currange--;
r29--;
}
r30 = r29 - 1;
if (CInt64_Equal(currange->range, cint64_zero) && r29 < end) {
short a = ALLOC_GPR();
short b = ALLOC_GPR();
load_immediate(a, currange->min.lo);
load_immediate(b, currange->min.hi);
emitpcode(PC_XOR, a, selector_gpr, a);
emitpcode(PC_XOR, b, selector_gprHi, b);
emitpcode(PC_OR, b, a, b);
emitpcode(PC_CMPI, 0, b, 0);
branch_conditional(0, EEQU, 1, currange->label);
r29++;
}
if (r29 == end) {
if (start == r30) {
if (caseranges[start].label == caseranges[end].label) {
branch_always(caseranges[start].label);
} else {
short a = ALLOC_GPR();
short b = ALLOC_GPR();
short c = ALLOC_GPR();
short d = ALLOC_GPR();
load_immediate(a, currange->min.lo);
load_immediate(b, currange->min.hi);
if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) {
emitpcode(PC_XORIS, c, selector_gprHi, 0x8000);
emitpcode(PC_XORIS, d, b, 0x8000);
} else {
c = selector_gprHi;
d = b;
}
emitpcode(PC_SUBFC, a, a, selector_gpr);
emitpcode(PC_SUBFE, b, d, c);
emitpcode(PC_SUBFE, b, a, a);
emitpcode(PC_NEG, b, b);
emitpcode(PC_CMPI, 0, b, 0);
branch_conditional(0, EEQU, 1, caseranges[end].label);
branch_always(caseranges[start].label);
}
} else {
short a = ALLOC_GPR();
short b = ALLOC_GPR();
short c = ALLOC_GPR();
short d = ALLOC_GPR();
load_immediate(a, currange->min.lo);
load_immediate(b, currange->min.hi);
if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) {
emitpcode(PC_XORIS, c, selector_gprHi, 0x8000);
emitpcode(PC_XORIS, d, b, 0x8000);
} else {
c = selector_gprHi;
d = b;
}
emitpcode(PC_SUBFC, a, a, selector_gpr);
emitpcode(PC_SUBFE, b, d, c);
emitpcode(PC_SUBFE, b, a, a);
emitpcode(PC_NEG, b, b);
emitpcode(PC_CMPI, 0, b, 0);
branch_conditional(0, EEQU, 1, caseranges[end].label);
I8_treecompare(start, r30);
}
} else {
if (start == r30) {
short a = ALLOC_GPR();
short b = ALLOC_GPR();
short c = ALLOC_GPR();
short d = ALLOC_GPR();
load_immediate(a, currange->min.lo);
load_immediate(b, currange->min.hi);
if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) {
emitpcode(PC_XORIS, c, selector_gprHi, 0x8000);
emitpcode(PC_XORIS, d, b, 0x8000);
} else {
c = selector_gprHi;
d = b;
}
emitpcode(PC_SUBFC, a, selector_gpr, a);
emitpcode(PC_SUBFE, b, c, d);
emitpcode(PC_SUBFE, b, a, a);
emitpcode(PC_NEG, b, b);
emitpcode(PC_CMPI, 0, b, 0);
branch_conditional(0, ENOTEQU, 1, caseranges[end].label);
I8_treecompare(r29, end);
} else {
PCodeLabel *label;
short a = ALLOC_GPR();
short b = ALLOC_GPR();
short c = ALLOC_GPR();
short d = ALLOC_GPR();
load_immediate(a, currange->min.lo);
load_immediate(b, currange->min.hi);
if (TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG && TYPE_INTEGRAL(selector_type)->integral != IT_ULONGLONG) {
emitpcode(PC_XORIS, c, selector_gprHi, 0x8000);
emitpcode(PC_XORIS, d, b, 0x8000);
} else {
c = selector_gprHi;
d = b;
}
emitpcode(PC_SUBFC, a, a, selector_gpr);
emitpcode(PC_SUBFE, b, d, c);
emitpcode(PC_SUBFE, b, a, a);
emitpcode(PC_NEG, b, b);
emitpcode(PC_CMPI, 0, b, 0);
label = makepclabel();
branch_conditional(0, EEQU, 1, label);
I8_treecompare(start, r30);
branch_label(label);
I8_treecompare(r29, end);
}
}
}
static void generate_tree(ENode *expr) {
Operand op;
memclrw(&op, sizeof(Operand));
if (TYPE_IS_8BYTES(expr->rtype)) {
GEN_NODE(expr, &op);
coerce_to_register_pair(&op, expr->rtype, 0, 0);
selector_type = expr->rtype;
selector_gpr = op.reg;
selector_gprHi = op.regHi;
I8_treecompare(0, nranges_minus1);
} else {
GEN_NODE(expr, &op);
if (expr->rtype->size < 4)
extend32(&op, expr->rtype, 0);
ENSURE_GPR(&op, expr->rtype, 0);
selector_type = expr->rtype;
selector_gpr = op.reg;
treecompare(0, nranges_minus1);
}
}
static Object *create_switch_table(void) {
Object *obj;
ObjectList *list;
UInt32 *outptr;
CaseRange *currange;
SInt32 size;
CInt64 value;
obj = galloc(sizeof(Object));
list = galloc(sizeof(ObjectList));
memclrw(obj, sizeof(Object));
memclrw(list, sizeof(ObjectList));
obj->otype = OT_OBJECT;
obj->access = ACCESSPUBLIC;
obj->datatype = DDATA;
obj->name = CParser_GetUniqueName();
obj->toc = NULL;
obj->sclass = TK_STATIC;
obj->qual = Q_CONST;
obj->flags |= OBJECT_FLAGS_2 | OBJECT_DEFINED;
obj->u.data.linkname = obj->name;
obj->type = NULL;
createIndirect(obj, 0, 0);
obj->type = TYPE(&void_ptr);
size = CInt64_GetULong(&range) + 1;
obj->u.data.u.switchtable.size = size;
obj->u.data.u.switchtable.data = lalloc(4 * size);
currange = caseranges;
outptr = (UInt32 *) obj->u.data.u.switchtable.data;
value = cint64_zero;
while (CInt64_LessEqual(value, range)) {
while (CInt64_Greater(CInt64_Add(first, value), CInt64_Add(currange->min, currange->range)))
currange++;
*outptr = CTool_CreateIndexFromPointer(currange->label);
value = CInt64_Add(value, cint64_one);
outptr++;
}
list->object = obj;
list->next = switchtables;
switchtables = list;
return list->object;
}
static void generate_table(ENode *expr, SwitchInfo *info) {
Object *table;
SwitchCase *curcase;
short reg;
short reg2;
short reg3;
Operand op1;
Operand op2;
CInt64 val3 = {0, 3};
memclrw(&op1, sizeof(Operand));
memclrw(&op2, sizeof(Operand));
if (CInt64_Greater(first, cint64_zero) && CInt64_Less(first, val3)) {
range = CInt64_Add(range, first);
first = cint64_zero;
}
table = create_switch_table();
CError_ASSERT(553, !TYPE_IS_8BYTES(expr->rtype));
GEN_NODE(expr, &op1);
if (expr->rtype->size < 4)
extend32(&op1, expr->rtype, 0);
ENSURE_GPR(&op1, expr->rtype, 0);
reg = op1.reg;
if (CInt64_NotEqual(first, cint64_zero)) {
SInt32 value;
reg = ALLOC_GPR();
value = -CInt64_GetULong(&first);
if (!FITS_IN_SHORT(value)) {
emitpcode(PC_ADDIS, reg, op1.reg, 0, HIGH_PART(value));
if (value)
emitpcode(PC_ADDI, reg, reg, 0, LOW_PART(value));
} else {
emitpcode(PC_ADDI, reg, op1.reg, 0, value);
}
}
if (!FITS_IN_SHORT(CInt64_GetULong(&range))) {
short tmp = ALLOC_GPR();
load_immediate(tmp, CInt64_GetULong(&range));
emitpcode(PC_CMPL, 0, reg, tmp);
} else {
emitpcode(PC_CMPLI, 0, reg, CInt64_GetULong(&range));
}
branch_conditional(0, EGREATER, 1, defaultlabel);
if (table->toc) {
op2.optype = OpndType_Symbol;
op2.object = table->toc;
indirect(&op2, NULL);
} else {
op2.optype = OpndType_Symbol;
op2.object = table;
}
if (op2.optype != OpndType_GPR) {
Coerce_to_register(&op2, TYPE(&void_ptr), reg2 = ALLOC_GPR());
}
if (op2.optype != OpndType_GPR) {
CError_FATAL(599);
} else {
if (op2.reg != reg2)
emitpcode(PC_MR, reg2, op2.reg);
}
if (CInt64_Equal(first, cint64_zero)) {
reg = ALLOC_GPR();
emitpcode(PC_RLWINM, reg, op1.reg, 2, 0, 29);
} else {
emitpcode(PC_RLWINM, reg, reg, 2, 0, 29);
}
reg3 = reg2;
emitpcode(PC_LWZX, reg3, reg3, reg);
for (curcase = info->cases; curcase; curcase = curcase->next)
pcbranch(pclastblock, curcase->label->pclabel);
pcbranch(pclastblock, info->defaultlabel->pclabel);
emitpcode(PC_MTCTR, reg3);
branch_indirect(table);
}
void switchstatement(ENode *expr, SwitchInfo *info) {
Boolean use_table;
SwitchCase *swcase;
use_table = copts.switch_tables;
ncases = 0;
for (swcase = info->cases; swcase; swcase = swcase->next) {
if (!swcase->label->pclabel)
swcase->label->pclabel = makepclabel();
ncases++;
}
CError_ASSERT(656, ncases >= 0 && ncases <= 0x3333332U);
if (!info->defaultlabel->pclabel)
info->defaultlabel->pclabel = makepclabel();
defaultlabel = info->defaultlabel->pclabel;
build_case_ranges(expr->rtype, info->cases, info->defaultlabel);
if (TYPE_IS_8BYTES(expr->rtype)) {
generate_tree(expr);
return;
}
if (!use_table || nranges_minus1 < 8 || (nranges_minus1 * 2) < ((range.lo / 2) + 4))
generate_tree(expr);
else
generate_table(expr, info);
}
void dumpswitchtables(Object *funcobj) {
Object *table;
ObjectList *list;
SInt32 size;
UInt32 *array;
for (list = switchtables; list; list = list->next) {
table = list->object;
CError_ASSERT(694, table->otype == OT_OBJECT && table->access == ACCESSPUBLIC && table->datatype == DDATA);
size = table->u.data.u.switchtable.size;
array = (UInt32 *) table->u.data.u.switchtable.data;
while (size--) {
*array = CTool_EndianConvertWord32(((PCodeLabel *) CTool_ResolveIndexToPointer(*array))->block->codeOffset);
array++;
}
ObjGen_DeclareSwitchTable(table, funcobj);
}
}

File diff suppressed because it is too large Load Diff