mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-26 15:01:31 +00:00
Add #no_init suffix directive for asm specifications.
This commit is contained in:
@@ -793,6 +793,26 @@ gb_internal void check_asm_specs(AsmCtx *asm_ctx, CheckerContext *ctx, Scope *sc
|
||||
error(spec->value, "Input parameters, and thus tied parameters, cannot be pinned to a flag style register");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (Ast *dir_ : spec->directives) {
|
||||
ast_node(dir, BasicDirective, dir_);
|
||||
String name = dir->name.string;
|
||||
if (name == "no_init") {
|
||||
i32 input_index = -1;
|
||||
check_asm_find_group(input, *asm_template_entity_decls, &input_index);
|
||||
if (input_index >= 0) {
|
||||
auto *i = &(*asm_template_entity_decls)[input_index];
|
||||
i->no_init = true;
|
||||
if (i->tie >= 0) {
|
||||
auto *o = &(*asm_template_entity_decls)[i->tie];
|
||||
o->no_init = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error(dir_, "Invalid directive for an asm specification, got '#%.*s'", LIT(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2451,6 +2471,9 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity
|
||||
// straight-line instruction stream. Seeded with input-pinned registers (they
|
||||
// carry their argument at entry); grows as instructions write registers.
|
||||
for (auto const &ed : ate->decls) {
|
||||
if (ed.no_init) {
|
||||
ptr_set_add(&asm_acc.defined_params, ed.entity);
|
||||
}
|
||||
switch (ed.param_group) {
|
||||
case AsmTemplateEntityDeclParamGroup_Input:
|
||||
if (ed.pin.len != 0) {
|
||||
@@ -2683,6 +2706,9 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity
|
||||
if (ed.tie >= 0) {
|
||||
continue;
|
||||
}
|
||||
if (ed.no_init) {
|
||||
continue;
|
||||
}
|
||||
if (!asm_acc.straight_line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -196,6 +196,8 @@ struct AsmTemplateEntityDecl {
|
||||
|
||||
i32 view_of; // total_index of the source operand this is a width-view of, else -1
|
||||
i32 view_bits; // the view width in bits, otherwise 0
|
||||
|
||||
bool no_init;
|
||||
};
|
||||
|
||||
// An Entity is a named "thing" in the language
|
||||
|
||||
@@ -533,10 +533,11 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) {
|
||||
case Ast_AsmRegister:
|
||||
break;
|
||||
case Ast_AsmSpec:
|
||||
n->AsmSpec.name = clone_ast(n->AsmSpec.name, f);
|
||||
n->AsmSpec.tied_name = clone_ast(n->AsmSpec.tied_name, f);
|
||||
n->AsmSpec.type = clone_ast(n->AsmSpec.type, f);
|
||||
n->AsmSpec.value = clone_ast(n->AsmSpec.value, f);
|
||||
n->AsmSpec.name = clone_ast(n->AsmSpec.name, f);
|
||||
n->AsmSpec.tied_name = clone_ast(n->AsmSpec.tied_name, f);
|
||||
n->AsmSpec.type = clone_ast(n->AsmSpec.type, f);
|
||||
n->AsmSpec.value = clone_ast(n->AsmSpec.value, f);
|
||||
n->AsmSpec.directives = clone_ast_array(n->AsmSpec.directives, f);
|
||||
break;
|
||||
case Ast_AsmClobber:
|
||||
n->AsmClobber.value = clone_ast(n->AsmClobber.value, f);
|
||||
@@ -2694,6 +2695,60 @@ gb_internal Ast *parse_asm_signature(AstFile *f, Token asm_token) {
|
||||
return ast_proc_type(f, asm_token, params, results, tags, cc, is_generic, diverging);
|
||||
}
|
||||
|
||||
gb_internal Ast *parse_asm_spec(AstFile *f) {
|
||||
Ast *name = parse_ident(f);
|
||||
Ast *tied_name = nullptr;
|
||||
Ast *type = nullptr;
|
||||
Ast *value = nullptr;
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
tied_name = parse_ident(f);
|
||||
}
|
||||
if (allow_token(f, Token_Colon)) {
|
||||
type = parse_type(f);
|
||||
}
|
||||
if (allow_token(f, Token_Eq)) {
|
||||
if (f->curr_token.kind == Token_Ident) {
|
||||
value = parse_ident(f);
|
||||
} else if (f->curr_token.kind == Token_Mod) {
|
||||
value = parse_asm_register(f);
|
||||
} else {
|
||||
error(f->curr_token, "Expected a register or scratch parameter");
|
||||
Ast *dummy = parse_expr(f, true);
|
||||
gb_unused(dummy);
|
||||
}
|
||||
}
|
||||
|
||||
if (tied_name != nullptr) {
|
||||
if (type != nullptr) {
|
||||
syntax_error(f->curr_token, "An asm specification for tied values cannot declare a type");
|
||||
}
|
||||
} else if (type == nullptr && value == nullptr) {
|
||||
syntax_error(f->curr_token, "An asm specification must specify at least either a type or a value if the value is not tied");
|
||||
}
|
||||
|
||||
Array<Ast *> directives = {};
|
||||
directives.allocator = heap_allocator();
|
||||
|
||||
while (f->curr_token.kind == Token_Hash) {
|
||||
Token token = expect_token(f, Token_Hash);
|
||||
Token name = expect_token_after(f, Token_Ident, "hash for directive");
|
||||
if (name.kind == Token_Ident) {
|
||||
Ast *directive = ast_basic_directive(f, token, name);
|
||||
array_add(&directives, directive);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Ast *spec = alloc_ast_node(f, Ast_AsmSpec);
|
||||
spec->AsmSpec.name = name;
|
||||
spec->AsmSpec.tied_name = tied_name;
|
||||
spec->AsmSpec.type = type;
|
||||
spec->AsmSpec.value = value;
|
||||
spec->AsmSpec.directives = directives;
|
||||
return spec;
|
||||
}
|
||||
|
||||
|
||||
gb_internal Ast *parse_asm_template(AstFile *f) {
|
||||
Token token = expect_token(f, Token_asm);
|
||||
|
||||
@@ -2718,41 +2773,7 @@ gb_internal Ast *parse_asm_template(AstFile *f) {
|
||||
f->curr_token.kind != Token_EOF) {
|
||||
Ast *spec = nullptr;
|
||||
if (f->curr_token.kind == Token_Ident) {
|
||||
Ast *name = parse_ident(f);
|
||||
Ast *tied_name = nullptr;
|
||||
Ast *type = nullptr;
|
||||
Ast *value = nullptr;
|
||||
if (allow_token(f, Token_ArrowRight)) {
|
||||
tied_name = parse_ident(f);
|
||||
}
|
||||
if (allow_token(f, Token_Colon)) {
|
||||
type = parse_type(f);
|
||||
}
|
||||
if (allow_token(f, Token_Eq)) {
|
||||
if (f->curr_token.kind == Token_Ident) {
|
||||
value = parse_ident(f);
|
||||
} else if (f->curr_token.kind == Token_Mod) {
|
||||
value = parse_asm_register(f);
|
||||
} else {
|
||||
error(f->curr_token, "Expected a register or scratch parameter");
|
||||
Ast *dummy = parse_expr(f, true);
|
||||
gb_unused(dummy);
|
||||
}
|
||||
}
|
||||
|
||||
if (tied_name != nullptr) {
|
||||
if (type != nullptr) {
|
||||
syntax_error(f->curr_token, "An asm specification for tied values cannot declare a type");
|
||||
}
|
||||
} else if (type == nullptr && value == nullptr) {
|
||||
syntax_error(f->curr_token, "An asm specification must specify at least either a type or a value if the value is not tied");
|
||||
}
|
||||
|
||||
spec = alloc_ast_node(f, Ast_AsmSpec);
|
||||
spec->AsmSpec.name = name;
|
||||
spec->AsmSpec.tied_name = tied_name;
|
||||
spec->AsmSpec.type = type;
|
||||
spec->AsmSpec.value = value;
|
||||
spec = parse_asm_spec(f);
|
||||
} else if (f->curr_token.kind == Token_Hash) {
|
||||
Token hash = expect_token(f, Token_Hash);
|
||||
Token name = expect_token(f, Token_Ident);
|
||||
|
||||
@@ -489,10 +489,11 @@ struct AstSplitArgs {
|
||||
Token flag; \
|
||||
}) \
|
||||
AST_KIND(AsmSpec, "asm specification", struct { \
|
||||
Ast *name; \
|
||||
Ast *tied_name; \
|
||||
Ast *type; \
|
||||
Ast *value; \
|
||||
Ast * name; \
|
||||
Ast * tied_name; \
|
||||
Ast * type; \
|
||||
Ast * value; \
|
||||
Array<Ast *> directives; \
|
||||
}) \
|
||||
AST_KIND(AsmClobber, "asm clobber", struct { \
|
||||
Token token; \
|
||||
|
||||
Reference in New Issue
Block a user