mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Begin work on asm label support.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user