zig/src-self-hosted/ir.zig

158 lines
3.5 KiB
Zig
Raw Normal View History

const std = @import("std");
const Value = @import("value.zig").Value;
2020-04-18 16:41:45 -07:00
const Type = @import("type.zig").Type;
2020-05-15 18:44:33 -07:00
const Module = @import("Module.zig");
2020-05-15 18:44:33 -07:00
/// These are in-memory, analyzed instructions. See `zir.Inst` for the representation
/// of instructions that correspond to the ZIR text format.
2020-04-20 21:56:30 -07:00
/// This struct owns the `Value` and `Type` memory. When the struct is deallocated,
/// so are the `Value` and `Type`. The value of a constant must be copied into
/// a memory location for the value to survive after a const instruction.
pub const Inst = struct {
2020-04-20 21:56:30 -07:00
tag: Tag,
ty: Type,
2020-04-21 10:50:04 -07:00
/// Byte offset into the source.
src: usize,
2020-04-20 21:56:30 -07:00
pub const Tag = enum {
assembly,
bitcast,
breakpoint,
rework self-hosted compiler for incremental builds * introduce std.ArrayListUnmanaged for when you have the allocator stored elsewhere * move std.heap.ArenaAllocator implementation to its own file. extract the main state into std.heap.ArenaAllocator.State, which can be stored as an alternative to storing the entire ArenaAllocator, saving 24 bytes per ArenaAllocator on 64 bit targets. * std.LinkedList.Node pointer field now defaults to being null initialized. * Rework self-hosted compiler Package API * Delete almost all the bitrotted self-hosted compiler code. The only bit rotted code left is in main.zig and compilation.zig * Add call instruction to ZIR * self-hosted compiler ir API and link API are reworked to support a long-running compiler that incrementally updates declarations * Introduce the concept of scopes to ZIR semantic analysis * ZIR text format supports referencing named decls that are declared later in the file * Figure out how memory management works for the long-running compiler and incremental compilation. The main roots are top level declarations. There is a table of decls. The key is a cryptographic hash of the fully qualified decl name. Each decl has an arena allocator where all of the memory related to that decl is stored. Each code block has its own arena allocator for the lifetime of the block. Values that want to survive when going out of scope in a block must get copied into the outer block. Finally, values must get copied into the Decl arena to be long-lived. * Delete the unused MemoryCell struct. Instead, comptime pointers are based on references to Decl structs. * Figure out how caching works. Each Decl will store a set of other Decls which must be recompiled when it changes. This branch is still work-in-progress; this commit breaks the build.
2020-05-09 23:05:54 -07:00
call,
2020-04-28 18:04:18 -07:00
cmp,
condbr,
constant,
2020-04-28 18:04:18 -07:00
isnonnull,
isnull,
ptrtoint,
ret,
unreach,
2020-04-20 21:56:30 -07:00
};
pub fn cast(base: *Inst, comptime T: type) ?*T {
if (base.tag != T.base_tag)
return null;
return @fieldParentPtr(T, "base", base);
2020-04-19 17:04:11 -07:00
}
2020-04-21 17:34:40 -07:00
pub fn Args(comptime T: type) type {
return std.meta.fieldInfo(T, "args").field_type;
}
2020-04-21 10:50:04 -07:00
/// Returns `null` if runtime-known.
pub fn value(base: *Inst) ?Value {
2020-04-28 18:04:18 -07:00
if (base.ty.onePossibleValue())
return Value.initTag(.the_one_possible_value);
const inst = base.cast(Constant) orelse return null;
return inst.val;
2020-04-21 10:50:04 -07:00
}
2020-04-20 21:56:30 -07:00
pub const Assembly = struct {
pub const base_tag = Tag.assembly;
base: Inst,
2020-04-21 17:34:40 -07:00
args: struct {
asm_source: []const u8,
is_volatile: bool,
2020-04-21 19:19:32 -07:00
output: ?[]const u8,
2020-04-21 17:34:40 -07:00
inputs: []const []const u8,
clobbers: []const []const u8,
args: []const *Inst,
},
};
pub const BitCast = struct {
pub const base_tag = Tag.bitcast;
base: Inst,
args: struct {
operand: *Inst,
},
};
2020-04-28 18:04:18 -07:00
pub const Breakpoint = struct {
pub const base_tag = Tag.breakpoint;
base: Inst,
args: void,
};
rework self-hosted compiler for incremental builds * introduce std.ArrayListUnmanaged for when you have the allocator stored elsewhere * move std.heap.ArenaAllocator implementation to its own file. extract the main state into std.heap.ArenaAllocator.State, which can be stored as an alternative to storing the entire ArenaAllocator, saving 24 bytes per ArenaAllocator on 64 bit targets. * std.LinkedList.Node pointer field now defaults to being null initialized. * Rework self-hosted compiler Package API * Delete almost all the bitrotted self-hosted compiler code. The only bit rotted code left is in main.zig and compilation.zig * Add call instruction to ZIR * self-hosted compiler ir API and link API are reworked to support a long-running compiler that incrementally updates declarations * Introduce the concept of scopes to ZIR semantic analysis * ZIR text format supports referencing named decls that are declared later in the file * Figure out how memory management works for the long-running compiler and incremental compilation. The main roots are top level declarations. There is a table of decls. The key is a cryptographic hash of the fully qualified decl name. Each decl has an arena allocator where all of the memory related to that decl is stored. Each code block has its own arena allocator for the lifetime of the block. Values that want to survive when going out of scope in a block must get copied into the outer block. Finally, values must get copied into the Decl arena to be long-lived. * Delete the unused MemoryCell struct. Instead, comptime pointers are based on references to Decl structs. * Figure out how caching works. Each Decl will store a set of other Decls which must be recompiled when it changes. This branch is still work-in-progress; this commit breaks the build.
2020-05-09 23:05:54 -07:00
pub const Call = struct {
pub const base_tag = Tag.call;
base: Inst,
args: struct {
func: *Inst,
args: []const *Inst,
},
};
2020-04-28 18:04:18 -07:00
pub const Cmp = struct {
pub const base_tag = Tag.cmp;
base: Inst,
args: struct {
lhs: *Inst,
op: std.math.CompareOperator,
rhs: *Inst,
},
};
pub const CondBr = struct {
pub const base_tag = Tag.condbr;
base: Inst,
args: struct {
condition: *Inst,
true_body: Module.Body,
false_body: Module.Body,
},
};
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,
},
};
2020-04-28 18:04:18 -07:00
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;
2020-04-28 18:04:18 -07:00
base: Inst,
args: struct {
ptr: *Inst,
2020-04-28 18:04:18 -07:00
},
};
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,
};
2020-04-17 21:09:43 -07:00
};