diff options
author | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
---|---|---|
committer | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
commit | 094b96ca1df4a035b5f93c351f773306c0241f3f (patch) | |
tree | 95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/BackEnd/PowerPC/InlineAssembler | |
parent | fc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff) | |
download | MWCC-094b96ca1df4a035b5f93c351f773306c0241f3f.tar.gz MWCC-094b96ca1df4a035b5f93c351f773306c0241f3f.zip |
move lots of source files around to match their actual placement in the original treemain
Diffstat (limited to 'compiler_and_linker/BackEnd/PowerPC/InlineAssembler')
4 files changed, 3889 insertions, 0 deletions
diff --git a/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/FuncLevelAsmPPC.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/FuncLevelAsmPPC.c new file mode 100644 index 0000000..340a54b --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/FuncLevelAsmPPC.c @@ -0,0 +1,393 @@ +#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) { +} diff --git a/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c new file mode 100644 index 0000000..897df9b --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c @@ -0,0 +1,230 @@ +#include "compiler/GCCInlineAsm.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInt64.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/InlineAsm.h" +#include "compiler/objects.h" + +Statement *first_ST_ASM; +IALookupResult gcc_name_list[20]; +int gcc_name_list_index; + +void InlineAsm_SkipComment(void) { + while (1) { + if (tk != '/') + break; + if (lookahead() != '*') + break; + + tk = lex(); + while (!((tk = lex()) == '*' && (tk = lex()) == '/')) { + // nothing + } + tk = lex(); + } +} + +static char gcc_parse_attribute(void) { + char ch; + + while (tk == TK_EOL) + tk = lex(); + + if (tk != '"') + CError_Error(CErrorStr105); + + while ((tk = lex()) != TK_IDENTIFIER) { + // nothing + } + + ch = tkidentifier->name[0]; + + if ((tk = lex()) != '"') + CError_Error(CErrorStr105); + tk = lex(); + + return ch; +} + +static void gcc_parse_name(Boolean flag, char attribute) { + IALookupResult *nameentry; + ENode *expr; + Object *tempobj; + ENode *tempexpr; + Statement *stmt; + + while (tk == TK_EOL) + tk = lex(); + + if (tk != '(') + CError_Error(CErrorStr114); + + tk = lex(); + + if (flag) { + if (tk != TK_IDENTIFIER) + CError_Error(CErrorStr105); + + InlineAsm_LookupSymbol(tkidentifier, &gcc_name_list[++gcc_name_list_index]); + if (gcc_name_list[gcc_name_list_index].object && gcc_name_list[gcc_name_list_index].object->u.var.info) + gcc_name_list[gcc_name_list_index].object->u.var.info->used = 1; + + tk = lex(); + } else { + in_assembler = 0; + cprep_nostring = 0; + nameentry = &gcc_name_list[++gcc_name_list_index]; + + expr = expression(); + if (attribute == 'i' || attribute == 'I') { + if (!ENODE_IS(expr, EINTCONST)) + CError_Error(CErrorStr144); + nameentry->value = CInt64_GetULong(&expr->data.intval); + nameentry->has_value = 1; + } else { + tempobj = create_temp_object(expr->rtype); + tempexpr = create_objectnode(tempobj); + if (tempobj->u.var.info) + tempobj->u.var.info->used = 1; + expr = makediadicnode(tempexpr, expr, EASS); + + stmt = CFunc_InsertBeforeStatement(ST_EXPRESSION, first_ST_ASM); + first_ST_ASM = stmt->next; + if (!first_ST_ASM->next) + curstmt = first_ST_ASM; + stmt->expr = expr; + + nameentry->name = tempobj->name; + nameentry->object = tempobj; + nameentry->label = NULL; + nameentry->type = NULL; + nameentry->has_value = 0; + } + } + + cprep_nostring = 1; + in_assembler = 1; + + if (tk != ')') + CError_Error(CErrorStr115); + tk = lex(); +} + +static void gcc_parse_expression(Boolean flag) { + while (1) { + gcc_parse_name(flag, gcc_parse_attribute()); + if (tk != ',') + break; + tk = lex(); + } +} + +static void gcc_parse_input(void) { + if (tk == ':') { + if ((tk = lex()) == ':' || tk == ')' || tk == '}') + return; + gcc_parse_expression(0); + } +} + +static void gcc_parse_output(void) { + if (tk == ':') { + if ((tk = lex()) == ':' || tk == ')' || tk == '}') + return; + gcc_parse_expression(1); + } +} + +static void gcc_parse_killed(void) { + if (tk == ':') { + while (1) { + if ((tk = lex()) != '"') + return; + + tk = lex(); + while (1) { + if (tk == '"') { + if (lookahead() == ',') { + tk = lex(); + break; + } + tk = lex(); + return; + } + tk = lex(); + } + } + } +} + +static void gcc_replace_arg_st_asm(Statement *stmt) { + InlineAsm *ia; + int i; + IAOperand *op; + short effect; + short rclass; + SInt32 num; + + if ((ia = (InlineAsm *) stmt->expr)) { + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + switch (op->type) { + case IAOpnd_Imm: + case IAOpnd_Reg: + case IAOpnd_3: + case IAOpnd_4: + case IAOpnd_Lab: + break; + + case IAOpnd_6: + if (op->u.unk6.unk4 == 2) { + effect = op->u.unk6.effect; + rclass = op->u.unk6.rclass; + num = op->u.unk6.num; + op->type = IAOpnd_Reg; + op->u.reg.effect = effect; + op->u.reg.rclass = rclass; + op->u.reg.object = NULL; + if (num <= gcc_name_list_index) + op->u.reg.object = gcc_name_list[num].object; + else + CError_Error(CErrorStr144); + op->u.reg.num = 0; + } else { + CError_FATAL(365); + } + break; + + case IAOpnd_7: + op->type = IAOpnd_Imm; + op->u.imm.value = gcc_name_list[op->u.unk7.value].value; + break; + } + } + } +} + +static void gcc_replace_arg(void) { + Statement *stmt; + + for (stmt = first_ST_ASM; stmt; stmt = stmt->next) { + if (stmt->type == ST_ASM) + gcc_replace_arg_st_asm(stmt); + } +} + +void InlineAsm_gcc_parse(void) { + gcc_name_list_index = -1; + cprep_eoltokens = 0; + + if (tk == TK_EOL) + tk = lex(); + + gcc_parse_output(); + gcc_parse_input(); + gcc_parse_killed(); + gcc_replace_arg(); +} diff --git a/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c new file mode 100644 index 0000000..46a95d2 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c @@ -0,0 +1,680 @@ +#include "compiler/InlineAsm.h" +#include "compiler/InlineAsmPPC.h" +#include "compiler/GCCInlineAsm.h" +#include "compiler/CompilerTools.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInit.h" +#include "compiler/CInline.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/COptimizer.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CScope.h" +#include "compiler/PCode.h" +#include "compiler/Registers.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/types.h" + +int allow_array_expressions = 1; + +int backtracking; +jmp_buf backtrack; +jmp_buf InlineAsm_assemblererror; +static int ASMstmtnb; + +void AssemblerError(void) { + longjmp(InlineAsm_assemblererror, 1); +} + +void InlineAsm_SyntaxError(short code) { + if (backtracking) + longjmp(backtrack, 1); + + if (tk == TK_EOL || tk == ';') + code = CErrorStr112; + CError_Error(code); +} + +CLabel *InlineAsm_LookupLabel(HashNameNode *name) { + CLabel *label; + + for (label = Labels; label; label = label->next) { + if (name == label->name) + break; + } + + return label; +} + +CLabel *InlineAsm_DeclareLabel(HashNameNode *name) { + CLabel *label = newlabel(); + label->name = name; + label->next = Labels; + Labels = label; + return label; +} + +static void InlineAsm_DefineLabel(HashNameNode *name) { + CLabel *label; + Statement *stmt; + + label = InlineAsm_LookupLabel(name); + if (!label) { + label = InlineAsm_DeclareLabel(name); + } else { + if (label->stmt) + CError_Error(CErrorStr171, name->name); + } + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label; + label->stmt = stmt; +} + +Boolean InlineAsm_LookupSymbolOrTag(HashNameNode *name, IALookupResult *result, Boolean allow_tag) { + ObjBase *obj; + NameSpace *nspace; + NameSpaceObjectList *list; + + result->name = name; + result->object = NULL; + result->label = NULL; + result->type = NULL; + result->has_value = 0; + + if ((result->label = InlineAsm_LookupLabel(name))) + return 1; + + for (nspace = cscope_current; nspace; nspace = nspace->parent) { + if ((list = CScope_FindName(nspace, name))) { + obj = list->object; + switch (obj->otype) { + case OT_ENUMCONST: + result->has_value = 1; + result->value = OBJ_ENUM_CONST(list->object)->val.lo; + return 1; + case OT_OBJECT: + if (OBJECT(obj)->datatype == DABSOLUTE) { + result->has_value = 1; + result->value = OBJECT(obj)->u.address; + } else { + if (OBJECT(obj)->datatype == DDATA && (OBJECT(obj)->qual & Q_INLINE_DATA)) + CInit_ExportConst(OBJECT(obj)); + result->object = OBJECT(obj); + } + return 1; + case OT_TYPE: + result->type = OBJ_TYPE(obj)->type; + return 1; + case OT_TYPETAG: + if (allow_tag) { + result->type = OBJ_TYPE_TAG(obj)->type; + return 1; + } + case OT_NAMESPACE: + case OT_MEMBERVAR: + return 0; + default: + CError_FATAL(245); + } + } + } + + return 0; +} + +Boolean InlineAsm_LookupSymbol(HashNameNode *name, IALookupResult *result) { + return InlineAsm_LookupSymbolOrTag(name, result, 0); +} + +static ObjMemberVar *isclassmember(TypeClass *tclass, HashNameNode *name) { + NameSpaceObjectList *list; + + list = CScope_FindName(tclass->nspace, name); + return (list && list->object->otype == OT_MEMBERVAR) ? OBJ_MEMBER_VAR(list->object) : NULL; +} + +SInt32 InlineAsm_StructMemberOffset(Type *type) { + StructMember *member; + ObjMemberVar *ivar; + SInt32 offset = 0; + + do { + if (IS_TYPE_STRUCT(type)) { + tk = lex(); + if (tk != TK_IDENTIFIER) + InlineAsm_SyntaxError(CErrorStr107); + member = ismember(TYPE_STRUCT(type), tkidentifier); + if (!member) + CError_Error(CErrorStr150, tkidentifier->name); + offset += member->offset; + type = member->type; + tk = lex(); + } else if (IS_TYPE_CLASS(type)) { + tk = lex(); + if (tk != TK_IDENTIFIER) + InlineAsm_SyntaxError(CErrorStr107); + ivar = isclassmember(TYPE_CLASS(type), tkidentifier); + if (!ivar) + CError_Error(CErrorStr150, tkidentifier->name); + offset += ivar->offset; + type = ivar->type; + tk = lex(); + } else { + CError_Error(CErrorStr149); + } + } while (tk == '.'); + + return offset; +} + +SInt32 InlineAsm_StructArrayMemberOffset(Type *type) { + StructMember *member; + ObjMemberVar *ivar; + SInt32 offset = 0; + + do { + if (tk == '.') { + if (IS_TYPE_STRUCT(type)) { + tk = lex(); + if (tk != TK_IDENTIFIER) + InlineAsm_SyntaxError(CErrorStr107); + member = ismember(TYPE_STRUCT(type), tkidentifier); + if (!member) + CError_Error(CErrorStr150, tkidentifier->name); + offset += member->offset; + type = member->type; + tk = lex(); + } else if (IS_TYPE_CLASS(type)) { + tk = lex(); + if (tk != TK_IDENTIFIER) + InlineAsm_SyntaxError(CErrorStr107); + ivar = isclassmember(TYPE_CLASS(type), tkidentifier); + if (!ivar) + CError_Error(CErrorStr150, tkidentifier->name); + offset += ivar->offset; + type = ivar->type; + tk = lex(); + } else { + CError_Error(CErrorStr149); + } + } else { + if (IS_TYPE_ARRAY(type)) { + type = TPTR_TARGET(type); + tk = lex(); + offset += type->size * InlineAsm_ConstantExpression(); + if (tk != ']') + InlineAsm_SyntaxError(125); + tk = lex(); + } else { + CError_Error(CErrorStr148); + } + } + } while (tk == '.' || tk == '['); + + return offset; +} + +SInt32 InlineAsm_StructPointerMemberOffset(Type *type) { + StructMember *member; + ObjMemberVar *ivar; + SInt32 offset; + + tk = lex(); + if (tk != TK_IDENTIFIER) + InlineAsm_SyntaxError(107); + + if (IS_TYPE_STRUCT(type)) { + member = ismember(TYPE_STRUCT(type), tkidentifier); + if (!member) + CError_Error(CErrorStr150, tkidentifier->name); + offset = member->offset; + type = member->type; + } else { + ivar = isclassmember(TYPE_CLASS(type), tkidentifier); + if (!ivar) + CError_Error(CErrorStr150, tkidentifier->name); + offset = ivar->offset; + type = ivar->type; + } + + tk = lex(); + if (tk == '.' || tk == '[') + offset += InlineAsm_StructArrayMemberOffset(type); + + return offset; +} + +static SInt32 DiadicOperator(SInt32 left, short op, SInt32 right) { + CInt64 left64; + CInt64 right64; + CInt64_SetLong(&left64, left); + CInt64_SetLong(&right64, right); + right64 = CMach_CalcIntDiadic(TYPE(&stsignedint), left64, op, right64); + return CInt64_GetULong(&right64); +} + +static SInt32 PrimaryExpression(void) { + IALookupResult result; + SInt32 value; + + switch (tk) { + case TK_IDENTIFIER: + if (InlineAsm_LookupSymbol(tkidentifier, &result)) { + if (result.has_value) { + tk = lex(); + return result.value; + } + + if (result.type && (IS_TYPE_STRUCT(result.type) || IS_TYPE_CLASS(result.type))) { + tk = lex(); + if (tk != '.') + InlineAsm_SyntaxError(120); + if (allow_array_expressions) + return InlineAsm_StructArrayMemberOffset(result.type); + else + return InlineAsm_StructMemberOffset(result.type); + } else { + InlineAsm_SyntaxError(124); + } + } else { + InlineAsm_SyntaxError(124); + } + break; + case TK_INTCONST: + value = tkintconst.lo; + tk = lex(); + return value; + case TK_SIZEOF: + return scansizeof(); + case '+': + tk = lex(); + return PrimaryExpression(); + case '-': + tk = lex(); + return -PrimaryExpression(); + case '!': + tk = lex(); + return PrimaryExpression() == 0; + case '~': + tk = lex(); + return ~PrimaryExpression(); + case '(': + tk = lex(); + value = InlineAsm_ConstantExpression(); + if (tk != ')') + InlineAsm_SyntaxError(115); + tk = lex(); + return value; + default: + InlineAsm_SyntaxError(120); + } + + return 0; +} + +static SInt32 ConstantExpressionTail(SInt32 value) { + SInt32 right; + short left_token; + short right_prec; + + while (1) { + left_token = tk; + tk = lex(); + right = PrimaryExpression(); + + right_prec = GetPrec(tk); + if (right_prec == 0) + return DiadicOperator(value, left_token, right); + + if (GetPrec(left_token) >= right_prec) { + value = DiadicOperator(value, left_token, right); + } else { + value = DiadicOperator(value, left_token, ConstantExpressionTail(right)); + if (GetPrec(tk) == 0) + return value; + } + } +} + +SInt32 InlineAsm_ConstantExpression(void) { + SInt32 value = PrimaryExpression(); + + if (GetPrec(tk) == 0) + return value; + else + return ConstantExpressionTail(value); +} + +HashNameNode *MakeLocalLabel(CInt64 num) { + char buf[80]; + sprintf(buf, "@%i_%i", ASMstmtnb, CInt64_GetULong(&num)); + return GetHashNameNodeExport(buf); +} + +static void ScanOptionalLabel(void) { + if (tk == TK_INTCONST) { + if (lookahead() == ':') { + InlineAsm_DefineLabel(MakeLocalLabel(tkintconst)); + tk = lex(); + tk = lex(); + } + } else { + if (tkidentifier->name[0] == '@') { + InlineAsm_DefineLabel(tkidentifier); + tk = lex(); + if (tk == ':') + tk = lex(); + } else { + HashNameNode *name = tkidentifier; + short t = lookahead(); + tkidentifier = name; + if (t == ':') { + InlineAsm_DefineLabel(name); + tk = lex(); + tk = lex(); + } + } + } +} + +static void ScanStatements(volatile short endToken, AssemblerType mode) { + if (setjmp(InlineAsm_assemblererror)) { + while (tk != TK_EOL && tk != endToken && tk != '}' && tk) + tk = lex(); + if (tk == ';' || tk == TK_EOL) + tk = lex(); + } else { + InlineAsm_Initialize(mode); + InlineAsm_gccmode = 0; + if (setjmp(InlineAsm_assemblererror)) { + while (tk != ';' && tk != TK_EOL && tk != endToken && tk != '}' && tk) + tk = lex(); + if (tk == ';' || tk == TK_EOL) + tk = lex(); + } + + while (tk && tk != endToken) { + backtracking = 0; + sourceoffset = CPrep_GetFileOffsetInfo(&cparser_fileoffset); + if (tk == '"') { + if (InlineAsm_gccmode) { + tk = lex(); + InlineAsm_gcc_parse(); + } else { + InlineAsm_gccmode = 1; + copts.cplusplus = 0; + copts.asmpoundcomment = 1; + tk = lex(); + } + } + + if (tk == '.') { + InlineAsm_ScanAssemblyDirective(); + } else if (tk == TK_IDENTIFIER) { + ScanOptionalLabel(); + if (tk == TK_IDENTIFIER) + InlineAsm_ScanAssemblyInstruction(); + } else if (tk == TK_INTCONST) { + ScanOptionalLabel(); + if (tk == TK_IDENTIFIER) + InlineAsm_ScanAssemblyInstruction(); + } + + if (InlineAsm_gccmode && tk == '"') { + tk = lex(); + InlineAsm_gcc_parse(); + } + + if (tk == ';' || tk == TK_EOL) { + CPrep_TokenStreamFlush(); + tk = lex(); + } else if (tk != endToken) { + if (endToken == ')') + CError_Error(CErrorStr115); + else + CError_Error(CErrorStr113); + } + } + } +} + +void InlineAsm_ScanStatements(volatile short endToken) { + ScanStatements(endToken, AssemblerType_0); +} + +void InlineAsm_ScanFunction(volatile short endToken) { + ScanStatements(endToken, AssemblerType_1); +} + +void InlineAsm_Assemble(void) { + short token = (tk == '(') ? ')' : '}'; + char save_pc = copts.asmpoundcomment; + char save_cpp = copts.cplusplus; + + cprep_nostring = 1; + CFunc_AppendStatement(ST_NOP); + first_ST_ASM = curstmt; + ASMstmtnb++; + + cprep_eoltokens = 1; + in_assembler = 1; + tk = lex(); + InlineAsm_ScanStatements(token); + in_assembler = 0; + cprep_eoltokens = 0; + cprep_nostring = 0; + + copts.asmpoundcomment = save_pc; + copts.cplusplus = save_cpp; +} + +void InlineAsm_PackAsmStatement(Statement *stmt, Statement *first, void **output, SInt32 *outsize) { + InlineAsm *src; + InlineAsm *dest; + IAOperand *op; + SInt32 i; + SInt32 size; + + src = (InlineAsm *) stmt->expr; + size = sizeof(InlineAsm) + sizeof(IAOperand) * src->argcount; + dest = galloc(size); + memcpy(dest, src, size); + + for (i = 0, op = dest->args; i < dest->argcount; i++, op++) { + switch (op->type) { + case IAOpnd_0: + break; + case IAOpnd_Reg: + case IAOpnd_4: + op->u.reg.object = (Object *) CInline_GetLocalID(op->u.reg.object); + break; + case IAOpnd_Lab: + op->u.lab.label = (CLabel *) CInline_GetStatementNumber(first, op->u.lab.label->stmt); + break; + case IAOpnd_LabDiff: + op->u.labdiff.label1 = (CLabel *) CInline_GetStatementNumber(first, op->u.labdiff.label1->stmt); + op->u.labdiff.label2 = (CLabel *) CInline_GetStatementNumber(first, op->u.labdiff.label2->stmt); + break; + } + } + + *output = dest; + *outsize = size; +} + +void InlineAsm_UnpackAsmStatement(Statement *stmt, CLabel **labelArray, Boolean flag, void *data, SInt32 size) { + InlineAsm *ia; + IAOperand *op; + SInt32 i; + + ia = galloc(size); + memcpy(ia, data, size); + + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + switch (op->type) { + case IAOpnd_0: + break; + case IAOpnd_Reg: + case IAOpnd_4: + op->u.reg.object = CInline_GetLocalObj((SInt32) op->u.reg.object, flag); + break; + case IAOpnd_Lab: + op->u.lab.label = labelArray[(SInt16) op->u.lab.label]; + break; + case IAOpnd_LabDiff: + op->u.labdiff.label1 = labelArray[(SInt16) op->u.labdiff.label1]; + op->u.labdiff.label2 = labelArray[(SInt16) op->u.labdiff.label2]; + break; + } + } + + stmt->expr = (ENode *) ia; +} + +void InlineAsm_CheckLocalUsage(Statement *stmt) { + InlineAsm *ia = (InlineAsm *) stmt->expr; + IAOperand *op; + SInt32 i; + + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + switch (op->type) { + case IAOpnd_Reg: + if (op->u.reg.object) + SetVarUsage(op->u.reg.object, 0); + break; + case IAOpnd_4: + SetVarUsage(op->u.obj.obj, 1); + break; + } + } +} + +CLabel *InlineAsm_GetReferencedLabel(Statement *stmt) { + InlineAsm *ia = (InlineAsm *) stmt->expr; + IAOperand *op; + SInt32 i; + + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + if (op->type == IAOpnd_Lab) + return op->u.lab.label; + if (op->type == IAOpnd_LabDiff) + return op->u.labdiff.label1; + } + + return NULL; +} + +CLabel *InlineAsm_GetReferencedLabel2(Statement *stmt) { + InlineAsm *ia = (InlineAsm *) stmt->expr; + IAOperand *op; + SInt32 i; + + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + if (op->type == IAOpnd_LabDiff) + return op->u.labdiff.label2; + } + + return NULL; +} + +Object *InlineAsm_GetObjectOffset(InlineAsm *ia, SInt32 index, SInt32 *offset) { + IAOperand *op; + SInt32 i; + SInt32 counter; + + for (i = 0, counter = 0, op = ia->args; i < ia->argcount; i++, op++) { + if (op->type == IAOpnd_3) { + if (counter++ == index) { + *offset = ((intptr_t) &op->u.obj.obj) - ((intptr_t) ia); + return op->u.obj.obj; + } + } + } + + return NULL; +} + +char *InlineAsm_DumpStatement(Statement *stmt) { + static char buffer[1024]; + InlineAsm *ia; + IAOperand *arg; + int i; + char ch; + SInt32 offset; + + ia = (InlineAsm *) stmt->expr; + + strcpy(buffer, "\""); + strcat(buffer, InlineAsm_GetMnemonic(ia)); + strcat(buffer, "\""); + + for (i = 0, arg = ia->args; i < ia->argcount; i++, arg++) { + char argbuf[1024]; + + switch (arg->type) { + case IAOpnd_Imm: + sprintf(argbuf, " imm(%ld)", arg->u.imm.value); + break; + case IAOpnd_Reg: + ch = ' '; + if (arg->u.reg.effect & EffectWrite) { + if (arg->u.reg.effect & EffectRead) + ch = '+'; + else + ch = '='; + } else { + if (!(arg->u.reg.effect & EffectRead)) + ch = '0'; + } + + if (arg->u.reg.object) { + sprintf(argbuf, + "%creg(%s)", + ch, + arg->u.reg.object->name->name); + } else { + sprintf(argbuf, + "%creg(%s%d)", + ch, + register_class_name[arg->u.reg.rclass], + arg->u.reg.num); + } + break; + + case IAOpnd_3: + case IAOpnd_4: + if (arg->u.obj.offset > 0) + sprintf(argbuf, " obj(%s+%ld)", arg->u.obj.obj->name->name, arg->u.obj.offset); + else if (arg->u.obj.offset < 0) + sprintf(argbuf, " obj(%s-%ld)", arg->u.obj.obj->name->name, -arg->u.obj.offset); + else + sprintf(argbuf, " obj(%s)", arg->u.obj.obj->name->name); + break; + + case IAOpnd_Lab: + sprintf(argbuf, " lab(%s)", arg->u.lab.label->uniquename->name); + break; + + case IAOpnd_LabDiff: + offset = !arg->negated ? 0 : arg->u.labdiff.offset; + sprintf(argbuf, + " labdiff(%s-%s%c%d)", + arg->u.labdiff.label1->uniquename->name, + arg->u.labdiff.label2->uniquename->name, + (arg->negated == 1) ? '-' : '+', + offset + ); + break; + } + + strcat(buffer, argbuf); + } + + return buffer; +} diff --git a/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsmPPC.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsmPPC.c new file mode 100644 index 0000000..464f9f9 --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsmPPC.c @@ -0,0 +1,2586 @@ +#include "compiler/InlineAsmPPC.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CInt64.h" +#include "compiler/CFunc.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/Alias.h" +#include "compiler/CodeGen.h" +#include "compiler/CodeGenOptPPC.h" +#include "compiler/CompilerTools.h" +#include "compiler/Exceptions.h" +#include "compiler/FuncLevelAsmPPC.h" +#include "compiler/InlineAsm.h" +#include "compiler/InlineAsmMnemonicsPPC.h" +#include "compiler/InlineAsmRegisters.h" +#include "compiler/InlineAsmRegistersPPC.h" +#include "compiler/PCode.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" + +char asm_alloc_flags[10]; +Section sm_section; +UInt32 cpu; +SInt32 fralloc_parameter_area_size; +Boolean user_responsible_for_frame; +Boolean supports_hardware_fpu; +UInt32 assembledinstructions; +AssemblerType assembler_type; +char volatileasm; +Boolean InlineAsm_gccmode; +Boolean InlineAsm_labelref; +CLabel *pic_base_label; + +// forward decls +static SInt32 InlineAsm_ConstantExpressionPPC(SInt32 value); +static Object *isvariableoperand(void); +static Object *isregisterstructpointeroperand(void); +static void registeroperand(IAOperand *op, char rclass, short effect); +static void DiadicOperatorPPC(IAExpr *left, short token, IAExpr *right); +static void InlineAsm_ExpressionPPC(IAExpr *expr, SInt32 value); +static void savepicbase(short reg, HashNameNode *name); + +CW_INLINE SInt32 ExtractValue(CInt64 value) { + return (SInt32) CInt64_GetULong(&value); +} + +static void IllegalObjectOperator(HashNameNode *name1, HashNameNode *name2, short token) { + char *opstr; + switch (token) { + case '*': opstr = "*"; break; + case '/': opstr = "/"; break; + case '%': opstr = "%"; break; + case '+': opstr = "+"; break; + case '-': opstr = "-"; break; + case TK_SHL: opstr = "<<"; break; + case TK_SHR: opstr = ">>"; break; + case '<': opstr = "<"; break; + case '>': opstr = ">"; break; + // bug? these two seem swapped + case TK_LESS_EQUAL: opstr = ">="; break; + case TK_GREATER_EQUAL: opstr = "<="; break; + case TK_LOGICAL_EQ: opstr = "=="; break; + case TK_LOGICAL_NE: opstr = "!="; break; + case '&': opstr = "&"; break; + case '^': opstr = "^"; break; + case '|': opstr = "|"; break; + case TK_LOGICAL_AND: opstr = "&&"; break; + case TK_LOGICAL_OR: opstr = "||"; break; + default: opstr = "???"; + } + + if (!name2) { + PPCError_Error(PPCErrorStr119, opstr, name1->name); + } else if (!name1) { + PPCError_Error(PPCErrorStr120, opstr, name2->name); + } else { + PPCError_Error(PPCErrorStr118, name1->name, opstr, name2->name); + } +} + +static void IllegalObjectInConst(IAExpr *expr) { + if (expr->xC) { + PPCError_Error(PPCErrorStr122, expr->xC->name->name); + } else if (expr->object) { + PPCError_Error(PPCErrorStr122, expr->object->name->name); + } else if (expr->label) { + PPCError_Error(PPCErrorStr166, expr->label->name->name); + } +} + +static void NotInRegisterError(char *name, char rclass) { + PPCError_Error(PPCErrorStr167, name, register_class_name[rclass]); +} + +static int isregisteroperand(char rclass) { + IARegister *reg; + + return (tk == TK_IDENTIFIER && (reg = InlineAsm_LookupRegisterPPCName(tkidentifier)) && reg->rclass == rclass); +} + +static SInt32 getcroperand(char rclass) { + SInt32 value; + IARegister *reg; + + value = 0; + if (tk == TK_IDENTIFIER && (reg = InlineAsm_LookupRegisterPPCName(tkidentifier)) && reg->rclass == rclass) { + value = reg->num; + } else { + PPCError_Error(PPCErrorStr167, tkidentifier->name); + } + + tk = lex(); + return value; +} + +static SInt32 getimmediateoperand(SInt32 minimum, SInt32 maximum) { + SInt32 value = InlineAsm_ConstantExpressionPPC(0); + if (value < minimum || value > maximum) + CError_Error(CErrorStr154); + return value; +} + +static void PrimaryExpressionPPC(IAExpr *expr, SInt32 value) { + Object *obj; + IALookupResult result; + IAExpr subexpr; + IAExprType type = IAExpr_0; + SInt32 v; + + switch (tk) { + case TK_IDENTIFIER: + if ((obj = isregisterstructpointeroperand())) { + tk = lex(); + InlineAsm_InitExpr5(expr, InlineAsm_StructPointerMemberOffset(TPTR_TARGET(obj->type))); + expr->object = obj; + return; + } + + if ((obj = isvariableoperand())) { + short reg; + InlineAsm_InitExpr5(expr, 0); + expr->xC = obj; + + if (obj->datatype == DLOCAL) + reg = 1; + else + reg = pic_base_reg; + + tk = lex(); + if (tk == '.' || tk == '[') { + InlineAsm_InitExpr5(&subexpr, InlineAsm_StructArrayMemberOffset(obj->type)); + DiadicOperatorPPC(expr, '+', &subexpr); + } + + if (tk == '+') { + tk = lex(); + InlineAsm_ExpressionPPC(&subexpr, value); + DiadicOperatorPPC(expr, '+', &subexpr); + } else if (tk == '-') { + tk = lex(); + InlineAsm_ExpressionPPC(&subexpr, value); + DiadicOperatorPPC(expr, '-', &subexpr); + } else if (!strcmp(tkidentifier->name, "@loword")) { + tk = lex(); + if (low_offset) { + InlineAsm_InitExpr5(&subexpr, low_offset); + DiadicOperatorPPC(expr, '+', &subexpr); + } + } else if (!strcmp(tkidentifier->name, "@hiword")) { + tk = lex(); + if (high_offset) { + InlineAsm_InitExpr5(&subexpr, high_offset); + DiadicOperatorPPC(expr, '+', &subexpr); + } + } + expr->reg = reg; + return; + } + + if (InlineAsm_LookupSymbolOrTag(tkidentifier, &result, 1)) { + if (result.has_value) { + tk = lex(); + InlineAsm_InitExpr5(expr, result.value); + return; + } + + if (result.type && (IS_TYPE_STRUCT(result.type) || IS_TYPE_CLASS(result.type))) { + tk = lex(); + if (tk != '.') + CError_Error(CErrorStr120); + + if (allow_array_expressions) { + InlineAsm_InitExpr5(expr, InlineAsm_StructArrayMemberOffset(result.type)); + return; + } + + InlineAsm_InitExpr5(expr, InlineAsm_StructMemberOffset(result.type)); + return; + } + + if (result.object && result.object->datatype == DABSOLUTE) { + tk = lex(); + InlineAsm_InitExpr5(expr, result.object->u.address); + return; + } + } else if (value) { + if (isregisteroperand(RegClass_CRFIELD)) { + InlineAsm_InitExpr5(expr, getcroperand(RegClass_CRFIELD)); + return; + } + if (isregisteroperand(RegClass_6)) { + InlineAsm_InitExpr5(expr, getcroperand(RegClass_6)); + return; + } + if (strlen(tkidentifier->name) == 6 && !strncmp(tkidentifier->name, "cr", 2) && tkidentifier->name[3] == '_') { + IARegister *reg; + char regname[4]; + regname[0] = tkidentifier->name[0]; + regname[1] = tkidentifier->name[1]; + regname[2] = tkidentifier->name[2]; + regname[3] = 0; + if ((reg = InlineAsm_LookupRegisterPPC(regname)) && reg->rclass == RegClass_CRFIELD) { + SInt32 v = reg->num * 4; + regname[0] = tkidentifier->name[4]; + regname[1] = tkidentifier->name[5]; + regname[2] = 0; + if ((reg = InlineAsm_LookupRegisterPPC(regname)) && reg->rclass == RegClass_6) { + tk = lex(); + InlineAsm_InitExpr5(expr, v + reg->num); + return; + } + } + } + } + + if (!strcmp("ha16", tkidentifier->name)) + type = IAExpr_8; + else if (!strcmp("hi16", tkidentifier->name)) + type = IAExpr_7; + else if (!strcmp("lo16", tkidentifier->name)) + type = IAExpr_6; + + if (type != IAExpr_0) { + tk = lex(); + if (tk == '(') { + SInt32 v; + tk = lex(); + PrimaryExpressionPPC(expr, value); + expr->type = type; + if (tk != ')') + CError_Error(CErrorStr115); + + tk = lex(); + if (InlineAsm_CheckExpr(expr)) { + expr->value = InlineAsm_GetExprValue(expr); + expr->type = IAExpr_5; + } + return; + } + + CError_Error(CErrorStr114); + } else { + if (!result.label) + result.label = InlineAsm_DeclareLabel(tkidentifier); + + InlineAsm_InitExpr5(expr, 0); + expr->flags |= IAFlag1; + expr->label = result.label; + tk = lex(); + return; + } + break; + + case TK_INTCONST: + v = CInt64_GetULong(&tkintconst); + tk = lex(); + InlineAsm_InitExpr5(expr, v); + return; + + case TK_SIZEOF: + InlineAsm_InitExpr5(expr, scansizeof()); + return; + + case '+': + tk = lex(); + PrimaryExpressionPPC(expr, value); + return; + + case '-': + tk = lex(); + PrimaryExpressionPPC(expr, value); + if (InlineAsm_CheckExpr(expr)) + expr->value = -expr->value; + else + CError_Error(CErrorStr124); + return; + + case '!': + tk = lex(); + PrimaryExpressionPPC(expr, value); + if (InlineAsm_CheckExpr(expr)) + expr->value = !expr->value; + else + CError_Error(CErrorStr124); + return; + + case '~': + tk = lex(); + PrimaryExpressionPPC(expr, value); + if (InlineAsm_CheckExpr(expr)) + expr->value = ~expr->value; + else + CError_Error(CErrorStr124); + return; + + case '(': + tk = lex(); + InlineAsm_ExpressionPPC(expr, value); + if (tk != ')') + CError_Error(CErrorStr115); + tk = lex(); + return; + + default: + CError_Error(CErrorStr120); + } + + InlineAsm_InitExpr5(expr, 0); +} + +static void DiadicOperatorPPC(IAExpr *left, short token, IAExpr *right) { + CInt64 leftval; + CInt64 rightval; + + CInt64_SetLong(&leftval, left->value); + CInt64_SetLong(&rightval, right->value); + rightval = CMach_CalcIntDiadic(TYPE(&stsignedint), leftval, token, rightval); + + if (left->xC) { + if (right->label) + PPCError_Error(PPCErrorStr124, left->xC->name->name, right->label->name->name); + + if (right->xC) { + if (left->x10) { + PPCError_Error(PPCErrorStr121, left->xC->name->name, left->x10->name->name, right->xC->name->name); + } else if (right->x10) { + PPCError_Error(PPCErrorStr121, left->xC->name->name, right->xC->name->name, right->x10->name->name); + } else if (token == '-') { + left->value = CInt64_GetULong(&rightval); + left->x10 = right->xC; + } else { + IllegalObjectOperator(left->xC->name, right->xC->name, token); + } + } else if (token == '-' || token == '+') { + left->value = CInt64_GetULong(&rightval); + } else { + IllegalObjectOperator(left->xC->name, NULL, token); + } + } else if (right->xC) { + if (right->label) + PPCError_Error(PPCErrorStr124, right->xC->name->name, right->label->name->name); + + if (token == '+') { + left->xC = right->xC; + left->x10 = right->x10; + left->value = CInt64_GetULong(&rightval); + } else { + IllegalObjectOperator(NULL, right->xC->name, token); + } + } else if (left->label) { + if (left->xC) + PPCError_Error(PPCErrorStr124, left->label->name->name, left->xC->name->name); + + if (right->label) { + if (left->x18) { + PPCError_Error(PPCErrorStr121, left->label->name->name, left->x18->name->name, right->label->name->name); + } else if (right->x18) { + PPCError_Error(PPCErrorStr121, left->label->name->name, right->label->name->name, right->x18->name->name); + } else if (token == '-') { + left->value = CInt64_GetULong(&rightval); + left->x18 = right->label; + } else { + IllegalObjectOperator(left->label->name, right->label->name, token); + } + } else if (token == '+' || token == '-') { + left->value = CInt64_GetULong(&rightval); + } else { + IllegalObjectOperator(NULL, left->label->name, token); + } + } else if (right->label) { + if (token == '+') { + left->label = right->label; + left->x18 = right->x18; + left->value = CInt64_GetULong(&rightval); + } else { + IllegalObjectOperator(NULL, right->label->name, token); + } + } else { + left->value = CInt64_GetULong(&rightval); + } + + left->flags |= right->flags; + if (left->type == IAOpnd_Lab) { + if (right->type != IAOpnd_Lab) + left->type = right->type; + } else { + if (right->type != IAOpnd_Lab && right->type != left->type) + PPCError_Error(PPCErrorStr126); + } +} + +static void ExpressionTailPPC(IAExpr *left, SInt32 value) { + IAExpr right; + short left_tk; + short right_prec; + + while (1) { + left_tk = tk; + tk = lex(); + + PrimaryExpressionPPC(&right, value); + right_prec = GetPrec(tk); + if (right_prec == 0) { + DiadicOperatorPPC(left, left_tk, &right); + break; + } + + if (GetPrec(left_tk) >= right_prec) { + DiadicOperatorPPC(left, left_tk, &right); + } else { + ExpressionTailPPC(&right, value); + DiadicOperatorPPC(left, left_tk, &right); + if (GetPrec(tk) == 0) + break; + } + } +} + +static void immediateoperand(IAOperand *op, SInt32 minval, SInt32 maxval) { + SInt32 value; + if (InlineAsm_gccmode && tk == '%') { + tk = lex(); + if (tk != TK_INTCONST) { + CError_Error(CErrorStr144); + } else { + CInt64 c = tkintconst; + value = CInt64_GetULong(&c); + if (value < 0) + CError_Error(CErrorStr144); + } + op->type = IAOpnd_7; + op->u.unk7.value = value; + op->u.unk7.unk1 = 1; + op->u.unk7.unk2 = 0; + op->u.unk7.unk3 = 0; + tk = lex(); + } else { + value = InlineAsm_ConstantExpressionPPC(0); + if (value < minval || value > maxval) + CError_Error(CErrorStr154); + op->type = IAOpnd_Imm; + op->u.imm.value = value; + } +} + +static SInt32 immediatevalue(IAOperand *op, SInt32 minval, SInt32 maxval) { + SInt32 value; + if (InlineAsm_gccmode && tk == '%') { + CError_Error(CErrorStr144); + return 0; + } else { + value = InlineAsm_ConstantExpressionPPC(0); + if (value < minval || value > maxval) + CError_Error(CErrorStr154); + op->type = IAOpnd_Imm; + op->u.imm.value = value; + return value; + } +} + +static void InlineAsm_ExpressionPPC(IAExpr *expr, SInt32 value) { + PrimaryExpressionPPC(expr, value); + if (GetPrec(tk)) + ExpressionTailPPC(expr, value); + if (GetPrec(tk)) + ExpressionTailPPC(expr, value); + + if (expr->type == IAExpr_5 && tk == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "@l")) { + expr->type = IAExpr_6; + tk = lex(); + } else if (!strcmp(tkidentifier->name, "@ha")) { + expr->type = IAExpr_8; + tk = lex(); + } else if (!strcmp(tkidentifier->name, "@h")) { + expr->type = IAExpr_7; + tk = lex(); + } + } +} + +static SInt32 InlineAsm_ConstantExpressionPPC(SInt32 value) { + IAExpr expr; + + InlineAsm_ExpressionPPC(&expr, value); + if (!InlineAsm_CheckExpr(&expr)) { + IllegalObjectInConst(&expr); + return 0; + } else { + return InlineAsm_GetExprValue(&expr); + } +} + +static SInt32 crbitoperand(void) { + SInt32 value = InlineAsm_ConstantExpressionPPC(1); + if (value < 0 || value > 31) + CError_Error(CErrorStr154); + return value; +} + +static void floatoperand(IAOperand *op, InlineAsm *ia, Type *type) { + Object *obj; + + obj = createfloatconstant(type, &tkfloatconst); + op[0].type = IAOpnd_Reg; + op[0].u.reg.rclass = RegClass_GPR; + op[0].u.reg.object = NULL; + op[0].u.reg.effect = EffectRead; + op[0].u.reg.num = pic_base_reg; + + ia->argcount++; + op[1].type = IAOpnd_4; + op[1].u.obj.obj = obj; + PPCError_Error(PPCErrorStr179); + op[1].u.obj.unk = IAExpr_2; + op[1].u.obj.offset = 0; + tk = lex(); +} + +static Object *isvariableoperand(void) { + IALookupResult result; + Object *obj; + + if (tk == TK_IDENTIFIER) { + InlineAsm_LookupSymbol(tkidentifier, &result); + if ((obj = result.object)) { + if (obj->datatype == DLOCAL) { + if (OBJECT_REG(obj)) + return NULL; + return obj; + } + + if (obj->datatype == DFUNC || obj->datatype == DVFUNC) + return obj; + + if (obj->datatype == DDATA) { + createIndirect(obj, 0, 0); + return obj; + } + } + } + + return NULL; +} + +static Object *isregisterstructpointeroperand(void) { + IALookupResult result; + Object *obj; + + if (tk != TK_IDENTIFIER) + return NULL; + + InlineAsm_LookupSymbol(tkidentifier, &result); + if ((obj = result.object)) { + if (obj->datatype != DLOCAL) + return NULL; + if (!OBJECT_REG(obj) && !is_register_object(obj)) + return NULL; + if (!IS_TYPE_POINTER(obj->type)) + return NULL; + if (!IS_TYPE_STRUCT(TPTR_TARGET(obj->type)) && !IS_TYPE_CLASS(TPTR_TARGET(obj->type))) + return NULL; + return obj; + } + + return NULL; +} + +static void memoryoperand(IAOperand *op, InlineAsm *ia, Boolean flag, short effect) { + IAExpr expr; + + InlineAsm_ExpressionPPC(&expr, 0); + if (expr.object) { + if (!flag) + CError_Error(CErrorStr155); + if (expr.xC) + PPCError_Error(PPCErrorStr122, expr.xC); + + op[0].type = IAOpnd_Reg; + op[0].u.reg.rclass = RegClass_GPR; + op[0].u.reg.object = expr.object; + op[0].u.reg.num = 0; + op[0].u.reg.effect = effect; + if (expr.object || expr.reg) + op[0].u.reg.effect = effect; + else + op[0].u.reg.effect = 0; + + ia->argcount++; + op[1].type = IAOpnd_Imm; + switch (expr.type) { + case IAExpr_5: + expr.type = IAExpr_6; + if (expr.object->datatype != DLOCAL || !OBJECT_REG(expr.object)) + PPCError_Error(PPCErrorStr180); + case IAExpr_2: + case IAExpr_6: + case IAExpr_7: + case IAExpr_8: + op[1].u.imm.value = InlineAsm_GetExprValue(&expr); + break; + default: + CError_Error(CErrorStr155); + } + + expr.object->flags |= OBJECT_USED; + return; + } + + if (expr.xC) { + if (expr.x10) + PPCError_Error(PPCErrorStr123, expr.xC->name->name, expr.x10->name->name); + + if (flag) { + if (tk == '(') { + if (flag) { + tk = lex(); + registeroperand(op, RegClass_GPR, effect); + if ((expr.type == IAExpr_8 || expr.type == IAExpr_7) && copts.codegen_pic && pic_base_reg) + CError_Error(CErrorStr155); + if (tk != ')') + CError_Error(CErrorStr115); + tk = lex(); + } + } else { + op[0].type = IAOpnd_Reg; + op[0].u.reg.rclass = RegClass_GPR; + op[0].u.reg.object = expr.object; + op[0].u.reg.num = expr.reg; + } + + if (expr.object || expr.reg) + op[0].u.reg.effect = effect; + else + op[0].u.reg.effect = 0; + + ia->argcount++; + op++; + } + + if (expr.xC->datatype == DLOCAL) { + op[0].type = IAOpnd_4; + op[0].u.obj.unk = IAExpr_1; + } else { + op[0].type = IAOpnd_3; + if (expr.type == IAExpr_5) { + expr.type = IAExpr_6; + PPCError_Error(PPCErrorStr180); + } + op[0].u.obj.unk = expr.type; + } + + op[0].u.obj.obj = expr.xC; + op[0].u.obj.offset = expr.value; + expr.xC->flags |= OBJECT_USED; + return; + } + + if (flag) { + if (tk == '(') { + tk = lex(); + registeroperand(op, RegClass_GPR, effect); + ia->argcount++; + op++; + if (tk != ')') + CError_Error(CErrorStr115); + tk = lex(); + } else { + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_GPR; + op->u.reg.object = expr.object; + op->u.reg.num = expr.reg; + ia->argcount++; + op++; + } + } + + if (expr.label) { + if (expr.x18) { + op->type = IAOpnd_LabDiff; + op->negated = 0; + op->u.labdiff.label1 = expr.label; + op->u.labdiff.label2 = expr.x18; + op->u.labdiff.offset = expr.value; + } else { + PPCError_Error(PPCErrorStr125, expr.label->name->name); + } + } else { + op->type = IAOpnd_Imm; + op->u.imm.value = InlineAsm_GetExprValue(&expr); + } +} + +static void registeroperand(IAOperand *op, char rclass, short effect) { + IARegister *reg; + Object *obj; + + if (tk == TK_IDENTIFIER && (reg = InlineAsm_LookupRegisterPPCName(tkidentifier)) && reg->rclass == rclass) { + SInt32 num; + obj = reg->object; + num = reg->num; + op->type = IAOpnd_Reg; + op->u.reg.rclass = rclass; + op->u.reg.object = obj; + op->u.reg.num = num; + op->u.reg.effect = effect; + if (obj) { + reg->object->flags |= OBJECT_USED; + Registers_GetVarInfo(obj)->flags |= VarInfoFlag40; + } + } else if (rclass == RegClass_CRFIELD) { + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_CRFIELD; + op->u.reg.object = NULL; + op->u.reg.num = getimmediateoperand(0, 7); + op->u.reg.effect = effect; + return; + } else if (rclass == RegClass_SPR) { + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.object = NULL; + op->u.reg.num = getimmediateoperand(0, 1024); + op->u.reg.effect = effect; + return; + } else if (tk == '%' && InlineAsm_gccmode) { + SInt32 num; + tk = lex(); + if (tk != TK_INTCONST) { + CError_Error(CErrorStr144); + } else { + num = ExtractValue(tkintconst); + if (num < 0) + CError_Error(CErrorStr144); + } + + op->type = IAOpnd_6; + op->u.unk6.num = num; + op->u.unk6.unk4 = 2; + op->u.unk6.effect = effect; + op->u.unk6.rclass = rclass; + tk = lex(); + return; + } else if (tk == TK_IDENTIFIER) { + NotInRegisterError(tkidentifier->name, rclass); + } else { + PPCError_Error(PPCErrorStr171); + } + + tk = lex(); + if (!strcmp(tkidentifier->name, "@loword")) { + tk = lex(); + } else if (!strcmp(tkidentifier->name, "@hiword")) { + if (reg->object) + op->u.reg.num = 1; + else + PPCError_Error(PPCErrorStr168); + tk = lex(); + } else if (rclass == RegClass_GPR) { + if (reg->object && reg->object->type->size == 8) { + HashNameNode *name = reg->object->name; + PPCError_Error(PPCErrorStr127, name->name, name->name, name->name); + } + } +} + +static void cr0_operand(IAOperand *op, short effect) { + IARegister *reg; + + if ((reg = InlineAsm_LookupRegisterPPC("cr0"))) { + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_CRFIELD; + op->u.reg.object = reg->object; + op->u.reg.num = reg->num; + op->u.reg.effect = effect; + } else { + NotInRegisterError("cr0", RegClass_CRFIELD); + } +} + +static void r0_operand(IAOperand *op) { + IARegister *reg; + + if ((reg = InlineAsm_LookupRegisterPPC("r0"))) { + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_GPR; + op->u.reg.object = reg->object; + op->u.reg.num = reg->num; + op->u.reg.effect = 0; + tk = lex(); + } else { + NotInRegisterError("r0", RegClass_GPR); + } +} + +static void labeloperand(InlineAsm *ia, IAOperand *op, Boolean flag1, Boolean flag2, Boolean flag3) { + IALookupResult result; + + if (tk == TK_IDENTIFIER) { + if (!InlineAsm_LookupSymbol(tkidentifier, &result)) + result.label = InlineAsm_DeclareLabel(tkidentifier); + + if (result.label) { + op->type = IAOpnd_Lab; + op->u.lab.label = result.label; + } else if (result.object && result.object->datatype == DFUNC) { + if (flag3) + ia->flags |= IAFlag2; + op->type = IAOpnd_3; + op->u.obj.obj = result.object; + op->u.obj.offset = 0; + + if (flag1) { + op->u.obj.unk = IAExpr_4; + if (flag2) + CError_Error(CErrorStr261); + } else { + op->u.obj.unk = IAExpr_2; + if (flag2) + op->u.obj.unk = IAExpr_10; + op->u.obj.unk = IAExpr_6; + PPCError_Error(PPCErrorStr180); + } + } else { + CError_Error(CErrorStr144); + } + + tk = lex(); + } else if (tk == '*') { + if (!flag2) { + tk = lex(); + if (tk == '+') { + tk = lex(); + if (flag1) + immediateoperand(op, -0x2000000, 0x1FFFFFF); + else + immediateoperand(op, -0x8000, 0xFFFF); + } else if (tk == '-') { + tk = lex(); + op->u.imm.value = flag1 ? -immediatevalue(op, -0x1FFFFFF, 0x2000000) : -immediatevalue(op, -0x7FFF, 0x10000); + } else { + CError_Error(CErrorStr144); + } + } else { + CError_Error(CErrorStr144); + } + } else { + if (flag2) { + if (flag1) + immediateoperand(op, -0x2000000, 0x1FFFFFF); + else + immediateoperand(op, -0x8000, 0xFFFF); + } else { + CError_Error(CErrorStr144); + } + } +} + +static void imm_or_labeldiff_operand(InlineAsm *ia, IAOperand *op, SInt32 minimum, SInt32 maximum, Boolean negate) { + IAExpr expr; + Object *obj; + SInt32 value; + + InlineAsm_ExpressionPPC(&expr, 0); + + if ((obj = expr.xC) && !expr.x10 && expr.type == IAExpr_5 && obj->datatype == DDATA && IS_TYPE_INT_OR_ENUM(obj->type) && (obj->qual & Q_INLINE_DATA)) { + switch (ia->opcode) { + case PC_ADDI: + case PC_ADDIC: + case PC_ADDICR: + case PC_ADDIS: + case PC_ORI: + case PC_ORIS: + if (ia->args[1].u.imm.value) { + SInt32 cmp; + if (obj->datatype != DLOCAL) { + cmp = copts.codegen_pic ? INVALID_PIC_REG : NO_REG; + } else { + cmp = local_base_register(obj); + } + if (ia->args[1].u.imm.value == cmp) + break; + } + case PC_LI: + case PC_LIS: + case PC_TWI: + case PC_OPWORD: + InlineAsm_InitExpr5(&expr, expr.value + CInt64_GetULong(&obj->u.data.u.intconst)); + break; + } + } + + if (expr.label) { + if (expr.x18) { + op->type = IAOpnd_LabDiff; + if (negate) + op->negated = 1; + else + op->negated = 0; + op->u.labdiff.label1 = expr.label; + op->u.labdiff.label2 = expr.x18; + op->u.labdiff.offset = expr.value; + } else { + PPCError_Error(PPCErrorStr125, expr.label->name->name); + } + return; + } + + if (expr.xC) { + if (!expr.x10) { + if (ia->opcode != PC_OPWORD && expr.type == IAExpr_5) { + IllegalObjectInConst(&expr); + return; + } + + if (expr.xC->datatype == DLOCAL) { + op->type = IAOpnd_4; + op->u.obj.unk = IAExpr_1; + } else { + op->type = IAOpnd_3; + if (expr.type == IAExpr_5) { + expr.type = IAExpr_6; + PPCError_Error(PPCErrorStr180); + } + op->u.obj.unk = expr.type; + } + op->u.obj.obj = expr.xC; + op->u.obj.offset = expr.value; + } else { + PPCError_Error(PPCErrorStr123, expr.xC->name->name, expr.x10->name->name); + } + return; + } + + value = InlineAsm_GetExprValue(&expr); + if (value < minimum || value > maximum) + CError_Error(CErrorStr154); + + op->type = IAOpnd_Imm; + if (negate) + op->u.imm.value = -value; + else + op->u.imm.value = value; +} + +static void eatcommatoken(void) { + if (tk == ',') + tk = lex(); + else + CError_Error(CErrorStr116); +} + +static InlineAsm *InlineAsm_ScanAssemblyOperands(IAMnemonic *mnemonic) { + OpcodeInfo *info; + InlineAsm *ia; + SInt32 buffersize; + IAOperand *op; + int argcount; + char *format; + IARegister *reg; + + char code; + short effect; + Boolean has_excl; + Boolean has_question; + Boolean negate; + UInt32 t; + + info = &opcodeinfo[mnemonic->x4]; + argcount = info->x8; + if (PCODE_FLAG_SET_F(info) & fCanSetRecordBit) + argcount++; + if (!(PCODE_FLAG_SET_F(info) & fSetsCarry) && (PCODE_FLAG_SET_F(info) & fCanSetCarry)) + argcount++; + if (PCODE_FLAG_SET_T(info) & fCanLink) + argcount++; + + buffersize = sizeof(InlineAsm) + sizeof(IAOperand) * argcount; + ia = galloc(buffersize); + memset(ia, 0, buffersize); + + ia->opcode = mnemonic->x4; + ia->flags = 0; + ia->argcount = 0; + + op = ia->args; + for (format = mnemonic->format; *format; format++) { + CError_ASSERT(1664, ia->argcount < argcount); + + if (*format == ',') { + eatcommatoken(); + format++; + } else if (*format == ';') { + format++; + } + + if (*format == '[' || *format == '(') + format++; + + effect = EffectRead; + has_excl = 0; + has_question = 0; + negate = 0; + if (*format == '=') { + effect = EffectWrite; + format++; + } else if (*format == '+') { + effect = EffectRead | EffectWrite; + format++; + } + + if (*format == '-') { + negate = 1; + format++; + } + + if (*format == '?') { + has_question = 1; + format++; + } + + if (*format == '!') { + has_excl = 1; + format++; + } + + switch (*format) { + case 'p': + continue; + case '&': + if (format[1] == '2') { + op[0] = op[-2]; + format++; + if (op->type == IAOpnd_Reg) + op->u.reg.effect = effect; + ia->argcount++; + + op[1] = op[-1]; + op++; + if (op->type == IAOpnd_Reg) + op->u.reg.effect = effect; + } else { + op[0] = op[-1]; + if (op->type == IAOpnd_Reg) + op->u.reg.effect = effect; + } + break; + + case '%': { + SInt32 value; + format += pcode_const_from_format(format + 1, &value); + op->type = IAOpnd_Imm; + op->u.imm.value = value; + break; + } + + case 'b': + if (!isregisteroperand(RegClass_GPR)) { + if (tk == TK_INTCONST && tkintconst.lo == 0) + r0_operand(op); + } else { + registeroperand(op, RegClass_GPR, effect); + if (op->u.reg.object == NULL && op->u.reg.num == 0) + op->u.reg.effect = 0; + } + break; + + case 'r': + registeroperand(op, RegClass_GPR, effect); + break; + + case 'B': + case 'a': + case 'i': + case 't': + case 'u': + case 'x': + { + SInt32 value, hi, lo; + code = *format; + value = 16; + if (code == 'a') { + if (isdigit(format[1])) + code = *(++format); + else + CError_FATAL(1804); + } + + if (isdigit(format[1])) { + format += pcode_const_from_format(format + 1, &value); + } else if (code == 't' || code == 'B') { + code = 'u'; + value = 5; + } + + pcode_get_hi_lo(value, code, &hi, &lo); + if (!has_question || tk == ',') { + if (has_question) + tk = lex(); + if (has_excl) + getimmediateoperand(lo, hi); + else + immediateoperand(op, lo, hi); + } else { + op->type = IAOpnd_Imm; + op->u.imm.value = 0; + } + + if (code == 'i' && value == 16) + op->u.imm.value = (short) op->u.imm.value; + if (negate) + op->u.imm.value = -op->u.imm.value; + + if (pcode_check_imm_bits(op->u.imm.value, value, code)) + CError_FATAL(1838); + + break; + } + + case 'O': + if (tk == TK_INTCONST && tkintconst.lo == 0) { + getimmediateoperand(0, 0); + eatcommatoken(); + } + continue; + + case 'f': + registeroperand(op, RegClass_FPR, effect); + break; + + case 'v': + registeroperand(op, RegClass_VR, effect); + break; + + case 'T': + if (!has_question || tk == ',') { + if (has_question) + tk = lex(); + + immediateoperand(op, 268, 269); + if (op->u.reg.num == 268) + op->u.reg.num = 284; + else + op->u.reg.num = 285; + } else { + op->u.reg.num = 284; + } + + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.effect = effect; + break; + + case 'S': + { + SInt32 value; + format += pcode_const_from_format(format + 1, &value); + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.num = value; + op->u.reg.effect = effect; + break; + } + + case 'c': + if (has_question) { + if (isregisteroperand(RegClass_CRFIELD) || tk == TK_INTCONST) { + registeroperand(op, RegClass_CRFIELD, effect); + } else { + cr0_operand(op, effect); + if (format[1] == ',') + format++; + } + } else { + registeroperand(op, RegClass_CRFIELD, effect); + } + break; + + case 'l': + switch (ia->opcode) { + case PC_B: + case PC_BL: + labeloperand(ia, op, 1, mnemonic->x10 & 2, mnemonic->x10 & 1); + break; + default: + labeloperand(ia, op, 0, mnemonic->x10 & 2, mnemonic->x10 & 1); + break; + } + break; + + case 'w': + imm_or_labeldiff_operand(ia, op, -0x80000000, 0x7FFFFFFF, negate); + break; + + case 'M': + case 'm': + case 'n': + imm_or_labeldiff_operand(ia, op, -0x8000, 0xFFFF, negate); + break; + + case 'Q': + { + SInt32 cr = crbitoperand(); + op->type = IAOpnd_Reg; + op->u.reg.num = cr >> 2; + op->u.reg.rclass = RegClass_CRFIELD; + op->u.reg.effect = effect; + + ia->argcount++; + op[1].type = IAOpnd_Imm; + op[1].u.imm.value = cr % 4; + op++; + break; + } + + case 'd': { + short effect2; + CError_ASSERT(1971, format[1] == '('); + format++; + effect2 = EffectRead; + if (format[1] == '=') { + effect2 = EffectWrite; + format++; + } else if (format[1] == '+') { + effect2 = EffectRead | EffectWrite; + format++; + } + + CError_ASSERT(1983, format[1] == 'b'); + CError_ASSERT(1985, format[2] == ')'); + format += 2; + + switch (ia->opcode) { + case PC_LFS: + if (tk == TK_FLOATCONST) + floatoperand(op, ia, TYPE(&stfloat)); + else + memoryoperand(op, ia, 1, effect2); + break; + case PC_LFD: + if (tk == TK_FLOATCONST) + floatoperand(op, ia, TYPE(&stdouble)); + else + memoryoperand(op, ia, 1, effect2); + break; + default: + memoryoperand(op, ia, 1, effect2); + } + + break; + } + + case 'N': + immediateoperand(op, 1, 32); + break; + + case 's': + registeroperand(op, RegClass_SPR, effect); + break; + + case 'D': + if (tk == TK_IDENTIFIER && (reg = InlineAsm_LookupDCRRegister(tkidentifier->name))) { + op->type = IAOpnd_Imm; + op->u.imm.value = reg->num; + } else { + immediateoperand(op, 0, 1023); + } + break; + + case 'Y': + { + SInt32 mask = 255; + SInt32 i; + if (ia->opcode == PC_MTCRF) { + if (ia->args[0].type != IAOpnd_Imm) + CError_Error(CErrorStr144); + mask = ia->args[0].u.imm.value; + } + for (i = 0; i < 8; i++) { + if ((0x80 >> i) & mask) { + op->type = IAOpnd_Reg; + op->u.reg.num = i; + op->u.reg.rclass = RegClass_CRFIELD; + op->u.reg.effect = effect; + ia->argcount++; + op++; + } + } + ia->argcount--; + op--; + break; + } + + case 'P': + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.object = NULL; + if (format[1] == '3') { + format++; + op->u.reg.num = getimmediateoperand(0, 7); + } else { + op->u.reg.num = getimmediateoperand(0, 3); + } + op->u.reg.effect = effect; + break; + + case 'C': + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.object = NULL; + op->u.reg.num = 9; + op->u.reg.effect = effect; + break; + + case 'L': + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.object = NULL; + op->u.reg.num = 8; + op->u.reg.effect = effect; + break; + + case 'X': + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_SPR; + op->u.reg.object = NULL; + op->u.reg.num = 1; + op->u.reg.effect = effect; + break; + + case 'Z': + op->type = IAOpnd_Reg; + op->u.reg.rclass = RegClass_CRFIELD; + op->u.reg.object = NULL; + t = info->flags & 0xC0000000; + if (t == 0x40000000) { + op->u.reg.num = 1; + } else if (t == 0xC0000000) { + op->u.reg.num = 6; + } else { + op->u.reg.num = 0; + } + op->u.reg.effect = effect; + break; + + default: + CError_FATAL(2266); + } + + while (format[1] && strchr("/<>|*", format[1])) { + int index; + SInt32 value; + SInt32 value2; + IAOperand tmp; + switch ((code = *(++format))) { + case '/': + index = -1; + if (format[1] == '2') { + index = -2; + format++; + } + + tmp = op[index]; + op[index] = op[0]; + op[0] = tmp; + break; + case '*': + case '<': + case '>': + case '|': + if (op->type == IAOpnd_Imm) + value = op->u.imm.value; + else if (op->type == IAOpnd_Reg) + value = op->u.reg.num; + else + CError_FATAL(2312); + + if (format[1] == 'p') { + format++; + if (op[-1].type == IAOpnd_Imm) + value2 = op[-1].u.imm.value; + else if (op[-1].type == IAOpnd_Reg) + value2 = op[-1].u.reg.num; + else + CError_FATAL(2322); + } else if (isdigit(format[1])) { + format += pcode_const_from_format(format + 1, &value2); + } else { + CError_FATAL(2327); + } + + switch (code) { + case '<': + value = value2 - value; + break; + case '>': + value = value - value2; + break; + case '|': + value = value + value2; + break; + case '*': + value = value * value2; + break; + default: + CError_FATAL(2348); + } + + if (op->type == IAOpnd_Imm) + op->u.imm.value = value; + else if (op->type == IAOpnd_Reg) + op->u.reg.num = value; + else + CError_FATAL(2355); + break; + } + } + + ia->argcount++; + op++; + if (format[1] == ']' || format[1] == ')') + format++; + } + + return ia; +} + +static int mnemonic_has_overflow(char *buf) { + int result = 0; + + if (buf[strlen(buf) - 1] == 'o') { + if (!strcmp(buf, "bso")) + return 0; + if (!strcmp(buf, "fcmpo")) + return 0; + if (!strcmp(buf, "eieio")) + return 0; + if (!strcmp(buf, "vslo")) + return 0; + if (!strcmp(buf, "vsro")) + return 0; + result = 1; + } + + return result; +} + +static int mnemonic_has_absolute(const char *buf) { + int result = 0; + char last = buf[strlen(buf) - 1]; + + if (buf[0] == 'b' && last == 'a') + result = 1; + + return result; +} + +static int mnemonic_has_linkregister(const char *buf) { + int result = 0; + char last = buf[strlen(buf) - 1]; + + if (buf[0] == 'b' && last == 'l') + result = 1; + + return result; +} + +static int mnemonic_has_record(char *buf) { + int result = 0; + + if (lookahead() == '.') { + tk = lex(); + result = 1; + strcat(buf, "."); + } + + return result; +} + +static void installregistervariables(void) { +} + +void InlineAsm_InitializePPC(void) { + Test_Version_Numbers(); + allow_array_expressions = 1; + supports_hardware_fpu = 1; + assembledinstructions = 0; + + switch (copts.processor) { + case CPU_PPC401: cpu = CPUMask_401; break; + case CPU_PPC403: cpu = CPUMask_403; break; + case CPU_PPC505: cpu = CPUMask_50x; break; + case CPU_PPC509: cpu = CPUMask_50x; break; + case CPU_PPC555: cpu = CPUMask_55x_56x; break; + case CPU_PPC556: cpu = CPUMask_55x_56x; break; + case CPU_PPC565: cpu = CPUMask_55x_56x; break; + case CPU_PPC601: cpu = CPUMask_601; break; + case CPU_PPC602: cpu = CPUMask_602; break; + case CPU_PPC8240: cpu = CPUMask_8240; break; + case CPU_PPC8260: cpu = CPUMask_8260; break; + case CPU_PPC603: cpu = CPUMask_603; break; + case CPU_PPC603e: cpu = CPUMask_603; break; + case CPU_PPC604: cpu = CPUMask_604; break; + case CPU_PPC604e: cpu = CPUMask_604; break; + case CPU_PPC740: cpu = CPUMask_740_750; break; + case CPU_PPC750: cpu = CPUMask_740_750; break; + case CPU_PPC801: cpu = CPUMask_801_821_860; break; + case CPU_PPC821: cpu = CPUMask_801_821_860; break; + case CPU_PPC823: cpu = CPUMask_823_850; break; + case CPU_PPC850: cpu = CPUMask_823_850; break; + case CPU_PPC860: cpu = CPUMask_801_821_860; break; + case CPU_PPC7400: case CPU_PPC7450: cpu = CPUMask_74xx; break; + case CPU_Generic: cpu = CPUMask_Generic; break; + default: + CError_FATAL(2613); + } + + if (copts.altivec_model) + cpu |= 0x40000000; +} + +void InlineAsm_Initialize(AssemblerType assemblertype) { + assembler_type = assemblertype; + + if (assembler_type == 0) { + InlineAsm_InitializePPC(); + pic_base_reg = INVALID_PIC_REG; + } else { + pic_base_reg = 0; + pic_base_label = NULL; + } + + InlineAsm_InitializeMnemonicsPPC(); + InlineAsm_InitializeRegisters(); + InlineAsm_InitializeRegistersPPC(); + + if (assembler_type == 0) { + installregistervariables(); + } else { + process_arguments(setup_assembly_argument, 0); + assign_local_addresses(); + } +} + +static IAEntryPoint *InlineAsm_CreateEntryPoint(HashNameNode *name, Boolean flag) { + Object *obj; + IAEntryPoint *ep; + IALookupResult result; + + if (InlineAsm_LookupSymbol(name, &result) && (obj = result.object)) { + if (!(obj->datatype == DFUNC && !(obj->flags & OBJECT_DEFINED))) + CError_Error(CErrorStr122, name->name); + + obj->flags |= OBJECT_DEFINED; + obj->sclass = flag ? TK_STATIC : TK_EXTERN; + + ep = lalloc(sizeof(IAEntryPoint)); + memclrw(ep, sizeof(IAEntryPoint)); + ep->x0 = IADirective_Entry; + ep->x2 = 1; + ep->x8 = obj; + ep->size = assembledinstructions * 4; + } else { + CError_Error(CErrorStr140, name->name); + } + + return ep; +} + +static InlineAsm *InlineAsm_CreateFrFree(void) { + InlineAsm *ia = lalloc(sizeof(InlineAsm)); + memclrw(ia, sizeof(InlineAsm)); + ia->opcode = IADirective_FrFree; + ia->flags = IAFlag1; + return ia; +} + +SInt32 InlineAsm_IsDirective(AssemblerType assemblertype) { + char *name; + SInt32 directive = IADirective_Null; + + if (tk == '.') + tk = lex(); + + if (tk == TK_IDENTIFIER) { + name = tkidentifier->name; + if (!strcmp(name, "machine")) { + directive = IADirective_Machine; + } else if (assemblertype == AssemblerType_1) { + if (!strcmp(name, "entry")) { + directive = IADirective_Entry; + } else if (!strcmp(name, "fralloc")) { + directive = IADirective_FrAlloc; + } else if (!strcmp(name, "nofralloc")) { + directive = IADirective_NoFrAlloc; + } else if (!strcmp(name, "frfree")) { + directive = IADirective_FrFree; + } else if (!strcmp(name, "smclass")) { + directive = IADirective_SmClass; + } else if (!strcmp(name, "picbase")) { + directive = IADirective_PicBase; + } else { + directive = IADirective_Null; + } + } + } + + return directive; +} + +void InlineAsm_ProcessDirective(SInt32 directive) { + Boolean flag; + Statement *stmt; + IAOperand op; + + switch (directive) { + case IADirective_Entry: + flag = 0; + tk = lex(); + if (tk == TK_STATIC) { + flag = 1; + tk = lex(); + } else if (tk == TK_EXTERN) { + tk = lex(); + } + + if (tk != TK_IDENTIFIER) + CError_Error(CErrorStr107); + + stmt = CFunc_AppendStatement(ST_ASM); + stmt->expr = NULL; + stmt->expr = (ENode *) InlineAsm_CreateEntryPoint(tkidentifier, flag); + stmt->sourceoffset = -1; + tk = lex(); + break; + + case IADirective_FrAlloc: + if (assembledinstructions) + CError_Error(CErrorStr166); + if (asm_alloc_flags[0]) + CError_Error(CErrorStr165); + if (asm_alloc_flags[1] || asm_alloc_flags[2]) + CError_Error(CErrorStr166); + + tk = lex(); + if (tk != TK_EOL && tk != ';') + fralloc_parameter_area_size = getimmediateoperand(0x20, 0x7FFE); + + requires_frame = 1; + asm_alloc_flags[0] = 1; + break; + + case IADirective_NoFrAlloc: + if (asm_alloc_flags[0] || asm_alloc_flags[1]) + CError_Error(CErrorStr165); + if (asm_alloc_flags[2]) + CError_Error(CErrorStr166); + if (assembledinstructions) + CError_Error(CErrorStr166); + tk = lex(); + + asm_alloc_flags[1] = 1; + user_responsible_for_frame = 1; + break; + + case IADirective_FrFree: + if (asm_alloc_flags[1] || asm_alloc_flags[2]) + CError_Error(CErrorStr166); + + asm_alloc_flags[2] = 1; + stmt = CFunc_AppendStatement(ST_ASM); + stmt->expr = NULL; + stmt->expr = (ENode *) InlineAsm_CreateFrFree(); + if (copts.filesyminfo) + stmt->sourceoffset = CPrep_GetFileOffsetInfo(&cparser_fileoffset); + else + stmt->sourceoffset = -1; + tk = lex(); + break; + + case IADirective_Machine: + tk = lex(); + if (tk == TK_INTCONST) { + switch (tkintconst.lo) { + case 401: cpu = CPUMask_401; break; + case 403: cpu = CPUMask_403; break; + case 505: cpu = CPUMask_50x; break; + case 509: cpu = CPUMask_50x; break; + case 555: cpu = CPUMask_55x_56x; break; + case 556: cpu = CPUMask_55x_56x; break; + case 565: cpu = CPUMask_55x_56x; break; + case 601: cpu = CPUMask_601; break; + case 602: cpu = CPUMask_602; break; + case 8240: cpu = CPUMask_8240; break; + case 8260: cpu = CPUMask_8260; break; + case 603: cpu = CPUMask_603; break; + case 604: cpu = CPUMask_604; break; + case 740: cpu = CPUMask_740_750; break; + case 750: cpu = CPUMask_740_750; break; + case 801: cpu = CPUMask_801_821_860; break; + case 821: cpu = CPUMask_801_821_860; break; + case 823: cpu = CPUMask_823_850; break; + case 850: cpu = CPUMask_823_850; break; + case 860: cpu = CPUMask_801_821_860; break; + case 7400: cpu = CPUMask_74xx; break; + default: + CError_Error(CErrorStr144); + } + } else if (tk == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "all")) { + cpu = CPUMask_All; + } else if (!strcmp(tkidentifier->name, "generic")) { + cpu = CPUMask_Generic; + } else if (!strcmp(tkidentifier->name, "603e")) { + cpu = CPUMask_603; + } else if (!strcmp(tkidentifier->name, "604e")) { + cpu = CPUMask_604; + } else if (!strcmp(tkidentifier->name, "PPC603e")) { + cpu = CPUMask_603; + } else if (!strcmp(tkidentifier->name, "PPC604e")) { + cpu = CPUMask_604; + } else if (!strcmp(tkidentifier->name, "altivec")) { + cpu = CPUMask_74xx; + } else { + CError_Error(CErrorStr144); + } + } else { + CError_Error(CErrorStr144); + } + tk = lex(); + break; + + case IADirective_SmClass: + tk = lex(); + if (tk == TK_IDENTIFIER) { + if (!strcmp(tkidentifier->name, "PR")) + sm_section = SECT_TEXT; + else + CError_Error(CErrorStr144); + } else { + CError_Error(CErrorStr144); + } + tk = lex(); + break; + + case IADirective_PicBase: + tk = lex(); + registeroperand(&op, RegClass_GPR, EffectRead); + + if (!(op.type == IAOpnd_Reg && op.u.reg.object == NULL)) + CError_Error(CErrorStr144); + + tk = lex(); + if (tk == TK_IDENTIFIER) { + savepicbase(op.u.reg.num, tkidentifier); + tk = lex(); + } else { + CError_Error(CErrorStr144); + } + break; + + default: + CError_Error(CErrorStr261); + } +} + +void InlineAsm_ScanAssemblyDirective(void) { + SInt32 directive; + + if ((directive = InlineAsm_IsDirective(assembler_type)) != IADirective_Null) + InlineAsm_ProcessDirective(directive); +} + +void InlineAsm_ScanAssemblyInstruction(void) { + Statement *stmt; + InlineAsm *ia; + IAMnemonic *mnemonic; + Boolean record_flag; + Boolean flag3; + Boolean flag4; + Boolean flag5; + Boolean flag1; + Boolean flag2; + SInt32 directive; + OpcodeInfo *info; + char buf[20]; + + flag1 = 0; + flag2 = 0; + if ((directive = InlineAsm_IsDirective(assembler_type)) != IADirective_Null) { + InlineAsm_ProcessDirective(directive); + return; + } + + stmt = CFunc_AppendStatement(ST_ASM); + stmt->expr = NULL; + if (copts.filesyminfo) + stmt->sourceoffset = CPrep_GetFileOffsetInfo(&cparser_fileoffset); + else + stmt->sourceoffset = -1; + + strncpy(buf, tkidentifier->name, sizeof(buf)); + record_flag = mnemonic_has_record(buf); + mnemonic = InlineAsm_LookupMnemonicPPC(buf); + if (!mnemonic) + CError_Error(CErrorStr261); + + info = &opcodeinfo[mnemonic->x4]; + flag3 = (FLAG_SET_F(info->flags) & fCanSetCarry) && (mnemonic->x10 & 0x400); + flag4 = (FLAG_SET_T(info->flags) & fCanBeAbsolute) && (mnemonic->x10 & 2); + flag5 = (FLAG_SET_T(info->flags) & fCanLink) && (mnemonic->x10 & 1); + + if ((cpu == CPUMask_Generic) && (cpu & CPUFLAG_LOW_MASK) != ((cpu & mnemonic->cpu) & CPUFLAG_LOW_MASK)) { + CError_Error(CErrorStr152); + } else if (((cpu & mnemonic->cpu) & CPUFLAG_LOW_MASK) == 0) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_10000000) && !(cpu & CPUFLAG_10000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_8000000) && !(cpu & CPUFLAG_8000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_2000000) && !(cpu & CPUFLAG_2000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_4000000) && !(cpu & CPUFLAG_4000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_1000000) && !(cpu & CPUFLAG_1000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_40000000) && !(cpu & CPUFLAG_40000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_20000000) && !(cpu & CPUFLAG_20000000)) { + CError_Error(CErrorStr152); + } else if ((mnemonic->cpu & CPUFLAG_800000) && !(cpu & CPUFLAG_800000)) { + CError_Error(CErrorStr152); + } + + tk = lex(); + if (tk == '+' || tk == '-') { + if ( + ((OPCODE_PART_1(mnemonic->x10) == 16) && (OPCODE_PART_2(mnemonic->x10) != 20)) || + ((OPCODE_PART_1(mnemonic->x10) == 19) && (OPCODE_PART_3(mnemonic->x10) == 528) && (OPCODE_PART_2(mnemonic->x10) != 20)) || + ((OPCODE_PART_1(mnemonic->x10) == 19) && (OPCODE_PART_3(mnemonic->x10) == 16) && (OPCODE_PART_2(mnemonic->x10) != 20)) + ) { + if (tk == '+') + flag1 = 1; + else if (tk == '-') + flag2 = 1; + tk = lex(); + } else { + CError_Error(CErrorStr120); + } + } + + stmt->expr = (ENode *) InlineAsm_ScanAssemblyOperands(mnemonic); + + ia = (InlineAsm *) stmt->expr; + if (record_flag) + ia->flags2 |= IAFlagsB_1; + if (flag3) + ia->flags2 |= IAFlagsB_2; + if (flag4) + ia->flags2 |= IAFlagsB_4; + if (flag5) + ia->flags2 |= IAFlagsB_8; + if (flag1) + ia->flags2 |= IAFlagsB_10; + if (flag2) + ia->flags2 |= IAFlagsB_20; + if (volatileasm) + ia->flags2 |= IAFlagsB_40; + + ++assembledinstructions; +} + +static PCode *InlineAsm_TranslateIRtoPCodePPC(InlineAsm *ia, int argcount, AssemblerType assemblertype) { + PCode *pc; + int index; + int extra_args; + int reg; + int newargcount; + SInt32 buffersize; + IAOperand *src; + PCodeArg *dest; + OpcodeInfo *info; + + info = &opcodeinfo[ia->opcode]; + index = 0; + extra_args = 0; + reg = 0; + + if ((PCODE_FLAG_SET_F(info) & fCanSetRecordBit) && !(PCODE_FLAG_SET_F(info) & fRecordBit)) + extra_args++; + + if (!(PCODE_FLAG_SET_F(info) & fSetsCarry) && (PCODE_FLAG_SET_F(info) & fCanSetCarry)) + extra_args++; + + if (argcount < ia->argcount) { + if ((argcount + extra_args) >= ia->argcount) { + extra_args -= (ia->argcount - argcount); + argcount = ia->argcount; + } else { + CError_FATAL(3317); + } + } + + if (ia->opcode == PC_B && ia->args[0].type == IAOpnd_Imm) + ia->flags2 |= IAFlagsB_40; + + if (ia->opcode == PC_TWI || ia->opcode == PC_TW || ia->opcode == PC_TRAP || ia->opcode == PC_SC) + ia->flags |= IAFlag2; + + if (ia->flags & IAFlag2) { + newargcount = argcount + branch_count_volatiles(); + if (copts.exceptions && current_statement && assembler_type == 0) + newargcount += countexceptionactionregisters(current_statement->dobjstack); + + buffersize = sizeof(PCode) + sizeof(PCodeArg) * (newargcount + extra_args); + pc = lalloc(buffersize); + memset(pc, 0, buffersize); + pc->argCount = newargcount; + } else if (ia->opcode == PC_STMW || ia->opcode == PC_LMW) { + reg = ia->args[0].u.reg.object ? OBJECT_REG(ia->args[0].u.reg.object) : ia->args[0].u.reg.num; + newargcount = argcount + (32 - reg); + + buffersize = sizeof(PCode) + sizeof(PCodeArg) * newargcount; + pc = lalloc(buffersize); + memset(pc, 0, buffersize); + pc->argCount = newargcount; + } else { + buffersize = sizeof(PCode) + sizeof(PCodeArg) * (argcount + extra_args); + pc = lalloc(buffersize); + memset(pc, 0, buffersize); + pc->argCount = (ia->argcount > argcount) ? ia->argcount : argcount; + } + + pc->op = ia->opcode; + pc->flags = info->flags; + pc->sourceoffset = current_statement ? current_statement->sourceoffset : -1; + + dest = pc->args; + src = ia->args; + argcount += extra_args; + while (index < argcount) { + if (index >= ia->argcount) { + dest->kind = PCOp_PLACEHOLDEROPERAND; + } else { + switch (src->type) { + case IAOpnd_0: + dest->kind = PCOp_PLACEHOLDEROPERAND; + break; + + case IAOpnd_Imm: + dest->kind = PCOp_IMMEDIATE; + dest->data.imm.value = src->u.imm.value; + if (pc->flags & (fIsRead | fIsWrite)) + pc->flags |= fIsPtrOp; + dest->data.imm.obj = NULL; + break; + + case IAOpnd_Reg: { + int r20; + r20 = 0; + if (src->u.reg.object) { + if (Registers_GetVarInfo(src->u.reg.object)->flags & VarInfoFlag2) { + if (src->u.reg.num == 1) + r20 = OBJECT_REG_HI(src->u.reg.object); + else + r20 = OBJECT_REG(src->u.reg.object); + } else { + if (Registers_GetVarInfo(src->u.reg.object)->flags & VarInfoFlag40) + PPCError_Error(PPCErrorStr172, src->u.reg.object->name->name); + else + PPCError_Error(PPCErrorStr167, src->u.reg.object->name->name); + } + } else if (src->u.reg.num == INVALID_PIC_REG) { + r20 = pic_base_reg; + } else { + r20 = src->u.reg.num; + } + + dest->kind = PCOp_REGISTER; + dest->arg = src->u.reg.rclass; + dest->data.reg.reg = r20; + dest->data.reg.effect = src->u.reg.effect; + if (pc->op == PC_RLWIMI && (dest->data.reg.effect & EffectWrite) && dest->arg == RegClass_GPR && !(dest->data.reg.effect & EffectRead)) + CError_FATAL(3442); + + if (dest->arg == RegClass_SPR) { + int i; + dest->kind = PCOp_SYSREG; + for (i = 0; i < 4; i++) { + if (dest->data.reg.reg == spr_to_sysreg[i]) { + dest->kind = PCOp_REGISTER; + dest->arg = RegClass_SPR; + dest->data.reg.reg = i; + break; + } + } + pcsetsideeffects(pc); + } else if (dest->arg == RegClass_6 || dest->arg == RegClass_DCR) { + short save = dest->data.reg.reg; + dest->kind = PCOp_IMMEDIATE; + dest->data.imm.value = save; + dest->data.imm.obj = NULL; + break; + } + + if ((src->u.reg.effect & EffectWrite) && dest->data.reg.reg < n_real_registers[dest->arg]) { + if (src->u.reg.object) { + if (Registers_GetVarInfo(src->u.reg.object)->flags & VarInfoFlag4) { + int reg, regHi; + CError_ASSERT(3474, dest->arg == RegClass_GPR); + + regHi = OBJECT_REG_HI(src->u.reg.object); + reg = OBJECT_REG(src->u.reg.object); + retain_GPR_pair(src->u.reg.object, reg, regHi); + } else { + retain_register(src->u.reg.object, dest->arg, dest->data.reg.reg); + } + } else { + retain_register(NULL, dest->arg, dest->data.reg.reg); + } + } + + break; + } + + case IAOpnd_Lab: + if (!src->u.lab.label->pclabel) + src->u.lab.label->pclabel = makepclabel(); + dest->kind = PCOp_LABEL; + dest->data.label.label = src->u.lab.label->pclabel; + break; + + case IAOpnd_3: + case IAOpnd_4: + dest->kind = PCOp_MEMORY; + dest->arg = src->u.obj.unk; + dest->data.mem.obj = src->u.obj.obj; + dest->data.mem.offset = src->u.obj.offset; + if (pc->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000)) { + pc->alias = make_alias(dest->data.mem.obj, dest->data.mem.offset, nbytes_loaded_or_stored_by(pc)); + if (is_volatile_object(dest->data.mem.obj)) + pc->flags |= fIsVolatile; + if (OBJ_GET_TARGET_CONST(dest->data.mem.obj)) + pc->flags |= fIsConst; + } + break; + + case IAOpnd_LabDiff: + if (src->u.labdiff.label1->pclabel == NULL) + src->u.labdiff.label1->pclabel = makepclabel(); + if (src->u.labdiff.label2->pclabel == NULL) + src->u.labdiff.label2->pclabel = makepclabel(); + if (pc->flags & (fIsRead | fIsWrite)) + pc->flags |= fIsPtrOp; + dest->kind = PCOp_LABELDIFF; + dest->data.labeldiff.labelA = src->u.labdiff.label1->pclabel; + dest->data.labeldiff.labelB = src->u.labdiff.label2->pclabel; + dest->arg = src->negated; + dest->data.labeldiff.offset = src->u.labdiff.offset; + break; + + default: + CError_FATAL(3528); + } + } + + index++; + dest++; + src++; + } + + if (ia->opcode == PC_STMW || ia->opcode == PC_LMW) { + int i; + for (i = reg; i < 32; i++, dest++) { + dest->kind = PCOp_REGISTER; + dest->arg = RegClass_GPR; + dest->data.reg.reg = i; + dest->data.reg.effect = ((ia->opcode == PC_LMW) ? EffectWrite : EffectRead); + } + } + + if (ia->flags & IAFlag2) { + UInt32 masks[5] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}; + branch_record_volatiles(dest, masks); + if (copts.exceptions && current_statement && assembler_type == 0) + noteexceptionactionregisters(current_statement->dobjstack, dest); + } + + return pc; +} + +void InlineAsm_TranslateIRtoPCode(Statement *stmt) { + InlineAsm *ia; + PCode *pc; + + ia = (InlineAsm *) stmt->expr; + pc = InlineAsm_TranslateIRtoPCodePPC(ia, opcodeinfo[ia->opcode].x8, assembler_type); + appendpcode(pclastblock, pc); + + if ((ia->flags2 & IAFlagsB_40) || !copts.optimizewithasm) + setpcodeflags(fSideEffects); + + if (ia->flags2 & IAFlagsB_1) { + if (PCODE_FLAG_SET_F(pc) & fCanSetRecordBit) + pcsetrecordbit(pclastblock->lastPCode); + else + CError_Error(CErrorStr261); + } + + if (ia->flags2 & IAFlagsB_2) { + if (PCODE_FLAG_SET_F(pc) & fCanSetCarry) + setpcodeflags(fOverflow); // idk? + else + CError_Error(CErrorStr261); + } + + if (ia->flags2 & IAFlagsB_4) { + if (PCODE_FLAG_SET_T(pc) & fCanBeAbsolute) { + int i; + for (i = 0; i < pc->argCount; i++) { + if (pc->args[i].kind == PCOp_LABEL || pc->args[i].kind == PCOp_MEMORY) { + PPCError_Error(PPCErrorStr177); + break; + } + } + setpcodeflags(fAbsolute); + } else { + CError_Error(CErrorStr261); + } + } + + if (ia->flags2 & IAFlagsB_8) { + if (PCODE_FLAG_SET_T(pc) & fCanLink) { + pcsetlinkbit(pclastblock->lastPCode); + if (!(ia->flags & IAFlag2)) { + pclastblock->lastPCode->flags &= ~fIsCall; + pclastblock->lastPCode->flags |= fIsBranch; + } + makes_call = 1; + } else { + CError_Error(CErrorStr261); + } + } + + if (ia->flags2 & IAFlagsB_10) + setpcodeflags(fCanSetRecordBit); + if (ia->flags2 & IAFlagsB_20) + setpcodeflags(fCanSetCarry); + + if (OPCODE_PART_1(opcodeinfo[pc->op].insn) == 16) { + PCodeLabel *dest = NULL; + PCodeLabel *src = makepclabel(); + switch (pc->op) { + case PC_BC: + if (pc->args[3].kind == PCOp_LABEL) + dest = pc->args[3].data.label.label; + break; + case PC_BT: + case PC_BF: + case PC_BDNZT: + case PC_BDNZF: + case PC_BDZT: + case PC_BDZF: + if (pc->args[2].kind == PCOp_LABEL) + dest = pc->args[2].data.label.label; + break; + case PC_BDNZ: + case PC_BDZ: + if (pc->args[0].kind == PCOp_LABEL) + dest = pc->args[0].data.label.label; + break; + default: + CError_FATAL(3715); + } + + if (dest) { + pcbranch(pclastblock, dest); + pcbranch(pclastblock, src); + makepcblock(); + pclabel(pclastblock, src); + } + return; + } + + if (OPCODE_PART_1(opcodeinfo[pc->op].insn) == 18) { + PCodeLabel *label; + if (ia->flags2 & IAFlagsB_8) { + label = makepclabel(); + pcbranch(pclastblock, label); + } + if (pc->args[0].kind == PCOp_LABEL) + pcbranch(pclastblock, pc->args[0].data.label.label); + makepcblock(); + if (ia->flags2 & IAFlagsB_8) { + pclabel(pclastblock, label); + } + return; + } + + if (OPCODE_PART_1(opcodeinfo[pc->op].insn) == 19) { + switch (pc->op) { + case PC_BLR: + case PC_RFI: + if (asm_alloc_flags[3]) + asm_alloc_flags[9] = 1; + else + asm_alloc_flags[8] = 1; + + if (asm_alloc_flags[4]) + asm_alloc_flags[5] = 1; + + if (pc->op == PC_BLR) + asm_alloc_flags[6] = 1; + else + asm_alloc_flags[7] = 1; + break; + } + } +} + +const char *InlineAsm_GetMnemonic(InlineAsm *ia) { + return opcodeinfo[ia->opcode].name; +} + +static void savepicbase(short reg, HashNameNode *name) { + IALookupResult result; + + if (!InlineAsm_LookupSymbol(name, &result)) + result.label = InlineAsm_DeclareLabel(name); + + pic_base_label = result.label; + pic_base_reg = reg; + uses_globals = 1; +} + +static SInt32 InlineAsm_OpcodeSize(InlineAsm *ia) { + if (opcodeinfo[ia->opcode].flags & (fIsRead | fIsWrite)) { + switch (ia->opcode) { + case PC_LBZ: + case PC_LBZU: + case PC_LBZX: + case PC_LBZUX: + case PC_STB: + case PC_STBU: + case PC_STBX: + case PC_STBUX: + return 1; + case PC_LHZ: + case PC_LHZU: + case PC_LHZX: + case PC_LHZUX: + case PC_LHA: + case PC_LHAU: + case PC_LHAX: + case PC_LHAUX: + case PC_LHBRX: + case PC_STH: + case PC_STHU: + case PC_STHX: + case PC_STHUX: + case PC_STHBRX: + return 2; + case PC_LWZ: + case PC_LWZU: + case PC_LWZX: + case PC_LWZUX: + case PC_LWBRX: + case PC_STW: + case PC_STWU: + case PC_STWX: + case PC_STWUX: + case PC_STWBRX: + case PC_LFS: + case PC_LFSU: + case PC_LFSX: + case PC_LFSUX: + case PC_STFS: + case PC_STFSU: + case PC_STFSX: + case PC_STFSUX: + case PC_LWARX: + case PC_STFIWX: + case PC_STWCX: + case PC_ECIWX: + case PC_ECOWX: + case PC_MFROM: + case PC_LSCBX: + return 4; + case PC_LMW: + case PC_STMW: + if (ia->args[0].type == IAOpnd_Reg && ia->args[0].u.reg.object == NULL) + return (32 - ia->args[0].u.reg.num) * 4; + else + return 128; + case PC_LFD: + case PC_LFDU: + case PC_LFDX: + case PC_LFDUX: + case PC_STFD: + case PC_STFDU: + case PC_STFDX: + case PC_STFDUX: + return 8; + case PC_LSWI: + case PC_STSWI: + return ia->args[2].u.imm.value; + case PC_LSWX: + case PC_STSWX: + return 128; + case PC_LVEBX: + case PC_STVEBX: + return 1; + case PC_LVEHX: + case PC_STVEHX: + return 2; + case PC_LVEWX: + case PC_STVEWX: + return 4; + case PC_LVSL: + case PC_LVSR: + case PC_LVX: + case PC_LVXL: + case PC_STVX: + case PC_STVXL: + return 16; + default: + CError_FATAL(3924); + } + } else { + if (opcodeinfo[ia->opcode].flags & fOpTypeGPR) + return 4; + if (opcodeinfo[ia->opcode].flags & fOpTypeFPR) + return 8; + if (opcodeinfo[ia->opcode].flags & fOpTypeVR) + return 16; + + if (opcodeinfo[ia->opcode].flags & fSideEffects) { + switch (ia->opcode) { + case PC_TLBIE: + case PC_TLBLD: + case PC_TLBLI: + return 4; + default: + CError_FATAL(3941); + } + } + } + + CError_FATAL(3944); + return 0; +} + +void CodeGen_GetAsmEffects(Statement *stmt, IAEffects *effects) { + InlineAsm *ia; + OpcodeInfo *info; + int i; + IAOperand *op; + VarInfo *vi; + + ia = (InlineAsm *) stmt->expr; + info = &opcodeinfo[ia->opcode]; + + effects->numoperands = 0; + effects->numlabels = 0; + effects->x1 = 0; + effects->x2 = 0; + effects->x3 = 0; + effects->x4 = 0; + effects->x0 = 0; + effects->x5 = 0; + + if (info->flags & fIsPtrOp) { + if (info->flags & fIsRead) + effects->x1 = 1; + if (info->flags & fIsWrite) + effects->x2 = 1; + } + + if (PCODE_FLAG_SET_T(info) & fCanLink) { + if (ia->flags2 & IAFlagsB_8) + effects->x4 = 1; + else if ((info->flags & fIsCall) || (info->flags & fIsWrite)) + effects->x3 = 1; + + if (ia->opcode == PC_B) { + if (ia->args[0].type == IAOpnd_Imm) + effects->x0 = 1; + effects->x5 = 1; + } + } + + if (info->flags & fSideEffects) + effects->x0 = 1; + + if (ia->opcode == PC_BC && (ia->flags2 & IAFlagsB_8)) + effects->x4 = 1; + + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + switch (op->type) { + case IAOpnd_0: + case IAOpnd_Imm: + break; + case IAOpnd_Reg: + if (op->u.reg.object) { + if ((vi = Registers_GetVarInfo(op->u.reg.object))) + vi->flags |= VarInfoFlag40; + if (op->u.reg.effect & EffectRead) { + if ( + TYPE_FITS_IN_REGISTER(op->u.reg.object->type) || + IS_TYPE_FLOAT(op->u.reg.object->type) || + IS_TYPE_VECTOR(op->u.reg.object->type) + ) { + effects->operands[effects->numoperands].type = IAEffect_0; + effects->operands[effects->numoperands].object = op->u.reg.object; + effects->operands[effects->numoperands].offset = 0; + effects->operands[effects->numoperands].size = op->u.reg.object->type->size; + effects->numoperands++; + } else { + CError_FATAL(4051); + } + } + } + break; + case IAOpnd_3: + case IAOpnd_4: + if (op->u.obj.obj) { + if (info->flags & fIsRead) { + effects->operands[effects->numoperands].type = IAEffect_0; + effects->operands[effects->numoperands].object = op->u.obj.obj; + effects->operands[effects->numoperands].offset = op->u.obj.offset; + effects->operands[effects->numoperands].size = InlineAsm_OpcodeSize(ia); + effects->numoperands++; + } else if (!(info->flags & (fIsBranch | fIsCall))) { + effects->operands[effects->numoperands].type = IAEffect_3; + effects->operands[effects->numoperands].object = op->u.obj.obj; + effects->operands[effects->numoperands].offset = op->u.obj.offset; + effects->operands[effects->numoperands].size = InlineAsm_OpcodeSize(ia); + effects->numoperands++; + } + } + break; + case IAOpnd_Lab: + effects->labels[effects->numlabels] = op->u.lab.label; + effects->numlabels++; + break; + case IAOpnd_LabDiff: + effects->labels[effects->numlabels] = op->u.labdiff.label1; + effects->numlabels++; + effects->labels[effects->numlabels] = op->u.labdiff.label2; + effects->numlabels++; + effects->x3 = 1; + break; + default: + CError_FATAL(4087); + } + + CError_ASSERT(4090, (UInt32) effects->numoperands <= IAMaxOperands); + CError_ASSERT(4093, (UInt32) effects->numlabels <= IAMaxLabels); + } + + for (i = 0, op = ia->args; i < ia->argcount; i++, op++) { + switch (op->type) { + case IAOpnd_Reg: + if (op->u.reg.object) { + if ((vi = Registers_GetVarInfo(op->u.reg.object))) + vi->flags |= VarInfoFlag40; + if (op->u.reg.effect & EffectWrite) { + if ( + TYPE_FITS_IN_REGISTER(op->u.reg.object->type) || + IS_TYPE_FLOAT(op->u.reg.object->type) || + IS_TYPE_VECTOR(op->u.reg.object->type) + ) { + effects->operands[effects->numoperands].type = IAEffect_1; + effects->operands[effects->numoperands].object = op->u.reg.object; + effects->operands[effects->numoperands].offset = 0; + effects->operands[effects->numoperands].size = op->u.reg.object->type->size; + effects->numoperands++; + } else { + CError_FATAL(4132); + } + } + } + break; + case IAOpnd_3: + case IAOpnd_4: + if (op->u.obj.obj) { + if (info->flags & fIsWrite) { + effects->operands[effects->numoperands].type = IAEffect_1; + effects->operands[effects->numoperands].object = op->u.obj.obj; + effects->operands[effects->numoperands].offset = op->u.obj.offset; + effects->operands[effects->numoperands].size = InlineAsm_OpcodeSize(ia); + effects->numoperands++; + } + } + break; + } + + CError_ASSERT(4151, (UInt32) effects->numoperands <= IAMaxOperands); + } + + if ((info->flags & (fIsBranch | fIsCall)) && (SInt32)effects->numlabels == 0) + effects->x3 = 1; +} + +void CodeGen_PropagateIntoAsm(Statement *stmt, Object *obj, ENode *expr) { + InlineAsm *ia; + Object *newobj; + + ia = (InlineAsm *) stmt->expr; + if (ENODE_IS(expr, EOBJREF)) { + newobj = expr->data.objref; + if (obj->otype == newobj->otype && obj->datatype == newobj->datatype) { + int i; + for (i = 0; i < ia->argcount; i++) { + switch (ia->args[i].type) { + case IAOpnd_Reg: + if (ia->args[i].u.reg.object == obj && + (ia->args[i].u.reg.effect & (EffectRead | EffectWrite)) == EffectRead) { + if (TYPE_FITS_IN_REGISTER(newobj->type) && + ia->args[i].u.reg.rclass == RegClass_GPR) { + ia->args[i].u.reg.object = newobj; + } else if (IS_TYPE_FLOAT(newobj->type) && + ia->args[i].u.reg.rclass == RegClass_FPR) { + ia->args[i].u.reg.object = newobj; + } else if (IS_TYPE_VECTOR(newobj->type) && + ia->args[i].u.reg.rclass == RegClass_VR) { + ia->args[i].u.reg.object = newobj; + } + } + break; + case IAOpnd_3: + case IAOpnd_4: + if (!(opcodeinfo[ia->opcode].flags & (fIsWrite | fPCodeFlag40000)) && + ia->args[i].u.obj.obj == obj) + ia->args[i].u.obj.obj = newobj; + break; + } + } + } + } +} + +Statement *CodeGen_CopyAsmStat(Statement *stmt) { + Statement *copy; + SInt32 size; + InlineAsm *ia; + InlineAsm *iacopy; + + copy = galloc(sizeof(Statement)); + *copy = *stmt; + + ia = (InlineAsm *) stmt->expr; + size = sizeof(InlineAsm) + sizeof(IAOperand) * ia->argcount; + iacopy = galloc(size); + memcpy(iacopy, ia, size); + copy->expr = (ENode *) iacopy; + + return copy; +} + |