| author | |
| committer | |
| log | f0a141f79978d6d04b7cac1986b9bda770d3d6f9 |
| tree | 43b99a9c9095517a21869dac8ab0e7e0de7ab7e7 |
| parent | 2aa18b909765a48878d3f30f638e79d6eee1b584 |
| parent | 276eb4402b3c54adef10033d1ec54bf2053cc563 |
| signature |
closes #3084
closes #30303 files changed, 69 insertions(+), 10 deletions(-)
src/ir.cpp+35| ... | @@ -6743,6 +6743,25 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t | ... | @@ -6743,6 +6743,25 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t |
| 6743 | return ErrorNone; | 6743 | return ErrorNone; |
| 6744 | } | 6744 | } |
| 6745 | 6745 | ||
| 6746 | static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_template) { | ||
| 6747 | const char *ptr = buf_ptr(src_template) + tok->start + 2; | ||
| 6748 | size_t len = tok->end - tok->start - 2; | ||
| 6749 | size_t result = 0; | ||
| 6750 | for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) { | ||
| 6751 | AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); | ||
| 6752 | if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) { | ||
| 6753 | return result; | ||
| 6754 | } | ||
| 6755 | } | ||
| 6756 | for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) { | ||
| 6757 | AsmInput *asm_input = node->data.asm_expr.input_list.at(i); | ||
| 6758 | if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) { | ||
| 6759 | return result; | ||
| 6760 | } | ||
| 6761 | } | ||
| 6762 | return SIZE_MAX; | ||
| 6763 | } | ||
| 6764 | |||
| 6746 | static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *node) { | 6765 | static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 6747 | Error err; | 6766 | Error err; |
| 6748 | assert(node->type == NodeTypeAsmExpr); | 6767 | assert(node->type == NodeTypeAsmExpr); |
| ... | @@ -6830,6 +6849,22 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod | ... | @@ -6830,6 +6849,22 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod |
| 6830 | input_list[i] = input_value; | 6849 | input_list[i] = input_value; |
| 6831 | } | 6850 | } |
| 6832 | 6851 | ||
| 6852 | for (size_t token_i = 0; token_i < tok_list.length; token_i += 1) { | ||
| 6853 | AsmToken asm_token = tok_list.at(token_i); | ||
| 6854 | if (asm_token.id == AsmTokenIdVar) { | ||
| 6855 | size_t index = find_asm_index(irb->codegen, node, &asm_token, template_buf); | ||
| 6856 | if (index == SIZE_MAX) { | ||
| 6857 | const char *ptr = buf_ptr(template_buf) + asm_token.start + 2; | ||
| 6858 | uint32_t len = asm_token.end - asm_token.start - 2; | ||
| 6859 | |||
| 6860 | add_node_error(irb->codegen, node, | ||
| 6861 | buf_sprintf("could not find '%.*s' in the inputs or outputs.", | ||
| 6862 | len, ptr)); | ||
| 6863 | return irb->codegen->invalid_instruction; | ||
| 6864 | } | ||
| 6865 | } | ||
| 6866 | } | ||
| 6867 | |||
| 6833 | return ir_build_asm(irb, scope, node, template_buf, tok_list.items, tok_list.length, | 6868 | return ir_build_asm(irb, scope, node, template_buf, tok_list.items, tok_list.length, |
| 6834 | input_list, output_types, output_vars, return_count, is_volatile); | 6869 | input_list, output_types, output_vars, return_count, is_volatile); |
| 6835 | } | 6870 | } |
test/compile_errors.zig+19| ... | @@ -2,6 +2,25 @@ const tests = @import("tests.zig"); | ... | @@ -2,6 +2,25 @@ const tests = @import("tests.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | 3 | ||
| 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.addCase(x: { | ||
| 6 | var tc = cases.create("variable in inline assembly template cannot be found", | ||
| 7 | \\export fn entry() void { | ||
| 8 | \\ var sp = asm volatile ( | ||
| 9 | \\ "mov %[foo], sp" | ||
| 10 | \\ : [bar] "=r" (-> usize) | ||
| 11 | \\ ); | ||
| 12 | \\} | ||
| 13 | , "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs."); | ||
| 14 | tc.target = tests.Target{ | ||
| 15 | .Cross = tests.CrossTarget{ | ||
| 16 | .arch = .x86_64, | ||
| 17 | .os = .linux, | ||
| 18 | .abi = .gnu, | ||
| 19 | }, | ||
| 20 | }; | ||
| 21 | break :x tc; | ||
| 22 | }); | ||
| 23 | |||
| 5 | cases.add( | 24 | cases.add( |
| 6 | "indirect recursion of async functions detected", | 25 | "indirect recursion of async functions detected", |
| 7 | \\var frame: ?anyframe = null; | 26 | \\var frame: ?anyframe = null; |
test/tests.zig+15-10| ... | @@ -2,6 +2,8 @@ const std = @import("std"); | ... | @@ -2,6 +2,8 @@ const std = @import("std"); |
| 2 | const debug = std.debug; | 2 | const debug = std.debug; |
| 3 | const warn = debug.warn; | 3 | const warn = debug.warn; |
| 4 | const build = std.build; | 4 | const build = std.build; |
| 5 | pub const Target = build.Target; | ||
| 6 | pub const CrossTarget = build.CrossTarget; | ||
| 5 | const Buffer = std.Buffer; | 7 | const Buffer = std.Buffer; |
| 6 | const io = std.io; | 8 | const io = std.io; |
| 7 | const fs = std.fs; | 9 | const fs = std.fs; |
| ... | @@ -20,24 +22,18 @@ const runtime_safety = @import("runtime_safety.zig"); | ... | @@ -20,24 +22,18 @@ const runtime_safety = @import("runtime_safety.zig"); |
| 20 | const translate_c = @import("translate_c.zig"); | 22 | const translate_c = @import("translate_c.zig"); |
| 21 | const gen_h = @import("gen_h.zig"); | 23 | const gen_h = @import("gen_h.zig"); |
| 22 | 24 | ||
| 23 | const TestTarget = struct { | 25 | const test_targets = [_]CrossTarget{ |
| 24 | os: builtin.Os, | 26 | CrossTarget{ |
| 25 | arch: builtin.Arch, | ||
| 26 | abi: builtin.Abi, | ||
| 27 | }; | ||
| 28 | |||
| 29 | const test_targets = [_]TestTarget{ | ||
| 30 | TestTarget{ | ||
| 31 | .os = .linux, | 27 | .os = .linux, |
| 32 | .arch = .x86_64, | 28 | .arch = .x86_64, |
| 33 | .abi = .gnu, | 29 | .abi = .gnu, |
| 34 | }, | 30 | }, |
| 35 | TestTarget{ | 31 | CrossTarget{ |
| 36 | .os = .macosx, | 32 | .os = .macosx, |
| 37 | .arch = .x86_64, | 33 | .arch = .x86_64, |
| 38 | .abi = .gnu, | 34 | .abi = .gnu, |
| 39 | }, | 35 | }, |
| 40 | TestTarget{ | 36 | CrossTarget{ |
| 41 | .os = .windows, | 37 | .os = .windows, |
| 42 | .arch = .x86_64, | 38 | .arch = .x86_64, |
| 43 | .abi = .msvc, | 39 | .abi = .msvc, |
| ... | @@ -568,6 +564,7 @@ pub const CompileErrorContext = struct { | ... | @@ -568,6 +564,7 @@ pub const CompileErrorContext = struct { |
| 568 | link_libc: bool, | 564 | link_libc: bool, |
| 569 | is_exe: bool, | 565 | is_exe: bool, |
| 570 | is_test: bool, | 566 | is_test: bool, |
| 567 | target: Target = .Native, | ||
| 571 | 568 | ||
| 572 | const SourceFile = struct { | 569 | const SourceFile = struct { |
| 573 | filename: []const u8, | 570 | filename: []const u8, |
| ... | @@ -655,6 +652,14 @@ pub const CompileErrorContext = struct { | ... | @@ -655,6 +652,14 @@ pub const CompileErrorContext = struct { |
| 655 | zig_args.append("--output-dir") catch unreachable; | 652 | zig_args.append("--output-dir") catch unreachable; |
| 656 | zig_args.append(b.pathFromRoot(b.cache_root)) catch unreachable; | 653 | zig_args.append(b.pathFromRoot(b.cache_root)) catch unreachable; |
| 657 | 654 | ||
| 655 | switch (self.case.target) { | ||
| 656 | .Native => {}, | ||
| 657 | .Cross => { | ||
| 658 | try zig_args.append("-target"); | ||
| 659 | try zig_args.append(try self.case.target.zigTriple(b.allocator)); | ||
| 660 | }, | ||
| 661 | } | ||
| 662 | |||
| 658 | switch (self.build_mode) { | 663 | switch (self.build_mode) { |
| 659 | Mode.Debug => {}, | 664 | Mode.Debug => {}, |
| 660 | Mode.ReleaseSafe => zig_args.append("--release-safe") catch unreachable, | 665 | Mode.ReleaseSafe => zig_args.append("--release-safe") catch unreachable, |