authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-03-31 00:04:04+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-31 00:04:04+03:00
log3c64c519e65861868e05c47de2d8605a579edf06
tree9e06748f9c048b4f54982db9163f6e46e8eb9746
parentd227f76afbacb619152ffd943cf3018e62e00adc
parent907dc1e13f657f349dbdecf739b2f1a13ad7011a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11246 from jmc-88/cbe-asm

CBE: improve support for asm inputs

5 files changed, 81 insertions(+), 47 deletions(-)

src/AstGen.zig+17-35
...@@ -6423,7 +6423,6 @@ fn identifier(...@@ -6423,7 +6423,6 @@ fn identifier(
64236423
6424 const astgen = gz.astgen;6424 const astgen = gz.astgen;
6425 const tree = astgen.tree;6425 const tree = astgen.tree;
6426 const gpa = astgen.gpa;
6427 const main_tokens = tree.nodes.items(.main_token);6426 const main_tokens = tree.nodes.items(.main_token);
64286427
6429 const ident_token = main_tokens[ident];6428 const ident_token = main_tokens[ident];
...@@ -6467,6 +6466,19 @@ fn identifier(...@@ -6467,6 +6466,19 @@ fn identifier(
6467 }6466 }
64686467
6469 // Local variables, including function parameters.6468 // Local variables, including function parameters.
6469 return localVarRef(gz, scope, rl, ident, ident_token);
6470}
6471
6472fn localVarRef(
6473 gz: *GenZir,
6474 scope: *Scope,
6475 rl: ResultLoc,
6476 ident: Ast.Node.Index,
6477 ident_token: Ast.Node.Index,
6478) InnerError!Zir.Inst.Ref {
6479 const astgen = gz.astgen;
6480 const gpa = astgen.gpa;
6481
6470 const name_str_index = try astgen.identAsString(ident_token);6482 const name_str_index = try astgen.identAsString(ident_token);
6471 var s = scope;6483 var s = scope;
6472 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already6484 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already
...@@ -6808,43 +6820,13 @@ fn asmExpr(...@@ -6808,43 +6820,13 @@ fn asmExpr(
6808 };6820 };
6809 } else {6821 } else {
6810 const ident_token = symbolic_name + 4;6822 const ident_token = symbolic_name + 4;
6811 const str_index = try astgen.identAsString(ident_token);6823 // TODO have a look at #215 and related issues and decide how to
6812 // TODO this needs extra code for local variables. Have a look at #215 and related6824 // handle outputs. Do we want this to be identifiers?
6813 // issues and decide how to handle outputs. Do we want this to be identifiers?
6814 // Or maybe we want to force this to be expressions with a pointer type.6825 // Or maybe we want to force this to be expressions with a pointer type.
6815 // Until that is figured out this is only hooked up for referencing Decls.
6816 // TODO we have put this as an identifier lookup just so that we don't get
6817 // unused vars for outputs. We need to check if this is correct in the future ^^
6818 // so we just put in this simple lookup. This is a workaround.
6819 {
6820 var s = scope;
6821 while (true) switch (s.tag) {
6822 .local_val => {
6823 const local_val = s.cast(Scope.LocalVal).?;
6824 if (local_val.name == str_index) {
6825 local_val.used = true;
6826 break;
6827 }
6828 s = local_val.parent;
6829 },
6830 .local_ptr => {
6831 const local_ptr = s.cast(Scope.LocalPtr).?;
6832 if (local_ptr.name == str_index) {
6833 local_ptr.used = true;
6834 break;
6835 }
6836 s = local_ptr.parent;
6837 },
6838 .gen_zir => s = s.cast(GenZir).?.parent,
6839 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
6840 .namespace, .top => break,
6841 };
6842 }
6843 const operand = try gz.addStrTok(.decl_ref, str_index, ident_token);
6844 outputs[i] = .{6826 outputs[i] = .{
6845 .name = name,6827 .name = name,
6846 .constraint = constraint,6828 .constraint = constraint,
6847 .operand = operand,6829 .operand = try localVarRef(gz, scope, rl, node, ident_token),
6848 };6830 };
6849 }6831 }
6850 }6832 }
...@@ -6860,7 +6842,7 @@ fn asmExpr(...@@ -6860,7 +6842,7 @@ fn asmExpr(
6860 const name = try astgen.identAsString(symbolic_name);6842 const name = try astgen.identAsString(symbolic_name);
6861 const constraint_token = symbolic_name + 2;6843 const constraint_token = symbolic_name + 2;
6862 const constraint = (try astgen.strLitAsString(constraint_token)).index;6844 const constraint = (try astgen.strLitAsString(constraint_token)).index;
6863 const operand = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input_node].lhs);6845 const operand = try expr(gz, scope, .none, node_datas[input_node].lhs);
6864 inputs[i] = .{6846 inputs[i] = .{
6865 .name = name,6847 .name = name,
6866 .constraint = constraint,6848 .constraint = constraint,
src/Sema.zig+13-2
...@@ -10253,6 +10253,11 @@ fn zirAsm(...@@ -10253,6 +10253,11 @@ fn zirAsm(
10253 const inputs_len = @truncate(u5, extended.small >> 5);10253 const inputs_len = @truncate(u5, extended.small >> 5);
10254 const clobbers_len = @truncate(u5, extended.small >> 10);10254 const clobbers_len = @truncate(u5, extended.small >> 10);
10255 const is_volatile = @truncate(u1, extended.small >> 15) != 0;10255 const is_volatile = @truncate(u1, extended.small >> 15) != 0;
10256 const is_global_assembly = sema.func == null;
10257
10258 if (block.is_comptime and !is_global_assembly) {
10259 try sema.requireRuntimeBlock(block, src);
10260 }
1025610261
10257 if (extra.data.asm_source == 0) {10262 if (extra.data.asm_source == 0) {
10258 // This can move to become an AstGen error after inline assembly improvements land10263 // This can move to become an AstGen error after inline assembly improvements land
...@@ -10299,7 +10304,14 @@ fn zirAsm(...@@ -10299,7 +10304,14 @@ fn zirAsm(
10299 const name = sema.code.nullTerminatedString(input.data.name);10304 const name = sema.code.nullTerminatedString(input.data.name);
10300 _ = name; // TODO: use the name10305 _ = name; // TODO: use the name
1030110306
10302 arg.* = sema.resolveInst(input.data.operand);10307 const uncasted_arg = sema.resolveInst(input.data.operand);
10308 const uncasted_arg_ty = sema.typeOf(uncasted_arg);
10309 switch (uncasted_arg_ty.zigTypeTag()) {
10310 .ComptimeInt => arg.* = try sema.coerce(block, Type.initTag(.usize), uncasted_arg, src),
10311 .ComptimeFloat => arg.* = try sema.coerce(block, Type.initTag(.f64), uncasted_arg, src),
10312 else => arg.* = uncasted_arg,
10313 }
10314
10303 const constraint = sema.code.nullTerminatedString(input.data.constraint);10315 const constraint = sema.code.nullTerminatedString(input.data.constraint);
10304 needed_capacity += constraint.len / 4 + 1;10316 needed_capacity += constraint.len / 4 + 1;
10305 inputs[arg_i] = constraint;10317 inputs[arg_i] = constraint;
...@@ -10317,7 +10329,6 @@ fn zirAsm(...@@ -10317,7 +10329,6 @@ fn zirAsm(
10317 needed_capacity += (asm_source.len + 3) / 4;10329 needed_capacity += (asm_source.len + 3) / 4;
1031810330
10319 const gpa = sema.gpa;10331 const gpa = sema.gpa;
10320 try sema.requireRuntimeBlock(block, src);
10321 try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity);10332 try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity);
10322 const asm_air = try block.addInst(.{10333 const asm_air = try block.addInst(.{
10323 .tag = .assembly,10334 .tag = .assembly,
src/codegen/c.zig+13-5
...@@ -3014,9 +3014,10 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3014,9 +3014,10 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
3014 } else null;3014 } else null;
30153015
3016 const writer = f.object.writer();3016 const writer = f.object.writer();
3017 const inputs_extra_begin = extra_i;3017 try writer.writeAll("{\n");
30183018
3019 for (inputs) |input| {3019 const inputs_extra_begin = extra_i;
3020 for (inputs) |input, i| {
3020 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);3021 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
3021 // This equation accounts for the fact that even if we have exactly 4 bytes3022 // This equation accounts for the fact that even if we have exactly 4 bytes
3022 // for the string, we still use the next u32 for the null terminator.3023 // for the string, we still use the next u32 for the null terminator.
...@@ -3032,7 +3033,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3032,7 +3033,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
3032 try f.writeCValue(writer, arg_c_value);3033 try f.writeCValue(writer, arg_c_value);
3033 try writer.writeAll(";\n");3034 try writer.writeAll(";\n");
3034 } else {3035 } else {
3035 return f.fail("TODO non-explicit inline asm regs", .{});3036 try writer.writeAll("register ");
3037 try f.renderType(writer, f.air.typeOf(input));
3038 try writer.print(" input_{d} = ", .{i});
3039 try f.writeCValue(writer, try f.resolveInst(input));
3040 try writer.writeAll(";\n");
3036 }3041 }
3037 }3042 }
30383043
...@@ -3074,12 +3079,15 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3074,12 +3079,15 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
3074 }3079 }
3075 try writer.print("\"r\"({s}_constant)", .{reg});3080 try writer.print("\"r\"({s}_constant)", .{reg});
3076 } else {3081 } else {
3077 // This is blocked by the earlier test3082 if (index > 0) {
3078 unreachable;3083 try writer.writeAll(", ");
3084 }
3085 try writer.print("\"r\"(input_{d})", .{index});
3079 }3086 }
3080 }3087 }
3081 }3088 }
3082 try writer.writeAll(");\n");3089 try writer.writeAll(");\n");
3090 try writer.writeAll("}\n");
30833091
3084 if (f.liveness.isUnused(inst))3092 if (f.liveness.isUnused(inst))
3085 return CValue.none;3093 return CValue.none;
test/behavior.zig+1-4
...@@ -165,10 +165,7 @@ test {...@@ -165,10 +165,7 @@ test {
165 }165 }
166166
167 if (builtin.os.tag != .wasi) {167 if (builtin.os.tag != .wasi) {
168 if (builtin.zig_backend == .stage1) {168 _ = @import("behavior/asm.zig");
169 // TODO get these tests passing with stage2
170 _ = @import("behavior/asm.zig");
171 }
172 }169 }
173170
174 if (builtin.zig_backend != .stage2_arm and171 if (builtin.zig_backend != .stage2_arm and
test/behavior/asm.zig+37-1
...@@ -5,7 +5,10 @@ const expect = std.testing.expect;...@@ -5,7 +5,10 @@ const expect = std.testing.expect;
5const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux;5const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux;
66
7comptime {7comptime {
8 if (is_x86_64_linux) {8 if (builtin.zig_backend != .stage2_arm and
9 builtin.zig_backend != .stage2_aarch64 and
10 is_x86_64_linux)
11 {
9 asm (12 asm (
10 \\.globl this_is_my_alias;13 \\.globl this_is_my_alias;
11 \\.type this_is_my_alias, @function;14 \\.type this_is_my_alias, @function;
...@@ -15,12 +18,26 @@ comptime {...@@ -15,12 +18,26 @@ comptime {
15}18}
1619
17test "module level assembly" {20test "module level assembly" {
21 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
22 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
23 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
27
18 if (is_x86_64_linux) {28 if (is_x86_64_linux) {
19 try expect(this_is_my_alias() == 1234);29 try expect(this_is_my_alias() == 1234);
20 }30 }
21}31}
2232
23test "output constraint modifiers" {33test "output constraint modifiers" {
34 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
36 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
37 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
38 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
39 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
40
24 // This is only testing compilation.41 // This is only testing compilation.
25 var a: u32 = 3;42 var a: u32 = 3;
26 asm volatile (""43 asm volatile (""
...@@ -36,6 +53,13 @@ test "output constraint modifiers" {...@@ -36,6 +53,13 @@ test "output constraint modifiers" {
36}53}
3754
38test "alternative constraints" {55test "alternative constraints" {
56 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
59 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
60 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
61 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
62
39 // Make sure we allow commas as a separator for alternative constraints.63 // Make sure we allow commas as a separator for alternative constraints.
40 var a: u32 = 3;64 var a: u32 = 3;
41 asm volatile (""65 asm volatile (""
...@@ -46,6 +70,11 @@ test "alternative constraints" {...@@ -46,6 +70,11 @@ test "alternative constraints" {
46}70}
4771
48test "sized integer/float in asm input" {72test "sized integer/float in asm input" {
73 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
74 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
75 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
77
49 asm volatile (""78 asm volatile (""
50 :79 :
51 : [_] "m" (@as(usize, 3)),80 : [_] "m" (@as(usize, 3)),
...@@ -89,6 +118,13 @@ test "sized integer/float in asm input" {...@@ -89,6 +118,13 @@ test "sized integer/float in asm input" {
89}118}
90119
91test "struct/array/union types as input values" {120test "struct/array/union types as input values" {
121 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
122 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
123 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
124 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
125 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
126 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
127
92 asm volatile (""128 asm volatile (""
93 :129 :
94 : [_] "m" (@as([1]u32, undefined)),130 : [_] "m" (@as([1]u32, undefined)),