summaryrefslogtreecommitdiff
path: root/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c')
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c1252
1 files changed, 1252 insertions, 0 deletions
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c
new file mode 100644
index 0000000..6fa4524
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/StackFrame.c
@@ -0,0 +1,1252 @@
+#include "compiler/StackFrame.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/PCode.h"
+#include "compiler/PCodeInfo.h"
+#include "compiler/PCodeUtilities.h"
+#include "compiler/RegisterInfo.h"
+#include "compiler/objects.h"
+#include "compiler/types.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 isConstantSize, int reg1, int reg2, SInt32 size);
+
+void init_stack_globals(Object *funcobj) {
+ RegClass rclass;
+ ObjClass 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[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;
+
+ CError_ASSERT(897, 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) {
+ CError_ASSERT(1005, !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) {
+ CError_ASSERT(1019, !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(CErrorStr210);
+}
+
+static void allocate_new_frame(int reg1, int reg2) {
+ if (dynamic_align_stack) {
+ CError_ASSERT(1116, reg1 != _CALLER_SP_);
+ emitpcode(PC_RLWINM, reg1, 1, 0, align_bits(frame_alignment, 1), 31);
+ if (frame_size > 0x7FFF) {
+ CError_FATAL(1122);
+ 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)
+ CError_FATAL(1153);
+ 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_
+ )
+ CError_FATAL(1197);
+
+ _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 {
+ CError_ASSERT(1326, !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 |= fIsProlog;
+ 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 |= fIsEpilogue;
+ 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.optimizesize && (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.optimizesize && (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 isConstantSize, int reg1, int reg2, SInt32 size) {
+ load_store_register(PC_LWZ, reg2, 1, NULL, 0);
+ if (isConstantSize) {
+ 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 isConstantSize, int reg1, int reg2, SInt32 size) {
+ if (copts.altivec_model)
+ update_frame_align(16);
+ do_allocate_dynamic_stack_space(isConstantSize, 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;
+ CError_ASSERT(2091, !has_varargs || _CALLER_SP_ != -1);
+ CError_ASSERT(2096, _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(fIsPtrOp | fIsArgInit);
+ }
+}
+
+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.littleendian && (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.uid = 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;
+ CError_ASSERT(2408, !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();
+}
+
+SInt32 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));
+}
+
+SInt32 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));
+}
+
+SInt32 local_offset_16(Object *obj) {
+ SInt32 offset32 = local_offset_32(obj);
+ SInt16 offset16 = (SInt16) offset32;
+ CError_ASSERT(2662, 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:
+ CError_FATAL(2754);
+ return base + 27;
+ }
+}
+
+Boolean is_large_frame(void) {
+ CError_ASSERT(2769, 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
+ CError_ASSERT(2825, 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.optimizesize && used_nonvolatile_registers[RegClass_GPR] > 2);
+ case RegClass_FPR:
+ return (used_nonvolatile_registers[RegClass_FPR] > 3) || (copts.optimizesize && used_nonvolatile_registers[RegClass_FPR] > 2);
+ case RegClass_VR:
+ return (used_nonvolatile_registers[RegClass_VR] > 3) || (copts.optimizesize && used_nonvolatile_registers[RegClass_VR] > 2);
+ default:
+ CError_FATAL(2862);
+ 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);
+
+ CError_ASSERT(2933, 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;
+ }
+}