MWCC/compiler_and_linker/unsorted/CodeGen.c

698 lines
21 KiB
C

#include "compiler.h"
#include "compiler/CError.h"
#include "compiler/PCode.h"
#include "compiler/PCodeInfo.h"
#include "compiler/PCodeUtilities.h"
#include "compiler/enode.h"
#include "compiler/objects.h"
#include "compiler/tokens.h"
#include "compiler/types.h"
static Macro powcM;
static Macro __powcM;
static Macro ppc_cpu;
static Macro profM;
static Macro hostM;
static Macro bendM;
static Macro _ppc_M;
static Macro longI;
static Macro IEEED;
Macro vecM;
Macro altivecM;
static Macro macM2;
static Macro appleM;
static Macro optM;
static Macro alignM;
static Macro _machM;
static Macro archM;
static Macro dynM;
static Macro ppcM;
Object *gFunction;
static ObjectList *temps;
PCodeLabel *returnlabel;
PCodeLabel *cleanreturnlabel;
Boolean needs_cleanup;
Statement *current_statement;
int has_catch_blocks;
int disable_optimizer;
SInt32 current_linenumber;
Boolean has_altivec_arrays;
short high_reg;
short low_reg;
short high_offset;
short low_offset;
short low_reg2;
short high_reg2;
PCodeLabel *pic_base_pcodelabel;
Object *dyld_stub_binding_helper;
Object *rt_cvt_fp2unsigned;
Object *rt_profile_entry;
Object *rt_profile_exit;
Object *rt_div2i;
Object *rt_div2u;
Object *rt_mod2i;
Object *rt_mod2u;
Object *rt_shr2i;
Object *rt_shr2u;
Object *rt_shl2i;
Object *rt_cvt_ull_dbl;
Object *rt_cvt_sll_dbl;
Object *rt_cvt_ull_flt;
Object *rt_cvt_sll_flt;
Object *rt_cvt_dbl_usll;
static void *saveheaperror;
enum {
GPRLimit = 10,
FPRLimit = 13,
VRLimit = 13
};
VarInfo *CodeGen_GetNewVarInfo(void) {
VarInfo *vi;
vi = lalloc(sizeof(VarInfo));
memclrw(vi, sizeof(VarInfo));
vi->deftoken = *CPrep_CurStreamElement();
vi->varnumber = localcount++;
return vi;
}
Object *maketemporary(Type *type) {
ObjectList *list;
Object *obj;
for (list = temps; list; list = list->next) {
obj = list->object;
if (obj->u.var.uid == 0 && obj->type == type) {
obj->u.var.uid = 1;
return obj;
}
}
obj = lalloc(sizeof(Object));
memclrw(obj, sizeof(Object));
obj->otype = OT_OBJECT;
obj->access = ACCESSPUBLIC;
obj->datatype = DLOCAL;
obj->type = type;
obj->name = CParser_GetUniqueName();
obj->u.var.info = CodeGen_GetNewVarInfo();
obj->u.var.uid = 1;
list = lalloc(sizeof(ObjectList));
memclrw(list, sizeof(ObjectList));
list->next = temps;
list->object = obj;
temps = list;
return obj;
}
static void free_temporaries(void) {
ObjectList *list;
for (list = temps; list; list = list->next)
list->object->u.var.uid = 0;
}
static void allocate_temporaries(void) {
ObjectList *list;
for (list = temps; list; list = list->next)
assign_local_memory(list->object);
}
void process_arguments(ArgumentProcessor func, Boolean flag) {
short gpr = 3;
short fpr = 1;
short vr = 2;
Type *type;
ObjectList *list;
for (list = arguments; list; list = list->next) {
type = list->object->type;
if (IS_TYPE_FLOAT(type)) {
func(list->object, (fpr <= FPRLimit) ? fpr : 0);
fpr++;
if (type->size == 4)
gpr++;
else
gpr += 2;
} else if (IS_TYPE_VECTOR(type)) {
func(list->object, (vr <= VRLimit) ? vr : 0);
vr++;
if (flag) {
if ((vr - 1) == 2)
gpr = 9;
else if ((vr - 1) > 2)
gpr = 11;
}
} else {
func(list->object, (gpr <= GPRLimit) ? gpr : 0);
if (TYPE_FITS_IN_REGISTER(type)) {
if (type->size <= 4)
gpr += 1;
else
gpr += 2;
} else {
gpr += (type->size >> 2);
if (type->size & 3)
gpr++;
}
}
}
last_argument_register[RegClass_GPR] = gpr - 1;
last_argument_register[RegClass_FPR] = fpr - 1;
last_argument_register[RegClass_VR] = vr - 1;
if (flag)
move_varargs_to_memory();
}
static void retain_argument_register(Object *obj, short reg) {
VarInfo *vi = Registers_GetVarInfo(obj);
Type *type = obj->type;
if (reg && !vi->noregister && vi->used) {
if (TYPE_FITS_IN_REGISTER(type)) {
if (type->size <= 4) {
retain_register(obj, RegClass_GPR, reg);
} else if (reg < GPRLimit) {
if (copts.little_endian)
retain_GPR_pair(obj, reg, reg + 1);
else
retain_GPR_pair(obj, reg + 1, reg);
}
} else if (IS_TYPE_FLOAT(type)) {
retain_register(obj, RegClass_FPR, reg);
} else if (IS_TYPE_VECTOR(type)) {
retain_register(obj, RegClass_VR, reg);
}
}
}
static void allocate_local_vregs(void) {
VarInfo *vi;
ObjectList *list;
Object *obj;
if (copts.codegen_pic && uses_globals && assignable_registers[RegClass_GPR]) {
if (assignable_registers[RegClass_GPR]) {
vi = pic_base.u.var.info;
vi->reg = 0;
assign_register_by_type(&pic_base);
pic_base_reg = vi->reg;
#line 497
CError_ASSERT(pic_base_reg);
} else {
#line 500
CError_FATAL();
}
} else {
pic_base_reg = 0;
}
for (list = exceptionlist; list; list = list->next) {
obj = list->object;
vi = Registers_GetVarInfo(obj);
if (vi->used && !vi->noregister) {
if (!OBJ_GET_TARGET_VOLATILE(obj) && !vi->reg)
assign_register_by_type(obj);
}
}
set_last_exception_registers();
for (list = arguments; list; list = list->next) {
obj = list->object;
vi = Registers_GetVarInfo(obj);
if (vi->used && !vi->noregister) {
if (!OBJ_GET_TARGET_VOLATILE(obj) && !vi->reg)
assign_register_by_type(obj);
}
}
for (list = locals; list; list = list->next) {
obj = list->object;
if (!IsTempName(obj->name)) {
vi = Registers_GetVarInfo(obj);
if (vi->used && !vi->noregister) {
if (!OBJ_GET_TARGET_VOLATILE(obj) && !vi->reg)
assign_register_by_type(obj);
}
}
}
open_fe_temp_registers();
for (list = locals; list; list = list->next) {
obj = list->object;
if (IsTempName(obj->name)) {
vi = Registers_GetVarInfo(obj);
if (vi->used && !vi->noregister) {
if (!OBJ_GET_TARGET_VOLATILE(obj) && !vi->reg)
assign_register_by_type(obj);
}
}
}
for (list = toclist; list; list = list->next) {
obj = list->object;
vi = Registers_GetVarInfo(obj);
if (!vi->reg && vi->used && vi->usage > 1)
assign_register_by_type(obj);
}
}
static void allocate_local_GPRs(void) {
ObjectList *list;
Object *obj;
Object *winning_obj;
SInt32 winning_usage;
VarInfo *vi;
Type *type;
if (copts.codegen_pic && uses_globals && assignable_registers[RegClass_GPR]) {
vi = pic_base.u.var.info;
vi->reg = 0;
assign_register_by_type(&pic_base);
pic_base_reg = vi->reg;
#line 605
CError_ASSERT(pic_base_reg);
} else {
pic_base_reg = 0;
}
while (assignable_registers[RegClass_GPR]) {
winning_obj = NULL;
winning_usage = -1;
if (!(disable_optimizer & 2)) {
for (list = arguments; list; list = list->next) {
obj = list->object;
vi = Registers_GetVarInfo(obj);
type = obj->type;
if (vi->flags & VarInfoFlag40)
vi->usage = 100000;
if (!vi->reg && vi->used && !vi->noregister) {
if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) {
if (TYPE_FITS_IN_REGISTER(type) && (!TYPE_IS_8BYTES(type) || assignable_registers[RegClass_GPR] >= 2)) {
winning_obj = obj;
winning_usage = vi->usage;
}
}
}
}
}
if (!(disable_optimizer & 2)) {
for (list = locals; list; list = list->next) {
obj = list->object;
vi = Registers_GetVarInfo(obj);
type = obj->type;
if (vi->flags & VarInfoFlag40)
vi->usage = 100000;
if (!vi->reg && vi->used && !vi->noregister) {
if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) {
if (TYPE_FITS_IN_REGISTER(type) && (!TYPE_IS_8BYTES(type) || assignable_registers[RegClass_GPR] >= 2)) {
winning_obj = obj;
winning_usage = vi->usage;
}
}
}
}
}
for (list = toclist; list; list = list->next) {
obj = list->object;
vi = Registers_GetVarInfo(obj);
if (vi->flags & VarInfoFlag40)
vi->usage = 100000;
if (!vi->reg && vi->used) {
if (vi->usage >= winning_usage && vi->usage >= 3) {
winning_obj = obj;
winning_usage = vi->usage;
}
}
}
if (!winning_obj)
break;
assign_register_by_type(winning_obj);
#line 698
CError_ASSERT(Registers_GetVarInfo(winning_obj)->flags & VarInfoFlag2);
}
}
static void allocate_local_FPRs(void) {
ObjectList *list;
Object *obj;
Object *winning_obj;
SInt32 winning_usage;
VarInfo *vi;
Type *type;
while (assignable_registers[RegClass_FPR]) {
winning_obj = NULL;
winning_usage = -1;
if (!(disable_optimizer & 2)) {
for (list = arguments; list; list = list->next) {
obj = list->object;
type = obj->type;
vi = Registers_GetVarInfo(obj);
if (vi->flags & VarInfoFlag40)
vi->usage = 100000;
if (!vi->reg && vi->used && !vi->noregister) {
if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) {
if (IS_TYPE_FLOAT(type)) {
winning_obj = obj;
winning_usage = vi->usage;
}
}
}
}
}
if (!(disable_optimizer & 2)) {
for (list = locals; list; list = list->next) {
obj = list->object;
vi = Registers_GetVarInfo(obj);
if (vi->flags & VarInfoFlag40)
vi->usage = 100000;
if (!vi->reg && vi->used && !vi->noregister) {
if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) {
if (IS_TYPE_FLOAT(obj->type)) {
winning_obj = obj;
winning_usage = vi->usage;
}
}
}
}
}
if (!winning_obj)
break;
assign_register_by_type(winning_obj);
#line 782
CError_ASSERT(Registers_GetVarInfo(winning_obj)->flags & VarInfoFlag2);
}
}
static void allocate_local_VRs(void) {
ObjectList *list;
Object *obj;
Object *winning_obj;
SInt32 winning_usage;
VarInfo *vi;
while (assignable_registers[RegClass_VR]) {
winning_obj = NULL;
winning_usage = -1;
if (!(disable_optimizer & 2)) {
for (list = arguments; list; list = list->next) {
obj = list->object;
vi = Registers_GetVarInfo(obj);
if (vi->flags & VarInfoFlag40)
vi->usage = 100000;
if (!vi->reg && vi->used && !vi->noregister) {
if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) {
if (IS_TYPE_VECTOR(obj->type)) {
winning_obj = obj;
winning_usage = vi->usage;
}
}
}
}
}
if (!(disable_optimizer & 2)) {
for (list = locals; list; list = list->next) {
obj = list->object;
vi = Registers_GetVarInfo(obj);
if (vi->flags & VarInfoFlag40)
vi->usage = 100000;
if (!vi->reg && vi->used && !vi->noregister) {
if (!OBJ_GET_TARGET_VOLATILE(obj) && vi->usage >= winning_usage && vi->usage >= 2) {
if (IS_TYPE_VECTOR(obj->type)) {
winning_obj = obj;
winning_usage = vi->usage;
}
}
}
}
}
if (!winning_obj)
break;
assign_register_by_type(winning_obj);
#line 846
CError_ASSERT(Registers_GetVarInfo(winning_obj)->flags & VarInfoFlag2);
}
}
static void allocate_locals(void) {
has_altivec_arrays = 0;
if (!requires_frame && !optimizing)
process_arguments(retain_argument_register, 0);
if (optimizing) {
allocate_local_vregs();
} else {
allocate_local_GPRs();
allocate_local_FPRs();
allocate_local_VRs();
}
assign_locals_to_memory(locals);
}
void move_assigned_argument(Object *obj, short reg) {
VarInfo *vi;
Type *type;
SInt32 bytesLeft;
SInt32 offset;
vi = Registers_GetVarInfo(obj);
type = obj->type;
#line 901
CError_ASSERT(obj->datatype == DLOCAL);
if (!vi->used)
return;
if (reg) {
if (vi->reg) {
if (TYPE_IS_8BYTES(type)) {
if (copts.little_endian) {
if (vi->reg != reg)
emitpcode(PC_MR, vi->reg, reg);
if (reg < GPRLimit) {
#line 916
CError_FAIL((vi->regHi == reg) || (vi->reg == (reg + 1)));
if (vi->regHi != (reg + 1))
emitpcode(PC_MR, vi->regHi, reg + 1);
} else {
load_store_register(PC_LWZ, vi->regHi, local_base_register(obj), obj, high_offset);
}
} else {
if (vi->regHi != reg)
emitpcode(PC_MR, vi->regHi, reg);
if (reg < GPRLimit) {
#line 931
CError_FAIL((vi->reg == reg) || (vi->regHi == (reg + 1)));
if (vi->reg != (reg + 1))
emitpcode(PC_MR, vi->reg, reg + 1);
} else {
load_store_register(PC_LWZ, vi->reg, local_base_register(obj), obj, low_offset);
}
}
} else if (vi->reg != reg) {
if (IS_TYPE_FLOAT(type)) {
emitpcode(PC_FMR, vi->reg, reg);
} else if (IS_TYPE_VECTOR(type)) {
emitpcode(PC_VMR, vi->reg, reg);
} else {
emitpcode(PC_MR, vi->reg, reg);
}
}
} else {
if (IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type)) {
load_store_register(PC_STW, reg, local_base_register(obj), obj, 0);
} else if (IS_TYPE_INT(type) || IS_TYPE_ENUM(type)) {
switch (type->size) {
case 1:
load_store_register(PC_STB, reg, local_base_register(obj), obj, 0);
break;
case 2:
load_store_register(PC_STH, reg, local_base_register(obj), obj, 0);
break;
case 4:
load_store_register(PC_STW, reg, local_base_register(obj), obj, 0);
break;
case 8:
load_store_register(PC_STW, reg, local_base_register(obj), obj, 0);
if (reg < GPRLimit)
load_store_register(PC_STW, reg + 1, local_base_register(obj), obj, 4);
break;
default:
#line 993
CError_FATAL();
}
} else if (IS_TYPE_FLOAT(type)) {
load_store_register((type->size == 4) ? PC_STFS : PC_STFD, reg, local_base_register(obj), obj, 0);
} else if (IS_TYPE_VECTOR(type)) {
load_store_register(PC_STVX, reg, local_base_register(obj), obj, 0);
} else {
bytesLeft = (11 - reg) * 4;
if (bytesLeft > obj->type->size)
bytesLeft = obj->type->size;
offset = 0;
while (bytesLeft > 0) {
load_store_register(PC_STW, reg, local_base_register(obj), obj, offset);
reg++;
offset += 4;
bytesLeft -= 4;
}
}
}
} else {
if (vi->reg) {
if (IS_TYPE_POINTER(type) || IS_TYPE_4BYTES_MEMBERPOINTER(type)) {
load_store_register(PC_LWZ, vi->reg, local_base_register(obj), obj, 0);
} else if (IS_TYPE_FLOAT(type)) {
load_store_register((type->size == 4) ? PC_LFS : PC_LFD, vi->reg, local_base_register(obj), obj, 0);
} else if (IS_TYPE_VECTOR(type)) {
load_store_register(PC_LVX, vi->reg, local_base_register(obj), obj, 0);
} else {
switch (type->size) {
case 1:
load_store_register(PC_LBZ, vi->reg, local_base_register(obj), obj, 0);
break;
case 2:
load_store_register(is_unsigned(type) ? PC_LHZ : PC_LHA, vi->reg, local_base_register(obj), obj, 0);
break;
case 4:
load_store_register(PC_LWZ, vi->reg, local_base_register(obj), obj, 0);
break;
case 8:
load_store_register(PC_LWZ, vi->regHi, local_base_register(obj), obj, high_offset);
load_store_register(PC_LWZ, vi->reg, local_base_register(obj), obj, low_offset);
break;
default:
#line 1095
CError_FATAL();
}
}
} else if (!optimizing) {
local_base_register(obj);
}
}
}
static void load_TOC_pointers(void) {
VarInfo *vi;
Object *obj;
ObjectList *list;
PCode *pc;
if (uses_globals && pic_base_reg) {
pic_base_pcodelabel = makepclabel();
pc = makepcode(PC_BC, 20, 7, 3);
pcsetlinkbit(pc);
pcsetsideeffects(pc);
appendpcode(pclastblock, pc);
pcbranch(pclastblock, pic_base_pcodelabel);
makepcblock();
pclabel(pclastblock, pic_base_pcodelabel);
emitpcode(PC_MFLR, pic_base_reg);
}
// TODO: depends on Operands
for (list = toclist; list; list = list->next) {
}
}
static Boolean has_vararglist(Object *funcobj) {
FuncArg *arg;
arg = TYPE_FUNC(funcobj->type)->args;
while (arg && arg != &elipsis)
arg = arg->next;
return arg == &elipsis;
}
void assign_labels() {
// TODO
}
static Boolean islaststatement(Statement *stmt) {
for (stmt = stmt->next; stmt; stmt = stmt->next) {
if (stmt->type > ST_LABEL)
return 0;
}
return 1;
}
static void newstatement(SInt32 sourceoffset, UInt16 value, int flag) {
PCodeBlock *block = pclastblock;
pcloopweight = value;
if (!block->pcodeCount)
block->loopWeight = value;
if (block->pcodeCount > 100)
branch_label(makepclabel());
if (flag)
block->flags |= fPCBlockFlag4000;
}
static void expressionstatement(ENode *expr) {
}
static void labelstatement() {}
static void gotostatement() {}
static void gotoexpression() {}
static void conditionalstatement() {}
static void returnstatement() {}
static void capturestackpointer() {}
static void resetstackpointer() {}
static void callprofiler() {}
static void exitprofiler() {}
void CodeGen_Generator() {}
void CodeGen_GenVDispatchThunk() {}
void CodeGen_SetupRuntimeObjects() {}
Boolean CodeGen_ReInitRuntimeObjects(Boolean is_precompiler) {}
Boolean CodeGen_IsPublicRuntimeObject(Object *obj) {}
void CodeGen_SOMStub() {}
void CodeGen_ParseDeclSpec() {}
static void CodeGen_EOLCheck() {}
static void schedule_for() {}
static void pragma_scheduling() {}
static void CodeGen_ParseLongIntegerORonORoff() {}
void CodeGen_ParsePragma(HashNameNode *name) {}
void CodeGen_UpdateObject(Object *object) {}
void CodeGen_UpdateBackEndOptions() {}
void CodeGen_objc_method_self_offset() {}
void CodeGen_objc_method_sel_offset() {}
void CodeGen_objc_method_arg_offset() {}
void CodeGen_objc_method_args_size() {}
void CodeGen_HandleIntrinsicCall() {}
void CodeGen_HandleTypeCast() {}
void CodeGen_AssignCheck() {}
void CodeGen_CollapseVectorExpression() {}
void CodeGen_InsertSpecialMacros() {}
char *CodeGen_ExpandSpecialMacro(Macro *macro) {}
void CodeGen_reportheapinfo() {}
static void CodeGen_heaperror() {}
void CodeGen_InitialSanityCheck() {}