#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); 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(119, opstr, name1->name); } else if (!name1) { PPCError_Error(120, opstr, name2->name); } else { PPCError_Error(118, name1->name, opstr, name2->name); } } static void IllegalObjectInConst(IAExpr *expr) { if (expr->xC) { PPCError_Error(122, expr->xC->name->name); } else if (expr->object) { PPCError_Error(122, expr->object->name->name); } else if (expr->label) { PPCError_Error(166, expr->label->name->name); } } static void NotInRegisterError(char *name, char rclass) { PPCError_Error(167, 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(167, 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(124, left->xC->name->name, right->label->name->name); if (right->xC) { if (left->x10) { PPCError_Error(121, left->xC->name->name, left->x10->name->name, right->xC->name->name); } else if (right->x10) { PPCError_Error(121, 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(124, 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(124, left->label->name->name, left->xC->name->name); if (right->label) { if (left->x18) { PPCError_Error(121, left->label->name->name, left->x18->name->name, right->label->name->name); } else if (right->x18) { PPCError_Error(121, 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(126); } } 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(179); 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(122, 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(180); 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_FLAGS_UNUSED; return; } if (expr.xC) { if (expr.x10) PPCError_Error(123, 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(180); } 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_FLAGS_UNUSED; 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(125, 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_FLAGS_UNUSED; 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(171); } 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(168); tk = lex(); } else if (rclass == RegClass_GPR) { if (reg->object && reg->object->type->size == 8) { HashNameNode *name = reg->object->name; PPCError_Error(127, 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(180); } } 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_10000)) { 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(125, 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(180); } op->u.obj.unk = expr.type; } op->u.obj.obj = expr.xC; op->u.obj.offset = expr.value; } else { PPCError_Error(123, 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) & fPCodeFlag8000000) argcount++; if (!(PCODE_FLAG_SET_F(info) & fPCodeFlag10000000) && (PCODE_FLAG_SET_F(info) & fPCodeFlag4000000)) argcount++; if (PCODE_FLAG_SET_T(info) & fPCodeFlag2000000) 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.cpu) { 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_FLAGS_4))) CError_Error(CErrorStr122, name->name); obj->flags |= OBJECT_FLAGS_4; 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_NEG7 && 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.isGeneratingDebugInfo) 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.isGeneratingDebugInfo) 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) & fPCodeFlag4000000) && (mnemonic->x10 & 0x400); flag4 = (FLAG_SET_T(info->flags) & fPCodeFlag20000000) && (mnemonic->x10 & 2); flag5 = (FLAG_SET_T(info->flags) & fPCodeFlag2000000) && (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) & fPCodeFlag8000000) && !(PCODE_FLAG_SET_F(info) & fPCodeFlag20000000)) extra_args++; if (!(PCODE_FLAG_SET_F(info) & fPCodeFlag10000000) && (PCODE_FLAG_SET_F(info) & fPCodeFlag4000000)) 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 & (fPCodeFlag2 | fPCodeFlag4)) pc->flags |= fPCodeFlag20; 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(172, src->u.reg.object->name->name); else PPCError_Error(167, 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 & (fPCodeFlag2 | fPCodeFlag4 | 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 & (fPCodeFlag2 | fPCodeFlag4)) pc->flags |= fPCodeFlag20; 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) & fPCodeFlag8000000) pcsetrecordbit(pclastblock->lastPCode); else CError_Error(CErrorStr261); } if (ia->flags2 & IAFlagsB_2) { if (PCODE_FLAG_SET_F(pc) & fPCodeFlag4000000) setpcodeflags(fOverflow); // idk? else CError_Error(CErrorStr261); } if (ia->flags2 & IAFlagsB_4) { if (PCODE_FLAG_SET_T(pc) & fPCodeFlag20000000) { int i; for (i = 0; i < pc->argCount; i++) { if (pc->args[i].kind == PCOp_LABEL || pc->args[i].kind == PCOp_MEMORY) { PPCError_Error(177); break; } } setpcodeflags(fAbsolute); // idk? } else { CError_Error(CErrorStr261); } } if (ia->flags2 & IAFlagsB_8) { if (PCODE_FLAG_SET_T(pc) & fPCodeFlag2000000) { pcsetlinkbit(pclastblock->lastPCode); if (!(ia->flags & IAFlag2)) { pclastblock->lastPCode->flags &= ~fPCodeFlag8; pclastblock->lastPCode->flags |= fPCodeFlag1; } makes_call = 1; } else { CError_Error(CErrorStr261); } } if (ia->flags2 & IAFlagsB_10) setpcodeflags(fPCodeFlag8000000); if (ia->flags2 & IAFlagsB_20) setpcodeflags(fPCodeFlag4000000); 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 & (fPCodeFlag2 | fPCodeFlag4)) { 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 & fPCodeFlag80000000) return 4; if (opcodeinfo[ia->opcode].flags & fPCodeFlag40000000) return 8; if (opcodeinfo[ia->opcode].flags & (fPCodeFlag80000000 | fPCodeFlag40000000)) 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 & fPCodeFlag20) { if (info->flags & fPCodeFlag2) effects->x1 = 1; if (info->flags & fPCodeFlag4) effects->x2 = 1; } if (PCODE_FLAG_SET_T(info) & fPCodeFlag2000000) { if (ia->flags2 & IAFlagsB_8) effects->x4 = 1; else if ((info->flags & fPCodeFlag8) || (info->flags & fPCodeFlag4)) 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 & fPCodeFlag2) { 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 & (fPCodeFlag1 | fPCodeFlag8))) { 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 & fPCodeFlag4) { 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 & (fPCodeFlag1 | fPCodeFlag8)) && (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 & (fPCodeFlag4 | 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; }