Commit 751903ba8f
Changed files (4)
src-self-hosted
src-self-hosted/ir/text.zig
@@ -18,6 +18,7 @@ pub const Inst = struct {
/// These names are used directly as the instruction names in the text format.
pub const Tag = enum {
+ breakpoint,
str,
int,
ptrtoint,
@@ -43,6 +44,7 @@ pub const Inst = struct {
pub fn TagToType(tag: Tag) type {
return switch (tag) {
+ .breakpoint => Breakpoint,
.str => Str,
.int => Int,
.ptrtoint => PtrToInt,
@@ -74,6 +76,14 @@ pub const Inst = struct {
return @fieldParentPtr(T, "base", base);
}
+ pub const Breakpoint = struct {
+ pub const base_tag = Tag.breakpoint;
+ base: Inst,
+
+ positionals: struct {},
+ kw_args: struct {},
+ };
+
pub const Str = struct {
pub const base_tag = Tag.str;
base: Inst,
@@ -419,6 +429,7 @@ pub const Module = struct {
) @TypeOf(stream).Error!void {
// TODO I tried implementing this with an inline for loop and hit a compiler bug
switch (decl.tag) {
+ .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, decl, inst_table),
.str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table),
.int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table),
.ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table),
@@ -1030,6 +1041,16 @@ const EmitZIR = struct {
}
}
+ fn emitTrivial(self: *EmitZIR, src: usize, comptime T: type) Allocator.Error!*Inst {
+ const new_inst = try self.arena.allocator.create(T);
+ new_inst.* = .{
+ .base = .{ .src = src, .tag = T.base_tag },
+ .positionals = .{},
+ .kw_args = .{},
+ };
+ return &new_inst.base;
+ }
+
fn emitBody(
self: *EmitZIR,
body: ir.Module.Body,
@@ -1038,24 +1059,9 @@ const EmitZIR = struct {
) Allocator.Error!void {
for (body.instructions) |inst| {
const new_inst = switch (inst.tag) {
- .unreach => blk: {
- const unreach_inst = try self.arena.allocator.create(Inst.Unreachable);
- unreach_inst.* = .{
- .base = .{ .src = inst.src, .tag = Inst.Unreachable.base_tag },
- .positionals = .{},
- .kw_args = .{},
- };
- break :blk &unreach_inst.base;
- },
- .ret => blk: {
- const ret_inst = try self.arena.allocator.create(Inst.Return);
- ret_inst.* = .{
- .base = .{ .src = inst.src, .tag = Inst.Return.base_tag },
- .positionals = .{},
- .kw_args = .{},
- };
- break :blk &ret_inst.base;
- },
+ .breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),
+ .unreach => try self.emitTrivial(inst.src, Inst.Unreachable),
+ .ret => try self.emitTrivial(inst.src, Inst.Return),
.constant => unreachable, // excluded from function bodies
.assembly => blk: {
const old_inst = inst.cast(ir.Inst.Assembly).?;
src-self-hosted/codegen.zig
@@ -77,6 +77,7 @@ const Function = struct {
fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {
switch (inst.tag) {
+ .breakpoint => return self.genBreakpoint(inst.src),
.unreach => return MCValue{ .unreach = {} },
.constant => unreachable, // excluded from function bodies
.assembly => return self.genAsm(inst.cast(ir.Inst.Assembly).?),
src-self-hosted/ir.zig
@@ -21,16 +21,17 @@ pub const Inst = struct {
src: usize,
pub const Tag = enum {
- unreach,
- ret,
- constant,
assembly,
- ptrtoint,
bitcast,
+ breakpoint,
cmp,
condbr,
- isnull,
+ constant,
isnonnull,
+ isnull,
+ ptrtoint,
+ ret,
+ unreach,
};
pub fn cast(base: *Inst, comptime T: type) ?*T {
@@ -53,25 +54,6 @@ pub const Inst = struct {
return inst.val;
}
- pub const Unreach = struct {
- pub const base_tag = Tag.unreach;
- base: Inst,
- args: void,
- };
-
- pub const Ret = struct {
- pub const base_tag = Tag.ret;
- base: Inst,
- args: void,
- };
-
- pub const Constant = struct {
- pub const base_tag = Tag.constant;
- base: Inst,
-
- val: Value,
- };
-
pub const Assembly = struct {
pub const base_tag = Tag.assembly;
base: Inst,
@@ -86,15 +68,6 @@ pub const Inst = struct {
},
};
- pub const PtrToInt = struct {
- pub const base_tag = Tag.ptrtoint;
-
- base: Inst,
- args: struct {
- ptr: *Inst,
- },
- };
-
pub const BitCast = struct {
pub const base_tag = Tag.bitcast;
@@ -104,6 +77,12 @@ pub const Inst = struct {
},
};
+ pub const Breakpoint = struct {
+ pub const base_tag = Tag.breakpoint;
+ base: Inst,
+ args: void,
+ };
+
pub const Cmp = struct {
pub const base_tag = Tag.cmp;
@@ -126,6 +105,22 @@ pub const Inst = struct {
},
};
+ pub const Constant = struct {
+ pub const base_tag = Tag.constant;
+ base: Inst,
+
+ val: Value,
+ };
+
+ pub const IsNonNull = struct {
+ pub const base_tag = Tag.isnonnull;
+
+ base: Inst,
+ args: struct {
+ operand: *Inst,
+ },
+ };
+
pub const IsNull = struct {
pub const base_tag = Tag.isnull;
@@ -135,14 +130,26 @@ pub const Inst = struct {
},
};
- pub const IsNonNull = struct {
- pub const base_tag = Tag.isnonnull;
+ pub const PtrToInt = struct {
+ pub const base_tag = Tag.ptrtoint;
base: Inst,
args: struct {
- operand: *Inst,
+ ptr: *Inst,
},
};
+
+ pub const Ret = struct {
+ pub const base_tag = Tag.ret;
+ base: Inst,
+ args: void,
+ };
+
+ pub const Unreach = struct {
+ pub const base_tag = Tag.unreach;
+ base: Inst,
+ args: void,
+ };
};
pub const TypedValue = struct {
@@ -159,6 +166,7 @@ pub const Module = struct {
link_mode: std.builtin.LinkMode,
output_mode: std.builtin.OutputMode,
object_format: std.Target.ObjectFormat,
+ optimize_mode: std.builtin.Mode,
pub const Export = struct {
name: []const u8,
@@ -198,6 +206,7 @@ pub const AnalyzeOptions = struct {
output_mode: std.builtin.OutputMode,
link_mode: std.builtin.LinkMode,
object_format: ?std.Target.ObjectFormat = null,
+ optimize_mode: std.builtin.Mode,
};
pub fn analyze(allocator: *Allocator, old_module: text.Module, options: AnalyzeOptions) !Module {
@@ -210,6 +219,9 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module, options: AnalyzeO
.exports = std.ArrayList(Module.Export).init(allocator),
.fns = std.ArrayList(Module.Fn).init(allocator),
.target = options.target,
+ .optimize_mode = options.optimize_mode,
+ .link_mode = options.link_mode,
+ .output_mode = options.output_mode,
};
defer ctx.errors.deinit();
defer ctx.decl_table.deinit();
@@ -229,9 +241,10 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module, options: AnalyzeO
.fns = ctx.fns.toOwnedSlice(),
.arena = ctx.arena,
.target = ctx.target,
- .link_mode = options.link_mode,
- .output_mode = options.output_mode,
+ .link_mode = ctx.link_mode,
+ .output_mode = ctx.output_mode,
.object_format = options.object_format orelse ctx.target.getObjectFormat(),
+ .optimize_mode = ctx.optimize_mode,
};
}
@@ -244,6 +257,9 @@ const Analyze = struct {
exports: std.ArrayList(Module.Export),
fns: std.ArrayList(Module.Fn),
target: Target,
+ link_mode: std.builtin.LinkMode,
+ optimize_mode: std.builtin.Mode,
+ output_mode: std.builtin.OutputMode,
const NewDecl = struct {
/// null means a semantic analysis error happened
@@ -495,6 +511,7 @@ const Analyze = struct {
fn analyzeInst(self: *Analyze, block: ?*Block, old_inst: *text.Inst) InnerError!*Inst {
switch (old_inst.tag) {
+ .breakpoint => return self.analyzeInstBreakpoint(block, old_inst.cast(text.Inst.Breakpoint).?),
.str => {
// We can use this reference because Inst.Const's Value is arena-allocated.
// The value would get copied to a MemoryCell before the `text.Inst.Str` lifetime ends.
@@ -530,6 +547,11 @@ const Analyze = struct {
}
}
+ fn analyzeInstBreakpoint(self: *Analyze, block: ?*Block, inst: *text.Inst.Breakpoint) InnerError!*Inst {
+ const b = try self.requireRuntimeBlock(block, inst.base.src);
+ return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){});
+ }
+
fn analyzeInstFn(self: *Analyze, block: ?*Block, fn_inst: *text.Inst.Fn) InnerError!*Inst {
const fn_type = try self.resolveType(block, fn_inst.positionals.fn_type);
@@ -909,8 +931,21 @@ const Analyze = struct {
});
}
+ fn wantSafety(self: *Analyze, block: ?*Block) bool {
+ return switch (self.optimize_mode) {
+ .Debug => true,
+ .ReleaseSafe => true,
+ .ReleaseFast => false,
+ .ReleaseSmall => false,
+ };
+ }
+
fn analyzeInstUnreachable(self: *Analyze, block: ?*Block, unreach: *text.Inst.Unreachable) InnerError!*Inst {
const b = try self.requireRuntimeBlock(block, unreach.base.src);
+ if (self.wantSafety(block)) {
+ // TODO Once we have a panic function to call, call it here instead of this.
+ _ = try self.addNewInstArgs(b, unreach.base.src, Type.initTag(.void), Inst.Breakpoint, {});
+ }
return self.addNewInstArgs(b, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {});
}
@@ -1258,6 +1293,7 @@ pub fn main() anyerror!void {
.target = native_info.target,
.output_mode = .Obj,
.link_mode = .Static,
+ .optimize_mode = .Debug,
});
defer analyzed_module.deinit(allocator);
src-self-hosted/link.zig
@@ -431,7 +431,7 @@ const Update = struct {
},
}
}
- if (self.entry_addr == null) {
+ if (self.entry_addr == null and self.module.output_mode == .Exe) {
const msg = try std.fmt.allocPrint(self.errors.allocator, "no entry point found", .{});
errdefer self.errors.allocator.free(msg);
try self.errors.append(.{
@@ -480,7 +480,15 @@ const Update = struct {
assert(index == 16);
- mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf.ET.EXEC), endian);
+ const elf_type = switch (self.module.output_mode) {
+ .Exe => elf.ET.EXEC,
+ .Obj => elf.ET.REL,
+ .Lib => switch (self.module.link_mode) {
+ .Static => elf.ET.REL,
+ .Dynamic => elf.ET.DYN,
+ },
+ };
+ mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf_type), endian);
index += 2;
const machine = self.module.target.cpu.arch.toElfMachine();
@@ -491,10 +499,11 @@ const Update = struct {
mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian);
index += 4;
+ const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?;
+
switch (ptr_width) {
.p32 => {
- // e_entry
- mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.entry_addr.?), endian);
+ mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian);
index += 4;
// e_phoff
@@ -507,7 +516,7 @@ const Update = struct {
},
.p64 => {
// e_entry
- mem.writeInt(u64, hdr_buf[index..][0..8], self.entry_addr.?, endian);
+ mem.writeInt(u64, hdr_buf[index..][0..8], e_entry, endian);
index += 8;
// e_phoff
@@ -748,7 +757,7 @@ const Update = struct {
pub fn writeFile(allocator: *Allocator, module: ir.Module, file: fs.File) !Result {
switch (module.output_mode) {
.Exe => {},
- .Obj => return error.TODOImplementWritingObjectFiles,
+ .Obj => {},
.Lib => return error.TODOImplementWritingLibFiles,
}
switch (module.object_format) {