diff options
Diffstat (limited to 'compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c')
-rw-r--r-- | compiler_and_linker/BackEnd/PowerPC/InlineAssembler/GCCInlineAsm.c | 230 |
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(); +} |