summaryrefslogtreecommitdiff
path: root/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c')
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c680
1 files changed, 680 insertions, 0 deletions
diff --git a/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c
new file mode 100644
index 0000000..46a95d2
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/InlineAsm.c
@@ -0,0 +1,680 @@
+#include "compiler/InlineAsm.h"
+#include "compiler/InlineAsmPPC.h"
+#include "compiler/GCCInlineAsm.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInit.h"
+#include "compiler/CInline.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/COptimizer.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CScope.h"
+#include "compiler/PCode.h"
+#include "compiler/Registers.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/types.h"
+
+int allow_array_expressions = 1;
+
+int backtracking;
+jmp_buf backtrack;
+jmp_buf InlineAsm_assemblererror;
+static int ASMstmtnb;
+
+void AssemblerError(void) {
+ longjmp(InlineAsm_assemblererror, 1);
+}
+
+void InlineAsm_SyntaxError(short code) {
+ if (backtracking)
+ longjmp(backtrack, 1);
+
+ if (tk == TK_EOL || tk == ';')
+ code = CErrorStr112;
+ CError_Error(code);
+}
+
+CLabel *InlineAsm_LookupLabel(HashNameNode *name) {
+ CLabel *label;
+
+ for (label = Labels; label; label = label->next) {
+ if (name == label->name)
+ break;
+ }
+
+ return label;
+}
+
+CLabel *InlineAsm_DeclareLabel(HashNameNode *name) {
+ CLabel *label = newlabel();
+ label->name = name;
+ label->next = Labels;
+ Labels = label;
+ return label;
+}
+
+static void InlineAsm_DefineLabel(HashNameNode *name) {
+ CLabel *label;
+ Statement *stmt;
+
+ label = InlineAsm_LookupLabel(name);
+ if (!label) {
+ label = InlineAsm_DeclareLabel(name);
+ } else {
+ if (label->stmt)
+ CError_Error(CErrorStr171, name->name);
+ }
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = label;
+ label->stmt = stmt;
+}
+
+Boolean InlineAsm_LookupSymbolOrTag(HashNameNode *name, IALookupResult *result, Boolean allow_tag) {
+ ObjBase *obj;
+ NameSpace *nspace;
+ NameSpaceObjectList *list;
+
+ result->name = name;
+ result->object = NULL;
+ result->label = NULL;
+ result->type = NULL;
+ result->has_value = 0;
+
+ if ((result->label = InlineAsm_LookupLabel(name)))
+ return 1;
+
+ for (nspace = cscope_current; nspace; nspace = nspace->parent) {
+ if ((list = CScope_FindName(nspace, name))) {
+ obj = list->object;
+ switch (obj->otype) {
+ case OT_ENUMCONST:
+ result->has_value = 1;
+ result->value = OBJ_ENUM_CONST(list->object)->val.lo;
+ return 1;
+ case OT_OBJECT:
+ if (OBJECT(obj)->datatype == DABSOLUTE) {
+ result->has_value = 1;
+ result->value = OBJECT(obj)->u.address;
+ } else {
+ if (OBJECT(obj)->datatype == DDATA && (OBJECT(obj)->qual & Q_INLINE_DATA))
+ CInit_ExportConst(OBJECT(obj));
+ result->object = OBJECT(obj);
+ }
+ return 1;
+ case OT_TYPE:
+ result->type = OBJ_TYPE(obj)->type;
+ return 1;
+ case OT_TYPETAG:
+ if (allow_tag) {
+ result->type = OBJ_TYPE_TAG(obj)->type;
+ return 1;
+ }
+ case OT_NAMESPACE:
+ case OT_MEMBERVAR:
+ return 0;
+ default:
+ CError_FATAL(245);
+ }
+ }
+ }
+
+ return 0;
+}
+
+Boolean InlineAsm_LookupSymbol(HashNameNode *name, IALookupResult *result) {
+ return InlineAsm_LookupSymbolOrTag(name, result, 0);
+}
+
+static ObjMemberVar *isclassmember(TypeClass *tclass, HashNameNode *name) {
+ NameSpaceObjectList *list;
+
+ list = CScope_FindName(tclass->nspace, name);
+ return (list && list->object->otype == OT_MEMBERVAR) ? OBJ_MEMBER_VAR(list->object) : NULL;
+}
+
+SInt32 InlineAsm_StructMemberOffset(Type *type) {
+ StructMember *member;
+ ObjMemberVar *ivar;
+ SInt32 offset = 0;
+
+ do {
+ if (IS_TYPE_STRUCT(type)) {
+ tk = lex();
+ if (tk != TK_IDENTIFIER)
+ InlineAsm_SyntaxError(CErrorStr107);
+ member = ismember(TYPE_STRUCT(type), tkidentifier);
+ if (!member)
+ CError_Error(CErrorStr150, tkidentifier->name);
+ offset += member->offset;
+ type = member->type;
+ tk = lex();
+ } else if (IS_TYPE_CLASS(type)) {
+ tk = lex();
+ if (tk != TK_IDENTIFIER)
+ InlineAsm_SyntaxError(CErrorStr107);
+ ivar = isclassmember(TYPE_CLASS(type), tkidentifier);
+ if (!ivar)
+ CError_Error(CErrorStr150, tkidentifier->name);
+ offset += ivar->offset;
+ type = ivar->type;
+ tk = lex();
+ } else {
+ CError_Error(CErrorStr149);
+ }
+ } while (tk == '.');
+
+ return offset;
+}
+
+SInt32 InlineAsm_StructArrayMemberOffset(Type *type) {
+ StructMember *member;
+ ObjMemberVar *ivar;
+ SInt32 offset = 0;
+
+ do {
+ if (tk == '.') {
+ if (IS_TYPE_STRUCT(type)) {
+ tk = lex();
+ if (tk != TK_IDENTIFIER)
+ InlineAsm_SyntaxError(CErrorStr107);
+ member = ismember(TYPE_STRUCT(type), tkidentifier);
+ if (!member)
+ CError_Error(CErrorStr150, tkidentifier->name);
+ offset += member->offset;
+ type = member->type;
+ tk = lex();
+ } else if (IS_TYPE_CLASS(type)) {
+ tk = lex();
+ if (tk != TK_IDENTIFIER)
+ InlineAsm_SyntaxError(CErrorStr107);
+ ivar = isclassmember(TYPE_CLASS(type), tkidentifier);
+ if (!ivar)
+ CError_Error(CErrorStr150, tkidentifier->name);
+ offset += ivar->offset;
+ type = ivar->type;
+ tk = lex();
+ } else {
+ CError_Error(CErrorStr149);
+ }
+ } else {
+ if (IS_TYPE_ARRAY(type)) {
+ type = TPTR_TARGET(type);
+ tk = lex();
+ offset += type->size * InlineAsm_ConstantExpression();
+ if (tk != ']')
+ InlineAsm_SyntaxError(125);
+ tk = lex();
+ } else {
+ CError_Error(CErrorStr148);
+ }
+ }
+ } while (tk == '.' || tk == '[');
+
+ return offset;
+}
+
+SInt32 InlineAsm_StructPointerMemberOffset(Type *type) {
+ StructMember *member;
+ ObjMemberVar *ivar;
+ SInt32 offset;
+
+ tk = lex();
+ if (tk != TK_IDENTIFIER)
+ InlineAsm_SyntaxError(107);
+
+ if (IS_TYPE_STRUCT(type)) {
+ member = ismember(TYPE_STRUCT(type), tkidentifier);
+ if (!member)
+ CError_Error(CErrorStr150, tkidentifier->name);
+ offset = member->offset;
+ type = member->type;
+ } else {
+ ivar = isclassmember(TYPE_CLASS(type), tkidentifier);
+ if (!ivar)
+ CError_Error(CErrorStr150, tkidentifier->name);
+ offset = ivar->offset;
+ type = ivar->type;
+ }
+
+ tk = lex();
+ if (tk == '.' || tk == '[')
+ offset += InlineAsm_StructArrayMemberOffset(type);
+
+ return offset;
+}
+
+static SInt32 DiadicOperator(SInt32 left, short op, SInt32 right) {
+ CInt64 left64;
+ CInt64 right64;
+ CInt64_SetLong(&left64, left);
+ CInt64_SetLong(&right64, right);
+ right64 = CMach_CalcIntDiadic(TYPE(&stsignedint), left64, op, right64);
+ return CInt64_GetULong(&right64);
+}
+
+static SInt32 PrimaryExpression(void) {
+ IALookupResult result;
+ SInt32 value;
+
+ switch (tk) {
+ case TK_IDENTIFIER:
+ if (InlineAsm_LookupSymbol(tkidentifier, &result)) {
+ if (result.has_value) {
+ tk = lex();
+ return result.value;
+ }
+
+ if (result.type && (IS_TYPE_STRUCT(result.type) || IS_TYPE_CLASS(result.type))) {
+ tk = lex();
+ if (tk != '.')
+ InlineAsm_SyntaxError(120);
+ if (allow_array_expressions)
+ return InlineAsm_StructArrayMemberOffset(result.type);
+ else
+ return InlineAsm_StructMemberOffset(result.type);
+ } else {
+ InlineAsm_SyntaxError(124);
+ }
+ } else {
+ InlineAsm_SyntaxError(124);
+ }
+ break;
+ case TK_INTCONST:
+ value = tkintconst.lo;
+ tk = lex();
+ return value;
+ case TK_SIZEOF:
+ return scansizeof();
+ case '+':
+ tk = lex();
+ return PrimaryExpression();
+ case '-':
+ tk = lex();
+ return -PrimaryExpression();
+ case '!':
+ tk = lex();
+ return PrimaryExpression() == 0;
+ case '~':
+ tk = lex();
+ return ~PrimaryExpression();
+ case '(':
+ tk = lex();
+ value = InlineAsm_ConstantExpression();
+ if (tk != ')')
+ InlineAsm_SyntaxError(115);
+ tk = lex();
+ return value;
+ default:
+ InlineAsm_SyntaxError(120);
+ }
+
+ return 0;
+}
+
+static SInt32 ConstantExpressionTail(SInt32 value) {
+ SInt32 right;
+ short left_token;
+ short right_prec;
+
+ while (1) {
+ left_token = tk;
+ tk = lex();
+ right = PrimaryExpression();
+
+ right_prec = GetPrec(tk);
+ if (right_prec == 0)
+ return DiadicOperator(value, left_token, right);
+
+ if (GetPrec(left_token) >= right_prec) {
+ value = DiadicOperator(value, left_token, right);
+ } else {
+ value = DiadicOperator(value, left_token, ConstantExpressionTail(right));
+ if (GetPrec(tk) == 0)
+ return value;
+ }
+ }
+}
+
+SInt32 InlineAsm_ConstantExpression(void) {
+ SInt32 value = PrimaryExpression();
+
+ if (GetPrec(tk) == 0)
+ return value;
+ else
+ return ConstantExpressionTail(value);
+}
+
+HashNameNode *MakeLocalLabel(CInt64 num) {
+ char buf[80];
+ sprintf(buf, "@%i_%i", ASMstmtnb, CInt64_GetULong(&num));
+ return GetHashNameNodeExport(buf);
+}
+
+static void ScanOptionalLabel(void) {
+ if (tk == TK_INTCONST) {
+ if (lookahead() == ':') {
+ InlineAsm_DefineLabel(MakeLocalLabel(tkintconst));
+ tk = lex();
+ tk = lex();
+ }
+ } else {
+ if (tkidentifier->name[0] == '@') {
+ InlineAsm_DefineLabel(tkidentifier);
+ tk = lex();
+ if (tk == ':')
+ tk = lex();
+ } else {
+ HashNameNode *name = tkidentifier;
+ short t = lookahead();
+ tkidentifier = name;
+ if (t == ':') {
+ InlineAsm_DefineLabel(name);
+ tk = lex();
+ tk = lex();
+ }
+ }
+ }
+}
+
+static void ScanStatements(volatile short endToken, AssemblerType mode) {
+ if (setjmp(InlineAsm_assemblererror)) {
+ while (tk != TK_EOL && tk != endToken && tk != '}' && tk)
+ tk = lex();
+ if (tk == ';' || tk == TK_EOL)
+ tk = lex();
+ } else {
+ InlineAsm_Initialize(mode);
+ InlineAsm_gccmode = 0;
+ if (setjmp(InlineAsm_assemblererror)) {
+ while (tk != ';' && tk != TK_EOL && tk != endToken && tk != '}' && tk)
+ tk = lex();
+ if (tk == ';' || tk == TK_EOL)
+ tk = lex();
+ }
+
+ while (tk && tk != endToken) {
+ backtracking = 0;
+ sourceoffset = CPrep_GetFileOffsetInfo(&cparser_fileoffset);
+ if (tk == '"') {
+ if (InlineAsm_gccmode) {
+ tk = lex();
+ InlineAsm_gcc_parse();
+ } else {
+ InlineAsm_gccmode = 1;
+ copts.cplusplus = 0;
+ copts.asmpoundcomment = 1;
+ tk = lex();
+ }
+ }
+
+ if (tk == '.') {
+ InlineAsm_ScanAssemblyDirective();
+ } else if (tk == TK_IDENTIFIER) {
+ ScanOptionalLabel();
+ if (tk == TK_IDENTIFIER)
+ InlineAsm_ScanAssemblyInstruction();
+ } else if (tk == TK_INTCONST) {
+ ScanOptionalLabel();
+ if (tk == TK_IDENTIFIER)
+ InlineAsm_ScanAssemblyInstruction();
+ }
+
+ if (InlineAsm_gccmode && tk == '"') {
+ tk = lex();
+ InlineAsm_gcc_parse();
+ }
+
+ if (tk == ';' || tk == TK_EOL) {
+ CPrep_TokenStreamFlush();
+ tk = lex();
+ } else if (tk != endToken) {
+ if (endToken == ')')
+ CError_Error(CErrorStr115);
+ else
+ CError_Error(CErrorStr113);
+ }
+ }
+ }
+}
+
+void InlineAsm_ScanStatements(volatile short endToken) {
+ ScanStatements(endToken, AssemblerType_0);
+}
+
+void InlineAsm_ScanFunction(volatile short endToken) {
+ ScanStatements(endToken, AssemblerType_1);
+}
+
+void InlineAsm_Assemble(void) {
+ short token = (tk == '(') ? ')' : '}';
+ char save_pc = copts.asmpoundcomment;
+ char save_cpp = copts.cplusplus;
+
+ cprep_nostring = 1;
+ CFunc_AppendStatement(ST_NOP);
+ first_ST_ASM = curstmt;
+ ASMstmtnb++;
+
+ cprep_eoltokens = 1;
+ in_assembler = 1;
+ tk = lex();
+ InlineAsm_ScanStatements(token);
+ in_assembler = 0;
+ cprep_eoltokens = 0;
+ cprep_nostring = 0;
+
+ copts.asmpoundcomment = save_pc;
+ copts.cplusplus = save_cpp;
+}
+
+void InlineAsm_PackAsmStatement(Statement *stmt, Statement *first, void **output, SInt32 *outsize) {
+ InlineAsm *src;
+ InlineAsm *dest;
+ IAOperand *op;
+ SInt32 i;
+ SInt32 size;
+
+ src = (InlineAsm *) stmt->expr;
+ size = sizeof(InlineAsm) + sizeof(IAOperand) * src->argcount;
+ dest = galloc(size);
+ memcpy(dest, src, size);
+
+ for (i = 0, op = dest->args; i < dest->argcount; i++, op++) {
+ switch (op->type) {
+ case IAOpnd_0:
+ break;
+ case IAOpnd_Reg:
+ case IAOpnd_4:
+ op->u.reg.object = (Object *) CInline_GetLocalID(op->u.reg.object);
+ break;
+ case IAOpnd_Lab:
+ op->u.lab.label = (CLabel *) CInline_GetStatementNumber(first, op->u.lab.label->stmt);
+ break;
+ case IAOpnd_LabDiff:
+ op->u.labdiff.label1 = (CLabel *) CInline_GetStatementNumber(first, op->u.labdiff.label1->stmt);
+ op->u.labdiff.label2 = (CLabel *) CInline_GetStatementNumber(first, op->u.labdiff.label2->stmt);
+ break;
+ }
+ }
+
+ *output = dest;
+ *outsize = size;
+}
+
+void InlineAsm_UnpackAsmStatement(Statement *stmt, CLabel **labelArray, Boolean flag, void *data, SInt32 size) {
+ InlineAsm *ia;
+ IAOperand *op;
+ SInt32 i;
+
+ ia = galloc(size);
+ memcpy(ia, data, size);
+
+ for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+ switch (op->type) {
+ case IAOpnd_0:
+ break;
+ case IAOpnd_Reg:
+ case IAOpnd_4:
+ op->u.reg.object = CInline_GetLocalObj((SInt32) op->u.reg.object, flag);
+ break;
+ case IAOpnd_Lab:
+ op->u.lab.label = labelArray[(SInt16) op->u.lab.label];
+ break;
+ case IAOpnd_LabDiff:
+ op->u.labdiff.label1 = labelArray[(SInt16) op->u.labdiff.label1];
+ op->u.labdiff.label2 = labelArray[(SInt16) op->u.labdiff.label2];
+ break;
+ }
+ }
+
+ stmt->expr = (ENode *) ia;
+}
+
+void InlineAsm_CheckLocalUsage(Statement *stmt) {
+ InlineAsm *ia = (InlineAsm *) stmt->expr;
+ IAOperand *op;
+ SInt32 i;
+
+ for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+ switch (op->type) {
+ case IAOpnd_Reg:
+ if (op->u.reg.object)
+ SetVarUsage(op->u.reg.object, 0);
+ break;
+ case IAOpnd_4:
+ SetVarUsage(op->u.obj.obj, 1);
+ break;
+ }
+ }
+}
+
+CLabel *InlineAsm_GetReferencedLabel(Statement *stmt) {
+ InlineAsm *ia = (InlineAsm *) stmt->expr;
+ IAOperand *op;
+ SInt32 i;
+
+ for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+ if (op->type == IAOpnd_Lab)
+ return op->u.lab.label;
+ if (op->type == IAOpnd_LabDiff)
+ return op->u.labdiff.label1;
+ }
+
+ return NULL;
+}
+
+CLabel *InlineAsm_GetReferencedLabel2(Statement *stmt) {
+ InlineAsm *ia = (InlineAsm *) stmt->expr;
+ IAOperand *op;
+ SInt32 i;
+
+ for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+ if (op->type == IAOpnd_LabDiff)
+ return op->u.labdiff.label2;
+ }
+
+ return NULL;
+}
+
+Object *InlineAsm_GetObjectOffset(InlineAsm *ia, SInt32 index, SInt32 *offset) {
+ IAOperand *op;
+ SInt32 i;
+ SInt32 counter;
+
+ for (i = 0, counter = 0, op = ia->args; i < ia->argcount; i++, op++) {
+ if (op->type == IAOpnd_3) {
+ if (counter++ == index) {
+ *offset = ((intptr_t) &op->u.obj.obj) - ((intptr_t) ia);
+ return op->u.obj.obj;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+char *InlineAsm_DumpStatement(Statement *stmt) {
+ static char buffer[1024];
+ InlineAsm *ia;
+ IAOperand *arg;
+ int i;
+ char ch;
+ SInt32 offset;
+
+ ia = (InlineAsm *) stmt->expr;
+
+ strcpy(buffer, "\"");
+ strcat(buffer, InlineAsm_GetMnemonic(ia));
+ strcat(buffer, "\"");
+
+ for (i = 0, arg = ia->args; i < ia->argcount; i++, arg++) {
+ char argbuf[1024];
+
+ switch (arg->type) {
+ case IAOpnd_Imm:
+ sprintf(argbuf, " imm(%ld)", arg->u.imm.value);
+ break;
+ case IAOpnd_Reg:
+ ch = ' ';
+ if (arg->u.reg.effect & EffectWrite) {
+ if (arg->u.reg.effect & EffectRead)
+ ch = '+';
+ else
+ ch = '=';
+ } else {
+ if (!(arg->u.reg.effect & EffectRead))
+ ch = '0';
+ }
+
+ if (arg->u.reg.object) {
+ sprintf(argbuf,
+ "%creg(%s)",
+ ch,
+ arg->u.reg.object->name->name);
+ } else {
+ sprintf(argbuf,
+ "%creg(%s%d)",
+ ch,
+ register_class_name[arg->u.reg.rclass],
+ arg->u.reg.num);
+ }
+ break;
+
+ case IAOpnd_3:
+ case IAOpnd_4:
+ if (arg->u.obj.offset > 0)
+ sprintf(argbuf, " obj(%s+%ld)", arg->u.obj.obj->name->name, arg->u.obj.offset);
+ else if (arg->u.obj.offset < 0)
+ sprintf(argbuf, " obj(%s-%ld)", arg->u.obj.obj->name->name, -arg->u.obj.offset);
+ else
+ sprintf(argbuf, " obj(%s)", arg->u.obj.obj->name->name);
+ break;
+
+ case IAOpnd_Lab:
+ sprintf(argbuf, " lab(%s)", arg->u.lab.label->uniquename->name);
+ break;
+
+ case IAOpnd_LabDiff:
+ offset = !arg->negated ? 0 : arg->u.labdiff.offset;
+ sprintf(argbuf,
+ " labdiff(%s-%s%c%d)",
+ arg->u.labdiff.label1->uniquename->name,
+ arg->u.labdiff.label2->uniquename->name,
+ (arg->negated == 1) ? '-' : '+',
+ offset
+ );
+ break;
+ }
+
+ strcat(buffer, argbuf);
+ }
+
+ return buffer;
+}