mirror of
https://git.wuffs.org/MWCC
synced 2025-12-19 18:05:33 +00:00
move lots of source files around to match their actual placement in the original tree
This commit is contained in:
2437
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/CodeGen.c
Normal file
2437
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/CodeGen.c
Normal file
File diff suppressed because it is too large
Load Diff
857
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Exceptions.c
Normal file
857
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Exceptions.c
Normal 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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
5348
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/InstrSelection.c
Normal file
5348
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/InstrSelection.c
Normal file
File diff suppressed because it is too large
Load Diff
4894
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Intrinsics.c
Normal file
4894
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Intrinsics.c
Normal file
File diff suppressed because it is too large
Load Diff
1040
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Operands.c
Normal file
1040
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Operands.c
Normal file
File diff suppressed because it is too large
Load Diff
1613
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeAssembly.c
Normal file
1613
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeAssembly.c
Normal file
File diff suppressed because it is too large
Load Diff
536
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeListing.c
Normal file
536
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeListing.c
Normal 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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
2753
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Peephole.c
Normal file
2753
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Peephole.c
Normal file
File diff suppressed because it is too large
Load Diff
1252
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c
Normal file
1252
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c
Normal file
File diff suppressed because it is too large
Load Diff
792
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c
Normal file
792
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StructMoves.c
Normal 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);
|
||||
}
|
||||
518
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Switch.c
Normal file
518
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/Switch.c
Normal 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);
|
||||
}
|
||||
}
|
||||
2272
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/TOC.c
Normal file
2272
compiler_and_linker/BackEnd/PowerPC/CodeGenerator/TOC.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user