stage2: codegen.zig updated to new AIR memory layout
This commit is contained in:
143
src/Air.zig
143
src/Air.zig
@@ -13,9 +13,9 @@ const Air = @This();
|
||||
instructions: std.MultiArrayList(Inst).Slice,
|
||||
/// The meaning of this data is determined by `Inst.Tag` value.
|
||||
/// The first few indexes are reserved. See `ExtraIndex` for the values.
|
||||
extra: []u32,
|
||||
values: []Value,
|
||||
variables: []*Module.Var,
|
||||
extra: []const u32,
|
||||
values: []const Value,
|
||||
variables: []const *Module.Var,
|
||||
|
||||
pub const ExtraIndex = enum(u32) {
|
||||
/// Payload index of the main `Block` in the `extra` array.
|
||||
@@ -378,22 +378,109 @@ pub fn getMainBody(air: Air) []const Air.Inst.Index {
|
||||
return air.extra[extra.end..][0..extra.data.body_len];
|
||||
}
|
||||
|
||||
pub fn getType(air: Air, inst: Air.Inst.Index) Type {
|
||||
_ = air;
|
||||
_ = inst;
|
||||
@panic("TODO Air getType");
|
||||
pub fn typeOf(air: Air, inst: Air.Inst.Ref) Type {
|
||||
const ref_int = @enumToInt(inst);
|
||||
if (ref_int < Air.Inst.Ref.typed_value_map.len) {
|
||||
return Air.Inst.Ref.typed_value_map[ref_int].ty;
|
||||
}
|
||||
return air.typeOfIndex(@intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len));
|
||||
}
|
||||
|
||||
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,
|
||||
.sub,
|
||||
.subwrap,
|
||||
.mul,
|
||||
.mulwrap,
|
||||
.div,
|
||||
.bit_and,
|
||||
.bit_or,
|
||||
.xor,
|
||||
=> return air.typeOf(datas[inst].bin_op.lhs),
|
||||
|
||||
.cmp_lt,
|
||||
.cmp_lte,
|
||||
.cmp_eq,
|
||||
.cmp_gte,
|
||||
.cmp_gt,
|
||||
.cmp_neq,
|
||||
.is_null,
|
||||
.is_non_null,
|
||||
.is_null_ptr,
|
||||
.is_non_null_ptr,
|
||||
.is_err,
|
||||
.is_non_err,
|
||||
.is_err_ptr,
|
||||
.is_non_err_ptr,
|
||||
.bool_and,
|
||||
.bool_or,
|
||||
=> return Type.initTag(.bool),
|
||||
|
||||
.const_ty => return Type.initTag(.type),
|
||||
|
||||
.alloc => return datas[inst].ty,
|
||||
|
||||
.assembly,
|
||||
.block,
|
||||
.constant,
|
||||
.varptr,
|
||||
.struct_field_ptr,
|
||||
=> return air.getRefType(datas[inst].ty_pl.ty),
|
||||
|
||||
.not,
|
||||
.bitcast,
|
||||
.load,
|
||||
.ref,
|
||||
.floatcast,
|
||||
.intcast,
|
||||
.optional_payload,
|
||||
.optional_payload_ptr,
|
||||
.wrap_optional,
|
||||
.unwrap_errunion_payload,
|
||||
.unwrap_errunion_err,
|
||||
.unwrap_errunion_payload_ptr,
|
||||
.unwrap_errunion_err_ptr,
|
||||
.wrap_errunion_payload,
|
||||
.wrap_errunion_err,
|
||||
=> return air.getRefType(datas[inst].ty_op.ty),
|
||||
|
||||
.loop,
|
||||
.br,
|
||||
.cond_br,
|
||||
.switch_br,
|
||||
.ret,
|
||||
.unreach,
|
||||
=> return Type.initTag(.noreturn),
|
||||
|
||||
.breakpoint,
|
||||
.dbg_stmt,
|
||||
.store,
|
||||
=> return Type.initTag(.void),
|
||||
|
||||
.ptrtoint => return Type.initTag(.usize),
|
||||
|
||||
.call => {
|
||||
const callee_ty = air.typeOf(datas[inst].pl_op.operand);
|
||||
return callee_ty.fnReturnType();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getRefType(air: Air, ref: Air.Inst.Ref) Type {
|
||||
var i: usize = @enumToInt(ref);
|
||||
if (i < Air.Inst.Ref.typed_value_map.len) {
|
||||
return Air.Inst.Ref.typed_value_map[i].val.toType(undefined) catch unreachable;
|
||||
const ref_int = @enumToInt(ref);
|
||||
if (ref_int < Air.Inst.Ref.typed_value_map.len) {
|
||||
return Air.Inst.Ref.typed_value_map[ref_int].val.toType(undefined) catch unreachable;
|
||||
}
|
||||
i -= Air.Inst.Ref.typed_value_map.len;
|
||||
const inst_index = ref_int - Air.Inst.Ref.typed_value_map.len;
|
||||
const air_tags = air.instructions.items(.tag);
|
||||
const air_datas = air.instructions.items(.data);
|
||||
assert(air_tags[i] == .const_ty);
|
||||
return air_datas[i].ty;
|
||||
assert(air_tags[inst_index] == .const_ty);
|
||||
return air_datas[inst_index].ty;
|
||||
}
|
||||
|
||||
/// Returns the requested data, as well as the new index which is at the start of the
|
||||
@@ -424,3 +511,33 @@ pub fn deinit(air: *Air, gpa: *std.mem.Allocator) void {
|
||||
gpa.free(air.variables);
|
||||
air.* = undefined;
|
||||
}
|
||||
|
||||
const ref_start_index: u32 = Air.Inst.Ref.typed_value_map.len;
|
||||
|
||||
pub fn indexToRef(inst: Air.Inst.Index) Air.Inst.Ref {
|
||||
return @intToEnum(Air.Inst.Ref, ref_start_index + inst);
|
||||
}
|
||||
|
||||
pub fn refToIndex(inst: Air.Inst.Ref) ?Air.Inst.Index {
|
||||
const ref_int = @enumToInt(inst);
|
||||
if (ref_int >= ref_start_index) {
|
||||
return ref_int - ref_start_index;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `null` if runtime-known.
|
||||
pub fn value(air: Air, inst: Air.Inst.Ref) ?Value {
|
||||
const ref_int = @enumToInt(inst);
|
||||
if (ref_int < Air.Inst.Ref.typed_value_map.len) {
|
||||
return Air.Inst.Ref.typed_value_map[ref_int].val;
|
||||
}
|
||||
const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
|
||||
const air_datas = air.instructions.items(.data);
|
||||
switch (air.instructions.items(.tag)[inst_index]) {
|
||||
.constant => return air.values[air_datas[inst_index].ty_pl.payload],
|
||||
.const_ty => unreachable,
|
||||
else => return air.typeOfIndex(inst_index).onePossibleValue(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6412,37 +6412,12 @@ fn multilineStringLiteral(
|
||||
node: ast.Node.Index,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const astgen = gz.astgen;
|
||||
const tree = astgen.tree;
|
||||
const node_datas = tree.nodes.items(.data);
|
||||
|
||||
const start = node_datas[node].lhs;
|
||||
const end = node_datas[node].rhs;
|
||||
|
||||
const gpa = gz.astgen.gpa;
|
||||
const string_bytes = &gz.astgen.string_bytes;
|
||||
const str_index = string_bytes.items.len;
|
||||
|
||||
// First line: do not append a newline.
|
||||
var tok_i = start;
|
||||
{
|
||||
const slice = tree.tokenSlice(tok_i);
|
||||
const line_bytes = slice[2 .. slice.len - 1];
|
||||
try string_bytes.appendSlice(gpa, line_bytes);
|
||||
tok_i += 1;
|
||||
}
|
||||
// Following lines: each line prepends a newline.
|
||||
while (tok_i <= end) : (tok_i += 1) {
|
||||
const slice = tree.tokenSlice(tok_i);
|
||||
const line_bytes = slice[2 .. slice.len - 1];
|
||||
try string_bytes.ensureCapacity(gpa, string_bytes.items.len + line_bytes.len + 1);
|
||||
string_bytes.appendAssumeCapacity('\n');
|
||||
string_bytes.appendSliceAssumeCapacity(line_bytes);
|
||||
}
|
||||
const str = try astgen.strLitNodeAsString(node);
|
||||
const result = try gz.add(.{
|
||||
.tag = .str,
|
||||
.data = .{ .str = .{
|
||||
.start = @intCast(u32, str_index),
|
||||
.len = @intCast(u32, string_bytes.items.len - str_index),
|
||||
.start = str.index,
|
||||
.len = str.len,
|
||||
} },
|
||||
});
|
||||
return rvalue(gz, rl, result, node);
|
||||
@@ -6620,9 +6595,14 @@ fn asmExpr(
|
||||
const tree = astgen.tree;
|
||||
const main_tokens = tree.nodes.items(.main_token);
|
||||
const node_datas = tree.nodes.items(.data);
|
||||
const node_tags = tree.nodes.items(.tag);
|
||||
const token_tags = tree.tokens.items(.tag);
|
||||
|
||||
const asm_source = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, full.ast.template);
|
||||
const asm_source = switch (node_tags[full.ast.template]) {
|
||||
.string_literal => try astgen.strLitAsString(main_tokens[full.ast.template]),
|
||||
.multiline_string_literal => try astgen.strLitNodeAsString(full.ast.template),
|
||||
else => return astgen.failNode(node, "assembly code must use string literal syntax", .{}),
|
||||
};
|
||||
|
||||
// See https://github.com/ziglang/zig/issues/215 and related issues discussing
|
||||
// possible inline assembly improvements. Until then here is status quo AstGen
|
||||
@@ -6752,7 +6732,7 @@ fn asmExpr(
|
||||
|
||||
const result = try gz.addAsm(.{
|
||||
.node = node,
|
||||
.asm_source = asm_source,
|
||||
.asm_source = asm_source.index,
|
||||
.is_volatile = full.volatile_token != null,
|
||||
.output_type_bits = output_type_bits,
|
||||
.outputs = outputs,
|
||||
@@ -8579,6 +8559,41 @@ fn strLitAsString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !IndexSlice {
|
||||
}
|
||||
}
|
||||
|
||||
fn strLitNodeAsString(astgen: *AstGen, node: ast.Node.Index) !IndexSlice {
|
||||
const tree = astgen.tree;
|
||||
const node_datas = tree.nodes.items(.data);
|
||||
|
||||
const start = node_datas[node].lhs;
|
||||
const end = node_datas[node].rhs;
|
||||
|
||||
const gpa = astgen.gpa;
|
||||
const string_bytes = &astgen.string_bytes;
|
||||
const str_index = string_bytes.items.len;
|
||||
|
||||
// First line: do not append a newline.
|
||||
var tok_i = start;
|
||||
{
|
||||
const slice = tree.tokenSlice(tok_i);
|
||||
const line_bytes = slice[2 .. slice.len - 1];
|
||||
try string_bytes.appendSlice(gpa, line_bytes);
|
||||
tok_i += 1;
|
||||
}
|
||||
// Following lines: each line prepends a newline.
|
||||
while (tok_i <= end) : (tok_i += 1) {
|
||||
const slice = tree.tokenSlice(tok_i);
|
||||
const line_bytes = slice[2 .. slice.len - 1];
|
||||
try string_bytes.ensureCapacity(gpa, string_bytes.items.len + line_bytes.len + 1);
|
||||
string_bytes.appendAssumeCapacity('\n');
|
||||
string_bytes.appendSliceAssumeCapacity(line_bytes);
|
||||
}
|
||||
const len = string_bytes.items.len - str_index;
|
||||
try string_bytes.append(gpa, 0);
|
||||
return IndexSlice{
|
||||
.index = @intCast(u32, str_index),
|
||||
.len = @intCast(u32, len),
|
||||
};
|
||||
}
|
||||
|
||||
fn testNameString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !u32 {
|
||||
const gpa = astgen.gpa;
|
||||
const string_bytes = &astgen.string_bytes;
|
||||
@@ -9440,7 +9455,7 @@ const GenZir = struct {
|
||||
args: struct {
|
||||
/// Absolute node index. This function does the conversion to offset from Decl.
|
||||
node: ast.Node.Index,
|
||||
asm_source: Zir.Inst.Ref,
|
||||
asm_source: u32,
|
||||
output_type_bits: u32,
|
||||
is_volatile: bool,
|
||||
outputs: []const Zir.Inst.Asm.Output,
|
||||
|
||||
@@ -21,7 +21,7 @@ const Log2Int = std.math.Log2Int;
|
||||
/// operand dies after this instruction.
|
||||
/// Instructions which need more data to track liveness have special handling via the
|
||||
/// `special` table.
|
||||
tomb_bits: []const usize,
|
||||
tomb_bits: []usize,
|
||||
/// Sparse table of specially handled instructions. The value is an index into the `extra`
|
||||
/// array. The meaning of the data depends on the AIR tag.
|
||||
special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32),
|
||||
@@ -98,7 +98,7 @@ pub fn operandDies(l: Liveness, inst: Air.Inst.Index, operand: OperandInt) bool
|
||||
return (l.tomb_bits[usize_index] & mask) != 0;
|
||||
}
|
||||
|
||||
pub fn clearOperandDeath(l: *Liveness, inst: Air.Inst.Index, operand: OperandInt) void {
|
||||
pub fn clearOperandDeath(l: Liveness, inst: Air.Inst.Index, operand: OperandInt) void {
|
||||
assert(operand < bpi - 1);
|
||||
const usize_index = (inst * bpi) / @bitSizeOf(usize);
|
||||
const mask = @as(usize, 1) <<
|
||||
@@ -106,16 +106,40 @@ pub fn clearOperandDeath(l: *Liveness, inst: Air.Inst.Index, operand: OperandInt
|
||||
l.tomb_bits[usize_index] |= mask;
|
||||
}
|
||||
|
||||
/// Higher level API.
|
||||
pub const CondBrSlices = struct {
|
||||
then_deaths: []const Air.Inst.Index,
|
||||
else_deaths: []const Air.Inst.Index,
|
||||
};
|
||||
|
||||
pub fn getCondBr(l: Liveness, inst: Air.Inst.Index) CondBrSlices {
|
||||
var index: usize = l.special.get(inst) orelse return .{
|
||||
.then_deaths = &.{},
|
||||
.else_deaths = &.{},
|
||||
};
|
||||
const then_death_count = l.extra[index];
|
||||
index += 1;
|
||||
const else_death_count = l.extra[index];
|
||||
index += 1;
|
||||
const then_deaths = l.extra[index..][0..then_death_count];
|
||||
index += then_death_count;
|
||||
return .{
|
||||
.then_deaths = then_deaths,
|
||||
.else_deaths = l.extra[index..][0..else_death_count],
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(l: *Liveness, gpa: *Allocator) void {
|
||||
gpa.free(l.tomb_bits);
|
||||
gpa.free(l.extra);
|
||||
l.special.deinit(gpa);
|
||||
l.* = undefined;
|
||||
}
|
||||
|
||||
/// How many tomb bits per AIR instruction.
|
||||
const bpi = 4;
|
||||
const Bpi = std.meta.Int(.unsigned, bpi);
|
||||
const OperandInt = std.math.Log2Int(Bpi);
|
||||
pub const bpi = 4;
|
||||
pub const Bpi = std.meta.Int(.unsigned, bpi);
|
||||
pub const OperandInt = std.math.Log2Int(Bpi);
|
||||
|
||||
/// In-progress data; on successful analysis converted into `Liveness`.
|
||||
const Analysis = struct {
|
||||
@@ -267,14 +291,14 @@ fn analyzeInst(
|
||||
const inst_data = inst_datas[inst].pl_op;
|
||||
const callee = inst_data.operand;
|
||||
const extra = a.air.extraData(Air.Call, inst_data.payload);
|
||||
const args = a.air.extra[extra.end..][0..extra.data.args_len];
|
||||
const args = @bitCast([]const Air.Inst.Ref, a.air.extra[extra.end..][0..extra.data.args_len]);
|
||||
if (args.len <= bpi - 2) {
|
||||
var buf: [bpi - 1]Air.Inst.Ref = undefined;
|
||||
var buf = [1]Air.Inst.Ref{.none} ** (bpi - 1);
|
||||
buf[0] = callee;
|
||||
std.mem.copy(Air.Inst.Ref, buf[1..], @bitCast([]const Air.Inst.Ref, args));
|
||||
std.mem.copy(Air.Inst.Ref, buf[1..], args);
|
||||
return trackOperands(a, new_set, inst, main_tomb, buf);
|
||||
}
|
||||
@panic("TODO: liveness analysis for function with greater than 2 args");
|
||||
@panic("TODO: liveness analysis for function call with greater than 2 args");
|
||||
},
|
||||
.struct_field_ptr => {
|
||||
const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data;
|
||||
@@ -285,12 +309,12 @@ fn analyzeInst(
|
||||
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 = a.air.extra[extra.end..][0..outputs_len];
|
||||
const inputs = a.air.extra[extra.end + outputs.len ..][0..inputs_len];
|
||||
if (outputs.len + inputs.len <= bpi - 1) {
|
||||
var buf: [bpi - 1]Air.Inst.Ref = undefined;
|
||||
std.mem.copy(Air.Inst.Ref, &buf, @bitCast([]const Air.Inst.Ref, outputs));
|
||||
std.mem.copy(Air.Inst.Ref, buf[outputs.len..], @bitCast([]const Air.Inst.Ref, inputs));
|
||||
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 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);
|
||||
return trackOperands(a, new_set, inst, main_tomb, buf);
|
||||
}
|
||||
@panic("TODO: liveness analysis for asm with greater than 3 args");
|
||||
|
||||
@@ -1309,7 +1309,7 @@ pub const Scope = struct {
|
||||
const result_index = @intCast(Air.Inst.Index, sema.air_instructions.len);
|
||||
sema.air_instructions.appendAssumeCapacity(inst);
|
||||
block.instructions.appendAssumeCapacity(result_index);
|
||||
return Sema.indexToRef(result_index);
|
||||
return Air.indexToRef(result_index);
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -3533,7 +3533,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
|
||||
const ty_ref = try sema.addType(param_type);
|
||||
const arg_index = @intCast(u32, sema.air_instructions.len);
|
||||
inner_block.instructions.appendAssumeCapacity(arg_index);
|
||||
param_inst.* = Sema.indexToRef(arg_index);
|
||||
param_inst.* = Air.indexToRef(arg_index);
|
||||
try sema.air_instructions.append(gpa, .{
|
||||
.tag = .arg,
|
||||
.data = .{
|
||||
|
||||
150
src/Sema.zig
150
src/Sema.zig
@@ -1301,7 +1301,7 @@ fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A
|
||||
|
||||
// Set the name of the Air.Arg instruction for use by codegen debug info.
|
||||
const air_arg = sema.param_inst_list[arg_index];
|
||||
sema.air_instructions.items(.data)[refToIndex(air_arg).?].ty_str.str = inst_data.start;
|
||||
sema.air_instructions.items(.data)[Air.refToIndex(air_arg).?].ty_str.str = inst_data.start;
|
||||
return air_arg;
|
||||
}
|
||||
|
||||
@@ -1389,7 +1389,7 @@ fn zirAllocInferred(
|
||||
// to the block even though it is currently a `.constant`.
|
||||
const result = try sema.addConstant(inferred_alloc_ty, Value.initPayload(&val_payload.base));
|
||||
try sema.requireFunctionBlock(block, src);
|
||||
try block.instructions.append(sema.gpa, refToIndex(result).?);
|
||||
try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1400,7 +1400,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
|
||||
const ptr = sema.resolveInst(inst_data.operand);
|
||||
const ptr_inst = refToIndex(ptr).?;
|
||||
const ptr_inst = Air.refToIndex(ptr).?;
|
||||
assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant);
|
||||
const air_datas = sema.air_instructions.items(.data);
|
||||
const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
|
||||
@@ -1586,7 +1586,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index)
|
||||
const bin_inst = sema.code.instructions.items(.data)[inst].bin;
|
||||
const ptr = sema.resolveInst(bin_inst.lhs);
|
||||
const value = sema.resolveInst(bin_inst.rhs);
|
||||
const ptr_inst = refToIndex(ptr).?;
|
||||
const ptr_inst = Air.refToIndex(ptr).?;
|
||||
assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant);
|
||||
const air_datas = sema.air_instructions.items(.data);
|
||||
const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
|
||||
@@ -1968,13 +1968,13 @@ fn analyzeBlockBody(
|
||||
|
||||
// Blocks must terminate with noreturn instruction.
|
||||
assert(child_block.instructions.items.len != 0);
|
||||
assert(sema.typeOf(indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1])).isNoReturn());
|
||||
assert(sema.typeOf(Air.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.
|
||||
try parent_block.instructions.appendSlice(gpa, child_block.instructions.items);
|
||||
return indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1]);
|
||||
return Air.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;
|
||||
@@ -2025,7 +2025,7 @@ fn analyzeBlockBody(
|
||||
continue;
|
||||
}
|
||||
assert(coerce_block.instructions.items[coerce_block.instructions.items.len - 1] ==
|
||||
refToIndex(coerced_operand).?);
|
||||
Air.refToIndex(coerced_operand).?);
|
||||
|
||||
// Convert the br operand to a block.
|
||||
const br_operand_ty_ref = try sema.addType(br_operand_ty);
|
||||
@@ -2034,7 +2034,7 @@ fn analyzeBlockBody(
|
||||
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.items(.data)[br].br.operand = Air.indexToRef(sub_block_inst);
|
||||
sema.air_instructions.appendAssumeCapacity(.{
|
||||
.tag = .block,
|
||||
.data = .{ .ty_pl = .{
|
||||
@@ -2054,7 +2054,7 @@ fn analyzeBlockBody(
|
||||
} },
|
||||
});
|
||||
}
|
||||
return indexToRef(merges.block_inst);
|
||||
return Air.indexToRef(merges.block_inst);
|
||||
}
|
||||
|
||||
fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void {
|
||||
@@ -2149,7 +2149,7 @@ fn zirBreak(sema: *Sema, start_block: *Scope.Block, inst: Zir.Inst.Index) Compil
|
||||
if (label.zir_block == zir_block) {
|
||||
const br_ref = try start_block.addBr(label.merges.block_inst, operand);
|
||||
try label.merges.results.append(sema.gpa, operand);
|
||||
try label.merges.br_list.append(sema.gpa, refToIndex(br_ref).?);
|
||||
try label.merges.br_list.append(sema.gpa, Air.refToIndex(br_ref).?);
|
||||
return inst;
|
||||
}
|
||||
}
|
||||
@@ -5310,7 +5310,7 @@ fn zirBoolBr(
|
||||
} } });
|
||||
|
||||
try parent_block.instructions.append(gpa, block_inst);
|
||||
return indexToRef(block_inst);
|
||||
return Air.indexToRef(block_inst);
|
||||
}
|
||||
|
||||
fn zirIsNonNull(
|
||||
@@ -7204,7 +7204,7 @@ fn analyzeVarRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, tv: TypedVal
|
||||
} },
|
||||
});
|
||||
try block.instructions.append(gpa, result_inst);
|
||||
return indexToRef(result_inst);
|
||||
return Air.indexToRef(result_inst);
|
||||
}
|
||||
|
||||
fn analyzeRef(
|
||||
@@ -8021,107 +8021,18 @@ fn enumFieldSrcLoc(
|
||||
} else unreachable;
|
||||
}
|
||||
|
||||
/// This is only meant to be called by `typeOf`.
|
||||
fn analyzeAsTypeInfallible(sema: *Sema, inst: Air.Inst.Ref) Type {
|
||||
var i: usize = @enumToInt(inst);
|
||||
if (i < Air.Inst.Ref.typed_value_map.len) {
|
||||
return Air.Inst.Ref.typed_value_map[i].val.toType(undefined) catch unreachable;
|
||||
}
|
||||
i -= Air.Inst.Ref.typed_value_map.len;
|
||||
assert(sema.air_instructions.items(.tag)[i] == .const_ty);
|
||||
return sema.air_instructions.items(.data)[i].ty;
|
||||
}
|
||||
|
||||
/// Returns the type of the AIR instruction.
|
||||
fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type {
|
||||
var i: usize = @enumToInt(inst);
|
||||
if (i < Air.Inst.Ref.typed_value_map.len) {
|
||||
return Air.Inst.Ref.typed_value_map[i].ty;
|
||||
}
|
||||
i -= Air.Inst.Ref.typed_value_map.len;
|
||||
return sema.getTmpAir().typeOf(inst);
|
||||
}
|
||||
|
||||
const air_datas = sema.air_instructions.items(.data);
|
||||
switch (sema.air_instructions.items(.tag)[i]) {
|
||||
.arg => return sema.analyzeAsTypeInfallible(air_datas[i].ty_str.ty),
|
||||
|
||||
.add,
|
||||
.addwrap,
|
||||
.sub,
|
||||
.subwrap,
|
||||
.mul,
|
||||
.mulwrap,
|
||||
.div,
|
||||
.bit_and,
|
||||
.bit_or,
|
||||
.xor,
|
||||
=> return sema.typeOf(air_datas[i].bin_op.lhs),
|
||||
|
||||
.cmp_lt,
|
||||
.cmp_lte,
|
||||
.cmp_eq,
|
||||
.cmp_gte,
|
||||
.cmp_gt,
|
||||
.cmp_neq,
|
||||
.is_null,
|
||||
.is_non_null,
|
||||
.is_null_ptr,
|
||||
.is_non_null_ptr,
|
||||
.is_err,
|
||||
.is_non_err,
|
||||
.is_err_ptr,
|
||||
.is_non_err_ptr,
|
||||
.bool_and,
|
||||
.bool_or,
|
||||
=> return Type.initTag(.bool),
|
||||
|
||||
.const_ty => return Type.initTag(.type),
|
||||
|
||||
.alloc => return air_datas[i].ty,
|
||||
|
||||
.assembly,
|
||||
.block,
|
||||
.constant,
|
||||
.varptr,
|
||||
.struct_field_ptr,
|
||||
=> return sema.analyzeAsTypeInfallible(air_datas[i].ty_pl.ty),
|
||||
|
||||
.not,
|
||||
.bitcast,
|
||||
.load,
|
||||
.ref,
|
||||
.floatcast,
|
||||
.intcast,
|
||||
.optional_payload,
|
||||
.optional_payload_ptr,
|
||||
.wrap_optional,
|
||||
.unwrap_errunion_payload,
|
||||
.unwrap_errunion_err,
|
||||
.unwrap_errunion_payload_ptr,
|
||||
.unwrap_errunion_err_ptr,
|
||||
.wrap_errunion_payload,
|
||||
.wrap_errunion_err,
|
||||
=> return sema.analyzeAsTypeInfallible(air_datas[i].ty_op.ty),
|
||||
|
||||
.loop,
|
||||
.br,
|
||||
.cond_br,
|
||||
.switch_br,
|
||||
.ret,
|
||||
.unreach,
|
||||
=> return Type.initTag(.noreturn),
|
||||
|
||||
.breakpoint,
|
||||
.dbg_stmt,
|
||||
.store,
|
||||
=> return Type.initTag(.void),
|
||||
|
||||
.ptrtoint => return Type.initTag(.usize),
|
||||
|
||||
.call => {
|
||||
const callee_ty = sema.typeOf(air_datas[i].pl_op.operand);
|
||||
return callee_ty.fnReturnType();
|
||||
},
|
||||
}
|
||||
fn getTmpAir(sema: Sema) Air {
|
||||
return .{
|
||||
.instructions = sema.air_instructions.slice(),
|
||||
.extra = sema.air_extra.items,
|
||||
.values = sema.air_values.items,
|
||||
.variables = sema.air_variables.items,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
|
||||
@@ -8185,7 +8096,7 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
|
||||
.tag = .const_ty,
|
||||
.data = .{ .ty = ty },
|
||||
});
|
||||
return indexToRef(@intCast(u32, sema.air_instructions.len - 1));
|
||||
return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
|
||||
}
|
||||
|
||||
fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref {
|
||||
@@ -8207,22 +8118,7 @@ fn addConstant(sema: *Sema, ty: Type, val: Value) CompileError!Air.Inst.Ref {
|
||||
.payload = @intCast(u32, sema.air_values.items.len - 1),
|
||||
} },
|
||||
});
|
||||
return indexToRef(@intCast(u32, sema.air_instructions.len - 1));
|
||||
}
|
||||
|
||||
const ref_start_index: u32 = Air.Inst.Ref.typed_value_map.len;
|
||||
|
||||
pub fn indexToRef(inst: Air.Inst.Index) Air.Inst.Ref {
|
||||
return @intToEnum(Air.Inst.Ref, ref_start_index + inst);
|
||||
}
|
||||
|
||||
pub fn refToIndex(inst: Air.Inst.Ref) ?Air.Inst.Index {
|
||||
const ref_int = @enumToInt(inst);
|
||||
if (ref_int >= ref_start_index) {
|
||||
return ref_int - ref_start_index;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
|
||||
}
|
||||
|
||||
pub fn addExtra(sema: *Sema, extra: anytype) Allocator.Error!u32 {
|
||||
|
||||
@@ -2176,7 +2176,8 @@ pub const Inst = struct {
|
||||
/// 2. clobber: u32 // index into string_bytes (null terminated) for every clobbers_len.
|
||||
pub const Asm = struct {
|
||||
src_node: i32,
|
||||
asm_source: Ref,
|
||||
// null-terminated string index
|
||||
asm_source: u32,
|
||||
/// 1 bit for each outputs_len: whether it uses `-> T` or not.
|
||||
/// 0b0 - operand is a pointer to where to store the output.
|
||||
/// 0b1 - operand is a type; asm expression has the output as the result.
|
||||
@@ -3383,9 +3384,10 @@ const Writer = struct {
|
||||
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;
|
||||
const asm_source = self.code.nullTerminatedString(extra.data.asm_source);
|
||||
|
||||
try self.writeFlag(stream, "volatile, ", is_volatile);
|
||||
try self.writeInstRef(stream, extra.data.asm_source);
|
||||
try stream.print("\"{}\", ", .{std.zig.fmtEscapes(asm_source)});
|
||||
try stream.writeAll(", ");
|
||||
|
||||
var extra_i: usize = extra.end;
|
||||
|
||||
1349
src/codegen.zig
1349
src/codegen.zig
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user