Begin work on asm label support.

This commit is contained in:
Christoffer Lerno
2024-11-23 17:10:37 +01:00
parent 9d99d556a1
commit b2724caeda
10 changed files with 54 additions and 16 deletions

View File

@@ -7,6 +7,13 @@
#define CAST_AND_EXTEND(x, n) \
(((int64_t)((x) << (64 - (n)))) >> (64 - (n)))
INLINE bool codegen_asm_label(Ast *ast)
{
if (ast->ast_kind != AST_ASM_LABEL) return false;
scratch_buffer_printf("${:private}%s.${:uid}:\n", ast->asm_label);
return true;
}
static inline void codegen_create_x86att_arg(AsmInlineBlock *block, unsigned input_offset, Expr *expr)
{
ExprAsmArg *arg = &expr->expr_asm_arg;
@@ -177,6 +184,7 @@ static inline char *codegen_create_x86_att_asm(AsmInlineBlock *block)
{
Ast *ast = astptr(next);
next = ast->next;
if (codegen_asm_label(ast)) continue;
scratch_buffer_append(ast->asm_stmt.instruction);
Expr** args = ast->asm_stmt.args;
unsigned arg_count = vec_size(args);
@@ -201,6 +209,7 @@ static inline char *codegen_create_aarch64_asm(AsmInlineBlock *block)
{
Ast *ast = astptr(next);
next = ast->next;
if (codegen_asm_label(ast)) continue;
scratch_buffer_append(ast->asm_stmt.instruction);
Expr** args = ast->asm_stmt.args;
unsigned arg_count = vec_size(args);
@@ -225,6 +234,7 @@ static inline char *codegen_create_riscv_asm(AsmInlineBlock *block)
{
Ast *ast = astptr(next);
next = ast->next;
if (codegen_asm_label(ast)) continue;
scratch_buffer_append(ast->asm_stmt.instruction);
Expr** args = ast->asm_stmt.args;
unsigned arg_count = vec_size(args);

View File

@@ -1376,8 +1376,8 @@ typedef struct
typedef struct
{
Clobbers clobbers;
const char *asm_block;
AstId asm_stmt;
Ast **labels;
ExprAsmArg **output_vars;
ExprAsmArg **input;
} AsmInlineBlock;
@@ -1454,8 +1454,10 @@ typedef struct Ast_
union
{
FlowCommon flow; // Shared struct
AstAsmBlock asm_block_stmt;
AstAsmStmt asm_stmt;
const char *asm_label;
AstAssertStmt assert_stmt; // 16
AstCaseStmt case_stmt; // 32
AstCompoundStmt compound_stmt; // 12

View File

@@ -727,6 +727,7 @@ RETRY:
MACRO_COPY_EXPRID(ast->nextcase_stmt.expr);
break;
case AST_NOP_STMT:
case AST_ASM_LABEL:
break;
case AST_BLOCK_EXIT_STMT:
case AST_RETURN_STMT:

View File

@@ -188,6 +188,7 @@ typedef enum
AST_POISONED,
AST_ASM_STMT,
AST_ASM_BLOCK_STMT,
AST_ASM_LABEL,
AST_ASSERT_STMT,
AST_BREAK_STMT,
AST_CASE_STMT,

View File

@@ -1612,6 +1612,7 @@ void llvm_emit_stmt(GenContext *c, Ast *ast)
case AST_FOREACH_STMT:
case AST_CONTRACT:
case AST_ASM_STMT:
case AST_ASM_LABEL:
case AST_CONTRACT_FAULT:
case AST_CASE_STMT:
case AST_DEFAULT_STMT:

View File

@@ -380,6 +380,14 @@ static inline Expr *parse_asm_expr(ParseContext *c)
static inline Ast *parse_asm_stmt(ParseContext *c)
{
Ast *asm_stmt = ast_new_curr(c, AST_ASM_STMT);
if (tok_is(c, TOKEN_CONST_IDENT))
{
asm_stmt->asm_label = symstr(c);
advance_and_verify(c, TOKEN_CONST_IDENT);
asm_stmt->ast_kind = AST_ASM_LABEL;
TRY_CONSUME_OR_RET(TOKEN_COLON, "Expected a ':' to terminate the label.", poisoned_ast);
return asm_stmt;
}
if (!tok_is(c, TOKEN_IDENT) && !tok_is(c, TOKEN_INT))
{
PRINT_ERROR_HERE("Expected an asm instruction here.");

View File

@@ -184,8 +184,7 @@ static inline bool sema_check_asm_arg_addr(SemaContext *context, AsmInlineBlock
{
if (!arg_type.is_address)
{
SEMA_ERROR(expr, "An address cannot appear in this slot.");
return false;
RETURN_SEMA_ERROR(expr, "An address cannot appear in this slot.");
}
ExprAsmArg *asm_arg = &expr->expr_asm_arg;
Expr *base = exprptr(asm_arg->base);
@@ -207,8 +206,7 @@ static inline bool sema_check_asm_arg_addr(SemaContext *context, AsmInlineBlock
TODO
break;
default:
SEMA_ERROR(expr, "Expected a register here.");
return false;
RETURN_SEMA_ERROR(expr, "Expected a register here.");
}
Expr *index = exprptrzero(asm_arg->idx);
@@ -232,8 +230,7 @@ static inline bool sema_check_asm_arg_addr(SemaContext *context, AsmInlineBlock
}
if (bit_size != index_size)
{
SEMA_ERROR(index, "Expected the same register size as for the base value.");
return false;
RETURN_SEMA_ERROR(index, "Expected the same register size as for the base value.");
}
}
if ((compiler.platform.arch == ARCH_TYPE_RISCV32 ||
@@ -243,8 +240,7 @@ static inline bool sema_check_asm_arg_addr(SemaContext *context, AsmInlineBlock
if ((asm_arg->neg_offset && asm_arg->offset > abs(INT12_MIN)) ||
(!asm_arg->neg_offset && asm_arg->offset > INT12_MAX))
{
SEMA_ERROR(expr, "RISC-V offset limited to 12-bits signed.");
return false;
RETURN_SEMA_ERROR(expr, "RISC-V offset limited to 12-bits signed.");
}
}
@@ -256,15 +252,10 @@ static inline bool sema_check_asm_arg_reg(SemaContext *context, AsmInlineBlock *
{
const char *name = expr->expr_asm_arg.reg.name;
AsmRegister *reg = expr->expr_asm_arg.reg.ref = asm_reg_by_name(&compiler.platform, name);
if (!reg)
{
SEMA_ERROR(expr, "Expected a valid register name.");
return false;
}
if (!reg) RETURN_SEMA_ERROR(expr, "Expected a valid register name.");
if (!sema_reg_is_valid_in_slot(reg, arg_type))
{
SEMA_ERROR(expr, "'%s' is not valid in this slot.", reg->name);
return false;
RETURN_SEMA_ERROR(expr, "'%s' is not valid in this slot.", reg->name);
}
if (arg_type.is_write)
{

View File

@@ -3700,6 +3700,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *er
continue;
case AST_POISONED:
case AST_ASM_STMT:
case AST_ASM_LABEL:
case AST_ASM_BLOCK_STMT:
case AST_ASSERT_STMT:
case AST_BREAK_STMT:

View File

@@ -111,6 +111,7 @@ static void sema_trace_stmt_liveness(Ast *ast)
sema_trace_stmt_liveness(astptr(ast->defer_stmt.body));
return;
case AST_NOP_STMT:
case AST_ASM_LABEL:
return;
case AST_COMPOUND_STMT:
sema_trace_stmt_chain_liveness(ast->compound_stmt.first_stmt);

View File

@@ -51,6 +51,22 @@ static bool sema_analyse_require(SemaContext *context, Ast *directive, AstId **a
static bool sema_analyse_ensure(SemaContext *context, Ast *directive);
static bool sema_analyse_optional_returns(SemaContext *context, Ast *directive);
static inline bool sema_analyse_asm_label(SemaContext *context, AsmInlineBlock *block, Ast *label)
{
const char *name = label->asm_label;
FOREACH(Ast *, other, block->labels)
{
if (name == other->asm_label)
{
SEMA_ERROR(label, "Duplicate ASM label '%s'.", name);
SEMA_NOTE(other, "The previous definition was here.");
return false;
}
}
vec_add(block->labels, label);
return true;
}
static inline bool sema_analyse_asm_stmt(SemaContext *context, Ast *stmt)
{
if (stmt->asm_block_stmt.is_string) return sema_analyse_asm_string_stmt(context, stmt);
@@ -68,6 +84,11 @@ static inline bool sema_analyse_asm_stmt(SemaContext *context, Ast *stmt)
{
Ast *ast = astptr(ast_id);
ast_id = ast->next;
if (ast->ast_kind == AST_ASM_LABEL)
{
sema_analyse_asm_label(context, block, ast);
continue;
}
if (!sema_analyse_asm(context, block, ast)) return false;
}
return true;
@@ -2910,6 +2931,7 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state
case AST_IF_CATCH_SWITCH_STMT:
case AST_CONTRACT:
case AST_ASM_STMT:
case AST_ASM_LABEL:
case AST_CONTRACT_FAULT:
UNREACHABLE
case AST_DECLS_STMT: