Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AIR independence day #10924

Merged
merged 3 commits into from
Feb 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lib/std/array_list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
pub fn allocatedSlice(self: Self) Slice {
return self.items.ptr[0..self.capacity];
}

/// Returns a slice of only the extra capacity after items.
/// This can be useful for writing directly into an ArrayList.
/// Note that such an operation must be followed up with a direct
/// modification of `self.items.len`.
pub fn unusedCapacitySlice(self: Self) Slice {
return self.allocatedSlice()[self.items.len..];
}
};
}

Expand Down
33 changes: 20 additions & 13 deletions src/Air.zig
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ pub const Inst = struct {
/// The first N instructions in the main block must be one arg instruction per
/// function parameter. This makes function parameters participate in
/// liveness analysis without any special handling.
/// Uses the `ty_str` field.
/// The string is the parameter name.
/// Uses the `ty` field.
arg,
/// Float or integer addition. For integers, wrapping is undefined behavior.
/// Both operands are guaranteed to be the same type, and the result type
Expand Down Expand Up @@ -615,11 +614,6 @@ pub const Inst = struct {
// Index into a different array.
payload: u32,
},
ty_str: struct {
ty: Ref,
// ZIR string table index.
str: u32,
},
br: struct {
block_inst: Index,
operand: Ref,
Expand Down Expand Up @@ -703,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 Expand Up @@ -759,8 +767,6 @@ pub fn typeOf(air: Air, inst: Air.Inst.Ref) Type {
pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
const datas = air.instructions.items(.data);
switch (air.instructions.items(.tag)[inst]) {
.arg => return air.getRefType(datas[inst].ty_str.ty),

.add,
.addwrap,
.add_sat,
Expand Down Expand Up @@ -827,6 +833,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {

.alloc,
.ret_ptr,
.arg,
=> return datas[inst].ty,

.assembly,
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
26 changes: 21 additions & 5 deletions src/Module.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1370,6 +1370,14 @@ pub const Fn = struct {
/// ZIR instruction.
zir_body_inst: Zir.Inst.Index,

/// Prefer to use `getParamName` to access this because of the future improvement
/// we want to do mentioned in the TODO below.
/// Stored in gpa.
/// TODO: change param ZIR instructions to be embedded inside the function
/// ZIR instruction instead of before it, so that `zir_body_inst` can be used to
/// determine param names rather than redundantly storing them here.
param_names: []const [:0]const u8,

/// Relative to owner Decl.
lbrace_line: u32,
/// Relative to owner Decl.
Expand Down Expand Up @@ -1466,6 +1474,18 @@ pub const Fn = struct {
gpa.destroy(node);
it = next;
}

for (func.param_names) |param_name| {
gpa.free(param_name);
}
gpa.free(func.param_names);
}

pub fn getParamName(func: Fn, index: u32) [:0]const u8 {
// TODO rework ZIR of parameters so that this function looks up
// param names in ZIR instead of redundantly saving them into Fn.
// const zir = func.owner_decl.getFileScope().zir;
return func.param_names[index];
}
};

Expand Down Expand Up @@ -4606,15 +4626,11 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
runtime_param_index += 1;
continue;
}
const ty_ref = try sema.addType(param_type);
const arg_index = @intCast(u32, sema.air_instructions.len);
inner_block.instructions.appendAssumeCapacity(arg_index);
sema.air_instructions.appendAssumeCapacity(.{
.tag = .arg,
.data = .{ .ty_str = .{
.ty = ty_ref,
.str = param.name,
} },
.data = .{ .ty = param_type },
});
sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index));
total_param_index += 1;
Expand Down
Loading