// Copyright (c) 2022 Christoffer Lerno. All rights reserved. // Use of this source code is governed by a LGPLv3.0 // a copy of which can be found in the LICENSE file. #include "codegen_internal.h" static inline void codegen_create_x86att_arg(AsmInlineBlock *block, unsigned input_offset, Expr *expr) { ExprAsmArg *arg = &expr->expr_asm_arg; switch (arg->kind) { case ASM_ARG_INT: scratch_buffer_append("$$"); scratch_buffer_append_unsigned_int(arg->value); return; case ASM_ARG_REG: { AsmRegister *reg = arg->reg.ref; scratch_buffer_append_char('%'); scratch_buffer_append(®->name[1]); return; } case ASM_ARG_VALUE: scratch_buffer_append_char('$'); scratch_buffer_append_unsigned_int(arg->index + input_offset); return; case ASM_ARG_MEMVAR: case ASM_ARG_REGVAR: scratch_buffer_append_char('$'); if (arg->ident.is_input && !arg->ident.copy_output) { scratch_buffer_append_unsigned_int(arg->index + input_offset); } else { scratch_buffer_append_unsigned_int(arg->index); } return; case ASM_ARG_ADDR: if (arg->offset) { if (arg->neg_offset) scratch_buffer_append_char('-'); scratch_buffer_append_unsigned_int(arg->offset); } scratch_buffer_append_char('('); if (arg->base) { codegen_create_x86att_arg(block, input_offset, exprptr(arg->base)); } if (arg->idx) { scratch_buffer_append_char(','); codegen_create_x86att_arg(block, input_offset, exprptr(arg->idx)); scratch_buffer_append_char(','); switch (arg->offset_type) { case ASM_SCALE_1: scratch_buffer_append_char('1'); break; case ASM_SCALE_2: scratch_buffer_append_char('2'); break; case ASM_SCALE_4: scratch_buffer_append_char('4'); break; case ASM_SCALE_8: scratch_buffer_append_char('8'); break; default: UNREACHABLE } } scratch_buffer_append_char(')'); return; case ASM_ARG_ADDROF: TODO } UNREACHABLE } static inline char *codegen_create_x86_att_asm(AsmInlineBlock *block) { AstId next = block->asm_stmt; scratch_buffer_clear(); unsigned input_arg_offset = vec_size(block->output_vars); while (next) { Ast *ast = astptr(next); next = ast->next; scratch_buffer_append(ast->asm_stmt.instruction); Expr** args = ast->asm_stmt.args; unsigned arg_count = vec_size(args); scratch_buffer_append_char(' '); if (arg_count > 1) { codegen_create_x86att_arg(block, input_arg_offset, args[1]); scratch_buffer_append(", "); } if (arg_count) { codegen_create_x86att_arg(block, input_arg_offset, args[0]); } scratch_buffer_append_char('\n'); } return scratch_buffer_to_string(); } const char *codegen_create_asm(Ast *ast, ClobberList *clobber_list) { assert(ast->ast_kind == AST_ASM_BLOCK_STMT); scratch_buffer_clear(); AsmInlineBlock *block = ast->asm_block_stmt.block; if (platform_target.arch == ARCH_TYPE_X86_64 || platform_target.arch == ARCH_TYPE_X86) { return codegen_create_x86_att_asm(block); } UNREACHABLE }