mirror of https://git.wuffs.org/MWCC
394 lines
11 KiB
C
394 lines
11 KiB
C
#include "compiler/FuncLevelAsmPPC.h"
|
|
#include "compiler/CCompiler.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CFunc.h"
|
|
#include "compiler/CMangler.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/CPrepTokenizer.h"
|
|
#include "compiler/CodeGen.h"
|
|
#include "compiler/Coloring.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/DumpIR.h"
|
|
#include "compiler/InlineAsmPPC.h"
|
|
#include "compiler/InlineAsmRegisters.h"
|
|
#include "compiler/ObjGenMachO.h"
|
|
#include "compiler/PCode.h"
|
|
#include "compiler/PCodeAssembly.h"
|
|
#include "compiler/PCodeListing.h"
|
|
#include "compiler/PCodeUtilities.h"
|
|
#include "compiler/PPCError.h"
|
|
#include "compiler/RegisterInfo.h"
|
|
#include "compiler/StackFrame.h"
|
|
#include "compiler/TOC.h"
|
|
#include "compiler/objects.h"
|
|
|
|
static EntryPoint *entrypoints_head;
|
|
static EntryPoint **entrypoints_tail;
|
|
|
|
void setup_assembly_argument(Object *obj, short reg) {
|
|
VarInfo *vi;
|
|
Type *type;
|
|
|
|
vi = Registers_GetVarInfo(obj);
|
|
type = obj->type;
|
|
vi->used = 1;
|
|
|
|
if (!requires_frame) {
|
|
if (is_register_object(obj)) {
|
|
if (!reg)
|
|
CError_Error(CErrorStr263, obj->name->name);
|
|
|
|
if (TYPE_IS_8BYTES(type)) {
|
|
short regLo;
|
|
short regHi;
|
|
if (reg < 10) {
|
|
if (copts.littleendian) {
|
|
regLo = reg;
|
|
regHi = reg + 1;
|
|
} else {
|
|
regLo = reg + 1;
|
|
regHi = reg;
|
|
}
|
|
retain_GPR_pair(obj, regLo, regHi);
|
|
InlineAsm_InsertRegister(obj->name->name, RegClass_GPR, regLo, obj);
|
|
}
|
|
} else if (IS_TYPE_FLOAT(type)) {
|
|
retain_register(obj, RegClass_FPR, reg);
|
|
InlineAsm_InsertRegister(obj->name->name, RegClass_FPR, reg, obj);
|
|
} else if (IS_TYPE_VECTOR(type)) {
|
|
retain_register(obj, RegClass_VR, reg);
|
|
InlineAsm_InsertRegister(obj->name->name, RegClass_VR, reg, obj);
|
|
} else {
|
|
retain_register(obj, RegClass_GPR, reg);
|
|
InlineAsm_InsertRegister(obj->name->name, RegClass_GPR, reg, obj);
|
|
}
|
|
}
|
|
} else {
|
|
if (is_register_object(obj)) {
|
|
vi = Registers_GetVarInfo(obj);
|
|
if (!vi->reg) {
|
|
assign_register_by_type(obj);
|
|
if (!(vi->flags & VarInfoFlag2))
|
|
CError_Error(CErrorStr263, obj->name->name);
|
|
else
|
|
InlineAsm_InsertRegister(obj->name->name, vi->rclass, vi->reg, obj);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void assign_local_addresses(void) {
|
|
VarInfo *vi;
|
|
ObjectList *list;
|
|
Object *object;
|
|
|
|
for (list = locals; list; list = list->next) {
|
|
vi = CodeGen_GetNewVarInfo();
|
|
list->object->u.var.info = vi;
|
|
list->object->flags |= OBJECT_USED;
|
|
vi->used = 1;
|
|
}
|
|
|
|
for (list = locals; list; list = list->next) {
|
|
object = list->object;
|
|
if (is_register_object(object)) {
|
|
vi = Registers_GetVarInfo(object);
|
|
if (!vi->reg) {
|
|
assign_register_by_type(object);
|
|
if (!(vi->flags & VarInfoFlag2))
|
|
CError_Error(CErrorStr263, object->name->name);
|
|
else
|
|
InlineAsm_InsertRegister(object->name->name, vi->rclass, vi->reg, object);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (list = locals; list; list = list->next) {
|
|
object = list->object;
|
|
if (OBJECT_REG(object) == 0)
|
|
assign_local_memory(object);
|
|
}
|
|
}
|
|
|
|
static void FuncAsm_PreScanDirectives(void) {
|
|
SInt32 directive;
|
|
Boolean save_eoltokens;
|
|
|
|
in_assembler = 1;
|
|
save_eoltokens = cprep_eoltokens;
|
|
cprep_eoltokens = 1;
|
|
|
|
if (setjmp(InlineAsm_assemblererror) == 0) {
|
|
while (tk == TK_IDENTIFIER && (directive = InlineAsm_IsDirective(AssemblerType_1))) {
|
|
InlineAsm_ProcessDirective(directive);
|
|
|
|
if (tk == ';' || tk == TK_EOL) {
|
|
CPrep_TokenStreamFlush();
|
|
tk = lex();
|
|
} else {
|
|
InlineAsm_SyntaxError(CErrorStr113);
|
|
}
|
|
|
|
if (directive == IADirective_FrAlloc) {
|
|
requires_frame = 1;
|
|
break;
|
|
} else if (directive == IADirective_NoFrAlloc) {
|
|
user_responsible_for_frame = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
in_assembler = 0;
|
|
cprep_eoltokens = save_eoltokens;
|
|
}
|
|
|
|
static void FuncAsm_AddEntryPoint(Statement *stmt, PCodeBlock *block) {
|
|
EntryPoint *ep;
|
|
IAEntryPoint *ia_ep;
|
|
|
|
ia_ep = (IAEntryPoint *) stmt->expr;
|
|
ep = lalloc(sizeof(EntryPoint));
|
|
memclrw(ep, sizeof(EntryPoint));
|
|
|
|
ep->object = ia_ep->x8;
|
|
ep->block = block;
|
|
|
|
*entrypoints_tail = ep;
|
|
entrypoints_tail = &ep->next;
|
|
|
|
block->flags |= fPCBlockFlag8000;
|
|
}
|
|
|
|
void Assembler(Object *func) {
|
|
PCodeBlock *block;
|
|
Statement *stmt;
|
|
Boolean flag17;
|
|
Boolean flag16;
|
|
char *name;
|
|
InlineAsm *ia;
|
|
Boolean save_unusedvar;
|
|
Boolean save_unusedarg;
|
|
|
|
flag17 = 0;
|
|
flag16 = 0;
|
|
|
|
init_endian();
|
|
init_stack_globals(func);
|
|
memclrw(asm_alloc_flags, sizeof(asm_alloc_flags));
|
|
fralloc_parameter_area_size = 0;
|
|
user_responsible_for_frame = 0;
|
|
assembledinstructions = 0;
|
|
|
|
entrypoints_head = NULL;
|
|
entrypoints_tail = &entrypoints_head;
|
|
|
|
stmt = curstmt;
|
|
|
|
if (func && func->name)
|
|
PrintProgressFunction(func->name->name);
|
|
|
|
CodeGen_InitialSanityCheck();
|
|
|
|
if (func->qual & Q_INLINE)
|
|
PPCError_Warning(PPCErrorStr173);
|
|
|
|
CheckCLabels();
|
|
|
|
if (fatalerrors)
|
|
return;
|
|
|
|
if (copts.filesyminfo)
|
|
CPrep_SetSourceFile(&cparser_fileoffset);
|
|
|
|
sm_section = SECT_TEXT;
|
|
|
|
initpcode();
|
|
|
|
pclabel(prologue = makepcblock(), makepclabel());
|
|
pclabel(block = makepcblock(), makepclabel());
|
|
pcbranch(prologue, block->labels);
|
|
|
|
resetTOCvarinfo();
|
|
InlineAsm_InitializePPC();
|
|
FuncAsm_PreScanDirectives();
|
|
|
|
disable_optimizer = 1;
|
|
|
|
init_registers();
|
|
assign_arguments_to_memory(func, 0, 0);
|
|
init_frame_sizes(0);
|
|
|
|
if (copts.debuglisting)
|
|
DumpIR(stmt, func);
|
|
|
|
cprep_eoltokens = 1;
|
|
in_assembler = 1;
|
|
|
|
save_unusedvar = copts.warn_unusedvar;
|
|
save_unusedarg = copts.warn_unusedarg;
|
|
copts.warn_unusedvar = 0;
|
|
copts.warn_unusedarg = 0;
|
|
|
|
InlineAsm_ScanFunction('}');
|
|
|
|
expandTOCreferences(&stmt->next);
|
|
|
|
if (!anyerrors && copts.debuglisting)
|
|
DumpIR(stmt, func);
|
|
|
|
in_assembler = 0;
|
|
cprep_eoltokens = 0;
|
|
|
|
name = CMangler_GetLinkName(func)->name;
|
|
func->flags |= OBJECT_DEFINED;
|
|
|
|
if (fralloc_parameter_area_size)
|
|
update_out_param_size(fralloc_parameter_area_size);
|
|
if (!user_responsible_for_frame)
|
|
process_arguments(move_assigned_argument, 0);
|
|
|
|
branch_label(makepclabel());
|
|
assign_labels(stmt->next);
|
|
|
|
copts.warn_unusedvar = save_unusedvar;
|
|
copts.warn_unusedarg = save_unusedarg;
|
|
|
|
for (stmt = stmt->next; stmt; stmt = stmt->next) {
|
|
current_statement = stmt;
|
|
switch (stmt->type) {
|
|
case ST_ASM:
|
|
if ((ia = (InlineAsm *) stmt->expr)) {
|
|
if (ia->flags & IAFlag1) {
|
|
if (ia->opcode == IADirective_Entry) {
|
|
branch_label(makepclabel());
|
|
FuncAsm_AddEntryPoint(stmt, pclastblock);
|
|
} else if (ia->opcode == IADirective_FrFree) {
|
|
if (flag16)
|
|
PPCError_Error(PPCErrorStr188);
|
|
else
|
|
flag16 = 1;
|
|
|
|
asm_alloc_flags[3] = 1;
|
|
asm_alloc_flags[4] = 1;
|
|
branch_label(makepclabel());
|
|
|
|
epilogue = pclastblock;
|
|
pclastblock->flags |= fIsEpilogue;
|
|
|
|
CheckCLabels();
|
|
if (fatalerrors)
|
|
return;
|
|
|
|
pccomputepredecessors();
|
|
if (copts.debuglisting)
|
|
pclistblocks(name, "[FUNCTION-LEVEL ASM] INITIAL CODE");
|
|
colorinstructions(func);
|
|
if (copts.debuglisting)
|
|
pclistblocks(name, "[FUNCTION-LEVEL ASM] AFTER REGISTER COLORING");
|
|
compute_frame_sizes();
|
|
generate_prologue(prologue, 0);
|
|
epilogue = pclastblock;
|
|
generate_epilogue(epilogue, 0);
|
|
if (copts.debuglisting)
|
|
pclistblocks(name, "[FUNCTION-LEVEL ASM] AFTER PROLOGUE/EPILOGUE CREATION");
|
|
|
|
flag17 = 1;
|
|
}
|
|
} else {
|
|
branch_label(makepclabel());
|
|
asm_alloc_flags[6] = 0;
|
|
asm_alloc_flags[7] = 0;
|
|
InlineAsm_TranslateIRtoPCode(stmt);
|
|
asm_alloc_flags[4] = 0;
|
|
}
|
|
}
|
|
break;
|
|
case ST_LABEL:
|
|
if (!stmt->label->pclabel->resolved)
|
|
branch_label(stmt->label->pclabel);
|
|
break;
|
|
default:
|
|
CError_FATAL(525);
|
|
}
|
|
}
|
|
|
|
current_statement = NULL;
|
|
|
|
if (fatalerrors)
|
|
return;
|
|
CheckCLabels();
|
|
if (fatalerrors)
|
|
return;
|
|
|
|
if (!flag17) {
|
|
branch_label(makepclabel());
|
|
|
|
epilogue = pclastblock;
|
|
pclastblock->flags |= fIsEpilogue;
|
|
|
|
pccomputepredecessors();
|
|
if (copts.debuglisting)
|
|
pclistblocks(name, "[FUNCTION-LEVEL ASM] INITIAL CODE");
|
|
|
|
if (!asm_alloc_flags[1]) {
|
|
colorinstructions(func);
|
|
if (fatalerrors)
|
|
return;
|
|
|
|
if (copts.debuglisting)
|
|
pclistblocks(name, "[FUNCTION-LEVEL ASM] AFTER REGISTER COLORING");
|
|
}
|
|
|
|
compute_frame_sizes();
|
|
if (asm_alloc_flags[1])
|
|
no_frame_for_asm();
|
|
|
|
if (fatalerrors)
|
|
return;
|
|
|
|
if (!asm_alloc_flags[1]) {
|
|
generate_prologue(prologue, 0);
|
|
generate_epilogue(epilogue, !asm_alloc_flags[6] && !asm_alloc_flags[7]);
|
|
}
|
|
|
|
if (copts.debuglisting)
|
|
pclistblocks(name, "[FUNCTION-LEVEL ASM] AFTER PROLOGUE/EPILOGUE CREATION");
|
|
}
|
|
|
|
if (fatalerrors)
|
|
return;
|
|
|
|
if (!asm_alloc_flags[1] && needs_frame()) {
|
|
if (asm_alloc_flags[3]) {
|
|
if (!asm_alloc_flags[5] || !asm_alloc_flags[6])
|
|
PPCError_Warning(PPCErrorStr187, "blr");
|
|
if (asm_alloc_flags[8])
|
|
PPCError_Warning(PPCErrorStr186);
|
|
} else {
|
|
PPCError_Warning(PPCErrorStr185, "blr");
|
|
}
|
|
}
|
|
|
|
func->section = sm_section;
|
|
|
|
if (copts.filesyminfo)
|
|
symdeclend = CPrep_GetFileOffsetInfo(&cparser_fileoffset);
|
|
|
|
copts.peephole = 0;
|
|
if (pic_base_label)
|
|
pic_base_pcodelabel = pic_base_label->pclabel;
|
|
assemblefunction(func, entrypoints_head);
|
|
|
|
if (copts.debuglisting)
|
|
pclistblocks(CMangler_GetLinkName(func)->name, "[FUNCTION-LEVEL ASM] FINAL CODE");
|
|
|
|
CFunc_WarnUnused();
|
|
}
|
|
|
|
void SetupAssembler(void) {
|
|
}
|
|
|
|
void CleanupAssembler(void) {
|
|
}
|