mirror of https://git.wuffs.org/MWCC
1266 lines
39 KiB
C
1266 lines
39 KiB
C
#include "compiler/StackFrame.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/PCode.h"
|
|
#include "compiler/PCodeInfo.h"
|
|
#include "compiler/PCodeUtilities.h"
|
|
#include "compiler/objects.h"
|
|
#include "compiler.h"
|
|
|
|
#define ALIGN(thing, alignment) ( ~((alignment) - 1) & ((thing) + (alignment) - 1) )
|
|
#define ALIGN_REMAINDER(thing, alignment) ( ALIGN(thing, alignment) - (thing) )
|
|
|
|
Boolean requires_frame;
|
|
Boolean makes_call;
|
|
Boolean uses_globals;
|
|
Boolean dynamic_stack;
|
|
Boolean large_stack;
|
|
static SInt32 out_param_alignment;
|
|
static SInt32 in_parameter_size;
|
|
static SInt32 in_param_alignment;
|
|
static SInt32 frame_alignment;
|
|
static SInt32 alloca_alignment;
|
|
static SInt32 linkage_area_size;
|
|
static SInt32 parameter_area_size;
|
|
static SInt32 parameter_area_size_estimate;
|
|
static SInt32 local_data_size;
|
|
static SInt32 local_data_limit;
|
|
static SInt32 large_data_near_size;
|
|
static SInt32 large_data_far_size;
|
|
static ObjectList *local_objects[ObjClassMax];
|
|
static ObjectList *local_objects_tail[ObjClassMax];
|
|
static SInt32 non_volatile_save_offset[RegClassMax];
|
|
static SInt32 VRSAVE_save_offset;
|
|
static SInt32 LR_save_offset;
|
|
static SInt32 nonvolatile_save_size;
|
|
static UInt32 vrsave_mask;
|
|
static SInt32 frame_size;
|
|
static SInt32 frame_size_estimate;
|
|
static SInt32 genuine_frame_size;
|
|
static Object *dummylocal;
|
|
static Boolean dynamic_align_stack;
|
|
static Boolean has_varargs;
|
|
static Boolean compressing_data_area;
|
|
static PCode *setup_caller_sp;
|
|
static PCode *align_instr1;
|
|
static PCode *align_instr2;
|
|
static short vrsave_register;
|
|
static PCode *loadvrsave;
|
|
static PCode *storevrsave;
|
|
Object *dummyvaparam;
|
|
void *dummyprofiler;
|
|
|
|
// forward declarations
|
|
static void insert_local_object(UInt8 oclass, Object *obj);
|
|
static void compress_data_area(void);
|
|
static UInt32 align_bits(UInt32 value, UInt8 bitcount);
|
|
static Boolean use_helper_function(char rclass);
|
|
static Boolean need_link_register(void);
|
|
static void call_helper_function(char *name, char rclass, short effect);
|
|
static void save_nonvolatile_FPRs(int reg, SInt32 offset);
|
|
static void save_nonvolatile_VRs(int reg, SInt32 offset);
|
|
static void restore_nonvolatile_FPRs(int reg, SInt32 offset);
|
|
static void restore_nonvolatile_VRs(int reg, SInt32 offset);
|
|
static void save_nonvolatile_GPRs(int reg, SInt32 offset);
|
|
static void restore_nonvolatile_GPRs(int reg, SInt32 offset);
|
|
static void do_allocate_dynamic_stack_space(Boolean flag1, int reg1, int reg2, SInt32 size);
|
|
|
|
void init_stack_globals(Object *funcobj) {
|
|
char rclass;
|
|
UInt8 oclass;
|
|
|
|
requires_frame = 0;
|
|
makes_call = 0;
|
|
uses_globals = 0;
|
|
dynamic_stack = 0;
|
|
large_stack = 0;
|
|
vrsave_register = -1;
|
|
dynamic_align_stack = 0;
|
|
compressing_data_area = 0;
|
|
align_instr1 = NULL;
|
|
align_instr2 = NULL;
|
|
setup_caller_sp = NULL;
|
|
dummyvaparam = NULL;
|
|
loadvrsave = NULL;
|
|
storevrsave = NULL;
|
|
local_data_size = 0;
|
|
local_data_limit = 0x2000;
|
|
large_data_near_size = 0;
|
|
large_data_far_size = 0;
|
|
frame_size_estimate = 0;
|
|
in_parameter_size = 0;
|
|
parameter_area_size = 0;
|
|
parameter_area_size_estimate = 0;
|
|
frame_alignment = 8;
|
|
out_param_alignment = 8;
|
|
in_param_alignment = 8;
|
|
alloca_alignment = 0;
|
|
has_varargs = 0;
|
|
linkage_area_size = 0;
|
|
frame_size = 0;
|
|
genuine_frame_size = 0;
|
|
nonvolatile_save_size = -1;
|
|
VRSAVE_save_offset = -1;
|
|
LR_save_offset = -1;
|
|
|
|
for (rclass = 0; rclass < RegClassMax; rclass++)
|
|
non_volatile_save_offset[(char) rclass] = -1;
|
|
|
|
dummyprofiler = NULL;
|
|
dummyvaparam = NULL;
|
|
dummylocal = NULL;
|
|
|
|
for (oclass = 0; oclass < ObjClassMax; oclass++) {
|
|
local_objects[oclass] = NULL;
|
|
local_objects_tail[oclass] = NULL;
|
|
}
|
|
}
|
|
|
|
void init_frame_sizes(Boolean has_varargs) {
|
|
ObjectList *scan;
|
|
Object *obj;
|
|
SInt32 r30;
|
|
SInt32 align;
|
|
SInt32 mask;
|
|
|
|
r30 = in_parameter_size + parameter_area_size_estimate;
|
|
frame_size_estimate = r30 + 2484;
|
|
for (scan = locals; scan; scan = scan->next) {
|
|
obj = scan->object;
|
|
{
|
|
align = CMach_AllocationAlignment(obj->type, obj->qual) - 1;
|
|
mask = ~align;
|
|
}
|
|
frame_size_estimate = (frame_size_estimate + align) & mask;
|
|
frame_size_estimate += obj->type->size;
|
|
}
|
|
|
|
if (frame_size_estimate > 0x8000) {
|
|
dynamic_stack = 1;
|
|
large_stack = 1;
|
|
requires_frame = 1;
|
|
}
|
|
|
|
local_data_limit = 0x8000 - (r30 + 2484);
|
|
|
|
if (dynamic_stack) {
|
|
requires_frame = 1;
|
|
dummylocal = galloc(sizeof(Object));
|
|
memclrw(dummylocal, sizeof(Object));
|
|
dummylocal->type = (Type *) &stvoid;
|
|
dummylocal->otype = OT_OBJECT;
|
|
dummylocal->name = GetHashNameNode("<dummy>");
|
|
dummylocal->datatype = DLOCAL;
|
|
dummylocal->u.var.info = CodeGen_GetNewVarInfo();
|
|
dummylocal->u.var.info->flags |= VarInfoFlag80;
|
|
dummylocal->u.var.info->noregister = 1;
|
|
}
|
|
|
|
if (dynamic_stack) {
|
|
retain_register(NULL, RegClass_GPR, 31);
|
|
_FP_ = 31;
|
|
} else {
|
|
_FP_ = 1;
|
|
}
|
|
}
|
|
|
|
void assign_local_memory(Object *obj) {
|
|
// some misassigned registers x.x
|
|
short align;
|
|
VarInfo *vi;
|
|
|
|
align = CMach_AllocationAlignment(obj->type, obj->qual);
|
|
if (!compressing_data_area && (obj->u.var.info->flags & VarInfoFlag80))
|
|
return;
|
|
|
|
update_frame_align(align);
|
|
if (local_data_size + (ALIGN_REMAINDER(local_data_size, align) + ALIGN(obj->type->size, align)) < local_data_limit) {
|
|
local_data_size = ALIGN(local_data_size, align);
|
|
vi = Registers_GetVarInfo(obj);
|
|
vi->flags &= ~VarInfoFlag2;
|
|
vi->flags |= VarInfoFlag80;
|
|
obj->u.var.uid = local_data_size;
|
|
local_data_size += ALIGN(obj->type->size, align);
|
|
insert_local_object(ObjClass0, obj);
|
|
return;
|
|
}
|
|
if (compressing_data_area || obj->type->size <= 32) {
|
|
large_data_near_size = ALIGN(large_data_near_size, align);
|
|
vi = Registers_GetVarInfo(obj);
|
|
vi->flags &= ~VarInfoFlag2;
|
|
vi->flags |= VarInfoFlag80;
|
|
obj->u.var.uid = 0x8000 + large_data_near_size;
|
|
large_data_near_size += ALIGN(obj->type->size, align);
|
|
insert_local_object(ObjClass1, obj);
|
|
} else {
|
|
large_data_far_size = ALIGN(large_data_far_size, align);
|
|
vi = Registers_GetVarInfo(obj);
|
|
vi->flags &= ~VarInfoFlag2;
|
|
vi->flags |= VarInfoFlag80;
|
|
obj->u.var.uid = 0x10000 + large_data_far_size;
|
|
large_data_far_size += ALIGN(obj->type->size, align);
|
|
insert_local_object(ObjClass2, obj);
|
|
}
|
|
}
|
|
|
|
void assign_locals_to_memory(ObjectList *first) {
|
|
ObjectList *list;
|
|
Object *obj;
|
|
SInt32 i;
|
|
|
|
for (i = 1; i < 1024; i <<= 1) {
|
|
for (list = first; list; list = list->next) {
|
|
obj = list->object;
|
|
if (Registers_GetVarInfo(obj)->used) {
|
|
if ((Registers_GetVarInfo(obj) ? Registers_GetVarInfo(obj)->reg : 0) == 0) {
|
|
if (obj->type->size <= i)
|
|
assign_local_memory(obj);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (list = first; list; list = list->next) {
|
|
obj = list->object;
|
|
if (Registers_GetVarInfo(obj)->used) {
|
|
if ((Registers_GetVarInfo(obj) ? Registers_GetVarInfo(obj)->reg : 0) == 0) {
|
|
assign_local_memory(list->object);
|
|
}
|
|
}
|
|
|
|
if (obj->type && IS_TYPE_ARRAY(obj->type) && IS_TYPE_VECTOR(TYPE_POINTER(obj->type)->target))
|
|
has_altivec_arrays = 1;
|
|
}
|
|
}
|
|
|
|
void compute_frame_sizes(void) {
|
|
SInt32 altivec_size;
|
|
SInt32 altivec_offset;
|
|
|
|
#line 897
|
|
CError_ASSERT(alloca_alignment == 0 || alloca_alignment == frame_alignment);
|
|
|
|
update_asm_nonvolatile_registers();
|
|
LR_save_offset = 8;
|
|
non_volatile_save_offset[RegClass_FPR] = -(used_nonvolatile_registers[RegClass_FPR] * 8);
|
|
non_volatile_save_offset[RegClass_GPR] = -(((15 - non_volatile_save_offset[RegClass_FPR]) & ~15) + used_nonvolatile_registers[RegClass_GPR] * 4);
|
|
nonvolatile_save_size = -non_volatile_save_offset[RegClass_GPR];
|
|
non_volatile_save_offset[RegClass_CRFIELD] = 4;
|
|
VRSAVE_save_offset = -1;
|
|
non_volatile_save_offset[RegClass_VR] = -1;
|
|
|
|
if (copts.altivec_model) {
|
|
if (vrsave_mask) {
|
|
VRSAVE_save_offset = non_volatile_save_offset[RegClass_GPR] - 4;
|
|
nonvolatile_save_size = nonvolatile_save_size + 4;
|
|
}
|
|
altivec_size = used_nonvolatile_registers[RegClass_VR] * 16;
|
|
if (altivec_size > 0)
|
|
nonvolatile_save_size = ALIGN(nonvolatile_save_size + altivec_size, frame_alignment);
|
|
}
|
|
|
|
if (parameter_area_size)
|
|
requires_frame = 1;
|
|
|
|
compress_data_area();
|
|
local_data_size = ALIGN(local_data_size, frame_alignment);
|
|
nonvolatile_save_size = ALIGN(nonvolatile_save_size, frame_alignment);
|
|
if (!requires_frame && (local_data_size + nonvolatile_save_size) <= 224) {
|
|
#line 1005
|
|
CError_ASSERT(!dynamic_align_stack);
|
|
linkage_area_size = 0;
|
|
frame_size = 0;
|
|
genuine_frame_size = local_data_size + nonvolatile_save_size;
|
|
} else {
|
|
requires_frame = 1;
|
|
if (parameter_area_size < 32)
|
|
parameter_area_size = 32;
|
|
parameter_area_size = ALIGN(parameter_area_size + 24, frame_alignment) - 24;
|
|
if (large_stack) {
|
|
#line 1019
|
|
CError_ASSERT(!large_data_far_size);
|
|
large_data_near_size += parameter_area_size;
|
|
parameter_area_size = 0;
|
|
}
|
|
linkage_area_size = 24;
|
|
frame_size = nonvolatile_save_size + (altivec_offset = parameter_area_size + 24 + local_data_size);
|
|
if (copts.altivec_model && used_nonvolatile_registers[RegClass_VR])
|
|
non_volatile_save_offset[RegClass_VR] = altivec_offset;
|
|
frame_size += ALIGN_REMAINDER(frame_size, 16);
|
|
frame_size = ALIGN(frame_size, frame_alignment);
|
|
genuine_frame_size = frame_size;
|
|
}
|
|
if (!large_stack && frame_size > 0x7FFF)
|
|
CError_ErrorTerm(210);
|
|
}
|
|
|
|
static void allocate_new_frame(int reg1, int reg2) {
|
|
if (dynamic_align_stack) {
|
|
#line 1116
|
|
CError_ASSERT(reg1 != _CALLER_SP_);
|
|
emitpcode(PC_RLWINM, reg1, 1, 0, align_bits(frame_alignment, 1), 31);
|
|
if (frame_size > 0x7FFF) {
|
|
#line 1122
|
|
CError_FATAL();
|
|
return;
|
|
}
|
|
|
|
if (frame_size)
|
|
emitpcode(PC_SUBFIC, reg1, reg1, -frame_size);
|
|
else
|
|
emitpcode(PC_SUBFIC, reg1, reg1, -genuine_frame_size);
|
|
|
|
if (reg2)
|
|
emitpcode(PC_MR, reg2, 1);
|
|
|
|
emitpcode(PC_STWUX, 1, 1, reg1);
|
|
} else {
|
|
if (frame_size > 0x7FFF) {
|
|
#line 1153
|
|
CError_FATAL();
|
|
} else {
|
|
emitpcode(PC_STWU, 1, 1, 0, -frame_size);
|
|
}
|
|
|
|
if (reg2)
|
|
emitpcode(PC_MR, reg2, 1);
|
|
}
|
|
}
|
|
|
|
void generate_prologue(PCodeBlock *block, Boolean has_varargs) {
|
|
PCodeBlock *save_block;
|
|
Boolean needs_lr;
|
|
Statement *save_statement;
|
|
Statement stmt;
|
|
UInt32 vrsave_low;
|
|
UInt32 vrsave_high;
|
|
|
|
save_block = pclastblock;
|
|
needs_lr = need_link_register();
|
|
save_statement = current_statement;
|
|
stmt.sourceoffset = functionbodyoffset;
|
|
current_statement = &stmt;
|
|
pclastblock = block;
|
|
|
|
if (setup_caller_sp && setup_caller_sp->block) {
|
|
if (
|
|
setup_caller_sp->op == PC_MR &&
|
|
setup_caller_sp->args[1].kind == PCOp_REGISTER &&
|
|
setup_caller_sp->args[1].arg == RegClass_GPR &&
|
|
setup_caller_sp->args[1].data.reg.reg == _FP_
|
|
) {
|
|
#line 1197
|
|
CError_FATAL();
|
|
}
|
|
_CALLER_SP_ = setup_caller_sp->args[0].data.reg.reg;
|
|
deletepcode(setup_caller_sp);
|
|
setup_caller_sp = NULL;
|
|
} else if (_CALLER_SP_ != _FP_) {
|
|
_CALLER_SP_ = -1;
|
|
}
|
|
|
|
if (align_instr1 && align_instr1->block) {
|
|
deletepcode(align_instr1);
|
|
align_instr1 = NULL;
|
|
}
|
|
|
|
if (align_instr2 && align_instr2->block) {
|
|
deletepcode(align_instr2);
|
|
align_instr2 = NULL;
|
|
}
|
|
|
|
if (loadvrsave && loadvrsave->block) {
|
|
deletepcode(loadvrsave);
|
|
loadvrsave = NULL;
|
|
}
|
|
|
|
if (storevrsave && storevrsave->block) {
|
|
deletepcode(storevrsave);
|
|
storevrsave = NULL;
|
|
}
|
|
|
|
if (needs_lr)
|
|
emitpcode(PC_MFLR, 0);
|
|
|
|
if (used_nonvolatile_registers[RegClass_CRFIELD]) {
|
|
emitpcode(PC_MFCR, 12);
|
|
emitpcode(PC_STW, 12, 1, 0, non_volatile_save_offset[RegClass_CRFIELD]);
|
|
}
|
|
|
|
if (used_nonvolatile_registers[RegClass_FPR])
|
|
save_nonvolatile_FPRs(1, 0);
|
|
if (used_nonvolatile_registers[RegClass_GPR])
|
|
save_nonvolatile_GPRs(1, 0);
|
|
if (needs_lr)
|
|
emitpcode(PC_STW, 0, 1, 0, 8);
|
|
|
|
if (frame_size) {
|
|
if (vrsave_mask) {
|
|
emitpcode(PC_MFSPR, 0, 256);
|
|
emitpcode(PC_STW, 0, 1, 0, VRSAVE_save_offset);
|
|
vrsave_register = 0;
|
|
}
|
|
allocate_new_frame(12, (_CALLER_SP_ > 0 && _CALLER_SP_ != _FP_) ? _CALLER_SP_ : 0);
|
|
} else {
|
|
#line 1326
|
|
CError_ASSERT(!dynamic_align_stack);
|
|
if (vrsave_mask)
|
|
emitpcode(PC_MFSPR, vrsave_register, 256);
|
|
}
|
|
|
|
if (vrsave_mask) {
|
|
vrsave_high = vrsave_mask >> 16;
|
|
vrsave_low = vrsave_mask & 0xFFFF;
|
|
if (vrsave_mask == 0xFFFFFFFF) {
|
|
emitpcode(PC_LI, 0, -1);
|
|
} else {
|
|
if (vrsave_high)
|
|
emitpcode(PC_ORIS, 0, vrsave_register, vrsave_high);
|
|
if (vrsave_low)
|
|
emitpcode(PC_ORI, 0, 0, vrsave_low);
|
|
}
|
|
emitpcode(PC_MTSPR, 256, 0);
|
|
}
|
|
|
|
if (used_nonvolatile_registers[RegClass_VR])
|
|
save_nonvolatile_VRs(1, 0);
|
|
|
|
if (dynamic_stack)
|
|
emitpcode(PC_MR, 31, 1);
|
|
|
|
if (large_stack)
|
|
do_allocate_dynamic_stack_space(1, 11, 0, large_data_near_size);
|
|
|
|
block->flags |= fPCBlockFlag1;
|
|
pclastblock = save_block;
|
|
current_statement = save_statement;
|
|
}
|
|
|
|
void generate_epilogue(PCodeBlock *block, Boolean add_blr) {
|
|
PCodeBlock *save_block;
|
|
Boolean needs_lr;
|
|
Statement *save_statement;
|
|
Statement stmt;
|
|
|
|
save_block = pclastblock;
|
|
needs_lr = need_link_register();
|
|
save_statement = current_statement;
|
|
if (!save_statement) {
|
|
stmt.sourceoffset = current_linenumber;
|
|
current_statement = &stmt;
|
|
}
|
|
pclastblock = block;
|
|
|
|
if (used_nonvolatile_registers[RegClass_VR])
|
|
restore_nonvolatile_VRs(_FP_, 0);
|
|
|
|
if (dynamic_align_stack) {
|
|
load_store_register(PC_LWZ, 1, 1, NULL, 0);
|
|
setpcodeflags(fSideEffects);
|
|
if (needs_lr)
|
|
load_store_register(PC_LWZ, 0, 1, 0, 8);
|
|
} else {
|
|
if (needs_lr)
|
|
load_store_register(PC_LWZ, 0, _FP_, 0, frame_size + 8);
|
|
if (frame_size > 0) {
|
|
if (dynamic_stack) {
|
|
load_store_register(PC_LWZ, 1, 1, 0, 0);
|
|
setpcodeflags(fSideEffects);
|
|
} else {
|
|
emitpcode(PC_ADDI, 1, 1, 0, frame_size);
|
|
setpcodeflags(fSideEffects);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (used_nonvolatile_registers[RegClass_CRFIELD]) {
|
|
load_store_register(PC_LWZ, 12, 1, NULL, non_volatile_save_offset[RegClass_CRFIELD]);
|
|
emitpcode(PC_MTCRF, 255, 12);
|
|
}
|
|
|
|
if (vrsave_mask) {
|
|
if (!requires_frame) {
|
|
emitpcode(PC_MTSPR, 256, vrsave_register);
|
|
} else {
|
|
emitpcode(PC_LWZ, 11, 1, 0, VRSAVE_save_offset);
|
|
emitpcode(PC_MTSPR, 256, 11);
|
|
}
|
|
}
|
|
|
|
if (used_nonvolatile_registers[RegClass_FPR])
|
|
restore_nonvolatile_FPRs(1, 0);
|
|
if (needs_lr && !use_helper_function(RegClass_GPR))
|
|
emitpcode(PC_MTLR, 0);
|
|
|
|
if (used_nonvolatile_registers[RegClass_GPR])
|
|
restore_nonvolatile_GPRs(1, 0);
|
|
if (needs_lr && use_helper_function(RegClass_GPR))
|
|
emitpcode(PC_MTLR, 0);
|
|
|
|
if (add_blr) {
|
|
emitpcode(PC_BLR);
|
|
setpcodeflags(fIsVolatile);
|
|
}
|
|
|
|
block->flags |= fPCBlockFlag2;
|
|
pclastblock = save_block;
|
|
current_statement = save_statement;
|
|
}
|
|
|
|
static void load_base_offset(int dest_reg, int base_reg, SInt32 offset) {
|
|
if (offset)
|
|
emitpcode(PC_ADDI, dest_reg, base_reg, 0, offset);
|
|
else
|
|
emitpcode(PC_MR, dest_reg, base_reg);
|
|
}
|
|
|
|
static void save_nonvolatile_FPRs(int reg, SInt32 offset) {
|
|
short i;
|
|
SInt32 o;
|
|
|
|
o = offset + non_volatile_save_offset[RegClass_FPR];
|
|
|
|
if (!use_helper_function(RegClass_FPR)) {
|
|
for (i = 1; i <= used_nonvolatile_registers[RegClass_FPR]; i++) {
|
|
emitpcode(PC_STFD, 32 - i, reg, NULL, o + (used_nonvolatile_registers[RegClass_FPR] - i) * 8);
|
|
setpcodeflags(fIsVolatile);
|
|
}
|
|
} else {
|
|
load_base_offset(11, reg, o + used_nonvolatile_registers[RegClass_FPR] * 8);
|
|
call_helper_function("__save_fpr_%d", RegClass_FPR, EffectRead);
|
|
}
|
|
}
|
|
|
|
static void save_nonvolatile_VRs(int reg, SInt32 offset) {
|
|
short i;
|
|
SInt32 o;
|
|
|
|
o = offset + non_volatile_save_offset[RegClass_VR];
|
|
|
|
if (!use_helper_function(RegClass_VR)) {
|
|
for (i = 1; i <= used_nonvolatile_registers[RegClass_VR]; i++) {
|
|
emitpcode(PC_LI, 0, o + (used_nonvolatile_registers[RegClass_VR] - i) * 16);
|
|
emitpcode(PC_STVX, 32 - i, reg, 0);
|
|
setpcodeflags(fIsVolatile);
|
|
}
|
|
} else {
|
|
load_base_offset(0, reg, o + used_nonvolatile_registers[RegClass_VR] * 16);
|
|
call_helper_function("__savev%d", RegClass_VR, EffectRead);
|
|
}
|
|
}
|
|
|
|
static void restore_nonvolatile_FPRs(int reg, SInt32 offset) {
|
|
short i;
|
|
SInt32 o;
|
|
|
|
o = offset + non_volatile_save_offset[RegClass_FPR];
|
|
|
|
if (!use_helper_function(RegClass_FPR)) {
|
|
for (i = 1; i <= used_nonvolatile_registers[RegClass_FPR]; i++) {
|
|
load_store_register(PC_LFD, 32 - i, reg, NULL, o + (used_nonvolatile_registers[RegClass_FPR] - i) * 8);
|
|
setpcodeflags(fIsVolatile);
|
|
}
|
|
} else {
|
|
load_base_offset(11, reg, o + used_nonvolatile_registers[RegClass_FPR] * 8);
|
|
call_helper_function("__restore_fpr_%d", RegClass_FPR, EffectWrite);
|
|
}
|
|
}
|
|
|
|
static void restore_nonvolatile_VRs(int reg, SInt32 offset) {
|
|
short i;
|
|
SInt32 o;
|
|
|
|
o = offset + non_volatile_save_offset[RegClass_VR];
|
|
|
|
if (!use_helper_function(RegClass_VR)) {
|
|
for (i = 1; i <= used_nonvolatile_registers[RegClass_VR]; i++) {
|
|
emitpcode(PC_LI, 0, o + (used_nonvolatile_registers[RegClass_VR] - i) * 16);
|
|
setpcodeflags(fIsVolatile);
|
|
emitpcode(PC_LVX, 32 - i, reg, 0);
|
|
setpcodeflags(fIsVolatile);
|
|
}
|
|
} else {
|
|
load_base_offset(0, reg, o + used_nonvolatile_registers[RegClass_VR] * 16);
|
|
call_helper_function("__restv%d", RegClass_VR, EffectWrite);
|
|
}
|
|
}
|
|
|
|
static void save_nonvolatile_GPRs(int reg, SInt32 offset) {
|
|
int i;
|
|
SInt32 o;
|
|
|
|
o = offset + non_volatile_save_offset[RegClass_GPR];
|
|
|
|
if (!use_helper_function(RegClass_GPR)) {
|
|
if (copts.use_lmw_stmw && ((used_nonvolatile_registers[RegClass_GPR] > 4) || (copts.optimize_for_size && (used_nonvolatile_registers[RegClass_GPR] > 1)))) {
|
|
emitpcode(PC_STMW, used_nonvolatile_registers[RegClass_GPR] - 1, 32 - used_nonvolatile_registers[RegClass_GPR], reg, 0, o);
|
|
} else {
|
|
for (i = 1; i <= used_nonvolatile_registers[RegClass_GPR]; i++) {
|
|
emitpcode(PC_STW, 32 - i, reg, 0, o + (used_nonvolatile_registers[RegClass_GPR] - i) * 4);
|
|
}
|
|
}
|
|
} else {
|
|
load_base_offset(11, reg, o + used_nonvolatile_registers[RegClass_GPR] * 4);
|
|
call_helper_function("__savegpr_%d", RegClass_GPR, EffectRead);
|
|
}
|
|
}
|
|
|
|
static void restore_nonvolatile_GPRs(int reg, SInt32 offset) {
|
|
int i;
|
|
SInt32 o;
|
|
|
|
o = offset + non_volatile_save_offset[RegClass_GPR];
|
|
|
|
if (!use_helper_function(RegClass_GPR)) {
|
|
if (copts.use_lmw_stmw && ((used_nonvolatile_registers[RegClass_GPR] > 4) || (copts.optimize_for_size && (used_nonvolatile_registers[RegClass_GPR] > 1)))) {
|
|
emitpcode(PC_LMW, used_nonvolatile_registers[RegClass_GPR] - 1, 32 - used_nonvolatile_registers[RegClass_GPR], reg, 0, o);
|
|
setpcodeflags(fIsVolatile);
|
|
} else {
|
|
for (i = 1; i <= used_nonvolatile_registers[RegClass_GPR]; i++) {
|
|
emitpcode(PC_LWZ, 32 - i, reg, 0, o + (used_nonvolatile_registers[RegClass_GPR] - i) * 4);
|
|
setpcodeflags(fIsVolatile);
|
|
}
|
|
}
|
|
} else {
|
|
load_base_offset(11, reg, o + used_nonvolatile_registers[RegClass_GPR] * 4);
|
|
call_helper_function("__restgpr_%d", RegClass_GPR, EffectWrite);
|
|
}
|
|
}
|
|
|
|
static void do_allocate_dynamic_stack_space(Boolean flag1, int reg1, int reg2, SInt32 size) {
|
|
load_store_register(PC_LWZ, reg2, 1, NULL, 0);
|
|
if (flag1) {
|
|
size = ALIGN(size, frame_alignment);
|
|
if (size < 0x8000) {
|
|
emitpcode(PC_STWU, reg2, 1, 0, -size);
|
|
} else {
|
|
emitpcode(PC_LIS, reg1, 0, (short) HIGH_PART(-size));
|
|
if (-size)
|
|
emitpcode(PC_ADDI, reg1, reg1, 0, LOW_PART(-size));
|
|
emitpcode(PC_STWUX, reg2, 1, reg1);
|
|
setpcodeflags(fIsVolatile | fSideEffects);
|
|
}
|
|
} else {
|
|
emitpcode(PC_STWUX, reg2, 1, reg1);
|
|
setpcodeflags(fIsVolatile | fSideEffects);
|
|
}
|
|
}
|
|
|
|
void allocate_dynamic_stack_space(Boolean flag1, int reg1, int reg2, SInt32 size) {
|
|
if (copts.altivec_model)
|
|
update_frame_align(16);
|
|
do_allocate_dynamic_stack_space(flag1, reg1, reg2, size);
|
|
add_immediate(reg1, 1, dummylocal, 0);
|
|
}
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma options align=mac68k
|
|
#endif
|
|
typedef struct Traceback {
|
|
UInt8 x0;
|
|
UInt8 x1;
|
|
UInt8 x2;
|
|
UInt8 x3;
|
|
UInt8 x4;
|
|
UInt8 x5;
|
|
|
|
UInt8 x6_0 : 2;
|
|
UInt8 x6_1 : 1; // set to 1
|
|
UInt8 x6_2 : 5;
|
|
|
|
UInt8 x7_0 : 1;
|
|
UInt8 x7_1 : 1; // set to 1
|
|
UInt8 has_dynamic_stack : 1; // set to 1 if dynamic_stack
|
|
UInt8 x7_3 : 3;
|
|
UInt8 uses_CRs : 1; // set to 1 if CRs used
|
|
UInt8 needs_link_register : 1; // set to 1 if link register used
|
|
|
|
UInt8 has_frame_size : 1; // set to 1 if frame_size is nonzero
|
|
UInt8 x8_1 : 1; // set to 0
|
|
UInt8 used_FPRs : 6; // stores non-volatile FPRs used
|
|
|
|
UInt8 x9_0 : 1; // set to 0
|
|
UInt8 x9_1 : 1; // set to 1 if VRs or vrsave used
|
|
UInt8 used_GPRs : 6; // stores non-volatile GPRs used
|
|
|
|
UInt8 xA;
|
|
UInt8 xB;
|
|
|
|
SInt32 funcsize;
|
|
SInt16 namelen;
|
|
char name[0];
|
|
} Traceback;
|
|
|
|
typedef struct TracebackExtra {
|
|
UInt8 used_VRs : 6;
|
|
UInt8 has_vrsave_mask : 1;
|
|
UInt8 is_varargs : 1;
|
|
UInt8 vec_arg_count : 7;
|
|
UInt8 has_vrsave_mask_or_used_VRs : 1;
|
|
} TracebackExtra;
|
|
#ifdef __MWERKS__
|
|
#pragma options align=reset
|
|
#endif
|
|
|
|
char *generate_traceback(SInt32 funcsize, char *funcname, SInt32 *tbsize, Object *func) {
|
|
char *work;
|
|
short namelen;
|
|
Traceback *buf;
|
|
SInt32 bufsize;
|
|
|
|
namelen = strlen(funcname);
|
|
bufsize = ALIGN(sizeof(Traceback) + namelen + (dynamic_stack ? 1 : 0) + ((used_nonvolatile_registers[RegClass_VR] || vrsave_mask) ? sizeof(TracebackExtra) : 0), 4);
|
|
buf = lalloc(bufsize);
|
|
memclrw(buf, bufsize);
|
|
|
|
buf->x4 = 0;
|
|
buf->x5 = copts.cplusplus ? 9 : 0;
|
|
buf->x6_1 = 1;
|
|
buf->x7_1 = 1;
|
|
if (dynamic_stack)
|
|
buf->has_dynamic_stack = 1;
|
|
if (used_nonvolatile_registers[RegClass_CRFIELD])
|
|
buf->uses_CRs = 1;
|
|
if (need_link_register())
|
|
buf->needs_link_register = 1;
|
|
if (frame_size)
|
|
buf->has_frame_size = 1;
|
|
buf->used_FPRs = used_nonvolatile_registers[RegClass_FPR];
|
|
buf->used_GPRs = used_nonvolatile_registers[RegClass_GPR];
|
|
buf->x8_1 = 0;
|
|
buf->x9_0 = 0;
|
|
buf->x9_1 = (used_nonvolatile_registers[RegClass_VR] || vrsave_mask) != 0;
|
|
buf->funcsize = funcsize;
|
|
buf->namelen = namelen;
|
|
|
|
work = buf->name;
|
|
strcpy(work, funcname);
|
|
work += namelen;
|
|
if (dynamic_stack) {
|
|
*(work++) = 31;
|
|
}
|
|
|
|
if (vrsave_mask || used_nonvolatile_registers[RegClass_VR]) {
|
|
TracebackExtra *extra;
|
|
Boolean is_varargs;
|
|
int vec_count;
|
|
FuncArg *args, *scan;
|
|
Type *type;
|
|
|
|
extra = (TracebackExtra *) work;
|
|
vec_count = 0;
|
|
args = TYPE_FUNC(func->type)->args;
|
|
scan = args;
|
|
while (scan && scan != &elipsis)
|
|
scan = scan->next;
|
|
is_varargs = scan == &elipsis;
|
|
while (args) {
|
|
if ((type = args->type) && IS_TYPE_VECTOR(type))
|
|
vec_count++;
|
|
args = args->next;
|
|
}
|
|
extra->used_VRs = used_nonvolatile_registers[RegClass_VR];
|
|
extra->has_vrsave_mask = vrsave_mask != 0;
|
|
extra->is_varargs = is_varargs;
|
|
extra->vec_arg_count = vec_count;
|
|
extra->has_vrsave_mask_or_used_VRs = vrsave_mask || used_nonvolatile_registers[RegClass_VR];
|
|
}
|
|
|
|
*tbsize = bufsize;
|
|
return (char *) buf;
|
|
}
|
|
|
|
static SInt32 localsbase(void) {
|
|
SInt32 size = parameter_area_size;
|
|
if (frame_size || dynamic_align_stack)
|
|
size += linkage_area_size;
|
|
else
|
|
size -= genuine_frame_size;
|
|
return size;
|
|
}
|
|
|
|
static SInt32 parametersbase(int flag) {
|
|
if (flag)
|
|
return 24;
|
|
|
|
return frame_size ? (genuine_frame_size + 24) : 24;
|
|
}
|
|
|
|
void check_dynamic_aligned_frame(void) {
|
|
PCode *pc;
|
|
|
|
if (used_nonvolatile_registers[RegClass_VR]) {
|
|
update_frame_align(16);
|
|
requires_frame = 1;
|
|
}
|
|
|
|
if (frame_alignment > in_param_alignment) {
|
|
dynamic_align_stack = 1;
|
|
requires_frame = 1;
|
|
#line 2091
|
|
CError_ASSERT(!has_varargs || _CALLER_SP_ != -1);
|
|
#line 2096
|
|
CError_ASSERT(_CALLER_SP_ != _FP_);
|
|
if (setup_caller_sp && setup_caller_sp->block) {
|
|
align_instr1 = makepcode(PC_RLWINM, 12, 1, 0, 5, 31);
|
|
insertpcodebefore(setup_caller_sp, align_instr1);
|
|
align_instr2 = makepcode(PC_STWUX, 1, 1, 12);
|
|
insertpcodeafter(setup_caller_sp, align_instr2);
|
|
}
|
|
} else {
|
|
dynamic_align_stack = 0;
|
|
if (setup_caller_sp && setup_caller_sp->block) {
|
|
pc = makepcode(PC_MR, _CALLER_SP_, _FP_);
|
|
insertpcodebefore(setup_caller_sp, pc);
|
|
deletepcode(setup_caller_sp);
|
|
setup_caller_sp = pc;
|
|
}
|
|
_CALLER_SP_ = _FP_;
|
|
}
|
|
|
|
vrsave_mask = 0;
|
|
if (copts.altivec_model) {
|
|
vrsave_mask = colored_vrs_as_vrsave(pcbasicblocks);
|
|
if (!requires_frame && vrsave_mask) {
|
|
vrsave_register = 11;
|
|
loadvrsave = makepcode(PC_LWZ, 11, 1, 0, -4);
|
|
appendpcode(prologue, loadvrsave);
|
|
storevrsave = makepcode(PC_STW, 11, 1, 0, -4);
|
|
appendpcode(epilogue, storevrsave);
|
|
}
|
|
}
|
|
}
|
|
|
|
void move_varargs_to_memory(void) {
|
|
short reg;
|
|
|
|
has_varargs = 1;
|
|
dummyvaparam = galloc(sizeof(Object));
|
|
memclrw(dummyvaparam, sizeof(Object));
|
|
|
|
dummyvaparam->type = (Type *) &stvoid;
|
|
dummyvaparam->otype = OT_OBJECT;
|
|
dummyvaparam->name = GetHashNameNode("<vaparam>");
|
|
dummyvaparam->datatype = DLOCAL;
|
|
dummyvaparam->u.var.info = CodeGen_GetNewVarInfo();
|
|
dummyvaparam->u.var.uid = 0;
|
|
dummyvaparam->u.var.info->noregister = 1;
|
|
Registers_GetVarInfo(dummyvaparam)->flags = (Registers_GetVarInfo(dummyvaparam)->flags & ~VarInfoFlag1) | VarInfoFlag1;
|
|
|
|
for (reg = last_argument_register[RegClass_GPR] + 1; (int)reg <= 10; reg++) {
|
|
emitpcode(PC_STW, reg, local_base_register(dummyvaparam), dummyvaparam, (reg - 3) * 4);
|
|
setpcodeflags(fPCodeFlag20 | fPCodeFlag8000);
|
|
}
|
|
}
|
|
|
|
void assign_arguments_to_memory(Object *func, UInt8 mysteryFlag, Boolean hasVarargs) {
|
|
// almost matches except for the not/andc issue
|
|
SInt32 pos;
|
|
ObjectList *list;
|
|
Object *obj;
|
|
Type *type;
|
|
short reg;
|
|
SInt32 chk;
|
|
Boolean flag;
|
|
|
|
pos = 0;
|
|
reg = 2;
|
|
|
|
for (list = arguments; list; list = list->next) {
|
|
obj = list->object;
|
|
type = obj->type;
|
|
if (!IS_TYPE_VECTOR(type)) {
|
|
obj->datatype = DLOCAL;
|
|
obj->u.var.info = CodeGen_GetNewVarInfo();
|
|
if (IS_TYPE_ARRAY(type) || IS_TYPE_NONVECTOR_STRUCT(type) || IS_TYPE_CLASS(type) ||
|
|
IS_TYPE_12BYTES_MEMBERPOINTER(type)) {
|
|
chk = CMach_ArgumentAlignment(type);
|
|
if (chk > 4) {
|
|
pos = ALIGN(pos, chk);
|
|
update_in_param_align(chk);
|
|
}
|
|
}
|
|
obj->u.var.uid = pos;
|
|
Registers_GetVarInfo(obj)->flags = (Registers_GetVarInfo(obj)->flags & ~VarInfoFlag1) | VarInfoFlag1;
|
|
if (!copts.little_endian && (IS_TYPE_INT(obj->type) || IS_TYPE_ENUM(obj->type)) && obj->type->size < 4)
|
|
obj->u.var.uid += 4 - obj->type->size;
|
|
pos += type->size;
|
|
pos = ALIGN(pos, 4);
|
|
} else {
|
|
obj->u.var.info = CodeGen_GetNewVarInfo();
|
|
obj->u.var.uid = 0;
|
|
obj->datatype = DLOCAL;
|
|
flag = 1;
|
|
if (reg <= 13)
|
|
flag = hasVarargs;
|
|
if (flag) {
|
|
pos = ALIGN(pos + 24, 16) - 24;
|
|
obj->u.var.offset = pos;
|
|
pos += 16;
|
|
update_in_param_align(16);
|
|
Registers_GetVarInfo(obj)->flags = (Registers_GetVarInfo(obj)->flags & ~VarInfoFlag1) | VarInfoFlag1;
|
|
} else {
|
|
assign_local_memory(obj);
|
|
Registers_GetVarInfo(obj)->flags = Registers_GetVarInfo(obj)->flags & ~VarInfoFlag1;
|
|
}
|
|
reg++;
|
|
}
|
|
}
|
|
|
|
in_parameter_size = (in_parameter_size < pos) ? pos : in_parameter_size;
|
|
#line 2408
|
|
CError_ASSERT(!dummyvaparam);
|
|
}
|
|
|
|
SInt32 set_out_param_displ(SInt32 a, Type *type, Boolean flag, SInt32 *outvar, SInt32 b) {
|
|
// does not match due to errant andc
|
|
SInt32 argAlign;
|
|
|
|
if (!flag && !b) {
|
|
*outvar = 0;
|
|
return a;
|
|
}
|
|
|
|
if (IS_TYPE_VECTOR(type)) {
|
|
update_out_param_align(16);
|
|
a = ALIGN(a + 16 + 24, 16) - 24;
|
|
} else if (IS_TYPE_ARRAY(type) || IS_TYPE_NONVECTOR_STRUCT(type) || IS_TYPE_CLASS(type) || IS_TYPE_12BYTES_MEMBERPOINTER(type)) {
|
|
argAlign = CMach_ArgumentAlignment(type);
|
|
if (argAlign > 4) {
|
|
a = ALIGN(a + 24, argAlign) - 24;
|
|
update_in_param_align(argAlign);
|
|
}
|
|
}
|
|
|
|
*outvar = a;
|
|
a = ALIGN(a + b, 4);
|
|
return a;
|
|
}
|
|
|
|
SInt32 out_param_displ_to_offset(SInt32 displ) {
|
|
return displ + 24;
|
|
}
|
|
|
|
Boolean needs_frame(void) {
|
|
return (frame_size > 224) || requires_frame;
|
|
}
|
|
|
|
void update_out_param_size(SInt32 size) {
|
|
if (size < 32)
|
|
size = 32;
|
|
if (parameter_area_size < size)
|
|
parameter_area_size = size;
|
|
}
|
|
|
|
void estimate_out_param_size(SInt32 size) {
|
|
if (parameter_area_size_estimate < size)
|
|
parameter_area_size_estimate = size;
|
|
}
|
|
|
|
void update_out_param_align(SInt32 align) {
|
|
if (out_param_alignment < align)
|
|
out_param_alignment = align;
|
|
update_frame_align(align);
|
|
}
|
|
|
|
void update_in_param_align(SInt32 align) {
|
|
if (in_param_alignment < align)
|
|
in_param_alignment = align;
|
|
}
|
|
|
|
void update_frame_align(SInt32 align) {
|
|
if (frame_alignment < align)
|
|
frame_alignment = align;
|
|
}
|
|
|
|
SInt32 local_offset_32(Object *obj) {
|
|
short align;
|
|
SInt32 offset;
|
|
|
|
if (obj->u.var.info->flags & VarInfoFlag1)
|
|
align = CMach_ArgumentAlignment(obj->type);
|
|
else
|
|
align = CMach_AllocationAlignment(obj->type, obj->qual);
|
|
|
|
offset = obj->u.var.uid;
|
|
if (offset > 0x7FFF)
|
|
offset = 0x8000 - offset - ALIGN(obj->type->size, align);
|
|
|
|
if (obj->u.var.info->flags & VarInfoFlag1)
|
|
return offset + parametersbase(local_base_register(obj) != _FP_);
|
|
else
|
|
return offset + localsbase();
|
|
}
|
|
|
|
SInt16 local_offset_lo(Object *obj, SInt32 offset) {
|
|
SInt32 combo = offset + local_offset_32(obj);
|
|
return LOW_PART(combo);
|
|
//return (SInt16) (offset + local_offset_32(obj));
|
|
}
|
|
|
|
SInt16 local_offset_ha(Object *obj, SInt32 offset) {
|
|
SInt32 combo = offset + local_offset_32(obj);
|
|
return HIGH_PART(combo);
|
|
//return (SInt16) ((combo >> 16) + ((combo & 0x8000) >> 15));
|
|
}
|
|
|
|
SInt16 local_offset_16(Object *obj) {
|
|
SInt32 offset32 = local_offset_32(obj);
|
|
SInt16 offset16 = (SInt16) offset32;
|
|
#line 2662
|
|
CError_ASSERT(offset32 == offset16);
|
|
return offset16;
|
|
}
|
|
|
|
Boolean local_is_16bit_offset(Object *obj) {
|
|
SInt32 offset32 = local_offset_32(obj);
|
|
SInt16 offset16 = (SInt16) offset32;
|
|
return offset32 == offset16;
|
|
}
|
|
|
|
int local_base_register(Object *obj) {
|
|
PCode *pc;
|
|
|
|
if (obj->u.var.info->flags & VarInfoFlag1) {
|
|
if (coloring && _CALLER_SP_ == -1) {
|
|
_CALLER_SP_ = used_virtual_registers[RegClass_GPR]++;
|
|
pc = makepcode(PC_LWZ, _CALLER_SP_, 1, 0, 0);
|
|
setup_caller_sp = pc;
|
|
appendpcode(prologue, pc);
|
|
}
|
|
return _CALLER_SP_;
|
|
} else {
|
|
return _FP_;
|
|
}
|
|
}
|
|
|
|
static UInt32 align_bits(UInt32 value, UInt8 bitcount) {
|
|
UInt32 base = bitcount != 0;
|
|
switch (value) {
|
|
case 0x0002: return base + 30;
|
|
case 0x0004: return base + 29;
|
|
case 0x0008: return base + 28;
|
|
case 0x0010: return base + 27;
|
|
case 0x0020: return base + 26;
|
|
case 0x0040: return base + 25;
|
|
case 0x0080: return base + 24;
|
|
case 0x0100: return base + 23;
|
|
case 0x0200: return base + 22;
|
|
case 0x0400: return base + 21;
|
|
case 0x0800: return base + 20;
|
|
case 0x1000: return base + 19;
|
|
case 0x2000: return base + 18;
|
|
default:
|
|
#line 2754
|
|
CError_FATAL();
|
|
return base + 27;
|
|
}
|
|
}
|
|
|
|
Boolean is_large_frame(void) {
|
|
#line 2769
|
|
CError_ASSERT(frame_size != -1);
|
|
return large_stack;
|
|
}
|
|
|
|
void no_frame_for_asm(void) {
|
|
frame_size = 0;
|
|
}
|
|
|
|
Boolean can_add_displ_to_local(Object *obj, SInt32 displ) {
|
|
if (obj->datatype != DLOCAL)
|
|
return 0;
|
|
|
|
if (local_offset_32(obj) == (short) local_offset_32(obj))
|
|
if ((displ + local_offset_32(obj)) == (short) (displ + local_offset_32(obj)))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
SInt32 get_alloca_alignment(void) {
|
|
SInt32 align = frame_alignment;
|
|
if (copts.altivec_model)
|
|
align = ALIGN(align, 16);
|
|
|
|
if (!alloca_alignment) {
|
|
alloca_alignment = align;
|
|
} else {
|
|
#line 2825
|
|
CError_ASSERT(alloca_alignment == align);
|
|
}
|
|
|
|
return align_bits(align, 0);
|
|
}
|
|
|
|
static Boolean use_helper_function(char rclass) {
|
|
if (copts.no_register_save_helpers)
|
|
return 0;
|
|
|
|
switch (rclass) {
|
|
case RegClass_GPR:
|
|
if (copts.use_lmw_stmw)
|
|
return 0;
|
|
return (used_nonvolatile_registers[RegClass_GPR] > 4) || (copts.optimize_for_size && used_nonvolatile_registers[RegClass_GPR] > 2);
|
|
case RegClass_FPR:
|
|
return (used_nonvolatile_registers[RegClass_FPR] > 3) || (copts.optimize_for_size && used_nonvolatile_registers[RegClass_FPR] > 2);
|
|
case RegClass_VR:
|
|
return (used_nonvolatile_registers[RegClass_VR] > 3) || (copts.optimize_for_size && used_nonvolatile_registers[RegClass_VR] > 2);
|
|
default:
|
|
#line 2862
|
|
CError_FATAL();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static Boolean need_link_register(void) {
|
|
if (copts.codegen_pic && uses_globals)
|
|
return 1;
|
|
|
|
if (makes_call)
|
|
return 1;
|
|
|
|
return use_helper_function(RegClass_FPR) || use_helper_function(RegClass_GPR) || use_helper_function(RegClass_VR);
|
|
}
|
|
|
|
static void call_helper_function(char *name, char rclass, short effect) {
|
|
char str[32];
|
|
Object *func;
|
|
NameSpace *save_scope;
|
|
PCode *pc;
|
|
int extra_args;
|
|
PCodeArg *arg;
|
|
short i;
|
|
|
|
extra_args = 1;
|
|
if (rclass == RegClass_VR)
|
|
extra_args = 2;
|
|
|
|
sprintf(str, name, 32 - used_nonvolatile_registers[rclass]);
|
|
|
|
save_scope = cscope_current;
|
|
cscope_current = cscope_root;
|
|
func = CParser_NewRTFunc(&stvoid, NULL, 2, 0);
|
|
cscope_current = save_scope;
|
|
|
|
func->name = GetHashNameNodeExport(str);
|
|
|
|
pc = makepcode(PC_BL, extra_args + used_nonvolatile_registers[rclass], func, 0);
|
|
for (i = 1, arg = &pc->args[1]; i <= used_nonvolatile_registers[rclass]; i++, arg++) {
|
|
arg->kind = PCOp_REGISTER;
|
|
arg->arg = rclass;
|
|
arg->data.reg.reg = n_real_registers[rclass] - i;
|
|
arg->data.reg.effect = effect;
|
|
}
|
|
|
|
if (rclass == RegClass_VR) {
|
|
arg[1].kind = PCOp_REGISTER;
|
|
arg[1].arg = RegClass_GPR;
|
|
arg[1].data.reg.reg = 12;
|
|
arg[1].data.reg.effect = EffectWrite;
|
|
arg[2].kind = PCOp_REGISTER;
|
|
arg[2].arg = RegClass_GPR;
|
|
arg[2].data.reg.reg = 0;
|
|
arg[2].data.reg.effect = EffectRead;
|
|
} else {
|
|
arg[1].kind = PCOp_REGISTER;
|
|
arg[1].arg = RegClass_GPR;
|
|
arg[1].data.reg.reg = 11;
|
|
arg[1].data.reg.effect = EffectRead;
|
|
}
|
|
|
|
appendpcode(pclastblock, pc);
|
|
setpcodeflags(fSideEffects);
|
|
}
|
|
|
|
static SInt32 nearest_power_of_two(SInt32 n) {
|
|
SInt32 power = 1;
|
|
do {
|
|
power <<= 1;
|
|
} while (power && power < n);
|
|
|
|
#line 2933
|
|
CError_ASSERT(power != 0);
|
|
return power;
|
|
}
|
|
|
|
static void compress_data_area(void) {
|
|
// doesn't quite match
|
|
SInt32 r0;
|
|
SInt32 r7;
|
|
ObjectList *list;
|
|
Object *obj;
|
|
PCodeBlock *block;
|
|
PCode *pc;
|
|
int i;
|
|
|
|
compressing_data_area = 1;
|
|
|
|
if (large_stack) {
|
|
r0 = 0;
|
|
} else {
|
|
r0 = parameter_area_size;
|
|
if (r0 < 32)
|
|
r0 = 32;
|
|
}
|
|
r7 = ALIGN(r0 + 24, frame_alignment) - 24;
|
|
local_data_limit = 0x8000 - ALIGN(24 + in_parameter_size + nonvolatile_save_size + r7, frame_alignment);
|
|
|
|
if (local_objects_tail[ObjClass0]) {
|
|
if (local_objects[ObjClass1]) {
|
|
local_objects_tail[ObjClass0]->next = local_objects[ObjClass1];
|
|
local_objects_tail[ObjClass0] = local_objects_tail[ObjClass1];
|
|
}
|
|
if (local_objects[ObjClass2]) {
|
|
local_objects_tail[ObjClass0]->next = local_objects[ObjClass2];
|
|
local_objects_tail[ObjClass0] = local_objects_tail[ObjClass2];
|
|
}
|
|
} else if (local_objects_tail[ObjClass1]) {
|
|
local_objects[ObjClass0] = local_objects[ObjClass1];
|
|
local_objects_tail[ObjClass0] = local_objects_tail[ObjClass1];
|
|
if (local_objects[ObjClass2]) {
|
|
local_objects_tail[ObjClass0]->next = local_objects[ObjClass2];
|
|
local_objects_tail[ObjClass0] = local_objects_tail[ObjClass2];
|
|
}
|
|
} else {
|
|
local_objects[ObjClass0] = local_objects[ObjClass2];
|
|
local_objects_tail[ObjClass0] = local_objects_tail[ObjClass2];
|
|
}
|
|
|
|
for (list = local_objects[ObjClass0]; list; list = list->next)
|
|
Registers_GetVarInfo(list->object)->used = 0;
|
|
|
|
for (block = pcbasicblocks; block; block = block->nextBlock) {
|
|
for (pc = block->firstPCode; pc; pc = pc->nextPCode) {
|
|
for (i = 0; i < pc->argCount; i++) {
|
|
if (pc->args[i].kind == PCOp_MEMORY && pc->args[i].data.mem.obj && pc->args[i].data.mem.obj->datatype == DLOCAL)
|
|
Registers_GetVarInfo(pc->args[i].data.mem.obj)->used = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
local_data_size = 0;
|
|
large_data_near_size = 0;
|
|
large_data_far_size = 0;
|
|
|
|
for (list = local_objects[ObjClass0]; list; list = list->next) {
|
|
obj = list->object;
|
|
if (Registers_GetVarInfo(obj)->used)
|
|
assign_local_memory(obj);
|
|
}
|
|
}
|
|
|
|
static void insert_local_object(UInt8 oclass, Object *obj) {
|
|
ObjectList *list;
|
|
|
|
if (!compressing_data_area) {
|
|
list = lalloc(sizeof(ObjectList));
|
|
memclrw(list, sizeof(ObjectList));
|
|
list->object = obj;
|
|
if (!local_objects[oclass])
|
|
local_objects[oclass] = list;
|
|
if (local_objects_tail[oclass])
|
|
local_objects_tail[oclass]->next = list;
|
|
local_objects_tail[oclass] = list;
|
|
}
|
|
}
|