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

CBE: improve support for asm inputs
This commit is contained in:
Veikka Tuominen 2022-03-31 00:04:04 +03:00 committed by GitHub
commit 3c64c519e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 47 deletions

View File

@ -6423,7 +6423,6 @@ fn identifier(
const astgen = gz.astgen;
const tree = astgen.tree;
const gpa = astgen.gpa;
const main_tokens = tree.nodes.items(.main_token);
const ident_token = main_tokens[ident];
@ -6467,6 +6466,19 @@ fn identifier(
}
// Local variables, including function parameters.
return localVarRef(gz, scope, rl, ident, ident_token);
}
fn localVarRef(
gz: *GenZir,
scope: *Scope,
rl: ResultLoc,
ident: Ast.Node.Index,
ident_token: Ast.Node.Index,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const gpa = astgen.gpa;
const name_str_index = try astgen.identAsString(ident_token);
var s = scope;
var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already
@ -6808,43 +6820,13 @@ fn asmExpr(
};
} else {
const ident_token = symbolic_name + 4;
const str_index = try astgen.identAsString(ident_token);
// TODO this needs extra code for local variables. Have a look at #215 and related
// issues and decide how to handle outputs. Do we want this to be identifiers?
// TODO have a look at #215 and related issues and decide how to
// handle outputs. Do we want this to be identifiers?
// Or maybe we want to force this to be expressions with a pointer type.
// Until that is figured out this is only hooked up for referencing Decls.
// TODO we have put this as an identifier lookup just so that we don't get
// unused vars for outputs. We need to check if this is correct in the future ^^
// so we just put in this simple lookup. This is a workaround.
{
var s = scope;
while (true) switch (s.tag) {
.local_val => {
const local_val = s.cast(Scope.LocalVal).?;
if (local_val.name == str_index) {
local_val.used = true;
break;
}
s = local_val.parent;
},
.local_ptr => {
const local_ptr = s.cast(Scope.LocalPtr).?;
if (local_ptr.name == str_index) {
local_ptr.used = true;
break;
}
s = local_ptr.parent;
},
.gen_zir => s = s.cast(GenZir).?.parent,
.defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
.namespace, .top => break,
};
}
const operand = try gz.addStrTok(.decl_ref, str_index, ident_token);
outputs[i] = .{
.name = name,
.constraint = constraint,
.operand = operand,
.operand = try localVarRef(gz, scope, rl, node, ident_token),
};
}
}
@ -6860,7 +6842,7 @@ fn asmExpr(
const name = try astgen.identAsString(symbolic_name);
const constraint_token = symbolic_name + 2;
const constraint = (try astgen.strLitAsString(constraint_token)).index;
const operand = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input_node].lhs);
const operand = try expr(gz, scope, .none, node_datas[input_node].lhs);
inputs[i] = .{
.name = name,
.constraint = constraint,

View File

@ -10253,6 +10253,11 @@ fn zirAsm(
const inputs_len = @truncate(u5, extended.small >> 5);
const clobbers_len = @truncate(u5, extended.small >> 10);
const is_volatile = @truncate(u1, extended.small >> 15) != 0;
const is_global_assembly = sema.func == null;
if (block.is_comptime and !is_global_assembly) {
try sema.requireRuntimeBlock(block, src);
}
if (extra.data.asm_source == 0) {
// This can move to become an AstGen error after inline assembly improvements land
@ -10299,7 +10304,14 @@ fn zirAsm(
const name = sema.code.nullTerminatedString(input.data.name);
_ = name; // TODO: use the name
arg.* = sema.resolveInst(input.data.operand);
const uncasted_arg = sema.resolveInst(input.data.operand);
const uncasted_arg_ty = sema.typeOf(uncasted_arg);
switch (uncasted_arg_ty.zigTypeTag()) {
.ComptimeInt => arg.* = try sema.coerce(block, Type.initTag(.usize), uncasted_arg, src),
.ComptimeFloat => arg.* = try sema.coerce(block, Type.initTag(.f64), uncasted_arg, src),
else => arg.* = uncasted_arg,
}
const constraint = sema.code.nullTerminatedString(input.data.constraint);
needed_capacity += constraint.len / 4 + 1;
inputs[arg_i] = constraint;
@ -10317,7 +10329,6 @@ fn zirAsm(
needed_capacity += (asm_source.len + 3) / 4;
const gpa = sema.gpa;
try sema.requireRuntimeBlock(block, src);
try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity);
const asm_air = try block.addInst(.{
.tag = .assembly,

View File

@ -3014,9 +3014,10 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
} else null;
const writer = f.object.writer();
const inputs_extra_begin = extra_i;
try writer.writeAll("{\n");
for (inputs) |input| {
const inputs_extra_begin = extra_i;
for (inputs) |input, i| {
const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
// This equation accounts for the fact that even if we have exactly 4 bytes
// 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 {
try f.writeCValue(writer, arg_c_value);
try writer.writeAll(";\n");
} else {
return f.fail("TODO non-explicit inline asm regs", .{});
try writer.writeAll("register ");
try f.renderType(writer, f.air.typeOf(input));
try writer.print(" input_{d} = ", .{i});
try f.writeCValue(writer, try f.resolveInst(input));
try writer.writeAll(";\n");
}
}
@ -3074,12 +3079,15 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
}
try writer.print("\"r\"({s}_constant)", .{reg});
} else {
// This is blocked by the earlier test
unreachable;
if (index > 0) {
try writer.writeAll(", ");
}
try writer.print("\"r\"(input_{d})", .{index});
}
}
}
try writer.writeAll(");\n");
try writer.writeAll("}\n");
if (f.liveness.isUnused(inst))
return CValue.none;

View File

@ -165,10 +165,7 @@ test {
}
if (builtin.os.tag != .wasi) {
if (builtin.zig_backend == .stage1) {
// TODO get these tests passing with stage2
_ = @import("behavior/asm.zig");
}
_ = @import("behavior/asm.zig");
}
if (builtin.zig_backend != .stage2_arm and

View File

@ -5,7 +5,10 @@ const expect = std.testing.expect;
const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux;
comptime {
if (is_x86_64_linux) {
if (builtin.zig_backend != .stage2_arm and
builtin.zig_backend != .stage2_aarch64 and
is_x86_64_linux)
{
asm (
\\.globl this_is_my_alias;
\\.type this_is_my_alias, @function;
@ -15,12 +18,26 @@ comptime {
}
test "module level assembly" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
if (is_x86_64_linux) {
try expect(this_is_my_alias() == 1234);
}
}
test "output constraint modifiers" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
// This is only testing compilation.
var a: u32 = 3;
asm volatile (""
@ -36,6 +53,13 @@ test "output constraint modifiers" {
}
test "alternative constraints" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
// Make sure we allow commas as a separator for alternative constraints.
var a: u32 = 3;
asm volatile (""
@ -46,6 +70,11 @@ test "alternative constraints" {
}
test "sized integer/float in asm input" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
asm volatile (""
:
: [_] "m" (@as(usize, 3)),
@ -89,6 +118,13 @@ test "sized integer/float in asm input" {
}
test "struct/array/union types as input values" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
asm volatile (""
:
: [_] "m" (@as([1]u32, undefined)),