aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-07-14 21:57:40 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-07-20 12:19:16 -0700
commitc020a302960c499ffe811dd0601a2d386c191b91 (patch)
treecdcc37a5a2efc0ade7be07c8c014d1f82f8d547b /src
parent27be4f31402557972ae28d552f4ec4617357d454 (diff)
downloadzig-c020a302960c499ffe811dd0601a2d386c191b91.tar.gz
zig-c020a302960c499ffe811dd0601a2d386c191b91.zip
Sema: remove br_block_flat AIR instruction
Thanks to the new AIR memory layout, we can do this by turning a br operand into a block, rather than having this special purpose instruction.
Diffstat (limited to 'src')
-rw-r--r--src/Air.zig4
-rw-r--r--src/Liveness.zig2
-rw-r--r--src/Module.zig2
-rw-r--r--src/Sema.zig170
4 files changed, 105 insertions, 73 deletions
diff --git a/src/Air.zig b/src/Air.zig
index e2eeae1130..60e6e9933d 100644
--- a/src/Air.zig
+++ b/src/Air.zig
@@ -308,10 +308,6 @@ pub const Inst = struct {
operand: Ref,
payload: u32,
},
- constant: struct {
- ty: Type,
- val: Value,
- },
dbg_stmt: struct {
line: u32,
column: u32,
diff --git a/src/Liveness.zig b/src/Liveness.zig
index 838f19d4a1..98af9eb429 100644
--- a/src/Liveness.zig
+++ b/src/Liveness.zig
@@ -299,8 +299,6 @@ fn analyzeInst(
const extra = a.air.extraData(Air.Block, inst_datas[inst].ty_pl.payload);
const body = a.air.extra[extra.end..][0..extra.data.body_len];
try analyzeWithContext(a, new_set, body);
- // We let this continue so that it can possibly mark the block as
- // unreferenced below.
return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none });
},
.loop => {
diff --git a/src/Module.zig b/src/Module.zig
index 4bd48dad05..94d8b63744 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -1185,7 +1185,7 @@ pub const Scope = struct {
block_inst: Air.Inst.Index,
/// Separate array list from break_inst_list so that it can be passed directly
/// to resolvePeerTypes.
- results: ArrayListUnmanaged(Air.Inst.Index),
+ results: ArrayListUnmanaged(Air.Inst.Ref),
/// Keeps track of the break instructions so that the operand can be replaced
/// if we need to add type coercion at the end of block analysis.
/// Same indexes, capacity, length as `results`.
diff --git a/src/Sema.zig b/src/Sema.zig
index 48ad8d97fc..b4e8cd5af5 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -163,36 +163,36 @@ pub fn analyzeBody(
const air_inst: Air.Inst.Ref = switch (tags[inst]) {
// zig fmt: off
.arg => try sema.zirArg(block, inst),
- //.alloc => try sema.zirAlloc(block, inst),
- //.alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
- //.alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
- //.alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst),
- //.alloc_mut => try sema.zirAllocMut(block, inst),
- //.alloc_comptime => try sema.zirAllocComptime(block, inst),
- //.anyframe_type => try sema.zirAnyframeType(block, inst),
- //.array_cat => try sema.zirArrayCat(block, inst),
- //.array_mul => try sema.zirArrayMul(block, inst),
- //.array_type => try sema.zirArrayType(block, inst),
- //.array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
- //.vector_type => try sema.zirVectorType(block, inst),
- //.as => try sema.zirAs(block, inst),
- //.as_node => try sema.zirAsNode(block, inst),
- //.bit_and => try sema.zirBitwise(block, inst, .bit_and),
- //.bit_not => try sema.zirBitNot(block, inst),
- //.bit_or => try sema.zirBitwise(block, inst, .bit_or),
- //.bitcast => try sema.zirBitcast(block, inst),
- //.bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
- //.block => try sema.zirBlock(block, inst),
- //.suspend_block => try sema.zirSuspendBlock(block, inst),
- //.bool_not => try sema.zirBoolNot(block, inst),
- //.bool_br_and => try sema.zirBoolBr(block, inst, false),
- //.bool_br_or => try sema.zirBoolBr(block, inst, true),
- //.c_import => try sema.zirCImport(block, inst),
- //.call => try sema.zirCall(block, inst, .auto, false),
- //.call_chkused => try sema.zirCall(block, inst, .auto, true),
- //.call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
- //.call_nosuspend => try sema.zirCall(block, inst, .no_async, false),
- //.call_async => try sema.zirCall(block, inst, .async_kw, false),
+ .alloc => try sema.zirAlloc(block, inst),
+ .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
+ .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
+ .alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst),
+ .alloc_mut => try sema.zirAllocMut(block, inst),
+ .alloc_comptime => try sema.zirAllocComptime(block, inst),
+ .anyframe_type => try sema.zirAnyframeType(block, inst),
+ .array_cat => try sema.zirArrayCat(block, inst),
+ .array_mul => try sema.zirArrayMul(block, inst),
+ .array_type => try sema.zirArrayType(block, inst),
+ .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
+ .vector_type => try sema.zirVectorType(block, inst),
+ .as => try sema.zirAs(block, inst),
+ .as_node => try sema.zirAsNode(block, inst),
+ .bit_and => try sema.zirBitwise(block, inst, .bit_and),
+ .bit_not => try sema.zirBitNot(block, inst),
+ .bit_or => try sema.zirBitwise(block, inst, .bit_or),
+ .bitcast => try sema.zirBitcast(block, inst),
+ .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
+ .block => try sema.zirBlock(block, inst),
+ .suspend_block => try sema.zirSuspendBlock(block, inst),
+ .bool_not => try sema.zirBoolNot(block, inst),
+ .bool_br_and => try sema.zirBoolBr(block, inst, false),
+ .bool_br_or => try sema.zirBoolBr(block, inst, true),
+ .c_import => try sema.zirCImport(block, inst),
+ .call => try sema.zirCall(block, inst, .auto, false),
+ .call_chkused => try sema.zirCall(block, inst, .auto, true),
+ .call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
+ .call_nosuspend => try sema.zirCall(block, inst, .no_async, false),
+ .call_async => try sema.zirCall(block, inst, .async_kw, false),
.cmp_eq => try sema.zirCmp(block, inst, .eq),
.cmp_gt => try sema.zirCmp(block, inst, .gt),
.cmp_gte => try sema.zirCmp(block, inst, .gte),
@@ -1957,24 +1957,23 @@ fn analyzeBlockBody(
// Blocks must terminate with noreturn instruction.
assert(child_block.instructions.items.len != 0);
- assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn());
+ assert(sema.getTypeOf(indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1])).isNoReturn());
if (merges.results.items.len == 0) {
// No need for a block instruction. We can put the new instructions
// directly into the parent block.
- const copied_instructions = try sema.arena.dupe(Air.Inst.Index, child_block.instructions.items);
- try parent_block.instructions.appendSlice(gpa, copied_instructions);
- return copied_instructions[copied_instructions.len - 1];
+ try parent_block.instructions.appendSlice(gpa, child_block.instructions.items);
+ return indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1]);
}
if (merges.results.items.len == 1) {
const last_inst_index = child_block.instructions.items.len - 1;
const last_inst = child_block.instructions.items[last_inst_index];
- if (last_inst.breakBlock()) |br_block| {
+ if (sema.getBreakBlock(last_inst)) |br_block| {
if (br_block == merges.block_inst) {
// No need for a block instruction. We can put the new instructions directly
// into the parent block. Here we omit the break instruction.
- const copied_instructions = try sema.arena.dupe(Air.Inst.Index, child_block.instructions.items[0..last_inst_index]);
- try parent_block.instructions.appendSlice(gpa, copied_instructions);
+ const without_break = child_block.instructions.items[0..last_inst_index];
+ try parent_block.instructions.appendSlice(gpa, without_break);
return merges.results.items[0];
}
}
@@ -1998,36 +1997,50 @@ fn analyzeBlockBody(
// Now that the block has its type resolved, we need to go back into all the break
// instructions, and insert type coercion on the operands.
for (merges.br_list.items) |br| {
- if (sema.getTypeOf(br.operand).eql(resolved_ty)) {
+ const br_operand = sema.air_instructions.items(.data)[br].br.operand;
+ const br_operand_src = src;
+ const br_operand_ty = sema.getTypeOf(br_operand);
+ if (br_operand_ty.eql(resolved_ty)) {
// No type coercion needed.
continue;
}
var coerce_block = parent_block.makeSubBlock();
defer coerce_block.instructions.deinit(gpa);
- const coerced_operand = try sema.coerce(&coerce_block, resolved_ty, br.operand, br.operand.src);
+ const coerced_operand = try sema.coerce(&coerce_block, resolved_ty, br_operand, br_operand_src);
// If no instructions were produced, such as in the case of a coercion of a
// constant value to a new type, we can simply point the br operand to it.
if (coerce_block.instructions.items.len == 0) {
- br.operand = coerced_operand;
+ sema.air_instructions.items(.data)[br].br.operand = coerced_operand;
continue;
}
- assert(coerce_block.instructions.items[coerce_block.instructions.items.len - 1] == coerced_operand);
- // Here we depend on the br instruction having been over-allocated (if necessary)
- // inside zirBreak so that it can be converted into a br_block_flat instruction.
- const br_src = br.base.src;
- const br_ty = br.base.ty;
- const br_block_flat = @ptrCast(*Inst.BrBlockFlat, br);
- br_block_flat.* = .{
- .base = .{
- .src = br_src,
- .ty = br_ty,
- .tag = .br_block_flat,
- },
- .block = merges.block_inst,
- .body = .{
- .instructions = try sema.arena.dupe(Air.Inst.Index, coerce_block.instructions.items),
- },
- };
+ assert(coerce_block.instructions.items[coerce_block.instructions.items.len - 1] ==
+ refToIndex(coerced_operand).?);
+
+ // Convert the br operand to a block.
+ try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
+ coerce_block.instructions.items.len);
+ try sema.air_instructions.ensureUnusedCapacity(gpa, 2);
+ const sub_block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
+ const sub_br_inst = sub_block_inst + 1;
+ sema.air_instructions.items(.data)[br].br.operand = indexToRef(sub_block_inst);
+ sema.air_instructions.appendAssumeCapacity(.{
+ .tag = .block,
+ .data = .{ .ty_pl = .{
+ .ty = try sema.addType(br_operand_ty),
+ .payload = sema.addExtraAssumeCapacity(Air.Block{
+ .body_len = @intCast(u32, coerce_block.instructions.items.len),
+ }),
+ } },
+ });
+ sema.air_extra.appendSliceAssumeCapacity(coerce_block.instructions.items);
+ sema.air_extra.appendAssumeCapacity(sub_br_inst);
+ sema.air_instructions.appendAssumeCapacity(.{
+ .tag = .br,
+ .data = .{ .br = .{
+ .block_inst = sub_block_inst,
+ .operand = coerced_operand,
+ } },
+ });
}
return indexToRef(merges.block_inst);
}
@@ -2257,10 +2270,11 @@ fn analyzeCall(
ensure_result_used: bool,
args: []const Air.Inst.Ref,
) CompileError!Air.Inst.Ref {
- if (func.ty.zigTypeTag() != .Fn)
- return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func.ty});
+ const func_ty = sema.getTypeOf(func);
+ if (func_ty.zigTypeTag() != .Fn)
+ return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func_ty});
- const cc = func.ty.fnCallingConvention();
+ const cc = func_ty.fnCallingConvention();
if (cc == .Naked) {
// TODO add error note: declared here
return sema.mod.fail(
@@ -2270,8 +2284,8 @@ fn analyzeCall(
.{},
);
}
- const fn_params_len = func.ty.fnParamLen();
- if (func.ty.fnIsVarArgs()) {
+ const fn_params_len = func_ty.fnParamLen();
+ if (func_ty.fnIsVarArgs()) {
assert(cc == .C);
if (args.len < fn_params_len) {
// TODO add error note: declared here
@@ -2310,11 +2324,9 @@ fn analyzeCall(
const gpa = sema.gpa;
- const ret_type = func.ty.fnReturnType();
-
const is_comptime_call = block.is_comptime or modifier == .compile_time;
const is_inline_call = is_comptime_call or modifier == .always_inline or
- func.ty.fnCallingConvention() == .Inline;
+ func_ty.fnCallingConvention() == .Inline;
const result: Air.Inst.Ref = if (is_inline_call) res: {
const func_val = try sema.resolveConstValue(block, func_src, func);
const module_fn = switch (func_val.tag()) {
@@ -2400,7 +2412,19 @@ fn analyzeCall(
break :res result;
} else res: {
try sema.requireRuntimeBlock(block, call_src);
- break :res try block.addCall(call_src, ret_type, func, args);
+ try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
+ args.len);
+ const func_inst = try block.addInst(.{
+ .tag = .call,
+ .data = .{ .pl_op = .{
+ .operand = func,
+ .payload = sema.addExtraAssumeCapacity(Air.Call{
+ .args_len = @intCast(u32, args.len),
+ }),
+ } },
+ });
+ sema.appendRefsAssumeCapacity(args);
+ break :res func_inst;
};
if (ensure_result_used) {
@@ -8140,3 +8164,17 @@ pub fn addExtraAssumeCapacity(sema: *Sema, extra: anytype) u32 {
}
return result;
}
+
+fn appendRefsAssumeCapacity(sema: *Sema, refs: []const Air.Inst.Ref) void {
+ const coerced = @bitCast([]const u32, refs);
+ sema.air_extra.appendSliceAssumeCapacity(coerced);
+}
+
+fn getBreakBlock(sema: *Sema, inst_index: Air.Inst.Index) ?Air.Inst.Index {
+ const air_datas = sema.air_instructions.items(.data);
+ const air_tags = sema.air_instructions.items(.tag);
+ switch (air_tags[inst_index]) {
+ .br => return air_datas[inst_index].br.block_inst,
+ else => return null,
+ }
+}