#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(); }