diff --git a/src/check_asm.cpp b/src/check_asm.cpp index b159ef1a8..a9988be18 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -426,7 +426,8 @@ gb_internal AsmTemplateEntityDeclKind check_asm_find_kind(Entity *entity, Array< }; -gb_internal void check_asm_specs(CheckerContext *ctx, Scope *scope, Slice const &specs, Array *asm_template_entity_decls) { +template +gb_internal void check_asm_specs(AsmCtx *asm_ctx, CheckerContext *ctx, Scope *scope, Slice const &specs, Array *asm_template_entity_decls) { StringSet pin_set = {}; string_set_init(&pin_set, specs.count); defer (string_set_destroy(&pin_set)); @@ -465,6 +466,8 @@ gb_internal void check_asm_specs(CheckerContext *ctx, Scope *scope, Slice ast_node(reg, AsmRegister, spec->value); pin = reg->name.string; if (pin.len != 0) { + Operand op = {}; + check_register(asm_ctx, &op, reg); if (string_set_update(&pin_set, pin)) { error(spec->value, "Pinned register %%%.*s has already been assigned", LIT(pin)); } @@ -1280,15 +1283,36 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity entity->type = type; + + bool has_side_effects = false; + bool is_align_stack = false; auto *clobber_registers_set = &entity->AsmTemplate.clobber_registers_set; - check_asm_specs(ctx, ate->param_scope, at->specs, &ate->decls); + check_asm_specs(asm_ctx, ctx, ate->param_scope, at->specs, &ate->decls); { // check clobbers bool clobber_cc = false; bool clobber_memory = false; for (Ast *clobber_ : at->clobbers) { ast_node(clobber, AsmClobber, clobber_); + + if (clobber->value == nullptr) { + if (clobber->name.string == "side_effects") { + if (has_side_effects) { + error(clobber->name, "#side_effects has already been defined as an asm specification"); + } + has_side_effects = true; + } else if (clobber->name.string == "align_stack") { + if (is_align_stack) { + error(clobber->name, "#align_stack has already been defined as an asm specification"); + } + is_align_stack = true; + } else { + error(clobber->name, "Unknown clobber directive '#%.*s'", LIT(clobber->name.string)); + } + continue; + } + switch (clobber->value->kind) { case_ast_node(asm_reg, AsmRegister, clobber->value) String reg = asm_reg->name.string; @@ -1321,8 +1345,10 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity } } - entity->AsmTemplate.clobber_cc = clobber_cc; - entity->AsmTemplate.clobber_memory = clobber_memory; + entity->AsmTemplate.clobber_cc = clobber_cc; + entity->AsmTemplate.clobber_memory = clobber_memory; + entity->AsmTemplate.has_side_effects = has_side_effects; + entity->AsmTemplate.is_align_stack = is_align_stack; } // collect label decls diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cf6c45d05..37eccae96 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -13633,12 +13633,6 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan } } - if (at->has_side_effects) { - str = gb_string_appendc(str, " #side_effects"); - } - if (at->is_align_stack) { - str = gb_string_appendc(str, " #align_stack"); - } if (at->specs.count) { str = gb_string_append_rune(str, '['); for_array(j, at->specs) { @@ -13688,8 +13682,12 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan case_end; case_ast_node(clobber, AsmClobber, node); - str = gb_string_appendc(str, "#clobber "); - str = write_expr_to_string(str, clobber->value, shorthand); + str = gb_string_appendc(str, "#"); + str = gb_string_append_length(str, clobber->name.string.text, clobber->name.string.len); + if (clobber->value) { + str = gb_string_appendc(str, " "); + str = write_expr_to_string(str, clobber->value, shorthand); + } case_end; case_ast_node(label, AsmLabelDecl, node); diff --git a/src/entity.cpp b/src/entity.cpp index e5f31eb7b..49faed0bd 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -556,8 +556,6 @@ gb_internal Entity *alloc_entity_asm_template(Scope *scope, Token token, Type *t GB_ASSERT(node->kind == Ast_AsmTemplate); Entity *entity = alloc_entity(Entity_AsmTemplate, scope, token, type); entity->AsmTemplate.node = node; - entity->AsmTemplate.has_side_effects = node->AsmTemplate.has_side_effects; - entity->AsmTemplate.is_align_stack = node->AsmTemplate.is_align_stack; return entity; } diff --git a/src/parser.cpp b/src/parser.cpp index 573566237..bea018906 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2590,34 +2590,8 @@ gb_internal Ast *parse_asm_signature(AstFile *f, Token asm_token) { gb_internal Ast *parse_asm_template(AstFile *f) { Token token = expect_token(f, Token_asm); - bool has_side_effects = false; - bool is_align_stack = false; - Ast *signature = parse_asm_signature(f, token); - while (f->curr_token.kind == Token_Hash) { - advance_token(f); - if (f->curr_token.kind == Token_Ident) { - Token token = advance_token(f); - String name = token.string; - if (name == "side_effects") { - if (has_side_effects) { - syntax_error(token, "Duplicate directive on inline asm expression: '#side_effects'"); - } - has_side_effects = true; - } else if (name == "align_stack") { - if (is_align_stack) { - syntax_error(token, "Duplicate directive on inline asm expression: '#align_stack'"); - } - is_align_stack = true; - } else { - syntax_error(token, "Invalid directive on inline asm expression: '#%.*s'", LIT(token.string)); - } - } else { - syntax_error(f->curr_token, "Expected an identifier after hash"); - } - } - Slice asm_specs = {}; Slice asm_clobbers = {}; @@ -2674,15 +2648,23 @@ gb_internal Ast *parse_asm_template(AstFile *f) { spec->AsmSpec.value = value; } else if (f->curr_token.kind == Token_Hash) { Token hash = expect_token(f, Token_Hash); - Token clobber_token = expect_token(f, Token_Ident); - if (clobber_token.string != "clobber") { - syntax_error(clobber_token, "Expected #clobber, got '%.*s'", LIT(clobber_token.string)); - } else { + Token name = expect_token(f, Token_Ident); + + if (name.string == "side_effects" || + name.string == "align_stack") { + Ast *clobber = alloc_ast_node(f, Ast_AsmClobber); + clobber->AsmClobber.token = hash; + clobber->AsmClobber.name = name; + array_add(&clobbers, clobber); + } else if (name.string == "clobber") { Ast *value = parse_asm_operand(f, false); Ast *clobber = alloc_ast_node(f, Ast_AsmClobber); clobber->AsmClobber.token = hash; + clobber->AsmClobber.name = name; clobber->AsmClobber.value = value; array_add(&clobbers, clobber); + } else { + syntax_error(name, "Expected #clobber, #side_effects, or #align_stack, got '%.*s'", LIT(name.string)); } } else { syntax_error(f->curr_token, "Expected am asm specification which begins with a identifier, got '%.*s'", LIT(f->curr_token.string)); @@ -2732,8 +2714,6 @@ gb_internal Ast *parse_asm_template(AstFile *f) { Ast *asm_template = alloc_ast_node(f, Ast_AsmTemplate); asm_template->AsmTemplate.token = token; - asm_template->AsmTemplate.has_side_effects = has_side_effects; - asm_template->AsmTemplate.is_align_stack = is_align_stack; asm_template->AsmTemplate.signature = signature; asm_template->AsmTemplate.specs = asm_specs; asm_template->AsmTemplate.clobbers = asm_clobbers; diff --git a/src/parser.hpp b/src/parser.hpp index aa75e3df4..0c884c72c 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -470,8 +470,6 @@ struct AstSplitArgs { }) \ AST_KIND(AsmTemplate, "asm template", struct { \ Token token; \ - bool has_side_effects; \ - bool is_align_stack; \ Ast * signature; \ Slice specs; \ Slice clobbers; \ @@ -490,6 +488,7 @@ struct AstSplitArgs { }) \ AST_KIND(AsmClobber, "asm clobber", struct { \ Token token; \ + Token name; \ Ast * value; \ }) \ AST_KIND(AsmLabelDecl, "asm label declaration", struct { \ diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp index 4f07c8e8e..b58b07c6a 100644 --- a/src/parser_pos.cpp +++ b/src/parser_pos.cpp @@ -177,7 +177,7 @@ Token ast_end_token(Ast *node) { return node->AsmRegister.name; case Ast_AsmSpec: if (node->AsmSpec.value) { - return ast_end_token(node->AsmSpec.value); + return ast_end_token(node->AsmSpec.value); } if (node->AsmSpec.type) { return ast_end_token(node->AsmSpec.type); @@ -187,7 +187,10 @@ Token ast_end_token(Ast *node) { } return ast_end_token(node->AsmSpec.name); case Ast_AsmClobber: - return ast_end_token(node->AsmClobber.value); + if (node->AsmClobber.value) { + return ast_end_token(node->AsmClobber.value); + } + return node->AsmClobber.name; case Ast_AsmLabelDecl: return ast_end_token(node->AsmLabelDecl.name); case Ast_AsmInstruction: