diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-02-18 19:41:32 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-02-18 19:41:32 -0700 |
| commit | 4e1e5ab6221b72ef2be9f1fb40c2e6d1235718fe (patch) | |
| tree | 2210dfbf4e6d445b6f3e6cdba4e6d18e5a41cbde /src/arch/x86_64/CodeGen.zig | |
| parent | 123076ea88a809888692b308ab5bb214dc3a2caf (diff) | |
| download | zig-4e1e5ab6221b72ef2be9f1fb40c2e6d1235718fe.tar.gz zig-4e1e5ab6221b72ef2be9f1fb40c2e6d1235718fe.zip | |
stage2: make AIR not reference ZIR for inline assembly
Instead it stores all the information it needs to into AIR.
closes #10784
Diffstat (limited to 'src/arch/x86_64/CodeGen.zig')
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 112 |
1 files changed, 69 insertions, 43 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index bf49aedd2d..6c04023c38 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -26,7 +26,6 @@ const Target = std.Target; const Type = @import("../../type.zig").Type; const TypedValue = @import("../../TypedValue.zig"); const Value = @import("../../value.zig").Value; -const Zir = @import("../../Zir.zig"); const InnerError = error{ OutOfMemory, @@ -3415,41 +3414,39 @@ fn brVoid(self: *Self, block: Air.Inst.Index) !void { } fn airAsm(self: *Self, inst: Air.Inst.Index) !void { - const air_datas = self.air.instructions.items(.data); - const air_extra = self.air.extraData(Air.Asm, air_datas[inst].ty_pl.payload); - const zir = self.mod_fn.owner_decl.getFileScope().zir; - const extended = zir.instructions.items(.data)[air_extra.data.zir_index].extended; - const zir_extra = zir.extraData(Zir.Inst.Asm, extended.operand); - const asm_source = zir.nullTerminatedString(zir_extra.data.asm_source); - const outputs_len = @truncate(u5, extended.small); - const args_len = @truncate(u5, extended.small >> 5); - const clobbers_len = @truncate(u5, extended.small >> 10); - _ = clobbers_len; // TODO honor these - const is_volatile = @truncate(u1, extended.small >> 15) != 0; - const args = @bitCast([]const Air.Inst.Ref, self.air.extra[air_extra.end..][0..args_len]); - - if (outputs_len > 1) { - return self.fail("TODO implement codegen for asm with more than 1 output", .{}); - } - var extra_i: usize = zir_extra.end; - const output_constraint: ?[]const u8 = out: { - var i: usize = 0; - while (i < outputs_len) : (i += 1) { - const output = zir.extraData(Zir.Inst.Asm.Output, extra_i); - extra_i = output.end; - break :out zir.nullTerminatedString(output.data.constraint); - } - break :out null; - }; + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + const extra = self.air.extraData(Air.Asm, ty_pl.payload); + const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0; + const clobbers_len = @truncate(u31, extra.data.flags); + var extra_i: usize = extra.end; + const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]); + extra_i += outputs.len; + const inputs = @bitCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]); + extra_i += inputs.len; const dead = !is_volatile and self.liveness.isUnused(inst); - const result: MCValue = if (dead) - .dead - else result: { - for (args) |arg| { - const input = zir.extraData(Zir.Inst.Asm.Input, extra_i); - extra_i = input.end; - const constraint = zir.nullTerminatedString(input.data.constraint); + const result: MCValue = if (dead) .dead else result: { + if (outputs.len > 1) { + return self.fail("TODO implement codegen for asm with more than 1 output", .{}); + } + + const output_constraint: ?[]const u8 = for (outputs) |output| { + if (output != .none) { + return self.fail("TODO implement codegen for non-expr asm", .{}); + } + const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.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. + extra_i += constraint.len / 4 + 1; + + break constraint; + } else null; + + for (inputs) |input| { + const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.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. + extra_i += constraint.len / 4 + 1; if (constraint.len < 3 or constraint[0] != '{' or constraint[constraint.len - 1] != '}') { return self.fail("unrecognized asm input constraint: '{s}'", .{constraint}); @@ -3458,11 +3455,25 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { const reg = parseRegName(reg_name) orelse return self.fail("unrecognized register: '{s}'", .{reg_name}); - const arg_mcv = try self.resolveInst(arg); + const arg_mcv = try self.resolveInst(input); try self.register_manager.getReg(reg, null); - try self.genSetReg(self.air.typeOf(arg), reg, arg_mcv); + try self.genSetReg(self.air.typeOf(input), reg, arg_mcv); + } + + { + var clobber_i: u32 = 0; + while (clobber_i < clobbers_len) : (clobber_i += 1) { + const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.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. + extra_i += clobber.len / 4 + 1; + + // TODO honor these + } } + const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; + { var iter = std.mem.tokenize(u8, asm_source, "\n\r"); while (iter.next()) |ins| { @@ -3529,14 +3540,29 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { break :result MCValue{ .none = {} }; } }; - if (args.len <= Liveness.bpi - 1) { + + simple: { var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1); - std.mem.copy(Air.Inst.Ref, &buf, args); + var buf_index: usize = 0; + for (outputs) |output| { + if (output == .none) continue; + + if (buf_index >= buf.len) break :simple; + buf[buf_index] = output; + buf_index += 1; + } + if (buf_index + inputs.len > buf.len) break :simple; + std.mem.copy(Air.Inst.Ref, buf[buf_index..], inputs); return self.finishAir(inst, result, buf); } - var bt = try self.iterateBigTomb(inst, args.len); - for (args) |arg| { - bt.feed(arg); + var bt = try self.iterateBigTomb(inst, outputs.len + inputs.len); + for (outputs) |output| { + if (output == .none) continue; + + bt.feed(output); + } + for (inputs) |input| { + bt.feed(input); } return bt.finishAir(result); } @@ -3615,7 +3641,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE const reg = try self.copyToTmpRegister(ty, mcv); return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); }, - else => return self.fail("TODO implement args on stack for {} with abi size > 8", .{mcv}), + else => return self.fail("TODO implement inputs on stack for {} with abi size > 8", .{mcv}), } }, .embedded_in_code => { @@ -3623,7 +3649,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE const reg = try self.copyToTmpRegister(ty, mcv); return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); } - return self.fail("TODO implement args on stack for {} with abi size > 8", .{mcv}); + return self.fail("TODO implement inputs on stack for {} with abi size > 8", .{mcv}); }, .memory, .direct_load, |
