mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
zir: add breakpoint() instruction and object file ability
This commit is contained in:
parent
f89dbe6c4e
commit
751903ba8f
@ -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).?),
|
||||
|
||||
@ -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,13 +105,11 @@ pub const Inst = struct {
|
||||
},
|
||||
};
|
||||
|
||||
pub const IsNull = struct {
|
||||
pub const base_tag = Tag.isnull;
|
||||
|
||||
pub const Constant = struct {
|
||||
pub const base_tag = Tag.constant;
|
||||
base: Inst,
|
||||
args: struct {
|
||||
operand: *Inst,
|
||||
},
|
||||
|
||||
val: Value,
|
||||
};
|
||||
|
||||
pub const IsNonNull = struct {
|
||||
@ -143,6 +120,36 @@ pub const Inst = struct {
|
||||
operand: *Inst,
|
||||
},
|
||||
};
|
||||
|
||||
pub const IsNull = struct {
|
||||
pub const base_tag = Tag.isnull;
|
||||
|
||||
base: Inst,
|
||||
args: struct {
|
||||
operand: *Inst,
|
||||
},
|
||||
};
|
||||
|
||||
pub const PtrToInt = struct {
|
||||
pub const base_tag = Tag.ptrtoint;
|
||||
|
||||
base: Inst,
|
||||
args: struct {
|
||||
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);
|
||||
|
||||
|
||||
@ -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).?;
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user