mirror of
https://github.com/odin-lang/Odin.git
synced 2026-09-02 10:13:35 +00:00
Merge pull request #7271 from odin-lang/bill/inline-asm
`asm` templates
This commit is contained in:
@@ -370,6 +370,7 @@ gb_internal void check_scope_decls(CheckerContext *c, Slice<Ast *> const &nodes,
|
||||
case Entity_Constant:
|
||||
case Entity_TypeName:
|
||||
case Entity_Procedure:
|
||||
case Entity_AsmTemplate:
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
@@ -2076,6 +2077,10 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam
|
||||
o->mode = Addressing_Value;
|
||||
break;
|
||||
|
||||
case Entity_AsmTemplate:
|
||||
o->mode = Addressing_Value;
|
||||
break;
|
||||
|
||||
default:
|
||||
compiler_error("Unknown EntityKind %.*s", LIT(entity_strings[e->kind]));
|
||||
break;
|
||||
@@ -5968,7 +5973,8 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
||||
add_entity_use(c, op_expr, e);
|
||||
expr_entity = e;
|
||||
|
||||
if (e != nullptr && (e->kind == Entity_Procedure || e->kind == Entity_ProcGroup) && selector->kind == Ast_Ident) {
|
||||
if (e != nullptr && (e->kind == Entity_Procedure || e->kind == Entity_ProcGroup || e->kind == Entity_AsmTemplate) &&
|
||||
selector->kind == Ast_Ident) {
|
||||
gbString sel_str = expr_to_string(selector);
|
||||
error(node, "'%s' is not declared by '%.*s'", sel_str, LIT(e->token.string));
|
||||
gb_string_free(sel_str);
|
||||
@@ -6339,6 +6345,10 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
||||
case Entity_Nil:
|
||||
operand->mode = Addressing_Value;
|
||||
break;
|
||||
|
||||
case Entity_AsmTemplate:
|
||||
operand->mode = Addressing_Value;
|
||||
break;
|
||||
}
|
||||
|
||||
add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value);
|
||||
@@ -8878,7 +8888,26 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
}
|
||||
} else {
|
||||
if (proc != nullptr) {
|
||||
check_expr_or_type(c, operand, proc);
|
||||
Ast *unnested_proc = unparen_expr(proc);
|
||||
if (unnested_proc->kind == Ast_AsmTemplate) {
|
||||
// NOTE(bill): asm templates can only be used within as a declaration OR within a procedure call directly
|
||||
ast_node(at, AsmTemplate, unnested_proc);
|
||||
Token token = at->token;
|
||||
DeclInfo *d = make_decl_info(c->scope, c->decl);
|
||||
Entity *e = alloc_entity_asm_template(d->scope, token, nullptr, unnested_proc);
|
||||
d->init_expr = unnested_proc;
|
||||
at->anonymous_entity = e;
|
||||
|
||||
check_asm_template_from_entity(c, e, d);
|
||||
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = e->type;
|
||||
operand->value = {};
|
||||
operand->expr = proc;
|
||||
add_type_and_value(c, proc, operand->mode, operand->type, operand->value);
|
||||
} else {
|
||||
check_expr_or_type(c, operand, proc);
|
||||
}
|
||||
} else {
|
||||
GB_ASSERT(operand->expr != nullptr);
|
||||
}
|
||||
@@ -12431,6 +12460,14 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
return kind;
|
||||
case_end;
|
||||
|
||||
case_ast_node(at, AsmTemplate, node);
|
||||
error(node, "'asm' templates must either be defined as a declaration or within a procedure call directly");
|
||||
o->mode = Addressing_NoValue;
|
||||
o->type = nullptr;
|
||||
o->expr = node;
|
||||
return kind;
|
||||
case_end;
|
||||
|
||||
case_ast_node(i, Implicit, node);
|
||||
switch (i->kind) {
|
||||
case Token_context:
|
||||
@@ -12512,6 +12549,12 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
o->mode = Addressing_Invalid;
|
||||
case_end;
|
||||
|
||||
case_ast_node(ag, AsmGroup, node);
|
||||
error(node, "Illegal use of a asm group");
|
||||
o->mode = Addressing_Invalid;
|
||||
case_end;
|
||||
|
||||
|
||||
case_ast_node(pl, ProcLit, node);
|
||||
CheckerContext ctx = *c;
|
||||
|
||||
@@ -12759,53 +12802,6 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(ia, InlineAsmExpr, node);
|
||||
if (c->curr_proc_decl == nullptr) {
|
||||
error(node, "Inline asm expressions are only allowed within a procedure body");
|
||||
}
|
||||
|
||||
auto param_types = array_make<Type *>(heap_allocator(), ia->param_types.count);
|
||||
Type *return_type = nullptr;
|
||||
for_array(i, ia->param_types) {
|
||||
param_types[i] = check_type(c, ia->param_types[i]);
|
||||
}
|
||||
if (ia->return_type != nullptr) {
|
||||
return_type = check_type(c, ia->return_type);
|
||||
}
|
||||
Operand x = {};
|
||||
check_expr(c, &x, ia->asm_string);
|
||||
if (x.mode != Addressing_Constant || !is_type_string(x.type)) {
|
||||
error(x.expr, "Expected a constant string for the inline asm main parameter");
|
||||
}
|
||||
check_expr(c, &x, ia->constraints_string);
|
||||
if (x.mode != Addressing_Constant || !is_type_string(x.type)) {
|
||||
error(x.expr, "Expected a constant string for the inline asm constraints parameter");
|
||||
}
|
||||
|
||||
Scope *scope = create_scope(c->info, c->scope);
|
||||
scope->flags |= ScopeFlag_Proc;
|
||||
|
||||
Type *params = alloc_type_tuple();
|
||||
Type *results = alloc_type_tuple();
|
||||
if (param_types.count != 0) {
|
||||
slice_init(¶ms->Tuple.variables, heap_allocator(), param_types.count);
|
||||
for_array(i, param_types) {
|
||||
params->Tuple.variables[i] = alloc_entity_param(scope, blank_token, param_types[i], false, true);
|
||||
}
|
||||
}
|
||||
if (return_type != nullptr) {
|
||||
slice_init(&results->Tuple.variables, heap_allocator(), 1);
|
||||
results->Tuple.variables[0] = alloc_entity_param(scope, blank_token, return_type, false, true);
|
||||
}
|
||||
|
||||
|
||||
Type *pt = alloc_type_proc(scope, params, param_types.count, results, return_type != nullptr ? 1 : 0, false, ProcCC_InlineAsm);
|
||||
o->type = pt;
|
||||
o->mode = Addressing_Value;
|
||||
o->expr = node;
|
||||
return Expr_Expr;
|
||||
case_end;
|
||||
|
||||
case Ast_DistinctType:
|
||||
case Ast_TypeidType:
|
||||
case Ast_PolyType:
|
||||
@@ -13080,6 +13076,16 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
|
||||
str = gb_string_append_rune(str, '}');
|
||||
case_end;
|
||||
|
||||
case_ast_node(pg, AsmGroup, node);
|
||||
str = gb_string_appendc(str, "asm{");
|
||||
for_array(i, pg->args) {
|
||||
if (i > 0) str = gb_string_appendc(str, ", ");
|
||||
str = write_expr_to_string(str, pg->args[i], shorthand);
|
||||
}
|
||||
str = gb_string_append_rune(str, '}');
|
||||
case_end;
|
||||
|
||||
|
||||
case_ast_node(pl, ProcLit, node);
|
||||
str = write_expr_to_string(str, pl->type, shorthand);
|
||||
if (pl->body) {
|
||||
@@ -13643,38 +13649,129 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
|
||||
str = gb_string_appendc(str, "}");
|
||||
case_end;
|
||||
|
||||
case_ast_node(ia, InlineAsmExpr, node);
|
||||
str = gb_string_appendc(str, "asm(");
|
||||
for_array(i, ia->param_types) {
|
||||
if (i > 0) {
|
||||
case_ast_node(at, AsmTemplate, node);
|
||||
str = gb_string_appendc(str, "asm");
|
||||
{
|
||||
ast_node(pt, ProcType, at->signature);
|
||||
|
||||
str = gb_string_appendc(str, "(");
|
||||
str = write_expr_to_string(str, pt->params, shorthand);
|
||||
str = gb_string_appendc(str, ")");
|
||||
if (pt->results != nullptr) {
|
||||
str = gb_string_appendc(str, " -> ");
|
||||
|
||||
bool parens_needed = false;
|
||||
if (pt->results && pt->results->kind == Ast_FieldList) {
|
||||
for (Ast *field : pt->results->FieldList.list) {
|
||||
ast_node(f, Field, field);
|
||||
if (f->names.count != 0) {
|
||||
parens_needed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parens_needed) {
|
||||
str = gb_string_append_rune(str, '(');
|
||||
}
|
||||
str = write_expr_to_string(str, pt->results, shorthand);
|
||||
if (parens_needed) {
|
||||
str = gb_string_append_rune(str, ')');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (at->specs.count) {
|
||||
str = gb_string_append_rune(str, '[');
|
||||
for_array(j, at->specs) {
|
||||
if (j > 0) {
|
||||
str = gb_string_appendc(str, ", ");
|
||||
}
|
||||
Ast *spec = at->specs[j];
|
||||
str = write_expr_to_string(str, spec, shorthand);
|
||||
}
|
||||
str = gb_string_append_rune(str, ']');
|
||||
}
|
||||
str = gb_string_append_rune(str, '{');
|
||||
for_array(j, at->instructions) {
|
||||
if (j > 0) {
|
||||
str = gb_string_appendc(str, "; ");
|
||||
}
|
||||
Ast *instr = at->instructions[j];
|
||||
str = write_expr_to_string(str, instr, shorthand);
|
||||
if (instr->kind == Ast_AsmLabelDecl) {
|
||||
str = gb_string_appendc(str, ":");
|
||||
}
|
||||
}
|
||||
str = gb_string_append_rune(str, '}');
|
||||
case_end;
|
||||
|
||||
case_ast_node(ar, AsmRegister, node);
|
||||
str = gb_string_appendc(str, "%");
|
||||
str = gb_string_append_length(str, ar->name.string.text, ar->name.string.len);
|
||||
case_end;
|
||||
|
||||
case_ast_node(spec, AsmSpec, node);
|
||||
if (spec->name) {
|
||||
str = write_expr_to_string(str, spec->name, shorthand);
|
||||
if (spec->tied_name) {
|
||||
str = gb_string_appendc(str, " -> ");
|
||||
str = write_expr_to_string(str, spec->tied_name, shorthand);
|
||||
}
|
||||
}
|
||||
if (spec->type) {
|
||||
str = gb_string_appendc(str, ": ");
|
||||
str = write_expr_to_string(str, spec->type, shorthand);
|
||||
}
|
||||
if (spec->value) {
|
||||
str = gb_string_appendc(str, " = ");
|
||||
str = write_expr_to_string(str, spec->value, shorthand);
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(clobber, AsmClobber, node);
|
||||
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);
|
||||
str = gb_string_appendc(str, ".");
|
||||
str = write_expr_to_string(str, label->name, shorthand);
|
||||
case_end;
|
||||
|
||||
case_ast_node(instr, AsmInstruction, node);
|
||||
str = write_expr_to_string(str, instr->name, shorthand);
|
||||
for_array(j, instr->operands) {
|
||||
if (j == 0) {
|
||||
str = gb_string_appendc(str, " ");
|
||||
} else {
|
||||
str = gb_string_appendc(str, ", ");
|
||||
}
|
||||
str = write_expr_to_string(str, ia->param_types[i], shorthand);
|
||||
Ast *operand = instr->operands[j];
|
||||
str = write_expr_to_string(str, operand, shorthand);
|
||||
}
|
||||
str = gb_string_appendc(str, ")");
|
||||
if (ia->return_type != nullptr) {
|
||||
str = gb_string_appendc(str, " -> ");
|
||||
str = write_expr_to_string(str, ia->return_type, shorthand);
|
||||
case_end;
|
||||
|
||||
case_ast_node(op, AsmMemoryOperand, node);
|
||||
str = gb_string_appendc(str, "[");
|
||||
str = write_expr_to_string(str, op->base, shorthand);
|
||||
if (op->index) {
|
||||
str = gb_string_appendc(str, " + ");
|
||||
str = write_expr_to_string(str, op->index, shorthand);
|
||||
if (op->scale) {
|
||||
str = gb_string_appendc(str, "*");
|
||||
str = write_expr_to_string(str, op->scale, shorthand);
|
||||
}
|
||||
}
|
||||
if (ia->has_side_effects) {
|
||||
str = gb_string_appendc(str, " #side_effects");
|
||||
if (op->disp) {
|
||||
str = gb_string_appendc(str, " + ");
|
||||
str = write_expr_to_string(str, op->disp, shorthand);
|
||||
}
|
||||
if (ia->is_align_stack) {
|
||||
str = gb_string_appendc(str, " #stack_align");
|
||||
}
|
||||
if (ia->dialect) {
|
||||
str = gb_string_appendc(str, " #");
|
||||
str = gb_string_appendc(str, inline_asm_dialect_strings[ia->dialect]);
|
||||
}
|
||||
str = gb_string_appendc(str, " {");
|
||||
if (shorthand) {
|
||||
str = gb_string_appendc(str, "...");
|
||||
} else {
|
||||
str = write_expr_to_string(str, ia->asm_string, shorthand);
|
||||
str = gb_string_appendc(str, ", ");
|
||||
str = write_expr_to_string(str, ia->constraints_string, shorthand);
|
||||
}
|
||||
str = gb_string_appendc(str, "}");
|
||||
str = gb_string_appendc(str, "]");
|
||||
case_end;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user