From 65389dc280b97365605bc3f7f4038c1972534b9a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 2 May 2022 20:19:31 -0700 Subject: stage2: improve inline asm stage1 compatibility * outputs can have names and be referenced with template replacements the same as inputs. * fix print_air.zig not decoding correctly. * LLVM backend: use a table for template names for simplicity --- src/codegen/c.zig | 10 +++++++--- src/codegen/llvm.zig | 37 +++++++++++++++++-------------------- 2 files changed, 24 insertions(+), 23 deletions(-) (limited to 'src/codegen') diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 2cd93d47fc..44b616c493 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3018,10 +3018,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { if (output != .none) { return f.fail("TODO implement codegen for non-expr asm", .{}); } + const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 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. - extra_i += constraint.len / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; break constraint; } else null; @@ -3031,10 +3033,12 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { const inputs_extra_begin = extra_i; for (inputs) |input, i| { - const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0); + const input_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); + const constraint = std.mem.sliceTo(input_bytes, 0); + const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 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. - extra_i += constraint.len / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') { const reg = constraint[1 .. constraint.len - 1]; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index c9ea5bebac..63e7eece99 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -4638,14 +4638,19 @@ pub const FuncGen = struct { var llvm_param_i: usize = 0; var total_i: usize = 0; + var name_map: std.StringArrayHashMapUnmanaged(void) = .{}; + try name_map.ensureUnusedCapacity(arena, outputs.len + inputs.len); + for (outputs) |output| { if (output != .none) { return self.todo("implement inline asm with non-returned output", .{}); } + const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 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. - extra_i += constraint.len / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; try llvm_constraints.ensureUnusedCapacity(self.gpa, constraint.len + 1); if (total_i != 0) { @@ -4654,17 +4659,17 @@ pub const FuncGen = struct { llvm_constraints.appendAssumeCapacity('='); llvm_constraints.appendSliceAssumeCapacity(constraint[1..]); + name_map.putAssumeCapacityNoClobber(name, {}); total_i += 1; } - const input_start_extra_i = extra_i; for (inputs) |input| { - const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); - const constraint = std.mem.sliceTo(input_bytes, 0); - const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); + const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); + const constraint = std.mem.sliceTo(extra_bytes, 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 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. - extra_i += (constraint.len + input_name.len + 1) / 4 + 1; + extra_i += (constraint.len + name.len + (2 + 3)) / 4; const arg_llvm_value = try self.resolveInst(input); @@ -4677,6 +4682,7 @@ pub const FuncGen = struct { } llvm_constraints.appendSliceAssumeCapacity(constraint); + name_map.putAssumeCapacityNoClobber(name, {}); llvm_param_i += 1; total_i += 1; } @@ -4739,20 +4745,11 @@ pub const FuncGen = struct { const name = asm_source[name_start..i]; state = .start; - extra_i = input_start_extra_i; - for (inputs) |_, input_i| { - const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]); - const constraint = std.mem.sliceTo(input_bytes, 0); - const input_name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); - extra_i += (constraint.len + input_name.len + 1) / 4 + 1; - - if (std.mem.eql(u8, name, input_name)) { - try rendered_template.writer().print("{d}", .{input_i}); - break; - } - } else { - return self.todo("TODO validate asm in Sema", .{}); - } + const index = name_map.getIndex(name) orelse { + // we should validate the assembly in Sema; by now it is too late + return self.todo("unknown input or output name: '{s}'", .{name}); + }; + try rendered_template.writer().print("{d}", .{index}); }, else => {}, }, -- cgit v1.2.3