summaryrefslogtreecommitdiff
path: root/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c')
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c230
1 files changed, 230 insertions, 0 deletions
diff --git a/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c
new file mode 100644
index 0000000..897df9b
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c
@@ -0,0 +1,230 @@
+#include "compiler/GCCInlineAsm.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInt64.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/InlineAsm.h"
+#include "compiler/objects.h"
+
+Statement *first_ST_ASM;
+IALookupResult gcc_name_list[20];
+int gcc_name_list_index;
+
+void InlineAsm_SkipComment(void) {
+ while (1) {
+ if (tk != '/')
+ break;
+ if (lookahead() != '*')
+ break;
+
+ tk = lex();
+ while (!((tk = lex()) == '*' && (tk = lex()) == '/')) {
+ // nothing
+ }
+ tk = lex();
+ }
+}
+
+static char gcc_parse_attribute(void) {
+ char ch;
+
+ while (tk == TK_EOL)
+ tk = lex();
+
+ if (tk != '"')
+ CError_Error(CErrorStr105);
+
+ while ((tk = lex()) != TK_IDENTIFIER) {
+ // nothing
+ }
+
+ ch = tkidentifier->name[0];
+
+ if ((tk = lex()) != '"')
+ CError_Error(CErrorStr105);
+ tk = lex();
+
+ return ch;
+}
+
+static void gcc_parse_name(Boolean flag, char attribute) {
+ IALookupResult *nameentry;
+ ENode *expr;
+ Object *tempobj;
+ ENode *tempexpr;
+ Statement *stmt;
+
+ while (tk == TK_EOL)
+ tk = lex();
+
+ if (tk != '(')
+ CError_Error(CErrorStr114);
+
+ tk = lex();
+
+ if (flag) {
+ if (tk != TK_IDENTIFIER)
+ CError_Error(CErrorStr105);
+
+ InlineAsm_LookupSymbol(tkidentifier, &gcc_name_list[++gcc_name_list_index]);
+ if (gcc_name_list[gcc_name_list_index].object && gcc_name_list[gcc_name_list_index].object->u.var.info)
+ gcc_name_list[gcc_name_list_index].object->u.var.info->used = 1;
+
+ tk = lex();
+ } else {
+ in_assembler = 0;
+ cprep_nostring = 0;
+ nameentry = &gcc_name_list[++gcc_name_list_index];
+
+ expr = expression();
+ if (attribute == 'i' || attribute == 'I') {
+ if (!ENODE_IS(expr, EINTCONST))
+ CError_Error(CErrorStr144);
+ nameentry->value = CInt64_GetULong(&expr->data.intval);
+ nameentry->has_value = 1;
+ } else {
+ tempobj = create_temp_object(expr->rtype);
+ tempexpr = create_objectnode(tempobj);
+ if (tempobj->u.var.info)
+ tempobj->u.var.info->used = 1;
+ expr = makediadicnode(tempexpr, expr, EASS);
+
+ stmt = CFunc_InsertBeforeStatement(ST_EXPRESSION, first_ST_ASM);
+ first_ST_ASM = stmt->next;
+ if (!first_ST_ASM->next)
+ curstmt = first_ST_ASM;
+ stmt->expr = expr;
+
+ nameentry->name = tempobj->name;
+ nameentry->object = tempobj;
+ nameentry->label = NULL;
+ nameentry->type = NULL;
+ nameentry->has_value = 0;
+ }
+ }
+
+ cprep_nostring = 1;
+ in_assembler = 1;
+
+ if (tk != ')')
+ CError_Error(CErrorStr115);
+ tk = lex();
+}
+
+static void gcc_parse_expression(Boolean flag) {
+ while (1) {
+ gcc_parse_name(flag, gcc_parse_attribute());
+ if (tk != ',')
+ break;
+ tk = lex();
+ }
+}
+
+static void gcc_parse_input(void) {
+ if (tk == ':') {
+ if ((tk = lex()) == ':' || tk == ')' || tk == '}')
+ return;
+ gcc_parse_expression(0);
+ }
+}
+
+static void gcc_parse_output(void) {
+ if (tk == ':') {
+ if ((tk = lex()) == ':' || tk == ')' || tk == '}')
+ return;
+ gcc_parse_expression(1);
+ }
+}
+
+static void gcc_parse_killed(void) {
+ if (tk == ':') {
+ while (1) {
+ if ((tk = lex()) != '"')
+ return;
+
+ tk = lex();
+ while (1) {
+ if (tk == '"') {
+ if (lookahead() == ',') {
+ tk = lex();
+ break;
+ }
+ tk = lex();
+ return;
+ }
+ tk = lex();
+ }
+ }
+ }
+}
+
+static void gcc_replace_arg_st_asm(Statement *stmt) {
+ InlineAsm *ia;
+ int i;
+ IAOperand *op;
+ short effect;
+ short rclass;
+ SInt32 num;
+
+ if ((ia = (InlineAsm *) stmt->expr)) {
+ for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
+ switch (op->type) {
+ case IAOpnd_Imm:
+ case IAOpnd_Reg:
+ case IAOpnd_3:
+ case IAOpnd_4:
+ case IAOpnd_Lab:
+ break;
+
+ case IAOpnd_6:
+ if (op->u.unk6.unk4 == 2) {
+ effect = op->u.unk6.effect;
+ rclass = op->u.unk6.rclass;
+ num = op->u.unk6.num;
+ op->type = IAOpnd_Reg;
+ op->u.reg.effect = effect;
+ op->u.reg.rclass = rclass;
+ op->u.reg.object = NULL;
+ if (num <= gcc_name_list_index)
+ op->u.reg.object = gcc_name_list[num].object;
+ else
+ CError_Error(CErrorStr144);
+ op->u.reg.num = 0;
+ } else {
+ CError_FATAL(365);
+ }
+ break;
+
+ case IAOpnd_7:
+ op->type = IAOpnd_Imm;
+ op->u.imm.value = gcc_name_list[op->u.unk7.value].value;
+ break;
+ }
+ }
+ }
+}
+
+static void gcc_replace_arg(void) {
+ Statement *stmt;
+
+ for (stmt = first_ST_ASM; stmt; stmt = stmt->next) {
+ if (stmt->type == ST_ASM)
+ gcc_replace_arg_st_asm(stmt);
+ }
+}
+
+void InlineAsm_gcc_parse(void) {
+ gcc_name_list_index = -1;
+ cprep_eoltokens = 0;
+
+ if (tk == TK_EOL)
+ tk = lex();
+
+ gcc_parse_output();
+ gcc_parse_input();
+ gcc_parse_killed();
+ gcc_replace_arg();
+}