diff options
| author | gingerBill <bill@gingerbill.org> | 2020-10-24 16:32:37 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2020-10-24 16:32:37 +0100 |
| commit | 4629754f7ced5df477eb017872ef65539db64a27 (patch) | |
| tree | fc2fc4b7a493c58adeb10bf54254fbbad66f2f67 /src/check_expr.cpp | |
| parent | 0061e63db010cdb2043af63527b4c25f45652a51 (diff) | |
Inline asm expression (-llvm-api)
See https://llvm.org/docs/LangRef.html#inline-assembler-expressions
Example:
```
x := asm(i32) -> i32 {
"bswap $0",
"=r,r",
}(123);
```
Allowed directives `#side_effect`, `#align_stack`, `#att`, `#intel` e.g. `asm() #side_effect #intel {...}`
Diffstat (limited to 'src/check_expr.cpp')
| -rw-r--r-- | src/check_expr.cpp | 92 |
1 files changed, 85 insertions, 7 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fe43a12a6..02b54c80a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4260,11 +4260,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (o.mode == Addressing_Invalid || o.mode == Addressing_Builtin) { return false; } - if (o.type == nullptr || o.type == t_invalid) { - error(o.expr, "Invalid argument to 'type_of'"); - return false; - } - if (o.type == nullptr || o.type == t_invalid) { + if (o.type == nullptr || o.type == t_invalid || is_type_asm_proc(o.type)) { error(o.expr, "Invalid argument to 'type_of'"); return false; } @@ -4300,7 +4296,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return false; } Type *t = o.type; - if (t == nullptr || t == t_invalid || is_type_polymorphic(t)) { + if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(t)) { if (is_type_polymorphic(t)) { error(ce->args[0], "Invalid argument for 'type_info_of', unspecialized polymorphic type"); } else { @@ -4339,7 +4335,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return false; } Type *t = o.type; - if (t == nullptr || t == t_invalid || is_type_polymorphic(operand->type)) { + if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(operand->type)) { error(ce->args[0], "Invalid argument for 'typeid_of'"); return false; } @@ -10010,6 +10006,57 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } 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"); + } + + if (!build_context.use_llvm_api) { + error(node, "Inline asm expressions are only currently allowed with -llvm-api"); + } + + 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->scope, heap_allocator()); + scope->flags |= ScopeFlag_Proc; + + Type *params = alloc_type_tuple(); + Type *results = alloc_type_tuple(); + if (param_types.count != 0) { + array_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) { + array_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_TypeidType: case Ast_PolyType: case Ast_ProcType: @@ -10539,6 +10586,37 @@ gbString write_expr_to_string(gbString str, Ast *node) { str = gb_string_appendc(str, "" ); str = write_expr_to_string(str, rt->type); case_end; + + + case_ast_node(ia, InlineAsmExpr, node); + str = gb_string_appendc(str, "asm("); + for_array(i, ia->param_types) { + if (i > 0) { + str = gb_string_appendc(str, ", "); + } + str = write_expr_to_string(str, ia->param_types[i]); + } + str = gb_string_appendc(str, ")"); + if (ia->return_type != nullptr) { + str = gb_string_appendc(str, " -> "); + str = write_expr_to_string(str, ia->return_type); + } + if (ia->has_side_effects) { + str = gb_string_appendc(str, " #side_effects"); + } + 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, " {"); + str = write_expr_to_string(str, ia->asm_string); + str = gb_string_appendc(str, ", "); + str = write_expr_to_string(str, ia->constraints_string); + str = gb_string_appendc(str, "}"); + case_end; } return str; |