mirror of https://git.wuffs.org/MWCC
2587 lines
83 KiB
C
2587 lines
83 KiB
C
#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;
|
|
}
|
|
|