stage2: codegen handles undefined values

* `optimize_mode` is passed to `link.File` and stored there
 * improve the debugging function `Module.dumpInst`
 * get rid of `Value.the_one_possible_value` in favor of a few more
   specific values for different types. This is less buggy, one less
   footgun.
 * `Type.onePossibleValue` now returns a `?Value` instead of `bool`.
 * codegen handles undefined values. `undef` is a new `MCValue` tag.
   It uses 0xaa values depending on optimization mode. However
   optimization mode does not yet support scope overrides.
 * link.zig: move the `Options` field from `File.Elf` and `File.C` to
   the base struct.
   - fix the Tag enum to adhere to style conventions
 * ZIR now supports emitting undefined values.
 * Fix the logic of comptime math to properly compare against zero using
   the `compareWithZero` function.
This commit is contained in:
Andrew Kelley
2020-07-28 21:57:13 -07:00
parent 2b8e7deeda
commit 4beff80b2f
8 changed files with 248 additions and 120 deletions

View File

@@ -47,7 +47,6 @@ export_owners: std.AutoHashMapUnmanaged(*Decl, []*Export) = .{},
/// Maps fully qualified namespaced names to the Decl struct for them.
decl_table: std.HashMapUnmanaged(Scope.NameHash, *Decl, Scope.name_hash_hash, Scope.name_hash_eql, false) = .{},
optimize_mode: std.builtin.Mode,
link_error_flags: link.File.ErrorFlags = .{},
work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic),
@@ -385,18 +384,6 @@ pub const Scope = struct {
};
}
pub fn dumpInst(self: *Scope, inst: *Inst) void {
const zir_module = self.namespace();
const loc = std.zig.findLineColumn(zir_module.source.bytes, inst.src);
std.debug.warn("{}:{}:{}: {}: ty={}\n", .{
zir_module.sub_file_path,
loc.line + 1,
loc.column + 1,
@tagName(inst.tag),
inst.ty,
});
}
/// Asserts the scope has a parent which is a ZIRModule or File and
/// returns the sub_file_path field.
pub fn subFilePath(base: *Scope) []const u8 {
@@ -802,6 +789,7 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
.output_mode = options.output_mode,
.link_mode = options.link_mode orelse .Static,
.object_format = options.object_format orelse options.target.getObjectFormat(),
.optimize_mode = options.optimize_mode,
});
errdefer bin_file.destroy();
@@ -838,7 +826,6 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
.bin_file_dir = bin_file_dir,
.bin_file_path = options.bin_file_path,
.bin_file = bin_file,
.optimize_mode = options.optimize_mode,
.work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa),
.keep_source_files_loaded = options.keep_source_files_loaded,
};
@@ -894,7 +881,11 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
}
pub fn target(self: Module) std.Target {
return self.bin_file.options().target;
return self.bin_file.options.target;
}
pub fn optimizeMode(self: Module) std.builtin.Mode {
return self.bin_file.options.optimize_mode;
}
/// Detect changes to source files, perform semantic analysis, and update the output files.
@@ -1991,14 +1982,14 @@ pub fn constType(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {
pub fn constVoid(self: *Module, scope: *Scope, src: usize) !*Inst {
return self.constInst(scope, src, .{
.ty = Type.initTag(.void),
.val = Value.initTag(.the_one_possible_value),
.val = Value.initTag(.void_value),
});
}
pub fn constNoReturn(self: *Module, scope: *Scope, src: usize) !*Inst {
return self.constInst(scope, src, .{
.ty = Type.initTag(.noreturn),
.val = Value.initTag(.the_one_possible_value),
.val = Value.initTag(.unreachable_value),
});
}
@@ -2162,7 +2153,8 @@ pub fn analyzeDeclRefByName(self: *Module, scope: *Scope, src: usize, decl_name:
}
pub fn wantSafety(self: *Module, scope: *Scope) bool {
return switch (self.optimize_mode) {
// TODO take into account scope's safety overrides
return switch (self.optimizeMode()) {
.Debug => true,
.ReleaseSafe => true,
.ReleaseFast => false,
@@ -2511,7 +2503,7 @@ pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_v
const elem_ty = ptr.ty.elemType();
const value = try self.coerce(scope, elem_ty, uncasted_value);
if (elem_ty.onePossibleValue())
if (elem_ty.onePossibleValue() != null)
return self.constVoid(scope, src);
// TODO handle comptime pointer writes
@@ -2803,3 +2795,35 @@ pub fn singleConstPtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Typ
type_payload.* = .{ .pointee_type = elem_ty };
return Type.initPayload(&type_payload.base);
}
pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {
const zir_module = scope.namespace();
const source = zir_module.getSource(self) catch @panic("dumpInst failed to get source");
const loc = std.zig.findLineColumn(source, inst.src);
if (inst.tag == .constant) {
std.debug.warn("constant ty={} val={} src={}:{}:{}\n", .{
inst.ty,
inst.castTag(.constant).?.val,
zir_module.subFilePath(),
loc.line + 1,
loc.column + 1,
});
} else if (inst.deaths == 0) {
std.debug.warn("{} ty={} src={}:{}:{}\n", .{
@tagName(inst.tag),
inst.ty,
zir_module.subFilePath(),
loc.line + 1,
loc.column + 1,
});
} else {
std.debug.warn("{} ty={} deaths={b} src={}:{}:{}\n", .{
@tagName(inst.tag),
inst.ty,
inst.deaths,
zir_module.subFilePath(),
loc.line + 1,
loc.column + 1,
});
}
}