stage2: first pass over Module.zig for AIR memory layout

This commit is contained in:
Andrew Kelley
2021-07-12 15:30:30 -07:00
parent ee6432537e
commit 913393fd3b
9 changed files with 429 additions and 455 deletions

View File

@@ -1155,7 +1155,7 @@ pub const Scope = struct {
/// This can vary during inline or comptime function calls. See `Sema.owner_decl`
/// for the one that will be the same for all Block instances.
src_decl: *Decl,
instructions: ArrayListUnmanaged(*ir.Inst),
instructions: ArrayListUnmanaged(Air.Inst.Index),
label: ?*Label = null,
inlining: ?*Inlining,
/// If runtime_index is not 0 then one of these is guaranteed to be non null.
@@ -1187,14 +1187,14 @@ pub const Scope = struct {
};
pub const Merges = struct {
block_inst: *ir.Inst.Block,
block_inst: Air.Inst.Index,
/// Separate array list from break_inst_list so that it can be passed directly
/// to resolvePeerTypes.
results: ArrayListUnmanaged(*ir.Inst),
results: ArrayListUnmanaged(Air.Inst.Index),
/// 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`.
br_list: ArrayListUnmanaged(*ir.Inst.Br),
br_list: ArrayListUnmanaged(Air.Inst.Index),
};
/// For debugging purposes.
@@ -1230,187 +1230,6 @@ pub const Scope = struct {
pub fn getFileScope(block: *Block) *Scope.File {
return block.src_decl.namespace.file_scope;
}
pub fn addNoOp(
block: *Scope.Block,
src: LazySrcLoc,
ty: Type,
comptime tag: ir.Inst.Tag,
) !*ir.Inst {
const inst = try block.sema.arena.create(tag.Type());
inst.* = .{
.base = .{
.tag = tag,
.ty = ty,
.src = src,
},
};
try block.instructions.append(block.sema.gpa, &inst.base);
return &inst.base;
}
pub fn addUnOp(
block: *Scope.Block,
src: LazySrcLoc,
ty: Type,
tag: ir.Inst.Tag,
operand: *ir.Inst,
) !*ir.Inst {
const inst = try block.sema.arena.create(ir.Inst.UnOp);
inst.* = .{
.base = .{
.tag = tag,
.ty = ty,
.src = src,
},
.operand = operand,
};
try block.instructions.append(block.sema.gpa, &inst.base);
return &inst.base;
}
pub fn addBinOp(
block: *Scope.Block,
src: LazySrcLoc,
ty: Type,
tag: ir.Inst.Tag,
lhs: *ir.Inst,
rhs: *ir.Inst,
) !*ir.Inst {
const inst = try block.sema.arena.create(ir.Inst.BinOp);
inst.* = .{
.base = .{
.tag = tag,
.ty = ty,
.src = src,
},
.lhs = lhs,
.rhs = rhs,
};
try block.instructions.append(block.sema.gpa, &inst.base);
return &inst.base;
}
pub fn addBr(
scope_block: *Scope.Block,
src: LazySrcLoc,
target_block: *ir.Inst.Block,
operand: *ir.Inst,
) !*ir.Inst.Br {
const inst = try scope_block.sema.arena.create(ir.Inst.Br);
inst.* = .{
.base = .{
.tag = .br,
.ty = Type.initTag(.noreturn),
.src = src,
},
.operand = operand,
.block = target_block,
};
try scope_block.instructions.append(scope_block.sema.gpa, &inst.base);
return inst;
}
pub fn addCondBr(
block: *Scope.Block,
src: LazySrcLoc,
condition: *ir.Inst,
then_body: ir.Body,
else_body: ir.Body,
) !*ir.Inst {
const inst = try block.sema.arena.create(ir.Inst.CondBr);
inst.* = .{
.base = .{
.tag = .condbr,
.ty = Type.initTag(.noreturn),
.src = src,
},
.condition = condition,
.then_body = then_body,
.else_body = else_body,
};
try block.instructions.append(block.sema.gpa, &inst.base);
return &inst.base;
}
pub fn addCall(
block: *Scope.Block,
src: LazySrcLoc,
ty: Type,
func: *ir.Inst,
args: []const *ir.Inst,
) !*ir.Inst {
const inst = try block.sema.arena.create(ir.Inst.Call);
inst.* = .{
.base = .{
.tag = .call,
.ty = ty,
.src = src,
},
.func = func,
.args = args,
};
try block.instructions.append(block.sema.gpa, &inst.base);
return &inst.base;
}
pub fn addSwitchBr(
block: *Scope.Block,
src: LazySrcLoc,
operand: *ir.Inst,
cases: []ir.Inst.SwitchBr.Case,
else_body: ir.Body,
) !*ir.Inst {
const inst = try block.sema.arena.create(ir.Inst.SwitchBr);
inst.* = .{
.base = .{
.tag = .switchbr,
.ty = Type.initTag(.noreturn),
.src = src,
},
.target = operand,
.cases = cases,
.else_body = else_body,
};
try block.instructions.append(block.sema.gpa, &inst.base);
return &inst.base;
}
pub fn addDbgStmt(block: *Scope.Block, src: LazySrcLoc, line: u32, column: u32) !*ir.Inst {
const inst = try block.sema.arena.create(ir.Inst.DbgStmt);
inst.* = .{
.base = .{
.tag = .dbg_stmt,
.ty = Type.initTag(.void),
.src = src,
},
.line = line,
.column = column,
};
try block.instructions.append(block.sema.gpa, &inst.base);
return &inst.base;
}
pub fn addStructFieldPtr(
block: *Scope.Block,
src: LazySrcLoc,
ty: Type,
struct_ptr: *ir.Inst,
field_index: u32,
) !*ir.Inst {
const inst = try block.sema.arena.create(ir.Inst.StructFieldPtr);
inst.* = .{
.base = .{
.tag = .struct_field_ptr,
.ty = ty,
.src = src,
},
.struct_ptr = struct_ptr,
.field_index = field_index,
};
try block.instructions.append(block.sema.gpa, &inst.base);
return &inst.base;
}
};
};
@@ -3594,30 +3413,14 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !Air {
defer decl.value_arena.?.* = arena.state;
const fn_ty = decl.ty;
const param_inst_list = try gpa.alloc(*ir.Inst, fn_ty.fnParamLen());
const param_inst_list = try gpa.alloc(Air.Inst.Index, fn_ty.fnParamLen());
defer gpa.free(param_inst_list);
for (param_inst_list) |*param_inst, param_index| {
const param_type = fn_ty.fnParamType(param_index);
const arg_inst = try arena.allocator.create(ir.Inst.Arg);
arg_inst.* = .{
.base = .{
.tag = .arg,
.ty = param_type,
.src = .unneeded,
},
.name = undefined, // Set in the semantic analysis of the arg instruction.
};
param_inst.* = &arg_inst.base;
}
const zir = decl.namespace.file_scope.zir;
var sema: Sema = .{
.mod = mod,
.gpa = gpa,
.arena = &arena.allocator,
.code = zir,
.code = decl.namespace.file_scope.zir,
.owner_decl = decl,
.namespace = decl.namespace,
.func = func,
@@ -3641,7 +3444,21 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !Air {
};
defer inner_block.instructions.deinit(gpa);
// AIR currently requires the arg parameters to be the first N instructions
// AIR requires the arg parameters to be the first N instructions.
for (param_inst_list) |*param_inst, param_index| {
const param_type = fn_ty.fnParamType(param_index);
const ty_ref = try sema.addType(param_type);
param_inst.* = @intCast(u32, sema.air_instructions.len);
try sema.air_instructions.append(gpa, .{
.tag = .arg,
.data = .{
.ty_str = .{
.ty = ty_ref,
.str = undefined, // Set in the semantic analysis of the arg instruction.
},
},
});
}
try inner_block.instructions.appendSlice(gpa, param_inst_list);
func.state = .in_progress;
@@ -3650,17 +3467,21 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !Air {
try sema.analyzeFnBody(&inner_block, func.zir_body_inst);
// Copy the block into place and mark that as the main block.
sema.air_extra.items[@enumToInt(Air.ExtraIndex.main_block)] = sema.air_extra.items.len;
try sema.air_extra.appendSlice(inner_block.instructions.items);
try sema.air_extra.ensureUnusedCapacity(gpa, inner_block.instructions.items.len + 1);
const main_block_index = sema.addExtraAssumeCapacity(Air.Block{
.body_len = @intCast(u32, inner_block.instructions.items.len),
});
sema.air_extra.appendSliceAssumeCapacity(inner_block.instructions.items);
sema.air_extra.items[@enumToInt(Air.ExtraIndex.main_block)] = main_block_index;
func.state = .success;
log.debug("set {s} to success", .{decl.name});
return Air{
.instructions = sema.air_instructions.toOwnedSlice(),
.extra = sema.air_extra.toOwnedSlice(),
.values = sema.air_values.toOwnedSlice(),
.variables = sema.air_variables.toOwnedSlice(),
.extra = sema.air_extra.toOwnedSlice(gpa),
.values = sema.air_values.toOwnedSlice(gpa),
.variables = sema.air_variables.toOwnedSlice(gpa),
};
}
@@ -3815,94 +3636,6 @@ pub fn analyzeExport(
de_gop.value_ptr.*[de_gop.value_ptr.len - 1] = new_export;
errdefer de_gop.value_ptr.* = mod.gpa.shrink(de_gop.value_ptr.*, de_gop.value_ptr.len - 1);
}
pub fn constInst(mod: *Module, arena: *Allocator, src: LazySrcLoc, typed_value: TypedValue) !*ir.Inst {
_ = mod;
const const_inst = try arena.create(ir.Inst.Constant);
const_inst.* = .{
.base = .{
.tag = ir.Inst.Constant.base_tag,
.ty = typed_value.ty,
.src = src,
},
.val = typed_value.val,
};
return &const_inst.base;
}
pub fn constType(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type) !*ir.Inst {
return mod.constInst(arena, src, .{
.ty = Type.initTag(.type),
.val = try ty.toValue(arena),
});
}
pub fn constVoid(mod: *Module, arena: *Allocator, src: LazySrcLoc) !*ir.Inst {
return mod.constInst(arena, src, .{
.ty = Type.initTag(.void),
.val = Value.initTag(.void_value),
});
}
pub fn constNoReturn(mod: *Module, arena: *Allocator, src: LazySrcLoc) !*ir.Inst {
return mod.constInst(arena, src, .{
.ty = Type.initTag(.noreturn),
.val = Value.initTag(.unreachable_value),
});
}
pub fn constUndef(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type) !*ir.Inst {
return mod.constInst(arena, src, .{
.ty = ty,
.val = Value.initTag(.undef),
});
}
pub fn constBool(mod: *Module, arena: *Allocator, src: LazySrcLoc, v: bool) !*ir.Inst {
return mod.constInst(arena, src, .{
.ty = Type.initTag(.bool),
.val = ([2]Value{ Value.initTag(.bool_false), Value.initTag(.bool_true) })[@boolToInt(v)],
});
}
pub fn constIntUnsigned(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, int: u64) !*ir.Inst {
return mod.constInst(arena, src, .{
.ty = ty,
.val = try Value.Tag.int_u64.create(arena, int),
});
}
pub fn constIntSigned(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, int: i64) !*ir.Inst {
return mod.constInst(arena, src, .{
.ty = ty,
.val = try Value.Tag.int_i64.create(arena, int),
});
}
pub fn constIntBig(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, big_int: BigIntConst) !*ir.Inst {
if (big_int.positive) {
if (big_int.to(u64)) |x| {
return mod.constIntUnsigned(arena, src, ty, x);
} else |err| switch (err) {
error.NegativeIntoUnsigned => unreachable,
error.TargetTooSmall => {}, // handled below
}
return mod.constInst(arena, src, .{
.ty = ty,
.val = try Value.Tag.int_big_positive.create(arena, big_int.limbs),
});
} else {
if (big_int.to(i64)) |x| {
return mod.constIntSigned(arena, src, ty, x);
} else |err| switch (err) {
error.NegativeIntoUnsigned => unreachable,
error.TargetTooSmall => {}, // handled below
}
return mod.constInst(arena, src, .{
.ty = ty,
.val = try Value.Tag.int_big_negative.create(arena, big_int.limbs),
});
}
}
pub fn deleteAnonDecl(mod: *Module, scope: *Scope, decl: *Decl) void {
const scope_decl = scope.ownerDecl().?;
@@ -4438,38 +4171,6 @@ pub fn errorUnionType(
});
}
pub fn dumpInst(mod: *Module, scope: *Scope, inst: *ir.Inst) void {
const zir_module = scope.namespace();
const source = zir_module.getSource(mod) catch @panic("dumpInst failed to get source");
const loc = std.zig.findLineColumn(source, inst.src);
if (inst.tag == .constant) {
std.debug.print("constant ty={} val={} src={s}:{d}:{d}\n", .{
inst.ty,
inst.castTag(.constant).?.val,
zir_module.subFilePath(),
loc.line + 1,
loc.column + 1,
});
} else if (inst.deaths == 0) {
std.debug.print("{s} ty={} src={s}:{d}:{d}\n", .{
@tagName(inst.tag),
inst.ty,
zir_module.subFilePath(),
loc.line + 1,
loc.column + 1,
});
} else {
std.debug.print("{s} ty={} deaths={b} src={s}:{d}:{d}\n", .{
@tagName(inst.tag),
inst.ty,
inst.deaths,
zir_module.subFilePath(),
loc.line + 1,
loc.column + 1,
});
}
}
pub fn getTarget(mod: Module) Target {
return mod.comp.bin_file.options.target;
}