authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2019-12-02 21:07:44+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-02 19:53:06-05:00
log26c8930b9594ab320b0e3add682e99063491142e
tree7c7162c26e30f92598cdcbf4a2309512bcdfd373
parentb7be57766b8c6d7fee27fd7c23e8c999a134bb27

Accept comptime-known expression for asm


8 files changed, 193 insertions(+), 88 deletions(-)

lib/std/zig/parse.zig+3-3
...@@ -1495,13 +1495,13 @@ fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1495,13 +1495,13 @@ fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1495 return &node.base;1495 return &node.base;
1496}1496}
14971497
1498/// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN STRINGLITERAL AsmOutput? RPAREN1498/// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
1499fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1499fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1500 const asm_token = eatToken(it, .Keyword_asm) orelse return null;1500 const asm_token = eatToken(it, .Keyword_asm) orelse return null;
1501 const volatile_token = eatToken(it, .Keyword_volatile);1501 const volatile_token = eatToken(it, .Keyword_volatile);
1502 _ = try expectToken(it, tree, .LParen);1502 _ = try expectToken(it, tree, .LParen);
1503 const template = try expectNode(arena, it, tree, parseStringLiteral, AstError{1503 const template = try expectNode(arena, it, tree, parseExpr, AstError{
1504 .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index },1504 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
1505 });1505 });
15061506
1507 const node = try arena.create(Node.Asm);1507 const node = try arena.create(Node.Asm);
lib/std/zig/parser_test.zig+23
...@@ -1,3 +1,26 @@...@@ -1,3 +1,26 @@
1test "zig fmt: asm expression with comptime content" {
2 try testCanonical(
3 \\comptime {
4 \\ asm ("foo" ++ "bar");
5 \\}
6 \\pub fn main() void {
7 \\ asm volatile ("foo" ++ "bar");
8 \\ asm volatile ("foo" ++ "bar"
9 \\ : [_] "" (x)
10 \\ );
11 \\ asm volatile ("foo" ++ "bar"
12 \\ : [_] "" (x)
13 \\ : [_] "" (y)
14 \\ );
15 \\ asm volatile ("foo" ++ "bar"
16 \\ : [_] "" (x)
17 \\ : [_] "" (y)
18 \\ : "h", "e", "l", "l", "o"
19 \\ );
20 \\}
21 \\
22 );
23}
1test "zig fmt: var struct field" {24test "zig fmt: var struct field" {
2 try testCanonical(25 try testCanonical(
3 \\pub const Pointer = struct {26 \\pub const Pointer = struct {
src/all_types.hpp+12-6
...@@ -949,7 +949,7 @@ struct AsmToken {...@@ -949,7 +949,7 @@ struct AsmToken {
949949
950struct AstNodeAsmExpr {950struct AstNodeAsmExpr {
951 Token *volatile_token;951 Token *volatile_token;
952 Token *asm_template;952 AstNode *asm_template;
953 ZigList<AsmOutput*> output_list;953 ZigList<AsmOutput*> output_list;
954 ZigList<AsmInput*> input_list;954 ZigList<AsmInput*> input_list;
955 ZigList<Buf*> clobber_list;955 ZigList<Buf*> clobber_list;
...@@ -2496,8 +2496,8 @@ enum IrInstructionId {...@@ -2496,8 +2496,8 @@ enum IrInstructionId {
2496 IrInstructionIdArrayType,2496 IrInstructionIdArrayType,
2497 IrInstructionIdAnyFrameType,2497 IrInstructionIdAnyFrameType,
2498 IrInstructionIdSliceType,2498 IrInstructionIdSliceType,
2499 IrInstructionIdGlobalAsm,2499 IrInstructionIdAsmSrc,
2500 IrInstructionIdAsm,2500 IrInstructionIdAsmGen,
2501 IrInstructionIdSizeOf,2501 IrInstructionIdSizeOf,
2502 IrInstructionIdTestNonNull,2502 IrInstructionIdTestNonNull,
2503 IrInstructionIdOptionalUnwrapPtr,2503 IrInstructionIdOptionalUnwrapPtr,
...@@ -3049,13 +3049,19 @@ struct IrInstructionSliceType {...@@ -3049,13 +3049,19 @@ struct IrInstructionSliceType {
3049 bool is_allow_zero;3049 bool is_allow_zero;
3050};3050};
30513051
3052struct IrInstructionGlobalAsm {3052struct IrInstructionAsmSrc {
3053 IrInstruction base;3053 IrInstruction base;
30543054
3055 Buf *asm_code;3055 IrInstruction *asm_template;
3056 IrInstruction **input_list;
3057 IrInstruction **output_types;
3058 ZigVar **output_vars;
3059 size_t return_count;
3060 bool has_side_effects;
3061 bool is_global;
3056};3062};
30573063
3058struct IrInstructionAsm {3064struct IrInstructionAsmGen {
3059 IrInstruction base;3065 IrInstruction base;
30603066
3061 Buf *asm_template;3067 Buf *asm_template;
src/ast_render.cpp+3-1
...@@ -884,7 +884,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -884,7 +884,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
884 {884 {
885 AstNodeAsmExpr *asm_expr = &node->data.asm_expr;885 AstNodeAsmExpr *asm_expr = &node->data.asm_expr;
886 const char *volatile_str = (asm_expr->volatile_token != nullptr) ? " volatile" : "";886 const char *volatile_str = (asm_expr->volatile_token != nullptr) ? " volatile" : "";
887 fprintf(ar->f, "asm%s (\"%s\"\n", volatile_str, buf_ptr(&asm_expr->asm_template->data.str_lit.str));887 fprintf(ar->f, "asm%s (", volatile_str);
888 render_node_ungrouped(ar, asm_expr->asm_template);
889 fprintf(ar->f, ")");
888 print_indent(ar);890 print_indent(ar);
889 fprintf(ar->f, ": ");891 fprintf(ar->f, ": ");
890 for (size_t i = 0; i < asm_expr->output_list.length; i += 1) {892 for (size_t i = 0; i < asm_expr->output_list.length; i += 1) {
src/codegen.cpp+4-4
...@@ -4437,7 +4437,7 @@ static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_...@@ -4437,7 +4437,7 @@ static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_
4437 return SIZE_MAX;4437 return SIZE_MAX;
4438}4438}
44394439
4440static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstructionAsm *instruction) {4440static LLVMValueRef ir_render_asm_gen(CodeGen *g, IrExecutable *executable, IrInstructionAsmGen *instruction) {
4441 AstNode *asm_node = instruction->base.source_node;4441 AstNode *asm_node = instruction->base.source_node;
4442 assert(asm_node->type == NodeTypeAsmExpr);4442 assert(asm_node->type == NodeTypeAsmExpr);
4443 AstNodeAsmExpr *asm_expr = &asm_node->data.asm_expr;4443 AstNodeAsmExpr *asm_expr = &asm_node->data.asm_expr;
...@@ -6135,7 +6135,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -6135,7 +6135,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
6135 case IrInstructionIdPtrCastSrc:6135 case IrInstructionIdPtrCastSrc:
6136 case IrInstructionIdCmpxchgSrc:6136 case IrInstructionIdCmpxchgSrc:
6137 case IrInstructionIdLoadPtr:6137 case IrInstructionIdLoadPtr:
6138 case IrInstructionIdGlobalAsm:
6139 case IrInstructionIdHasDecl:6138 case IrInstructionIdHasDecl:
6140 case IrInstructionIdUndeclaredIdent:6139 case IrInstructionIdUndeclaredIdent:
6141 case IrInstructionIdCallSrc:6140 case IrInstructionIdCallSrc:
...@@ -6156,6 +6155,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -6156,6 +6155,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
6156 case IrInstructionIdAwaitSrc:6155 case IrInstructionIdAwaitSrc:
6157 case IrInstructionIdSplatSrc:6156 case IrInstructionIdSplatSrc:
6158 case IrInstructionIdMergeErrSets:6157 case IrInstructionIdMergeErrSets:
6158 case IrInstructionIdAsmSrc:
6159 zig_unreachable();6159 zig_unreachable();
61606160
6161 case IrInstructionIdDeclVarGen:6161 case IrInstructionIdDeclVarGen:
...@@ -6192,8 +6192,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -6192,8 +6192,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
6192 return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);6192 return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
6193 case IrInstructionIdUnionFieldPtr:6193 case IrInstructionIdUnionFieldPtr:
6194 return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction);6194 return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction);
6195 case IrInstructionIdAsm:6195 case IrInstructionIdAsmGen:
6196 return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);6196 return ir_render_asm_gen(g, executable, (IrInstructionAsmGen *)instruction);
6197 case IrInstructionIdTestNonNull:6197 case IrInstructionIdTestNonNull:
6198 return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction);6198 return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction);
6199 case IrInstructionIdOptionalUnwrapPtr:6199 case IrInstructionIdOptionalUnwrapPtr:
src/ir.cpp+97-62
...@@ -339,10 +339,10 @@ static void destroy_instruction(IrInstruction *inst) {...@@ -339,10 +339,10 @@ static void destroy_instruction(IrInstruction *inst) {
339 return destroy(reinterpret_cast<IrInstructionSliceType *>(inst), name);339 return destroy(reinterpret_cast<IrInstructionSliceType *>(inst), name);
340 case IrInstructionIdAnyFrameType:340 case IrInstructionIdAnyFrameType:
341 return destroy(reinterpret_cast<IrInstructionAnyFrameType *>(inst), name);341 return destroy(reinterpret_cast<IrInstructionAnyFrameType *>(inst), name);
342 case IrInstructionIdGlobalAsm:342 case IrInstructionIdAsmSrc:
343 return destroy(reinterpret_cast<IrInstructionGlobalAsm *>(inst), name);343 return destroy(reinterpret_cast<IrInstructionAsmSrc *>(inst), name);
344 case IrInstructionIdAsm:344 case IrInstructionIdAsmGen:
345 return destroy(reinterpret_cast<IrInstructionAsm *>(inst), name);345 return destroy(reinterpret_cast<IrInstructionAsmGen *>(inst), name);
346 case IrInstructionIdSizeOf:346 case IrInstructionIdSizeOf:
347 return destroy(reinterpret_cast<IrInstructionSizeOf *>(inst), name);347 return destroy(reinterpret_cast<IrInstructionSizeOf *>(inst), name);
348 case IrInstructionIdTestNonNull:348 case IrInstructionIdTestNonNull:
...@@ -1028,12 +1028,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {...@@ -1028,12 +1028,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {
1028 return IrInstructionIdSliceType;1028 return IrInstructionIdSliceType;
1029}1029}
10301030
1031static constexpr IrInstructionId ir_instruction_id(IrInstructionGlobalAsm *) {1031static constexpr IrInstructionId ir_instruction_id(IrInstructionAsmSrc *) {
1032 return IrInstructionIdGlobalAsm;1032 return IrInstructionIdAsmSrc;
1033}1033}
10341034
1035static constexpr IrInstructionId ir_instruction_id(IrInstructionAsm *) {1035static constexpr IrInstructionId ir_instruction_id(IrInstructionAsmGen *) {
1036 return IrInstructionIdAsm;1036 return IrInstructionIdAsmGen;
1037}1037}
10381038
1039static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) {1039static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) {
...@@ -2268,18 +2268,39 @@ static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode...@@ -2268,18 +2268,39 @@ static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode
2268 return &instruction->base;2268 return &instruction->base;
2269}2269}
22702270
2271static IrInstruction *ir_build_global_asm(IrBuilder *irb, Scope *scope, AstNode *source_node, Buf *asm_code) {2271static IrInstruction *ir_build_asm_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
2272 IrInstructionGlobalAsm *instruction = ir_build_instruction<IrInstructionGlobalAsm>(irb, scope, source_node);2272 IrInstruction *asm_template, IrInstruction **input_list, IrInstruction **output_types,
2273 instruction->asm_code = asm_code;2273 ZigVar **output_vars, size_t return_count, bool has_side_effects, bool is_global)
2274{
2275 IrInstructionAsmSrc *instruction = ir_build_instruction<IrInstructionAsmSrc>(irb, scope, source_node);
2276 instruction->asm_template = asm_template;
2277 instruction->input_list = input_list;
2278 instruction->output_types = output_types;
2279 instruction->output_vars = output_vars;
2280 instruction->return_count = return_count;
2281 instruction->has_side_effects = has_side_effects;
2282 instruction->is_global = is_global;
2283
2284 assert(source_node->type == NodeTypeAsmExpr);
2285 for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) {
2286 IrInstruction *output_type = output_types[i];
2287 if (output_type) ir_ref_instruction(output_type, irb->current_basic_block);
2288 }
2289
2290 for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) {
2291 IrInstruction *input_value = input_list[i];
2292 ir_ref_instruction(input_value, irb->current_basic_block);
2293 }
2294
2274 return &instruction->base;2295 return &instruction->base;
2275}2296}
22762297
2277static IrInstruction *ir_build_asm(IrBuilder *irb, Scope *scope, AstNode *source_node,2298static IrInstruction *ir_build_asm_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node,
2278 Buf *asm_template, AsmToken *token_list, size_t token_list_len,2299 Buf *asm_template, AsmToken *token_list, size_t token_list_len,
2279 IrInstruction **input_list, IrInstruction **output_types, ZigVar **output_vars, size_t return_count,2300 IrInstruction **input_list, IrInstruction **output_types, ZigVar **output_vars, size_t return_count,
2280 bool has_side_effects)2301 bool has_side_effects)
2281{2302{
2282 IrInstructionAsm *instruction = ir_build_instruction<IrInstructionAsm>(irb, scope, source_node);2303 IrInstructionAsmGen *instruction = ir_build_instruction<IrInstructionAsmGen>(&ira->new_irb, scope, source_node);
2283 instruction->asm_template = asm_template;2304 instruction->asm_template = asm_template;
2284 instruction->token_list = token_list;2305 instruction->token_list = token_list;
2285 instruction->token_list_len = token_list_len;2306 instruction->token_list_len = token_list_len;
...@@ -2292,12 +2313,12 @@ static IrInstruction *ir_build_asm(IrBuilder *irb, Scope *scope, AstNode *source...@@ -2292,12 +2313,12 @@ static IrInstruction *ir_build_asm(IrBuilder *irb, Scope *scope, AstNode *source
2292 assert(source_node->type == NodeTypeAsmExpr);2313 assert(source_node->type == NodeTypeAsmExpr);
2293 for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) {2314 for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) {
2294 IrInstruction *output_type = output_types[i];2315 IrInstruction *output_type = output_types[i];
2295 if (output_type) ir_ref_instruction(output_type, irb->current_basic_block);2316 if (output_type) ir_ref_instruction(output_type, ira->new_irb.current_basic_block);
2296 }2317 }
22972318
2298 for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) {2319 for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) {
2299 IrInstruction *input_value = input_list[i];2320 IrInstruction *input_value = input_list[i];
2300 ir_ref_instruction(input_value, irb->current_basic_block);2321 ir_ref_instruction(input_value, ira->new_irb.current_basic_block);
2301 }2322 }
23022323
2303 return &instruction->base;2324 return &instruction->base;
...@@ -7494,7 +7515,7 @@ static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, Ast...@@ -7494,7 +7515,7 @@ static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, Ast
7494 return ir_build_const_undefined(irb, scope, node);7515 return ir_build_const_undefined(irb, scope, node);
7495}7516}
74967517
7497static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_template,7518static Error parse_asm_template(IrAnalyze *ira, AstNode *source_node, Buf *asm_template,
7498 ZigList<AsmToken> *tok_list)7519 ZigList<AsmToken> *tok_list)
7499{7520{
7500 // TODO Connect the errors in this function back up to the actual source location7521 // TODO Connect the errors in this function back up to the actual source location
...@@ -7542,7 +7563,7 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t...@@ -7542,7 +7563,7 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t
7542 cur_tok->end = i;7563 cur_tok->end = i;
7543 state = StateStart;7564 state = StateStart;
7544 } else {7565 } else {
7545 add_node_error(irb->codegen, source_node,7566 add_node_error(ira->codegen, source_node,
7546 buf_create_from_str("expected a '%' or '['"));7567 buf_create_from_str("expected a '%' or '['"));
7547 return ErrorSemanticAnalyzeFail;7568 return ErrorSemanticAnalyzeFail;
7548 }7569 }
...@@ -7565,7 +7586,7 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t...@@ -7565,7 +7586,7 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t
7565 {7586 {
7566 // do nothing7587 // do nothing
7567 } else {7588 } else {
7568 add_node_error(irb->codegen, source_node,7589 add_node_error(ira->codegen, source_node,
7569 buf_sprintf("invalid substitution character: '%c'", c));7590 buf_sprintf("invalid substitution character: '%c'", c));
7570 return ErrorSemanticAnalyzeFail;7591 return ErrorSemanticAnalyzeFail;
7571 }7592 }
...@@ -7578,7 +7599,7 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t...@@ -7578,7 +7599,7 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t
7578 break;7599 break;
7579 case StatePercent:7600 case StatePercent:
7580 case StateVar:7601 case StateVar:
7581 add_node_error(irb->codegen, source_node, buf_sprintf("unexpected end of assembly template"));7602 add_node_error(ira->codegen, source_node, buf_sprintf("unexpected end of assembly template"));
7582 return ErrorSemanticAnalyzeFail;7603 return ErrorSemanticAnalyzeFail;
7583 case StateTemplate:7604 case StateTemplate:
7584 cur_tok->end = buf_len(asm_template);7605 cur_tok->end = buf_len(asm_template);
...@@ -7607,14 +7628,16 @@ static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_...@@ -7607,14 +7628,16 @@ static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_
7607}7628}
76087629
7609static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *node) {7630static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
7610 Error err;
7611 assert(node->type == NodeTypeAsmExpr);7631 assert(node->type == NodeTypeAsmExpr);
7612 AstNodeAsmExpr *asm_expr = &node->data.asm_expr;7632 AstNodeAsmExpr *asm_expr = &node->data.asm_expr;
7633
7634 IrInstruction *asm_template = ir_gen_node(irb, asm_expr->asm_template, scope);
7635 if (asm_template == irb->codegen->invalid_instruction)
7636 return irb->codegen->invalid_instruction;
7637
7613 bool is_volatile = asm_expr->volatile_token != nullptr;7638 bool is_volatile = asm_expr->volatile_token != nullptr;
7614 bool in_fn_scope = (scope_fn_entry(scope) != nullptr);7639 bool in_fn_scope = (scope_fn_entry(scope) != nullptr);
76157640
7616 Buf *template_buf = &asm_expr->asm_template->data.str_lit.str;
7617
7618 if (!in_fn_scope) {7641 if (!in_fn_scope) {
7619 if (is_volatile) {7642 if (is_volatile) {
7620 add_token_error(irb->codegen, node->owner, asm_expr->volatile_token,7643 add_token_error(irb->codegen, node->owner, asm_expr->volatile_token,
...@@ -7630,12 +7653,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod...@@ -7630,12 +7653,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
7630 return irb->codegen->invalid_instruction;7653 return irb->codegen->invalid_instruction;
7631 }7654 }
76327655
7633 return ir_build_global_asm(irb, scope, node, template_buf);7656 return ir_build_asm_src(irb, scope, node, asm_template, nullptr, nullptr,
7634 }7657 nullptr, 0, is_volatile, true);
7635
7636 ZigList<AsmToken> tok_list = {};
7637 if ((err = parse_asm_template(irb, node, template_buf, &tok_list))) {
7638 return irb->codegen->invalid_instruction;
7639 }7658 }
76407659
7641 IrInstruction **input_list = allocate<IrInstruction *>(asm_expr->input_list.length);7660 IrInstruction **input_list = allocate<IrInstruction *>(asm_expr->input_list.length);
...@@ -7693,24 +7712,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod...@@ -7693,24 +7712,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
7693 input_list[i] = input_value;7712 input_list[i] = input_value;
7694 }7713 }
76957714
7696 for (size_t token_i = 0; token_i < tok_list.length; token_i += 1) {7715 return ir_build_asm_src(irb, scope, node, asm_template, input_list, output_types,
7697 AsmToken asm_token = tok_list.at(token_i);7716 output_vars, return_count, is_volatile, false);
7698 if (asm_token.id == AsmTokenIdVar) {
7699 size_t index = find_asm_index(irb->codegen, node, &asm_token, template_buf);
7700 if (index == SIZE_MAX) {
7701 const char *ptr = buf_ptr(template_buf) + asm_token.start + 2;
7702 uint32_t len = asm_token.end - asm_token.start - 2;
7703
7704 add_node_error(irb->codegen, node,
7705 buf_sprintf("could not find '%.*s' in the inputs or outputs",
7706 len, ptr));
7707 return irb->codegen->invalid_instruction;
7708 }
7709 }
7710 }
7711
7712 return ir_build_asm(irb, scope, node, template_buf, tok_list.items, tok_list.length,
7713 input_list, output_types, output_vars, return_count, is_volatile);
7714}7717}
77157718
7716static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,7719static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
...@@ -20150,21 +20153,49 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,...@@ -20150,21 +20153,49 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
20150 return result;20153 return result;
20151}20154}
2015220155
20153static IrInstruction *ir_analyze_instruction_global_asm(IrAnalyze *ira, IrInstructionGlobalAsm *instruction) {20156static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAsmSrc *asm_instruction) {
20154 buf_append_char(&ira->codegen->global_asm, '\n');20157 Error err;
20155 buf_append_buf(&ira->codegen->global_asm, instruction->asm_code);
20156
20157 return ir_const_void(ira, &instruction->base);
20158}
2015920158
20160static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAsm *asm_instruction) {
20161 assert(asm_instruction->base.source_node->type == NodeTypeAsmExpr);20159 assert(asm_instruction->base.source_node->type == NodeTypeAsmExpr);
2016220160
20161 AstNode *node = asm_instruction->base.source_node;
20163 AstNodeAsmExpr *asm_expr = &asm_instruction->base.source_node->data.asm_expr;20162 AstNodeAsmExpr *asm_expr = &asm_instruction->base.source_node->data.asm_expr;
2016420163
20164 Buf *template_buf = ir_resolve_str(ira, asm_instruction->asm_template->child);
20165 if (template_buf == nullptr)
20166 return ira->codegen->invalid_instruction;
20167
20168 if (asm_instruction->is_global) {
20169 buf_append_char(&ira->codegen->global_asm, '\n');
20170 buf_append_buf(&ira->codegen->global_asm, template_buf);
20171
20172 return ir_const_void(ira, &asm_instruction->base);
20173 }
20174
20165 if (!ir_emit_global_runtime_side_effect(ira, &asm_instruction->base))20175 if (!ir_emit_global_runtime_side_effect(ira, &asm_instruction->base))
20166 return ira->codegen->invalid_instruction;20176 return ira->codegen->invalid_instruction;
2016720177
20178 ZigList<AsmToken> tok_list = {};
20179 if ((err = parse_asm_template(ira, node, template_buf, &tok_list))) {
20180 return ira->codegen->invalid_instruction;
20181 }
20182
20183 for (size_t token_i = 0; token_i < tok_list.length; token_i += 1) {
20184 AsmToken asm_token = tok_list.at(token_i);
20185 if (asm_token.id == AsmTokenIdVar) {
20186 size_t index = find_asm_index(ira->codegen, node, &asm_token, template_buf);
20187 if (index == SIZE_MAX) {
20188 const char *ptr = buf_ptr(template_buf) + asm_token.start + 2;
20189 uint32_t len = asm_token.end - asm_token.start - 2;
20190
20191 add_node_error(ira->codegen, node,
20192 buf_sprintf("could not find '%.*s' in the inputs or outputs",
20193 len, ptr));
20194 return ira->codegen->invalid_instruction;
20195 }
20196 }
20197 }
20198
20168 // TODO validate the output types and variable types20199 // TODO validate the output types and variable types
2016920200
20170 IrInstruction **input_list = allocate<IrInstruction *>(asm_expr->input_list.length);20201 IrInstruction **input_list = allocate<IrInstruction *>(asm_expr->input_list.length);
...@@ -20197,9 +20228,9 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs...@@ -20197,9 +20228,9 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs
20197 input_list[i] = input_value;20228 input_list[i] = input_value;
20198 }20229 }
2019920230
20200 IrInstruction *result = ir_build_asm(&ira->new_irb,20231 IrInstruction *result = ir_build_asm_gen(ira,
20201 asm_instruction->base.scope, asm_instruction->base.source_node,20232 asm_instruction->base.scope, asm_instruction->base.source_node,
20202 asm_instruction->asm_template, asm_instruction->token_list, asm_instruction->token_list_len,20233 template_buf, tok_list.items, tok_list.length,
20203 input_list, output_types, asm_instruction->output_vars, asm_instruction->return_count,20234 input_list, output_types, asm_instruction->output_vars, asm_instruction->return_count,
20204 asm_instruction->has_side_effects);20235 asm_instruction->has_side_effects);
20205 result->value->type = return_type;20236 result->value->type = return_type;
...@@ -27722,6 +27753,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -27722,6 +27753,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
27722 case IrInstructionIdSplatGen:27753 case IrInstructionIdSplatGen:
27723 case IrInstructionIdVectorExtractElem:27754 case IrInstructionIdVectorExtractElem:
27724 case IrInstructionIdVectorStoreElem:27755 case IrInstructionIdVectorStoreElem:
27756 case IrInstructionIdAsmGen:
27725 zig_unreachable();27757 zig_unreachable();
2772627758
27727 case IrInstructionIdReturn:27759 case IrInstructionIdReturn:
...@@ -27768,10 +27800,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -27768,10 +27800,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
27768 return ir_analyze_instruction_any_frame_type(ira, (IrInstructionAnyFrameType *)instruction);27800 return ir_analyze_instruction_any_frame_type(ira, (IrInstructionAnyFrameType *)instruction);
27769 case IrInstructionIdSliceType:27801 case IrInstructionIdSliceType:
27770 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);27802 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);
27771 case IrInstructionIdGlobalAsm:27803 case IrInstructionIdAsmSrc:
27772 return ir_analyze_instruction_global_asm(ira, (IrInstructionGlobalAsm *)instruction);27804 return ir_analyze_instruction_asm(ira, (IrInstructionAsmSrc *)instruction);
27773 case IrInstructionIdAsm:
27774 return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
27775 case IrInstructionIdArrayType:27805 case IrInstructionIdArrayType:
27776 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);27806 return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
27777 case IrInstructionIdSizeOf:27807 case IrInstructionIdSizeOf:
...@@ -28183,7 +28213,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -28183,7 +28213,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
28183 case IrInstructionIdAssertZero:28213 case IrInstructionIdAssertZero:
28184 case IrInstructionIdAssertNonNull:28214 case IrInstructionIdAssertNonNull:
28185 case IrInstructionIdResizeSlice:28215 case IrInstructionIdResizeSlice:
28186 case IrInstructionIdGlobalAsm:
28187 case IrInstructionIdUndeclaredIdent:28216 case IrInstructionIdUndeclaredIdent:
28188 case IrInstructionIdEndExpr:28217 case IrInstructionIdEndExpr:
28189 case IrInstructionIdPtrOfArrayToSlice:28218 case IrInstructionIdPtrOfArrayToSlice:
...@@ -28303,9 +28332,15 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -28303,9 +28332,15 @@ bool ir_has_side_effects(IrInstruction *instruction) {
28303 case IrInstructionIdVectorExtractElem:28332 case IrInstructionIdVectorExtractElem:
28304 return false;28333 return false;
2830528334
28306 case IrInstructionIdAsm:28335 case IrInstructionIdAsmSrc:
28336 {
28337 IrInstructionAsmSrc *asm_instruction = (IrInstructionAsmSrc *)instruction;
28338 return asm_instruction->has_side_effects;
28339 }
28340
28341 case IrInstructionIdAsmGen:
28307 {28342 {
28308 IrInstructionAsm *asm_instruction = (IrInstructionAsm *)instruction;28343 IrInstructionAsmGen *asm_instruction = (IrInstructionAsmGen *)instruction;
28309 return asm_instruction->has_side_effects;28344 return asm_instruction->has_side_effects;
28310 }28345 }
28311 case IrInstructionIdUnwrapErrPayload:28346 case IrInstructionIdUnwrapErrPayload:
src/ir_print.cpp+50-11
...@@ -124,10 +124,10 @@ const char* ir_instruction_type_str(IrInstructionId id) {...@@ -124,10 +124,10 @@ const char* ir_instruction_type_str(IrInstructionId id) {
124 return "AnyFrameType";124 return "AnyFrameType";
125 case IrInstructionIdSliceType:125 case IrInstructionIdSliceType:
126 return "SliceType";126 return "SliceType";
127 case IrInstructionIdGlobalAsm:127 case IrInstructionIdAsmSrc:
128 return "GlobalAsm";128 return "AsmSrc";
129 case IrInstructionIdAsm:129 case IrInstructionIdAsmGen:
130 return "Asm";130 return "AsmGen";
131 case IrInstructionIdSizeOf:131 case IrInstructionIdSizeOf:
132 return "SizeOf";132 return "SizeOf";
133 case IrInstructionIdTestNonNull:133 case IrInstructionIdTestNonNull:
...@@ -888,11 +888,50 @@ static void ir_print_any_frame_type(IrPrint *irp, IrInstructionAnyFrameType *ins...@@ -888,11 +888,50 @@ static void ir_print_any_frame_type(IrPrint *irp, IrInstructionAnyFrameType *ins
888 }888 }
889}889}
890890
891static void ir_print_global_asm(IrPrint *irp, IrInstructionGlobalAsm *instruction) {891static void ir_print_asm_src(IrPrint *irp, IrInstructionAsmSrc *instruction) {
892 fprintf(irp->f, "asm(\"%s\")", buf_ptr(instruction->asm_code));892 assert(instruction->base.source_node->type == NodeTypeAsmExpr);
893 AstNodeAsmExpr *asm_expr = &instruction->base.source_node->data.asm_expr;
894 const char *volatile_kw = instruction->has_side_effects ? " volatile" : "";
895 fprintf(irp->f, "asm%s (", volatile_kw);
896 ir_print_other_instruction(irp, instruction->asm_template);
897
898 for (size_t i = 0; i < asm_expr->output_list.length; i += 1) {
899 AsmOutput *asm_output = asm_expr->output_list.at(i);
900 if (i != 0) fprintf(irp->f, ", ");
901
902 fprintf(irp->f, "[%s] \"%s\" (",
903 buf_ptr(asm_output->asm_symbolic_name),
904 buf_ptr(asm_output->constraint));
905 if (asm_output->return_type) {
906 fprintf(irp->f, "-> ");
907 ir_print_other_instruction(irp, instruction->output_types[i]);
908 } else {
909 fprintf(irp->f, "%s", buf_ptr(asm_output->variable_name));
910 }
911 fprintf(irp->f, ")");
912 }
913
914 fprintf(irp->f, " : ");
915 for (size_t i = 0; i < asm_expr->input_list.length; i += 1) {
916 AsmInput *asm_input = asm_expr->input_list.at(i);
917
918 if (i != 0) fprintf(irp->f, ", ");
919 fprintf(irp->f, "[%s] \"%s\" (",
920 buf_ptr(asm_input->asm_symbolic_name),
921 buf_ptr(asm_input->constraint));
922 ir_print_other_instruction(irp, instruction->input_list[i]);
923 fprintf(irp->f, ")");
924 }
925 fprintf(irp->f, " : ");
926 for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1) {
927 Buf *reg_name = asm_expr->clobber_list.at(i);
928 if (i != 0) fprintf(irp->f, ", ");
929 fprintf(irp->f, "\"%s\"", buf_ptr(reg_name));
930 }
931 fprintf(irp->f, ")");
893}932}
894933
895static void ir_print_asm(IrPrint *irp, IrInstructionAsm *instruction) {934static void ir_print_asm_gen(IrPrint *irp, IrInstructionAsmGen *instruction) {
896 assert(instruction->base.source_node->type == NodeTypeAsmExpr);935 assert(instruction->base.source_node->type == NodeTypeAsmExpr);
897 AstNodeAsmExpr *asm_expr = &instruction->base.source_node->data.asm_expr;936 AstNodeAsmExpr *asm_expr = &instruction->base.source_node->data.asm_expr;
898 const char *volatile_kw = instruction->has_side_effects ? " volatile" : "";937 const char *volatile_kw = instruction->has_side_effects ? " volatile" : "";
...@@ -2121,11 +2160,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool...@@ -2121,11 +2160,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool
2121 case IrInstructionIdAnyFrameType:2160 case IrInstructionIdAnyFrameType:
2122 ir_print_any_frame_type(irp, (IrInstructionAnyFrameType *)instruction);2161 ir_print_any_frame_type(irp, (IrInstructionAnyFrameType *)instruction);
2123 break;2162 break;
2124 case IrInstructionIdGlobalAsm:2163 case IrInstructionIdAsmSrc:
2125 ir_print_global_asm(irp, (IrInstructionGlobalAsm *)instruction);2164 ir_print_asm_src(irp, (IrInstructionAsmSrc *)instruction);
2126 break;2165 break;
2127 case IrInstructionIdAsm:2166 case IrInstructionIdAsmGen:
2128 ir_print_asm(irp, (IrInstructionAsm *)instruction);2167 ir_print_asm_gen(irp, (IrInstructionAsmGen *)instruction);
2129 break;2168 break;
2130 case IrInstructionIdSizeOf:2169 case IrInstructionIdSizeOf:
2131 ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);2170 ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);
src/parser.cpp+1-1
...@@ -1891,7 +1891,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc) {...@@ -1891,7 +1891,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc) {
18911891
1892 Token *volatile_token = eat_token_if(pc, TokenIdKeywordVolatile);1892 Token *volatile_token = eat_token_if(pc, TokenIdKeywordVolatile);
1893 expect_token(pc, TokenIdLParen);1893 expect_token(pc, TokenIdLParen);
1894 Token *asm_template = expect_token(pc, TokenIdStringLiteral);1894 AstNode *asm_template = ast_expect(pc, ast_parse_expr);
1895 AstNode *res = ast_parse_asm_output(pc);1895 AstNode *res = ast_parse_asm_output(pc);
1896 if (res == nullptr)1896 if (res == nullptr)
1897 res = ast_create_node_no_line_info(pc, NodeTypeAsmExpr);1897 res = ast_create_node_no_line_info(pc, NodeTypeAsmExpr);