Skip to content

Commit

Permalink
stage2: make AIR not reference ZIR for inline assembly
Browse files Browse the repository at this point in the history
Instead it stores all the information it needs to into AIR.

closes #10784
  • Loading branch information
andrewrk committed Feb 19, 2022
1 parent 123076e commit 4e1e5ab
Show file tree
Hide file tree
Showing 11 changed files with 506 additions and 351 deletions.
22 changes: 18 additions & 4 deletions src/Air.zig
Original file line number Diff line number Diff line change
Expand Up @@ -697,11 +697,25 @@ pub const Bin = struct {
/// Trailing:
/// 0. `Inst.Ref` for every outputs_len
/// 1. `Inst.Ref` for every inputs_len
/// 2. for every outputs_len
/// - constraint: memory at this position is reinterpreted as a null
/// terminated string. pad to the next u32 after the null byte.
/// 3. for every inputs_len
/// - constraint: memory at this position is reinterpreted as a null
/// terminated string. pad to the next u32 after the null byte.
/// 4. for every clobbers_len
/// - clobber_name: memory at this position is reinterpreted as a null
/// terminated string. pad to the next u32 after the null byte.
/// 5. A number of u32 elements follow according to the equation `(source_len + 3) / 4`.
/// Memory starting at this position is reinterpreted as the source bytes.
pub const Asm = struct {
/// Index to the corresponding ZIR instruction.
/// `asm_source`, `outputs_len`, `inputs_len`, `clobbers_len`, `is_volatile`, and
/// clobbers are found via here.
zir_index: u32,
/// Length of the assembly source in bytes.
source_len: u32,
outputs_len: u32,
inputs_len: u32,
/// The MSB is `is_volatile`.
/// The rest of the bits are `clobbers_len`.
flags: u32,
};

pub const Cmpxchg = struct {
Expand Down
4 changes: 2 additions & 2 deletions src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2778,15 +2778,15 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
errdefer if (!liveness_frame_ended) liveness_frame.end();

log.debug("analyze liveness of {s}", .{decl.name});
var liveness = try Liveness.analyze(gpa, air, decl.getFileScope().zir);
var liveness = try Liveness.analyze(gpa, air);
defer liveness.deinit(gpa);

liveness_frame.end();
liveness_frame_ended = true;

if (builtin.mode == .Debug and comp.verbose_air) {
std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});
@import("print_air.zig").dump(gpa, air, decl.getFileScope().zir, liveness);
@import("print_air.zig").dump(gpa, air, liveness);
std.debug.print("# End Function AIR: {s}\n\n", .{decl.name});
}

Expand Down
38 changes: 23 additions & 15 deletions src/Liveness.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ const log = std.log.scoped(.liveness);
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const Air = @import("Air.zig");
const Zir = @import("Zir.zig");
const Log2Int = std.math.Log2Int;

/// This array is split into sets of 4 bits per AIR instruction.
Expand Down Expand Up @@ -52,7 +51,7 @@ pub const SwitchBr = struct {
else_death_count: u32,
};

pub fn analyze(gpa: Allocator, air: Air, zir: Zir) Allocator.Error!Liveness {
pub fn analyze(gpa: Allocator, air: Air) Allocator.Error!Liveness {
const tracy = trace(@src());
defer tracy.end();

Expand All @@ -66,7 +65,6 @@ pub fn analyze(gpa: Allocator, air: Air, zir: Zir) Allocator.Error!Liveness {
),
.extra = .{},
.special = .{},
.zir = &zir,
};
errdefer gpa.free(a.tomb_bits);
errdefer a.special.deinit(gpa);
Expand Down Expand Up @@ -157,7 +155,6 @@ const Analysis = struct {
tomb_bits: []usize,
special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32),
extra: std.ArrayListUnmanaged(u32),
zir: *const Zir,

fn storeTombBits(a: *Analysis, inst: Air.Inst.Index, tomb_bits: Bpi) void {
const usize_index = (inst * bpi) / @bitSizeOf(usize);
Expand Down Expand Up @@ -444,15 +441,24 @@ fn analyzeInst(
},
.assembly => {
const extra = a.air.extraData(Air.Asm, inst_datas[inst].ty_pl.payload);
const extended = a.zir.instructions.items(.data)[extra.data.zir_index].extended;
const outputs_len = @truncate(u5, extended.small);
const inputs_len = @truncate(u5, extended.small >> 5);
const outputs = @bitCast([]const Air.Inst.Ref, a.air.extra[extra.end..][0..outputs_len]);
const args = @bitCast([]const Air.Inst.Ref, a.air.extra[extra.end + outputs.len ..][0..inputs_len]);
if (outputs.len + args.len <= bpi - 1) {
var extra_i: usize = extra.end;
const outputs = @bitCast([]const Air.Inst.Ref, a.air.extra[extra_i..][0..extra.data.outputs_len]);
extra_i += outputs.len;
const inputs = @bitCast([]const Air.Inst.Ref, a.air.extra[extra_i..][0..extra.data.inputs_len]);
extra_i += inputs.len;

simple: {
var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1);
std.mem.copy(Air.Inst.Ref, &buf, outputs);
std.mem.copy(Air.Inst.Ref, buf[outputs.len..], args);
var buf_index: usize = 0;
for (outputs) |output| {
if (output != .none) {
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 trackOperands(a, new_set, inst, main_tomb, buf);
}
var extra_tombs: ExtraTombs = .{
Expand All @@ -462,10 +468,12 @@ fn analyzeInst(
.main_tomb = main_tomb,
};
for (outputs) |output| {
try extra_tombs.feed(output);
if (output != .none) {
try extra_tombs.feed(output);
}
}
for (args) |arg| {
try extra_tombs.feed(arg);
for (inputs) |input| {
try extra_tombs.feed(input);
}
return extra_tombs.finish();
},
Expand Down
52 changes: 46 additions & 6 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,7 @@ fn zirExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.frame_address => return sema.zirFrameAddress( block, extended),
.alloc => return sema.zirAllocExtended( block, extended),
.builtin_extern => return sema.zirBuiltinExtern( block, extended),
.@"asm" => return sema.zirAsm( block, extended, inst),
.@"asm" => return sema.zirAsm( block, extended),
.typeof_peer => return sema.zirTypeofPeer( block, extended),
.compile_log => return sema.zirCompileLog( block, extended),
.add_with_overflow => return sema.zirOverflowArithmetic(block, extended, extended.opcode),
Expand Down Expand Up @@ -9083,7 +9083,6 @@ fn zirAsm(
sema: *Sema,
block: *Block,
extended: Zir.Inst.Extended.InstData,
inst: Zir.Inst.Index,
) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
Expand All @@ -9094,6 +9093,7 @@ fn zirAsm(
const outputs_len = @truncate(u5, extended.small);
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;

if (extra.data.asm_source == 0) {
// This can move to become an AstGen error after inline assembly improvements land
Expand All @@ -9107,6 +9107,7 @@ fn zirAsm(

var extra_i = extra.end;
var output_type_bits = extra.data.output_type_bits;
var needed_capacity: usize = @typeInfo(Air.Asm).Struct.fields.len + outputs_len + inputs_len;

const Output = struct { constraint: []const u8, ty: Type };
const output: ?Output = if (outputs_len == 0) null else blk: {
Expand All @@ -9121,6 +9122,8 @@ fn zirAsm(
}

const constraint = sema.code.nullTerminatedString(output.data.constraint);
needed_capacity += constraint.len / 4 + 1;

break :blk Output{
.constraint = constraint,
.ty = try sema.resolveType(block, ret_ty_src, output.data.operand),
Expand All @@ -9138,28 +9141,65 @@ fn zirAsm(
_ = name; // TODO: use the name

arg.* = sema.resolveInst(input.data.operand);
inputs[arg_i] = sema.code.nullTerminatedString(input.data.constraint);
const constraint = sema.code.nullTerminatedString(input.data.constraint);
needed_capacity += constraint.len / 4 + 1;
inputs[arg_i] = constraint;
}

const clobbers = try sema.arena.alloc([]const u8, clobbers_len);
for (clobbers) |*name| {
name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
extra_i += 1;

needed_capacity += name.*.len / 4 + 1;
}

try sema.requireRuntimeBlock(block, src);
const asm_source = sema.code.nullTerminatedString(extra.data.asm_source);
needed_capacity += (asm_source.len + 3) / 4;

const gpa = sema.gpa;
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Asm).Struct.fields.len + args.len);
try sema.requireRuntimeBlock(block, src);
try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity);
const asm_air = try block.addInst(.{
.tag = .assembly,
.data = .{ .ty_pl = .{
.ty = if (output) |o| try sema.addType(o.ty) else Air.Inst.Ref.void_type,
.payload = sema.addExtraAssumeCapacity(Air.Asm{
.zir_index = inst,
.source_len = @intCast(u32, asm_source.len),
.outputs_len = outputs_len,
.inputs_len = @intCast(u32, args.len),
.flags = (@as(u32, @boolToInt(is_volatile)) << 31) | @intCast(u32, clobbers.len),
}),
} },
});
if (output != null) {
// Indicate the output is the asm instruction return value.
sema.air_extra.appendAssumeCapacity(@enumToInt(Air.Inst.Ref.none));
}
sema.appendRefsAssumeCapacity(args);
if (output) |o| {
const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
mem.copy(u8, buffer, o.constraint);
buffer[o.constraint.len] = 0;
sema.air_extra.items.len += o.constraint.len / 4 + 1;
}
for (inputs) |constraint| {
const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
mem.copy(u8, buffer, constraint);
buffer[constraint.len] = 0;
sema.air_extra.items.len += constraint.len / 4 + 1;
}
for (clobbers) |clobber| {
const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
mem.copy(u8, buffer, clobber);
buffer[clobber.len] = 0;
sema.air_extra.items.len += clobber.len / 4 + 1;
}
{
const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
mem.copy(u8, buffer, asm_source);
sema.air_extra.items.len += (asm_source.len + 3) / 4;
}
return asm_air;
}

Expand Down
Loading

0 comments on commit 4e1e5ab

Please sign in to comment.