mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
self-hosted: working towards conditional branching test case
New features:
* Functions can have parameters in semantic analysis. Codegen
is not implemented yet.
* Support for i8, i16, i32, i64, u8, u16, u32, u64 primitive
identifiers.
* New ZIR instructions: arg, block, and breakvoid
Implementation details:
* Move Module.Body to ir.Body
* Scope.Block gains a parent field and an optional Label field
* Fix bug in integer type equality comparison.
Here's the test case I'm working towards:
```
@void = primitive(void)
@i32 = primitive(i32)
@fnty = fntype([@i32, @i32], @void)
@0 = str("entry")
@1 = export(@0, "entry")
@entry = fn(@fnty, {
%0 = arg(0)
%1 = arg(1)
%2 = add(%0, %1)
%3 = int(7)
%4 = block("if", {
%neq = cmp(%2, neq, %3)
%5 = condbr(%neq, {
%6 = unreachable()
}, {
%7 = breakvoid("if")
})
})
%11 = returnvoid()
})
```
$ ./zig-cache/bin/zig build-obj test.zir
test.zir:9:12: error: TODO implement function parameters for Arch.x86_64
That's where I left off.
This commit is contained in:
parent
e820678ca1
commit
130c7fd23b
@ -15,6 +15,7 @@ const ir = @import("ir.zig");
|
|||||||
const zir = @import("zir.zig");
|
const zir = @import("zir.zig");
|
||||||
const Module = @This();
|
const Module = @This();
|
||||||
const Inst = ir.Inst;
|
const Inst = ir.Inst;
|
||||||
|
const Body = ir.Body;
|
||||||
const ast = std.zig.ast;
|
const ast = std.zig.ast;
|
||||||
const trace = @import("tracy.zig").trace;
|
const trace = @import("tracy.zig").trace;
|
||||||
|
|
||||||
@ -649,11 +650,19 @@ pub const Scope = struct {
|
|||||||
pub const Block = struct {
|
pub const Block = struct {
|
||||||
pub const base_tag: Tag = .block;
|
pub const base_tag: Tag = .block;
|
||||||
base: Scope = Scope{ .tag = base_tag },
|
base: Scope = Scope{ .tag = base_tag },
|
||||||
|
parent: ?*Block,
|
||||||
func: ?*Fn,
|
func: ?*Fn,
|
||||||
decl: *Decl,
|
decl: *Decl,
|
||||||
instructions: ArrayListUnmanaged(*Inst),
|
instructions: ArrayListUnmanaged(*Inst),
|
||||||
/// Points to the arena allocator of DeclAnalysis
|
/// Points to the arena allocator of DeclAnalysis
|
||||||
arena: *Allocator,
|
arena: *Allocator,
|
||||||
|
label: ?Label = null,
|
||||||
|
|
||||||
|
pub const Label = struct {
|
||||||
|
name: []const u8,
|
||||||
|
results: ArrayListUnmanaged(*Inst),
|
||||||
|
block_inst: *Inst.Block,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This is a temporary structure, references to it are valid only
|
/// This is a temporary structure, references to it are valid only
|
||||||
@ -676,10 +685,6 @@ pub const Scope = struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Body = struct {
|
|
||||||
instructions: []*Inst,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const AllErrors = struct {
|
pub const AllErrors = struct {
|
||||||
arena: std.heap.ArenaAllocator.State,
|
arena: std.heap.ArenaAllocator.State,
|
||||||
list: []const Message,
|
list: []const Message,
|
||||||
@ -1139,13 +1144,16 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
|||||||
|
|
||||||
const body_node = fn_proto.body_node orelse
|
const body_node = fn_proto.body_node orelse
|
||||||
return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
|
return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
|
||||||
if (fn_proto.params_len != 0) {
|
|
||||||
return self.failTok(
|
const param_decls = fn_proto.params();
|
||||||
&fn_type_scope.base,
|
const param_types = try fn_type_scope.arena.allocator.alloc(*zir.Inst, param_decls.len);
|
||||||
fn_proto.params()[0].name_token.?,
|
for (param_decls) |param_decl, i| {
|
||||||
"TODO implement function parameters",
|
const param_type_node = switch (param_decl.param_type) {
|
||||||
.{},
|
.var_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),
|
||||||
);
|
.var_args => |tok| return self.failTok(&fn_type_scope.base, tok, "TODO implement var args", .{}),
|
||||||
|
.type_expr => |node| node,
|
||||||
|
};
|
||||||
|
param_types[i] = try self.astGenExpr(&fn_type_scope.base, param_type_node);
|
||||||
}
|
}
|
||||||
if (fn_proto.lib_name) |lib_name| {
|
if (fn_proto.lib_name) |lib_name| {
|
||||||
return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{});
|
return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{});
|
||||||
@ -1174,7 +1182,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
|||||||
const fn_src = tree.token_locs[fn_proto.fn_token].start;
|
const fn_src = tree.token_locs[fn_proto.fn_token].start;
|
||||||
const fn_type_inst = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.FnType, .{
|
const fn_type_inst = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.FnType, .{
|
||||||
.return_type = return_type_inst,
|
.return_type = return_type_inst,
|
||||||
.param_types = &[0]*zir.Inst{},
|
.param_types = param_types,
|
||||||
}, .{});
|
}, .{});
|
||||||
_ = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.Return, .{ .operand = fn_type_inst }, .{});
|
_ = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.Return, .{ .operand = fn_type_inst }, .{});
|
||||||
|
|
||||||
@ -1184,6 +1192,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
|
|||||||
const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
|
const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
|
||||||
|
|
||||||
var block_scope: Scope.Block = .{
|
var block_scope: Scope.Block = .{
|
||||||
|
.parent = null,
|
||||||
.func = null,
|
.func = null,
|
||||||
.decl = decl,
|
.decl = decl,
|
||||||
.instructions = .{},
|
.instructions = .{},
|
||||||
@ -1302,10 +1311,25 @@ fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir
|
|||||||
.Call => return self.astGenCall(scope, @fieldParentPtr(ast.Node.Call, "base", ast_node)),
|
.Call => return self.astGenCall(scope, @fieldParentPtr(ast.Node.Call, "base", ast_node)),
|
||||||
.Unreachable => return self.astGenUnreachable(scope, @fieldParentPtr(ast.Node.Unreachable, "base", ast_node)),
|
.Unreachable => return self.astGenUnreachable(scope, @fieldParentPtr(ast.Node.Unreachable, "base", ast_node)),
|
||||||
.ControlFlowExpression => return self.astGenControlFlowExpression(scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)),
|
.ControlFlowExpression => return self.astGenControlFlowExpression(scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)),
|
||||||
|
.If => return self.astGenIf(scope, @fieldParentPtr(ast.Node.If, "base", ast_node)),
|
||||||
else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}),
|
else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.Inst {
|
||||||
|
if (if_node.payload) |payload| {
|
||||||
|
return self.failNode(scope, payload, "TODO implement astGenIf for optionals", .{});
|
||||||
|
}
|
||||||
|
if (if_node.@"else") |else_node| {
|
||||||
|
if (else_node.payload) |payload| {
|
||||||
|
return self.failNode(scope, payload, "TODO implement astGenIf for error unions", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const cond = try self.astGenExpr(scope, if_node.condition);
|
||||||
|
const body = try self.astGenExpr(scope, if_node.condition);
|
||||||
|
return self.failNode(scope, if_node.condition, "TODO implement astGenIf", .{});
|
||||||
|
}
|
||||||
|
|
||||||
fn astGenControlFlowExpression(
|
fn astGenControlFlowExpression(
|
||||||
self: *Module,
|
self: *Module,
|
||||||
scope: *Scope,
|
scope: *Scope,
|
||||||
@ -1351,7 +1375,18 @@ fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerE
|
|||||||
),
|
),
|
||||||
error.InvalidCharacter => break :integer,
|
error.InvalidCharacter => break :integer,
|
||||||
};
|
};
|
||||||
return self.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{});
|
const val = switch (bit_count) {
|
||||||
|
8 => if (is_signed) Value.initTag(.i8_type) else Value.initTag(.u8_type),
|
||||||
|
16 => if (is_signed) Value.initTag(.i16_type) else Value.initTag(.u16_type),
|
||||||
|
32 => if (is_signed) Value.initTag(.i32_type) else Value.initTag(.u32_type),
|
||||||
|
64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type),
|
||||||
|
else => return self.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{}),
|
||||||
|
};
|
||||||
|
const src = tree.token_locs[ident.token].start;
|
||||||
|
return self.addZIRInstConst(scope, src, .{
|
||||||
|
.ty = Type.initTag(.type),
|
||||||
|
.val = val,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1494,16 +1529,18 @@ fn astGenBuiltinCall(self: *Module, scope: *Scope, call: *ast.Node.BuiltinCall)
|
|||||||
|
|
||||||
fn astGenCall(self: *Module, scope: *Scope, call: *ast.Node.Call) InnerError!*zir.Inst {
|
fn astGenCall(self: *Module, scope: *Scope, call: *ast.Node.Call) InnerError!*zir.Inst {
|
||||||
const tree = scope.tree();
|
const tree = scope.tree();
|
||||||
|
|
||||||
if (call.params_len != 0) {
|
|
||||||
return self.failNode(scope, &call.base, "TODO implement fn calls with parameters", .{});
|
|
||||||
}
|
|
||||||
const lhs = try self.astGenExpr(scope, call.lhs);
|
const lhs = try self.astGenExpr(scope, call.lhs);
|
||||||
|
|
||||||
|
const param_nodes = call.params();
|
||||||
|
const args = try scope.cast(Scope.GenZIR).?.arena.allocator.alloc(*zir.Inst, param_nodes.len);
|
||||||
|
for (param_nodes) |param_node, i| {
|
||||||
|
args[i] = try self.astGenExpr(scope, param_node);
|
||||||
|
}
|
||||||
|
|
||||||
const src = tree.token_locs[call.lhs.firstToken()].start;
|
const src = tree.token_locs[call.lhs.firstToken()].start;
|
||||||
return self.addZIRInst(scope, src, zir.Inst.Call, .{
|
return self.addZIRInst(scope, src, zir.Inst.Call, .{
|
||||||
.func = lhs,
|
.func = lhs,
|
||||||
.args = &[0]*zir.Inst{},
|
.args = args,
|
||||||
}, .{});
|
}, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1871,6 +1908,7 @@ fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {
|
|||||||
var arena = decl.typed_value.most_recent.arena.?.promote(self.allocator);
|
var arena = decl.typed_value.most_recent.arena.?.promote(self.allocator);
|
||||||
defer decl.typed_value.most_recent.arena.?.* = arena.state;
|
defer decl.typed_value.most_recent.arena.?.* = arena.state;
|
||||||
var inner_block: Scope.Block = .{
|
var inner_block: Scope.Block = .{
|
||||||
|
.parent = null,
|
||||||
.func = func,
|
.func = func,
|
||||||
.decl = decl,
|
.decl = decl,
|
||||||
.instructions = .{},
|
.instructions = .{},
|
||||||
@ -2323,7 +2361,10 @@ fn analyzeInstConst(self: *Module, scope: *Scope, const_inst: *zir.Inst.Const) I
|
|||||||
|
|
||||||
fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
|
fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
|
||||||
switch (old_inst.tag) {
|
switch (old_inst.tag) {
|
||||||
|
.arg => return self.analyzeInstArg(scope, old_inst.cast(zir.Inst.Arg).?),
|
||||||
|
.block => return self.analyzeInstBlock(scope, old_inst.cast(zir.Inst.Block).?),
|
||||||
.breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?),
|
.breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?),
|
||||||
|
.breakvoid => return self.analyzeInstBreakVoid(scope, old_inst.cast(zir.Inst.BreakVoid).?),
|
||||||
.call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?),
|
.call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?),
|
||||||
.compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?),
|
.compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?),
|
||||||
.@"const" => return self.analyzeInstConst(scope, old_inst.cast(zir.Inst.Const).?),
|
.@"const" => return self.analyzeInstConst(scope, old_inst.cast(zir.Inst.Const).?),
|
||||||
@ -2436,11 +2477,105 @@ fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.Compile
|
|||||||
return self.fail(scope, inst.base.src, "{}", .{inst.positionals.msg});
|
return self.fail(scope, inst.base.src, "{}", .{inst.positionals.msg});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn analyzeInstArg(self: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst {
|
||||||
|
const b = try self.requireRuntimeBlock(scope, inst.base.src);
|
||||||
|
const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
|
||||||
|
const param_count = fn_ty.fnParamLen();
|
||||||
|
if (inst.positionals.index >= param_count) {
|
||||||
|
return self.fail(scope, inst.base.src, "parameter index {} outside list of length {}", .{
|
||||||
|
inst.positionals.index,
|
||||||
|
param_count,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const param_type = fn_ty.fnParamType(inst.positionals.index);
|
||||||
|
return self.addNewInstArgs(b, inst.base.src, param_type, Inst.Arg, .{
|
||||||
|
.index = inst.positionals.index,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {
|
||||||
|
const parent_block = scope.cast(Scope.Block).?;
|
||||||
|
|
||||||
|
// Reserve space for a Block instruction so that generated Break instructions can
|
||||||
|
// point to it, even if it doesn't end up getting used because the code ends up being
|
||||||
|
// comptime evaluated.
|
||||||
|
const block_inst = try parent_block.arena.create(Inst.Block);
|
||||||
|
block_inst.* = .{
|
||||||
|
.base = .{
|
||||||
|
.tag = Inst.Block.base_tag,
|
||||||
|
.ty = undefined, // Set after analysis.
|
||||||
|
.src = inst.base.src,
|
||||||
|
},
|
||||||
|
.args = undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
var child_block: Scope.Block = .{
|
||||||
|
.parent = parent_block,
|
||||||
|
.func = parent_block.func,
|
||||||
|
.decl = parent_block.decl,
|
||||||
|
.instructions = .{},
|
||||||
|
.arena = parent_block.arena,
|
||||||
|
// TODO @as here is working around a miscompilation compiler bug :(
|
||||||
|
.label = @as(?Scope.Block.Label, Scope.Block.Label{
|
||||||
|
.name = inst.positionals.label,
|
||||||
|
.results = .{},
|
||||||
|
.block_inst = block_inst,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const label = &child_block.label.?;
|
||||||
|
|
||||||
|
defer child_block.instructions.deinit(self.allocator);
|
||||||
|
defer label.results.deinit(self.allocator);
|
||||||
|
|
||||||
|
try self.analyzeBody(&child_block.base, inst.positionals.body);
|
||||||
|
|
||||||
|
// Blocks must terminate with noreturn instruction.
|
||||||
|
assert(child_block.instructions.items.len != 0);
|
||||||
|
assert(child_block.instructions.items[child_block.instructions.items.len - 1].tag.isNoReturn());
|
||||||
|
|
||||||
|
if (label.results.items.len <= 1) {
|
||||||
|
// No need to add the Block instruction; we can add the instructions to the parent block directly.
|
||||||
|
// Blocks are terminated with a noreturn instruction which we do not want to include.
|
||||||
|
const instrs = child_block.instructions.items;
|
||||||
|
try parent_block.instructions.appendSlice(self.allocator, instrs[0 .. instrs.len - 1]);
|
||||||
|
if (label.results.items.len == 1) {
|
||||||
|
return label.results.items[0];
|
||||||
|
} else {
|
||||||
|
return self.constNoReturn(scope, inst.base.src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to set the type and emit the Block instruction. This allows machine code generation
|
||||||
|
// to emit a jump instruction to after the block when it encounters the break.
|
||||||
|
try parent_block.instructions.append(self.allocator, &block_inst.base);
|
||||||
|
block_inst.base.ty = try self.resolvePeerTypes(scope, label.results.items);
|
||||||
|
block_inst.args.body = .{ .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items) };
|
||||||
|
return &block_inst.base;
|
||||||
|
}
|
||||||
|
|
||||||
fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoint) InnerError!*Inst {
|
fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoint) InnerError!*Inst {
|
||||||
const b = try self.requireRuntimeBlock(scope, inst.base.src);
|
const b = try self.requireRuntimeBlock(scope, inst.base.src);
|
||||||
return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, {});
|
return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn analyzeInstBreakVoid(self: *Module, scope: *Scope, inst: *zir.Inst.BreakVoid) InnerError!*Inst {
|
||||||
|
const label_name = inst.positionals.label;
|
||||||
|
const void_inst = try self.constVoid(scope, inst.base.src);
|
||||||
|
|
||||||
|
var opt_block = scope.cast(Scope.Block);
|
||||||
|
while (opt_block) |block| {
|
||||||
|
if (block.label) |*label| {
|
||||||
|
if (mem.eql(u8, label.name, label_name)) {
|
||||||
|
try label.results.append(self.allocator, void_inst);
|
||||||
|
return self.constNoReturn(scope, inst.base.src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opt_block = block.parent;
|
||||||
|
} else {
|
||||||
|
return self.fail(scope, inst.base.src, "use of undeclared label '{}'", .{label_name});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn analyzeInstDeclRefStr(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr) InnerError!*Inst {
|
fn analyzeInstDeclRefStr(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr) InnerError!*Inst {
|
||||||
const decl_name = try self.resolveConstString(scope, inst.positionals.name);
|
const decl_name = try self.resolveConstString(scope, inst.positionals.name);
|
||||||
return self.analyzeDeclRefByName(scope, inst.base.src, decl_name);
|
return self.analyzeDeclRefByName(scope, inst.base.src, decl_name);
|
||||||
@ -2602,35 +2737,38 @@ fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError
|
|||||||
fn analyzeInstFnType(self: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
|
fn analyzeInstFnType(self: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
|
||||||
const return_type = try self.resolveType(scope, fntype.positionals.return_type);
|
const return_type = try self.resolveType(scope, fntype.positionals.return_type);
|
||||||
|
|
||||||
if (return_type.zigTypeTag() == .NoReturn and
|
// Hot path for some common function types.
|
||||||
fntype.positionals.param_types.len == 0 and
|
if (fntype.positionals.param_types.len == 0) {
|
||||||
fntype.kw_args.cc == .Unspecified)
|
if (return_type.zigTypeTag() == .NoReturn and fntype.kw_args.cc == .Unspecified) {
|
||||||
{
|
|
||||||
return self.constType(scope, fntype.base.src, Type.initTag(.fn_noreturn_no_args));
|
return self.constType(scope, fntype.base.src, Type.initTag(.fn_noreturn_no_args));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (return_type.zigTypeTag() == .Void and
|
if (return_type.zigTypeTag() == .Void and fntype.kw_args.cc == .Unspecified) {
|
||||||
fntype.positionals.param_types.len == 0 and
|
|
||||||
fntype.kw_args.cc == .Unspecified)
|
|
||||||
{
|
|
||||||
return self.constType(scope, fntype.base.src, Type.initTag(.fn_void_no_args));
|
return self.constType(scope, fntype.base.src, Type.initTag(.fn_void_no_args));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (return_type.zigTypeTag() == .NoReturn and
|
if (return_type.zigTypeTag() == .NoReturn and fntype.kw_args.cc == .Naked) {
|
||||||
fntype.positionals.param_types.len == 0 and
|
|
||||||
fntype.kw_args.cc == .Naked)
|
|
||||||
{
|
|
||||||
return self.constType(scope, fntype.base.src, Type.initTag(.fn_naked_noreturn_no_args));
|
return self.constType(scope, fntype.base.src, Type.initTag(.fn_naked_noreturn_no_args));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (return_type.zigTypeTag() == .Void and
|
if (return_type.zigTypeTag() == .Void and fntype.kw_args.cc == .C) {
|
||||||
fntype.positionals.param_types.len == 0 and
|
|
||||||
fntype.kw_args.cc == .C)
|
|
||||||
{
|
|
||||||
return self.constType(scope, fntype.base.src, Type.initTag(.fn_ccc_void_no_args));
|
return self.constType(scope, fntype.base.src, Type.initTag(.fn_ccc_void_no_args));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return self.fail(scope, fntype.base.src, "TODO implement fntype instruction more", .{});
|
const arena = scope.arena();
|
||||||
|
const param_types = try arena.alloc(Type, fntype.positionals.param_types.len);
|
||||||
|
for (fntype.positionals.param_types) |param_type, i| {
|
||||||
|
param_types[i] = try self.resolveType(scope, param_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = try arena.create(Type.Payload.Function);
|
||||||
|
payload.* = .{
|
||||||
|
.cc = fntype.kw_args.cc,
|
||||||
|
.return_type = return_type,
|
||||||
|
.param_types = param_types,
|
||||||
|
};
|
||||||
|
return self.constType(scope, fntype.base.src, Type.initPayload(&payload.base));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyzeInstPrimitive(self: *Module, scope: *Scope, primitive: *zir.Inst.Primitive) InnerError!*Inst {
|
fn analyzeInstPrimitive(self: *Module, scope: *Scope, primitive: *zir.Inst.Primitive) InnerError!*Inst {
|
||||||
@ -2757,10 +2895,17 @@ fn analyzeInstElemPtr(self: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inn
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.Add) InnerError!*Inst {
|
fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.Add) InnerError!*Inst {
|
||||||
|
const tracy = trace(@src());
|
||||||
|
defer tracy.end();
|
||||||
|
|
||||||
const lhs = try self.resolveInst(scope, inst.positionals.lhs);
|
const lhs = try self.resolveInst(scope, inst.positionals.lhs);
|
||||||
const rhs = try self.resolveInst(scope, inst.positionals.rhs);
|
const rhs = try self.resolveInst(scope, inst.positionals.rhs);
|
||||||
|
|
||||||
if (lhs.ty.zigTypeTag() == .Int and rhs.ty.zigTypeTag() == .Int) {
|
if (lhs.ty.zigTypeTag() == .Int and rhs.ty.zigTypeTag() == .Int) {
|
||||||
|
if (!lhs.ty.eql(rhs.ty)) {
|
||||||
|
return self.fail(scope, inst.base.src, "TODO implement peer type resolution", .{});
|
||||||
|
}
|
||||||
|
|
||||||
if (lhs.value()) |lhs_val| {
|
if (lhs.value()) |lhs_val| {
|
||||||
if (rhs.value()) |rhs_val| {
|
if (rhs.value()) |rhs_val| {
|
||||||
// TODO is this a performance issue? maybe we should try the operation without
|
// TODO is this a performance issue? maybe we should try the operation without
|
||||||
@ -2777,10 +2922,6 @@ fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.Add) InnerError!
|
|||||||
result_bigint.add(lhs_bigint, rhs_bigint);
|
result_bigint.add(lhs_bigint, rhs_bigint);
|
||||||
const result_limbs = result_bigint.limbs[0..result_bigint.len];
|
const result_limbs = result_bigint.limbs[0..result_bigint.len];
|
||||||
|
|
||||||
if (!lhs.ty.eql(rhs.ty)) {
|
|
||||||
return self.fail(scope, inst.base.src, "TODO implement peer type resolution", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
const val_payload = if (result_bigint.positive) blk: {
|
const val_payload = if (result_bigint.positive) blk: {
|
||||||
const val_payload = try scope.arena().create(Value.Payload.IntBigPositive);
|
const val_payload = try scope.arena().create(Value.Payload.IntBigPositive);
|
||||||
val_payload.* = .{ .limbs = result_limbs };
|
val_payload.* = .{ .limbs = result_limbs };
|
||||||
@ -2797,6 +2938,12 @@ fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.Add) InnerError!
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const b = try self.requireRuntimeBlock(scope, inst.base.src);
|
||||||
|
return self.addNewInstArgs(b, inst.base.src, lhs.ty, Inst.Add, .{
|
||||||
|
.lhs = lhs,
|
||||||
|
.rhs = rhs,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.fail(scope, inst.base.src, "TODO implement more analyze add", .{});
|
return self.fail(scope, inst.base.src, "TODO implement more analyze add", .{});
|
||||||
@ -2936,6 +3083,7 @@ fn analyzeInstCondBr(self: *Module, scope: *Scope, inst: *zir.Inst.CondBr) Inner
|
|||||||
const parent_block = try self.requireRuntimeBlock(scope, inst.base.src);
|
const parent_block = try self.requireRuntimeBlock(scope, inst.base.src);
|
||||||
|
|
||||||
var true_block: Scope.Block = .{
|
var true_block: Scope.Block = .{
|
||||||
|
.parent = parent_block,
|
||||||
.func = parent_block.func,
|
.func = parent_block.func,
|
||||||
.decl = parent_block.decl,
|
.decl = parent_block.decl,
|
||||||
.instructions = .{},
|
.instructions = .{},
|
||||||
@ -2945,6 +3093,7 @@ fn analyzeInstCondBr(self: *Module, scope: *Scope, inst: *zir.Inst.CondBr) Inner
|
|||||||
try self.analyzeBody(&true_block.base, inst.positionals.true_body);
|
try self.analyzeBody(&true_block.base, inst.positionals.true_body);
|
||||||
|
|
||||||
var false_block: Scope.Block = .{
|
var false_block: Scope.Block = .{
|
||||||
|
.parent = parent_block,
|
||||||
.func = parent_block.func,
|
.func = parent_block.func,
|
||||||
.decl = parent_block.decl,
|
.decl = parent_block.decl,
|
||||||
.instructions = .{},
|
.instructions = .{},
|
||||||
@ -3178,7 +3327,7 @@ fn cmpNumeric(
|
|||||||
const casted_lhs = try self.coerce(scope, dest_type, lhs);
|
const casted_lhs = try self.coerce(scope, dest_type, lhs);
|
||||||
const casted_rhs = try self.coerce(scope, dest_type, lhs);
|
const casted_rhs = try self.coerce(scope, dest_type, lhs);
|
||||||
|
|
||||||
return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, .{
|
return self.addNewInstArgs(b, src, Type.initTag(.bool), Inst.Cmp, .{
|
||||||
.lhs = casted_lhs,
|
.lhs = casted_lhs,
|
||||||
.rhs = casted_rhs,
|
.rhs = casted_rhs,
|
||||||
.op = op,
|
.op = op,
|
||||||
@ -3197,6 +3346,12 @@ fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Type {
|
||||||
|
if (instructions.len == 0)
|
||||||
|
return Type.initTag(.noreturn);
|
||||||
|
return self.fail(scope, instructions[0].src, "TODO peer type resolution", .{});
|
||||||
|
}
|
||||||
|
|
||||||
fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
|
fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
|
||||||
// If the types are the same, we can return the operand.
|
// If the types are the same, we can return the operand.
|
||||||
if (dest_type.eql(inst.ty))
|
if (dest_type.eql(inst.ty))
|
||||||
@ -3238,7 +3393,10 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
|
|||||||
if (inst.value()) |val| {
|
if (inst.value()) |val| {
|
||||||
return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
|
return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
|
||||||
} else {
|
} else {
|
||||||
return self.fail(scope, inst.src, "TODO implement runtime integer widening", .{});
|
return self.fail(scope, inst.src, "TODO implement runtime integer widening ({} to {})", .{
|
||||||
|
inst.ty,
|
||||||
|
dest_type,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return self.fail(scope, inst.src, "TODO implement more int widening {} to {}", .{ inst.ty, dest_type });
|
return self.fail(scope, inst.src, "TODO implement more int widening {} to {}", .{ inst.ty, dest_type });
|
||||||
|
|||||||
@ -174,6 +174,9 @@ const Function = struct {
|
|||||||
|
|
||||||
fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {
|
fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {
|
||||||
switch (inst.tag) {
|
switch (inst.tag) {
|
||||||
|
.add => return self.genAdd(inst.cast(ir.Inst.Add).?),
|
||||||
|
.arg => return self.genArg(inst.src),
|
||||||
|
.block => return self.genBlock(inst.cast(ir.Inst.Block).?),
|
||||||
.breakpoint => return self.genBreakpoint(inst.src),
|
.breakpoint => return self.genBreakpoint(inst.src),
|
||||||
.call => return self.genCall(inst.cast(ir.Inst.Call).?),
|
.call => return self.genCall(inst.cast(ir.Inst.Call).?),
|
||||||
.unreach => return MCValue{ .unreach = {} },
|
.unreach => return MCValue{ .unreach = {} },
|
||||||
@ -190,6 +193,19 @@ const Function = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn genAdd(self: *Function, inst: *ir.Inst.Add) !MCValue {
|
||||||
|
switch (self.target.cpu.arch) {
|
||||||
|
else => return self.fail(inst.base.src, "TODO implement add for {}", .{self.target.cpu.arch}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn genArg(self: *Function, src: usize) !MCValue {
|
||||||
|
switch (self.target.cpu.arch) {
|
||||||
|
else => return self.fail(src, "TODO implement function parameters for {}", .{self.target.cpu.arch}),
|
||||||
|
}
|
||||||
|
return .none;
|
||||||
|
}
|
||||||
|
|
||||||
fn genBreakpoint(self: *Function, src: usize) !MCValue {
|
fn genBreakpoint(self: *Function, src: usize) !MCValue {
|
||||||
switch (self.target.cpu.arch) {
|
switch (self.target.cpu.arch) {
|
||||||
.i386, .x86_64 => {
|
.i386, .x86_64 => {
|
||||||
@ -302,6 +318,12 @@ const Function = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn genBlock(self: *Function, inst: *ir.Inst.Block) !MCValue {
|
||||||
|
switch (self.target.cpu.arch) {
|
||||||
|
else => return self.fail(inst.base.src, "TODO implement codegen Block for {}", .{self.target.cpu.arch}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn genAsm(self: *Function, inst: *ir.Inst.Assembly) !MCValue {
|
fn genAsm(self: *Function, inst: *ir.Inst.Assembly) !MCValue {
|
||||||
// TODO convert to inline function
|
// TODO convert to inline function
|
||||||
switch (self.target.cpu.arch) {
|
switch (self.target.cpu.arch) {
|
||||||
|
|||||||
@ -15,8 +15,11 @@ pub const Inst = struct {
|
|||||||
src: usize,
|
src: usize,
|
||||||
|
|
||||||
pub const Tag = enum {
|
pub const Tag = enum {
|
||||||
|
add,
|
||||||
|
arg,
|
||||||
assembly,
|
assembly,
|
||||||
bitcast,
|
bitcast,
|
||||||
|
block,
|
||||||
breakpoint,
|
breakpoint,
|
||||||
call,
|
call,
|
||||||
cmp,
|
cmp,
|
||||||
@ -28,6 +31,33 @@ pub const Inst = struct {
|
|||||||
ret,
|
ret,
|
||||||
retvoid,
|
retvoid,
|
||||||
unreach,
|
unreach,
|
||||||
|
|
||||||
|
/// Returns whether the instruction is one of the control flow "noreturn" types.
|
||||||
|
/// Function calls do not count. When ZIR is generated, the compiler automatically
|
||||||
|
/// emits an `Unreach` after a function call with the `noreturn` return type.
|
||||||
|
pub fn isNoReturn(tag: Tag) bool {
|
||||||
|
return switch (tag) {
|
||||||
|
.add,
|
||||||
|
.arg,
|
||||||
|
.assembly,
|
||||||
|
.bitcast,
|
||||||
|
.block,
|
||||||
|
.breakpoint,
|
||||||
|
.cmp,
|
||||||
|
.constant,
|
||||||
|
.isnonnull,
|
||||||
|
.isnull,
|
||||||
|
.ptrtoint,
|
||||||
|
.call,
|
||||||
|
=> false,
|
||||||
|
|
||||||
|
.condbr,
|
||||||
|
.ret,
|
||||||
|
.retvoid,
|
||||||
|
.unreach,
|
||||||
|
=> true,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn cast(base: *Inst, comptime T: type) ?*T {
|
pub fn cast(base: *Inst, comptime T: type) ?*T {
|
||||||
@ -50,6 +80,25 @@ pub const Inst = struct {
|
|||||||
return inst.val;
|
return inst.val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const Add = struct {
|
||||||
|
pub const base_tag = Tag.add;
|
||||||
|
base: Inst,
|
||||||
|
|
||||||
|
args: struct {
|
||||||
|
lhs: *Inst,
|
||||||
|
rhs: *Inst,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Arg = struct {
|
||||||
|
pub const base_tag = Tag.arg;
|
||||||
|
base: Inst,
|
||||||
|
|
||||||
|
args: struct {
|
||||||
|
index: usize,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
pub const Assembly = struct {
|
pub const Assembly = struct {
|
||||||
pub const base_tag = Tag.assembly;
|
pub const base_tag = Tag.assembly;
|
||||||
base: Inst,
|
base: Inst,
|
||||||
@ -73,6 +122,14 @@ pub const Inst = struct {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Block = struct {
|
||||||
|
pub const base_tag = Tag.block;
|
||||||
|
base: Inst,
|
||||||
|
args: struct {
|
||||||
|
body: Body,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
pub const Breakpoint = struct {
|
pub const Breakpoint = struct {
|
||||||
pub const base_tag = Tag.breakpoint;
|
pub const base_tag = Tag.breakpoint;
|
||||||
base: Inst,
|
base: Inst,
|
||||||
@ -105,8 +162,8 @@ pub const Inst = struct {
|
|||||||
base: Inst,
|
base: Inst,
|
||||||
args: struct {
|
args: struct {
|
||||||
condition: *Inst,
|
condition: *Inst,
|
||||||
true_body: Module.Body,
|
true_body: Body,
|
||||||
false_body: Module.Body,
|
false_body: Body,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -164,3 +221,7 @@ pub const Inst = struct {
|
|||||||
args: void,
|
args: void,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Body = struct {
|
||||||
|
instructions: []*Inst,
|
||||||
|
};
|
||||||
|
|||||||
@ -21,8 +21,14 @@ pub const Type = extern union {
|
|||||||
switch (self.tag()) {
|
switch (self.tag()) {
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
.isize,
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
.c_ushort,
|
.c_ushort,
|
||||||
.c_int,
|
.c_int,
|
||||||
@ -57,6 +63,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args => return .Fn,
|
.fn_void_no_args => return .Fn,
|
||||||
.fn_naked_noreturn_no_args => return .Fn,
|
.fn_naked_noreturn_no_args => return .Fn,
|
||||||
.fn_ccc_void_no_args => return .Fn,
|
.fn_ccc_void_no_args => return .Fn,
|
||||||
|
.function => return .Fn,
|
||||||
|
|
||||||
.array, .array_u8_sentinel_0 => return .Array,
|
.array, .array_u8_sentinel_0 => return .Array,
|
||||||
.single_const_pointer => return .Pointer,
|
.single_const_pointer => return .Pointer,
|
||||||
@ -126,10 +133,14 @@ pub const Type = extern union {
|
|||||||
@panic("TODO implement more pointer Type equality comparison");
|
@panic("TODO implement more pointer Type equality comparison");
|
||||||
},
|
},
|
||||||
.Int => {
|
.Int => {
|
||||||
if (a.tag() != b.tag()) {
|
|
||||||
// Detect that e.g. u64 != usize, even if the bits match on a particular target.
|
// Detect that e.g. u64 != usize, even if the bits match on a particular target.
|
||||||
|
const a_is_named_int = a.isNamedInt();
|
||||||
|
const b_is_named_int = b.isNamedInt();
|
||||||
|
if (a_is_named_int != b_is_named_int)
|
||||||
return false;
|
return false;
|
||||||
}
|
if (a_is_named_int)
|
||||||
|
return a.tag() == b.tag();
|
||||||
|
// Remaining cases are arbitrary sized integers.
|
||||||
// The target will not be branched upon, because we handled target-dependent cases above.
|
// The target will not be branched upon, because we handled target-dependent cases above.
|
||||||
const info_a = a.intInfo(@as(Target, undefined));
|
const info_a = a.intInfo(@as(Target, undefined));
|
||||||
const info_b = b.intInfo(@as(Target, undefined));
|
const info_b = b.intInfo(@as(Target, undefined));
|
||||||
@ -176,8 +187,14 @@ pub const Type = extern union {
|
|||||||
} else switch (self.ptr_otherwise.tag) {
|
} else switch (self.ptr_otherwise.tag) {
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
.isize,
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
.c_ushort,
|
.c_ushort,
|
||||||
.c_int,
|
.c_int,
|
||||||
@ -231,6 +248,21 @@ pub const Type = extern union {
|
|||||||
},
|
},
|
||||||
.int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
|
.int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
|
||||||
.int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
|
.int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
|
||||||
|
.function => {
|
||||||
|
const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise);
|
||||||
|
const new_payload = try allocator.create(Payload.Function);
|
||||||
|
const param_types = try allocator.alloc(Type, payload.param_types.len);
|
||||||
|
for (payload.param_types) |param_type, i| {
|
||||||
|
param_types[i] = try param_type.copy(allocator);
|
||||||
|
}
|
||||||
|
new_payload.* = .{
|
||||||
|
.base = payload.base,
|
||||||
|
.return_type = try payload.return_type.copy(allocator),
|
||||||
|
.param_types = param_types,
|
||||||
|
.cc = payload.cc,
|
||||||
|
};
|
||||||
|
return Type{ .ptr_otherwise = &new_payload.base };
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +278,7 @@ pub const Type = extern union {
|
|||||||
comptime fmt: []const u8,
|
comptime fmt: []const u8,
|
||||||
options: std.fmt.FormatOptions,
|
options: std.fmt.FormatOptions,
|
||||||
out_stream: var,
|
out_stream: var,
|
||||||
) !void {
|
) @TypeOf(out_stream).Error!void {
|
||||||
comptime assert(fmt.len == 0);
|
comptime assert(fmt.len == 0);
|
||||||
var ty = self;
|
var ty = self;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -254,8 +286,14 @@ pub const Type = extern union {
|
|||||||
switch (t) {
|
switch (t) {
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
.isize,
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
.c_ushort,
|
.c_ushort,
|
||||||
.c_int,
|
.c_int,
|
||||||
@ -288,6 +326,16 @@ pub const Type = extern union {
|
|||||||
.fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
|
.fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
|
||||||
.fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),
|
.fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),
|
||||||
.single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
|
.single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
|
||||||
|
.function => {
|
||||||
|
const payload = @fieldParentPtr(Payload.Function, "base", ty.ptr_otherwise);
|
||||||
|
try out_stream.writeAll("fn(");
|
||||||
|
for (payload.param_types) |param_type, i| {
|
||||||
|
if (i != 0) try out_stream.writeAll(", ");
|
||||||
|
try param_type.format("", .{}, out_stream);
|
||||||
|
}
|
||||||
|
try out_stream.writeAll(") ");
|
||||||
|
try payload.return_type.format("", .{}, out_stream);
|
||||||
|
},
|
||||||
|
|
||||||
.array_u8_sentinel_0 => {
|
.array_u8_sentinel_0 => {
|
||||||
const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
|
const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
|
||||||
@ -322,8 +370,14 @@ pub const Type = extern union {
|
|||||||
switch (self.tag()) {
|
switch (self.tag()) {
|
||||||
.u8 => return Value.initTag(.u8_type),
|
.u8 => return Value.initTag(.u8_type),
|
||||||
.i8 => return Value.initTag(.i8_type),
|
.i8 => return Value.initTag(.i8_type),
|
||||||
.isize => return Value.initTag(.isize_type),
|
.u16 => return Value.initTag(.u16_type),
|
||||||
|
.i16 => return Value.initTag(.i16_type),
|
||||||
|
.u32 => return Value.initTag(.u32_type),
|
||||||
|
.i32 => return Value.initTag(.i32_type),
|
||||||
|
.u64 => return Value.initTag(.u64_type),
|
||||||
|
.i64 => return Value.initTag(.i64_type),
|
||||||
.usize => return Value.initTag(.usize_type),
|
.usize => return Value.initTag(.usize_type),
|
||||||
|
.isize => return Value.initTag(.isize_type),
|
||||||
.c_short => return Value.initTag(.c_short_type),
|
.c_short => return Value.initTag(.c_short_type),
|
||||||
.c_ushort => return Value.initTag(.c_ushort_type),
|
.c_ushort => return Value.initTag(.c_ushort_type),
|
||||||
.c_int => return Value.initTag(.c_int_type),
|
.c_int => return Value.initTag(.c_int_type),
|
||||||
@ -365,8 +419,14 @@ pub const Type = extern union {
|
|||||||
return switch (self.tag()) {
|
return switch (self.tag()) {
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
.isize,
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
.c_ushort,
|
.c_ushort,
|
||||||
.c_int,
|
.c_int,
|
||||||
@ -386,6 +446,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args,
|
.fn_void_no_args,
|
||||||
.fn_naked_noreturn_no_args,
|
.fn_naked_noreturn_no_args,
|
||||||
.fn_ccc_void_no_args,
|
.fn_ccc_void_no_args,
|
||||||
|
.function,
|
||||||
.single_const_pointer_to_comptime_int,
|
.single_const_pointer_to_comptime_int,
|
||||||
.const_slice_u8,
|
.const_slice_u8,
|
||||||
.array_u8_sentinel_0,
|
.array_u8_sentinel_0,
|
||||||
@ -417,9 +478,14 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args, // represents machine code; not a pointer
|
.fn_void_no_args, // represents machine code; not a pointer
|
||||||
.fn_naked_noreturn_no_args, // represents machine code; not a pointer
|
.fn_naked_noreturn_no_args, // represents machine code; not a pointer
|
||||||
.fn_ccc_void_no_args, // represents machine code; not a pointer
|
.fn_ccc_void_no_args, // represents machine code; not a pointer
|
||||||
|
.function, // represents machine code; not a pointer
|
||||||
.array_u8_sentinel_0,
|
.array_u8_sentinel_0,
|
||||||
=> return 1,
|
=> return 1,
|
||||||
|
|
||||||
|
.i16, .u16 => return 2,
|
||||||
|
.i32, .u32 => return 4,
|
||||||
|
.i64, .u64 => return 8,
|
||||||
|
|
||||||
.isize,
|
.isize,
|
||||||
.usize,
|
.usize,
|
||||||
.single_const_pointer_to_comptime_int,
|
.single_const_pointer_to_comptime_int,
|
||||||
@ -473,8 +539,14 @@ pub const Type = extern union {
|
|||||||
return switch (self.tag()) {
|
return switch (self.tag()) {
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
.isize,
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
.c_ushort,
|
.c_ushort,
|
||||||
.c_int,
|
.c_int,
|
||||||
@ -505,6 +577,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args,
|
.fn_void_no_args,
|
||||||
.fn_naked_noreturn_no_args,
|
.fn_naked_noreturn_no_args,
|
||||||
.fn_ccc_void_no_args,
|
.fn_ccc_void_no_args,
|
||||||
|
.function,
|
||||||
.int_unsigned,
|
.int_unsigned,
|
||||||
.int_signed,
|
.int_signed,
|
||||||
=> false,
|
=> false,
|
||||||
@ -519,8 +592,14 @@ pub const Type = extern union {
|
|||||||
return switch (self.tag()) {
|
return switch (self.tag()) {
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
.isize,
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
.c_ushort,
|
.c_ushort,
|
||||||
.c_int,
|
.c_int,
|
||||||
@ -552,6 +631,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args,
|
.fn_void_no_args,
|
||||||
.fn_naked_noreturn_no_args,
|
.fn_naked_noreturn_no_args,
|
||||||
.fn_ccc_void_no_args,
|
.fn_ccc_void_no_args,
|
||||||
|
.function,
|
||||||
.int_unsigned,
|
.int_unsigned,
|
||||||
.int_signed,
|
.int_signed,
|
||||||
=> false,
|
=> false,
|
||||||
@ -565,8 +645,14 @@ pub const Type = extern union {
|
|||||||
return switch (self.tag()) {
|
return switch (self.tag()) {
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
.isize,
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
.c_ushort,
|
.c_ushort,
|
||||||
.c_int,
|
.c_int,
|
||||||
@ -596,6 +682,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args,
|
.fn_void_no_args,
|
||||||
.fn_naked_noreturn_no_args,
|
.fn_naked_noreturn_no_args,
|
||||||
.fn_ccc_void_no_args,
|
.fn_ccc_void_no_args,
|
||||||
|
.function,
|
||||||
.int_unsigned,
|
.int_unsigned,
|
||||||
.int_signed,
|
.int_signed,
|
||||||
=> unreachable,
|
=> unreachable,
|
||||||
@ -612,8 +699,14 @@ pub const Type = extern union {
|
|||||||
return switch (self.tag()) {
|
return switch (self.tag()) {
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
.isize,
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
.c_ushort,
|
.c_ushort,
|
||||||
.c_int,
|
.c_int,
|
||||||
@ -641,6 +734,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args,
|
.fn_void_no_args,
|
||||||
.fn_naked_noreturn_no_args,
|
.fn_naked_noreturn_no_args,
|
||||||
.fn_ccc_void_no_args,
|
.fn_ccc_void_no_args,
|
||||||
|
.function,
|
||||||
.int_unsigned,
|
.int_unsigned,
|
||||||
.int_signed,
|
.int_signed,
|
||||||
=> unreachable,
|
=> unreachable,
|
||||||
@ -657,8 +751,14 @@ pub const Type = extern union {
|
|||||||
return switch (self.tag()) {
|
return switch (self.tag()) {
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
.isize,
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
.c_ushort,
|
.c_ushort,
|
||||||
.c_int,
|
.c_int,
|
||||||
@ -686,6 +786,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args,
|
.fn_void_no_args,
|
||||||
.fn_naked_noreturn_no_args,
|
.fn_naked_noreturn_no_args,
|
||||||
.fn_ccc_void_no_args,
|
.fn_ccc_void_no_args,
|
||||||
|
.function,
|
||||||
.single_const_pointer,
|
.single_const_pointer,
|
||||||
.single_const_pointer_to_comptime_int,
|
.single_const_pointer_to_comptime_int,
|
||||||
.const_slice_u8,
|
.const_slice_u8,
|
||||||
@ -703,8 +804,14 @@ pub const Type = extern union {
|
|||||||
return switch (self.tag()) {
|
return switch (self.tag()) {
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
.isize,
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
.c_ushort,
|
.c_ushort,
|
||||||
.c_int,
|
.c_int,
|
||||||
@ -732,6 +839,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args,
|
.fn_void_no_args,
|
||||||
.fn_naked_noreturn_no_args,
|
.fn_naked_noreturn_no_args,
|
||||||
.fn_ccc_void_no_args,
|
.fn_ccc_void_no_args,
|
||||||
|
.function,
|
||||||
.single_const_pointer,
|
.single_const_pointer,
|
||||||
.single_const_pointer_to_comptime_int,
|
.single_const_pointer_to_comptime_int,
|
||||||
.const_slice_u8,
|
.const_slice_u8,
|
||||||
@ -766,6 +874,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args,
|
.fn_void_no_args,
|
||||||
.fn_naked_noreturn_no_args,
|
.fn_naked_noreturn_no_args,
|
||||||
.fn_ccc_void_no_args,
|
.fn_ccc_void_no_args,
|
||||||
|
.function,
|
||||||
.array,
|
.array,
|
||||||
.single_const_pointer,
|
.single_const_pointer,
|
||||||
.single_const_pointer_to_comptime_int,
|
.single_const_pointer_to_comptime_int,
|
||||||
@ -778,6 +887,9 @@ pub const Type = extern union {
|
|||||||
.c_uint,
|
.c_uint,
|
||||||
.c_ulong,
|
.c_ulong,
|
||||||
.c_ulonglong,
|
.c_ulonglong,
|
||||||
|
.u16,
|
||||||
|
.u32,
|
||||||
|
.u64,
|
||||||
=> false,
|
=> false,
|
||||||
|
|
||||||
.int_signed,
|
.int_signed,
|
||||||
@ -787,11 +899,14 @@ pub const Type = extern union {
|
|||||||
.c_int,
|
.c_int,
|
||||||
.c_long,
|
.c_long,
|
||||||
.c_longlong,
|
.c_longlong,
|
||||||
|
.i16,
|
||||||
|
.i32,
|
||||||
|
.i64,
|
||||||
=> true,
|
=> true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asserts the type is a fixed-width integer.
|
/// Asserts the type is an integer.
|
||||||
pub fn intInfo(self: Type, target: Target) struct { signed: bool, bits: u16 } {
|
pub fn intInfo(self: Type, target: Target) struct { signed: bool, bits: u16 } {
|
||||||
return switch (self.tag()) {
|
return switch (self.tag()) {
|
||||||
.f16,
|
.f16,
|
||||||
@ -813,6 +928,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args,
|
.fn_void_no_args,
|
||||||
.fn_naked_noreturn_no_args,
|
.fn_naked_noreturn_no_args,
|
||||||
.fn_ccc_void_no_args,
|
.fn_ccc_void_no_args,
|
||||||
|
.function,
|
||||||
.array,
|
.array,
|
||||||
.single_const_pointer,
|
.single_const_pointer,
|
||||||
.single_const_pointer_to_comptime_int,
|
.single_const_pointer_to_comptime_int,
|
||||||
@ -824,6 +940,12 @@ pub const Type = extern union {
|
|||||||
.int_signed => .{ .signed = true, .bits = self.cast(Payload.IntSigned).?.bits },
|
.int_signed => .{ .signed = true, .bits = self.cast(Payload.IntSigned).?.bits },
|
||||||
.u8 => .{ .signed = false, .bits = 8 },
|
.u8 => .{ .signed = false, .bits = 8 },
|
||||||
.i8 => .{ .signed = true, .bits = 8 },
|
.i8 => .{ .signed = true, .bits = 8 },
|
||||||
|
.u16 => .{ .signed = false, .bits = 16 },
|
||||||
|
.i16 => .{ .signed = true, .bits = 16 },
|
||||||
|
.u32 => .{ .signed = false, .bits = 32 },
|
||||||
|
.i32 => .{ .signed = true, .bits = 32 },
|
||||||
|
.u64 => .{ .signed = false, .bits = 64 },
|
||||||
|
.i64 => .{ .signed = true, .bits = 64 },
|
||||||
.usize => .{ .signed = false, .bits = target.cpu.arch.ptrBitWidth() },
|
.usize => .{ .signed = false, .bits = target.cpu.arch.ptrBitWidth() },
|
||||||
.isize => .{ .signed = true, .bits = target.cpu.arch.ptrBitWidth() },
|
.isize => .{ .signed = true, .bits = target.cpu.arch.ptrBitWidth() },
|
||||||
.c_short => .{ .signed = true, .bits = CType.short.sizeInBits(target) },
|
.c_short => .{ .signed = true, .bits = CType.short.sizeInBits(target) },
|
||||||
@ -837,6 +959,59 @@ pub const Type = extern union {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn isNamedInt(self: Type) bool {
|
||||||
|
return switch (self.tag()) {
|
||||||
|
.f16,
|
||||||
|
.f32,
|
||||||
|
.f64,
|
||||||
|
.f128,
|
||||||
|
.c_longdouble,
|
||||||
|
.c_void,
|
||||||
|
.bool,
|
||||||
|
.void,
|
||||||
|
.type,
|
||||||
|
.anyerror,
|
||||||
|
.comptime_int,
|
||||||
|
.comptime_float,
|
||||||
|
.noreturn,
|
||||||
|
.@"null",
|
||||||
|
.@"undefined",
|
||||||
|
.fn_noreturn_no_args,
|
||||||
|
.fn_void_no_args,
|
||||||
|
.fn_naked_noreturn_no_args,
|
||||||
|
.fn_ccc_void_no_args,
|
||||||
|
.function,
|
||||||
|
.array,
|
||||||
|
.single_const_pointer,
|
||||||
|
.single_const_pointer_to_comptime_int,
|
||||||
|
.array_u8_sentinel_0,
|
||||||
|
.const_slice_u8,
|
||||||
|
.int_unsigned,
|
||||||
|
.int_signed,
|
||||||
|
.u8,
|
||||||
|
.i8,
|
||||||
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
|
=> false,
|
||||||
|
|
||||||
|
.usize,
|
||||||
|
.isize,
|
||||||
|
.c_short,
|
||||||
|
.c_ushort,
|
||||||
|
.c_int,
|
||||||
|
.c_uint,
|
||||||
|
.c_long,
|
||||||
|
.c_ulong,
|
||||||
|
.c_longlong,
|
||||||
|
.c_ulonglong,
|
||||||
|
=> true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn isFloat(self: Type) bool {
|
pub fn isFloat(self: Type) bool {
|
||||||
return switch (self.tag()) {
|
return switch (self.tag()) {
|
||||||
.f16,
|
.f16,
|
||||||
@ -870,6 +1045,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args => 0,
|
.fn_void_no_args => 0,
|
||||||
.fn_naked_noreturn_no_args => 0,
|
.fn_naked_noreturn_no_args => 0,
|
||||||
.fn_ccc_void_no_args => 0,
|
.fn_ccc_void_no_args => 0,
|
||||||
|
.function => @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise).param_types.len,
|
||||||
|
|
||||||
.f16,
|
.f16,
|
||||||
.f32,
|
.f32,
|
||||||
@ -893,6 +1069,12 @@ pub const Type = extern union {
|
|||||||
.const_slice_u8,
|
.const_slice_u8,
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
.isize,
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
@ -917,6 +1099,10 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args => return,
|
.fn_void_no_args => return,
|
||||||
.fn_naked_noreturn_no_args => return,
|
.fn_naked_noreturn_no_args => return,
|
||||||
.fn_ccc_void_no_args => return,
|
.fn_ccc_void_no_args => return,
|
||||||
|
.function => {
|
||||||
|
const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise);
|
||||||
|
std.mem.copy(Type, types, payload.param_types);
|
||||||
|
},
|
||||||
|
|
||||||
.f16,
|
.f16,
|
||||||
.f32,
|
.f32,
|
||||||
@ -940,6 +1126,68 @@ pub const Type = extern union {
|
|||||||
.const_slice_u8,
|
.const_slice_u8,
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
|
.usize,
|
||||||
|
.isize,
|
||||||
|
.c_short,
|
||||||
|
.c_ushort,
|
||||||
|
.c_int,
|
||||||
|
.c_uint,
|
||||||
|
.c_long,
|
||||||
|
.c_ulong,
|
||||||
|
.c_longlong,
|
||||||
|
.c_ulonglong,
|
||||||
|
.int_unsigned,
|
||||||
|
.int_signed,
|
||||||
|
=> unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Asserts the type is a function.
|
||||||
|
pub fn fnParamType(self: Type, index: usize) Type {
|
||||||
|
switch (self.tag()) {
|
||||||
|
.function => {
|
||||||
|
const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise);
|
||||||
|
return payload.param_types[index];
|
||||||
|
},
|
||||||
|
|
||||||
|
.fn_noreturn_no_args,
|
||||||
|
.fn_void_no_args,
|
||||||
|
.fn_naked_noreturn_no_args,
|
||||||
|
.fn_ccc_void_no_args,
|
||||||
|
.f16,
|
||||||
|
.f32,
|
||||||
|
.f64,
|
||||||
|
.f128,
|
||||||
|
.c_longdouble,
|
||||||
|
.c_void,
|
||||||
|
.bool,
|
||||||
|
.void,
|
||||||
|
.type,
|
||||||
|
.anyerror,
|
||||||
|
.comptime_int,
|
||||||
|
.comptime_float,
|
||||||
|
.noreturn,
|
||||||
|
.@"null",
|
||||||
|
.@"undefined",
|
||||||
|
.array,
|
||||||
|
.single_const_pointer,
|
||||||
|
.single_const_pointer_to_comptime_int,
|
||||||
|
.array_u8_sentinel_0,
|
||||||
|
.const_slice_u8,
|
||||||
|
.u8,
|
||||||
|
.i8,
|
||||||
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
.isize,
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
@ -966,6 +1214,8 @@ pub const Type = extern union {
|
|||||||
.fn_ccc_void_no_args,
|
.fn_ccc_void_no_args,
|
||||||
=> Type.initTag(.void),
|
=> Type.initTag(.void),
|
||||||
|
|
||||||
|
.function => @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise).return_type,
|
||||||
|
|
||||||
.f16,
|
.f16,
|
||||||
.f32,
|
.f32,
|
||||||
.f64,
|
.f64,
|
||||||
@ -988,6 +1238,12 @@ pub const Type = extern union {
|
|||||||
.const_slice_u8,
|
.const_slice_u8,
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
.isize,
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
@ -1011,6 +1267,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args => .Unspecified,
|
.fn_void_no_args => .Unspecified,
|
||||||
.fn_naked_noreturn_no_args => .Naked,
|
.fn_naked_noreturn_no_args => .Naked,
|
||||||
.fn_ccc_void_no_args => .C,
|
.fn_ccc_void_no_args => .C,
|
||||||
|
.function => @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise).cc,
|
||||||
|
|
||||||
.f16,
|
.f16,
|
||||||
.f32,
|
.f32,
|
||||||
@ -1034,6 +1291,12 @@ pub const Type = extern union {
|
|||||||
.const_slice_u8,
|
.const_slice_u8,
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
.isize,
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
@ -1057,6 +1320,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args => false,
|
.fn_void_no_args => false,
|
||||||
.fn_naked_noreturn_no_args => false,
|
.fn_naked_noreturn_no_args => false,
|
||||||
.fn_ccc_void_no_args => false,
|
.fn_ccc_void_no_args => false,
|
||||||
|
.function => false,
|
||||||
|
|
||||||
.f16,
|
.f16,
|
||||||
.f32,
|
.f32,
|
||||||
@ -1080,6 +1344,12 @@ pub const Type = extern union {
|
|||||||
.const_slice_u8,
|
.const_slice_u8,
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
.isize,
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
@ -1107,6 +1377,12 @@ pub const Type = extern union {
|
|||||||
.comptime_float,
|
.comptime_float,
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
.isize,
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
@ -1133,6 +1409,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args,
|
.fn_void_no_args,
|
||||||
.fn_naked_noreturn_no_args,
|
.fn_naked_noreturn_no_args,
|
||||||
.fn_ccc_void_no_args,
|
.fn_ccc_void_no_args,
|
||||||
|
.function,
|
||||||
.array,
|
.array,
|
||||||
.single_const_pointer,
|
.single_const_pointer,
|
||||||
.single_const_pointer_to_comptime_int,
|
.single_const_pointer_to_comptime_int,
|
||||||
@ -1154,6 +1431,12 @@ pub const Type = extern union {
|
|||||||
.comptime_float,
|
.comptime_float,
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
.isize,
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
@ -1171,6 +1454,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args,
|
.fn_void_no_args,
|
||||||
.fn_naked_noreturn_no_args,
|
.fn_naked_noreturn_no_args,
|
||||||
.fn_ccc_void_no_args,
|
.fn_ccc_void_no_args,
|
||||||
|
.function,
|
||||||
.single_const_pointer_to_comptime_int,
|
.single_const_pointer_to_comptime_int,
|
||||||
.array_u8_sentinel_0,
|
.array_u8_sentinel_0,
|
||||||
.const_slice_u8,
|
.const_slice_u8,
|
||||||
@ -1211,6 +1495,12 @@ pub const Type = extern union {
|
|||||||
.comptime_float,
|
.comptime_float,
|
||||||
.u8,
|
.u8,
|
||||||
.i8,
|
.i8,
|
||||||
|
.u16,
|
||||||
|
.i16,
|
||||||
|
.u32,
|
||||||
|
.i32,
|
||||||
|
.u64,
|
||||||
|
.i64,
|
||||||
.usize,
|
.usize,
|
||||||
.isize,
|
.isize,
|
||||||
.c_short,
|
.c_short,
|
||||||
@ -1228,6 +1518,7 @@ pub const Type = extern union {
|
|||||||
.fn_void_no_args,
|
.fn_void_no_args,
|
||||||
.fn_naked_noreturn_no_args,
|
.fn_naked_noreturn_no_args,
|
||||||
.fn_ccc_void_no_args,
|
.fn_ccc_void_no_args,
|
||||||
|
.function,
|
||||||
.single_const_pointer_to_comptime_int,
|
.single_const_pointer_to_comptime_int,
|
||||||
.array_u8_sentinel_0,
|
.array_u8_sentinel_0,
|
||||||
.const_slice_u8,
|
.const_slice_u8,
|
||||||
@ -1254,8 +1545,14 @@ pub const Type = extern union {
|
|||||||
// The first section of this enum are tags that require no payload.
|
// The first section of this enum are tags that require no payload.
|
||||||
u8,
|
u8,
|
||||||
i8,
|
i8,
|
||||||
isize,
|
u16,
|
||||||
|
i16,
|
||||||
|
u32,
|
||||||
|
i32,
|
||||||
|
u64,
|
||||||
|
i64,
|
||||||
usize,
|
usize,
|
||||||
|
isize,
|
||||||
c_short,
|
c_short,
|
||||||
c_ushort,
|
c_ushort,
|
||||||
c_int,
|
c_int,
|
||||||
@ -1292,6 +1589,7 @@ pub const Type = extern union {
|
|||||||
single_const_pointer,
|
single_const_pointer,
|
||||||
int_signed,
|
int_signed,
|
||||||
int_unsigned,
|
int_unsigned,
|
||||||
|
function,
|
||||||
|
|
||||||
pub const last_no_payload_tag = Tag.const_slice_u8;
|
pub const last_no_payload_tag = Tag.const_slice_u8;
|
||||||
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
|
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
|
||||||
@ -1330,6 +1628,14 @@ pub const Type = extern union {
|
|||||||
|
|
||||||
bits: u16,
|
bits: u16,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Function = struct {
|
||||||
|
base: Payload = Payload{ .tag = .function },
|
||||||
|
|
||||||
|
param_types: []Type,
|
||||||
|
return_type: Type,
|
||||||
|
cc: std.builtin.CallingConvention,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -23,8 +23,14 @@ pub const Value = extern union {
|
|||||||
// The first section of this enum are tags that require no payload.
|
// The first section of this enum are tags that require no payload.
|
||||||
u8_type,
|
u8_type,
|
||||||
i8_type,
|
i8_type,
|
||||||
isize_type,
|
u16_type,
|
||||||
|
i16_type,
|
||||||
|
u32_type,
|
||||||
|
i32_type,
|
||||||
|
u64_type,
|
||||||
|
i64_type,
|
||||||
usize_type,
|
usize_type,
|
||||||
|
isize_type,
|
||||||
c_short_type,
|
c_short_type,
|
||||||
c_ushort_type,
|
c_ushort_type,
|
||||||
c_int_type,
|
c_int_type,
|
||||||
@ -114,8 +120,14 @@ pub const Value = extern union {
|
|||||||
} else switch (self.ptr_otherwise.tag) {
|
} else switch (self.ptr_otherwise.tag) {
|
||||||
.u8_type,
|
.u8_type,
|
||||||
.i8_type,
|
.i8_type,
|
||||||
.isize_type,
|
.u16_type,
|
||||||
|
.i16_type,
|
||||||
|
.u32_type,
|
||||||
|
.i32_type,
|
||||||
|
.u64_type,
|
||||||
|
.i64_type,
|
||||||
.usize_type,
|
.usize_type,
|
||||||
|
.isize_type,
|
||||||
.c_short_type,
|
.c_short_type,
|
||||||
.c_ushort_type,
|
.c_ushort_type,
|
||||||
.c_int_type,
|
.c_int_type,
|
||||||
@ -222,6 +234,12 @@ pub const Value = extern union {
|
|||||||
while (true) switch (val.tag()) {
|
while (true) switch (val.tag()) {
|
||||||
.u8_type => return out_stream.writeAll("u8"),
|
.u8_type => return out_stream.writeAll("u8"),
|
||||||
.i8_type => return out_stream.writeAll("i8"),
|
.i8_type => return out_stream.writeAll("i8"),
|
||||||
|
.u16_type => return out_stream.writeAll("u16"),
|
||||||
|
.i16_type => return out_stream.writeAll("i16"),
|
||||||
|
.u32_type => return out_stream.writeAll("u32"),
|
||||||
|
.i32_type => return out_stream.writeAll("i32"),
|
||||||
|
.u64_type => return out_stream.writeAll("u64"),
|
||||||
|
.i64_type => return out_stream.writeAll("i64"),
|
||||||
.isize_type => return out_stream.writeAll("isize"),
|
.isize_type => return out_stream.writeAll("isize"),
|
||||||
.usize_type => return out_stream.writeAll("usize"),
|
.usize_type => return out_stream.writeAll("usize"),
|
||||||
.c_short_type => return out_stream.writeAll("c_short"),
|
.c_short_type => return out_stream.writeAll("c_short"),
|
||||||
@ -308,8 +326,14 @@ pub const Value = extern union {
|
|||||||
|
|
||||||
.u8_type => Type.initTag(.u8),
|
.u8_type => Type.initTag(.u8),
|
||||||
.i8_type => Type.initTag(.i8),
|
.i8_type => Type.initTag(.i8),
|
||||||
.isize_type => Type.initTag(.isize),
|
.u16_type => Type.initTag(.u16),
|
||||||
|
.i16_type => Type.initTag(.i16),
|
||||||
|
.u32_type => Type.initTag(.u32),
|
||||||
|
.i32_type => Type.initTag(.i32),
|
||||||
|
.u64_type => Type.initTag(.u64),
|
||||||
|
.i64_type => Type.initTag(.i64),
|
||||||
.usize_type => Type.initTag(.usize),
|
.usize_type => Type.initTag(.usize),
|
||||||
|
.isize_type => Type.initTag(.isize),
|
||||||
.c_short_type => Type.initTag(.c_short),
|
.c_short_type => Type.initTag(.c_short),
|
||||||
.c_ushort_type => Type.initTag(.c_ushort),
|
.c_ushort_type => Type.initTag(.c_ushort),
|
||||||
.c_int_type => Type.initTag(.c_int),
|
.c_int_type => Type.initTag(.c_int),
|
||||||
@ -366,8 +390,14 @@ pub const Value = extern union {
|
|||||||
.ty,
|
.ty,
|
||||||
.u8_type,
|
.u8_type,
|
||||||
.i8_type,
|
.i8_type,
|
||||||
.isize_type,
|
.u16_type,
|
||||||
|
.i16_type,
|
||||||
|
.u32_type,
|
||||||
|
.i32_type,
|
||||||
|
.u64_type,
|
||||||
|
.i64_type,
|
||||||
.usize_type,
|
.usize_type,
|
||||||
|
.isize_type,
|
||||||
.c_short_type,
|
.c_short_type,
|
||||||
.c_ushort_type,
|
.c_ushort_type,
|
||||||
.c_int_type,
|
.c_int_type,
|
||||||
@ -426,8 +456,14 @@ pub const Value = extern union {
|
|||||||
.ty,
|
.ty,
|
||||||
.u8_type,
|
.u8_type,
|
||||||
.i8_type,
|
.i8_type,
|
||||||
.isize_type,
|
.u16_type,
|
||||||
|
.i16_type,
|
||||||
|
.u32_type,
|
||||||
|
.i32_type,
|
||||||
|
.u64_type,
|
||||||
|
.i64_type,
|
||||||
.usize_type,
|
.usize_type,
|
||||||
|
.isize_type,
|
||||||
.c_short_type,
|
.c_short_type,
|
||||||
.c_ushort_type,
|
.c_ushort_type,
|
||||||
.c_int_type,
|
.c_int_type,
|
||||||
@ -487,8 +523,14 @@ pub const Value = extern union {
|
|||||||
.ty,
|
.ty,
|
||||||
.u8_type,
|
.u8_type,
|
||||||
.i8_type,
|
.i8_type,
|
||||||
.isize_type,
|
.u16_type,
|
||||||
|
.i16_type,
|
||||||
|
.u32_type,
|
||||||
|
.i32_type,
|
||||||
|
.u64_type,
|
||||||
|
.i64_type,
|
||||||
.usize_type,
|
.usize_type,
|
||||||
|
.isize_type,
|
||||||
.c_short_type,
|
.c_short_type,
|
||||||
.c_ushort_type,
|
.c_ushort_type,
|
||||||
.c_int_type,
|
.c_int_type,
|
||||||
@ -553,8 +595,14 @@ pub const Value = extern union {
|
|||||||
.ty,
|
.ty,
|
||||||
.u8_type,
|
.u8_type,
|
||||||
.i8_type,
|
.i8_type,
|
||||||
.isize_type,
|
.u16_type,
|
||||||
|
.i16_type,
|
||||||
|
.u32_type,
|
||||||
|
.i32_type,
|
||||||
|
.u64_type,
|
||||||
|
.i64_type,
|
||||||
.usize_type,
|
.usize_type,
|
||||||
|
.isize_type,
|
||||||
.c_short_type,
|
.c_short_type,
|
||||||
.c_ushort_type,
|
.c_ushort_type,
|
||||||
.c_int_type,
|
.c_int_type,
|
||||||
@ -648,8 +696,14 @@ pub const Value = extern union {
|
|||||||
.ty,
|
.ty,
|
||||||
.u8_type,
|
.u8_type,
|
||||||
.i8_type,
|
.i8_type,
|
||||||
.isize_type,
|
.u16_type,
|
||||||
|
.i16_type,
|
||||||
|
.u32_type,
|
||||||
|
.i32_type,
|
||||||
|
.u64_type,
|
||||||
|
.i64_type,
|
||||||
.usize_type,
|
.usize_type,
|
||||||
|
.isize_type,
|
||||||
.c_short_type,
|
.c_short_type,
|
||||||
.c_ushort_type,
|
.c_ushort_type,
|
||||||
.c_int_type,
|
.c_int_type,
|
||||||
@ -705,8 +759,14 @@ pub const Value = extern union {
|
|||||||
.ty,
|
.ty,
|
||||||
.u8_type,
|
.u8_type,
|
||||||
.i8_type,
|
.i8_type,
|
||||||
.isize_type,
|
.u16_type,
|
||||||
|
.i16_type,
|
||||||
|
.u32_type,
|
||||||
|
.i32_type,
|
||||||
|
.u64_type,
|
||||||
|
.i64_type,
|
||||||
.usize_type,
|
.usize_type,
|
||||||
|
.isize_type,
|
||||||
.c_short_type,
|
.c_short_type,
|
||||||
.c_ushort_type,
|
.c_ushort_type,
|
||||||
.c_int_type,
|
.c_int_type,
|
||||||
@ -807,8 +867,14 @@ pub const Value = extern union {
|
|||||||
.ty,
|
.ty,
|
||||||
.u8_type,
|
.u8_type,
|
||||||
.i8_type,
|
.i8_type,
|
||||||
.isize_type,
|
.u16_type,
|
||||||
|
.i16_type,
|
||||||
|
.u32_type,
|
||||||
|
.i32_type,
|
||||||
|
.u64_type,
|
||||||
|
.i64_type,
|
||||||
.usize_type,
|
.usize_type,
|
||||||
|
.isize_type,
|
||||||
.c_short_type,
|
.c_short_type,
|
||||||
.c_ushort_type,
|
.c_ushort_type,
|
||||||
.c_int_type,
|
.c_int_type,
|
||||||
@ -870,8 +936,14 @@ pub const Value = extern union {
|
|||||||
.ty,
|
.ty,
|
||||||
.u8_type,
|
.u8_type,
|
||||||
.i8_type,
|
.i8_type,
|
||||||
.isize_type,
|
.u16_type,
|
||||||
|
.i16_type,
|
||||||
|
.u32_type,
|
||||||
|
.i32_type,
|
||||||
|
.u64_type,
|
||||||
|
.i64_type,
|
||||||
.usize_type,
|
.usize_type,
|
||||||
|
.isize_type,
|
||||||
.c_short_type,
|
.c_short_type,
|
||||||
.c_ushort_type,
|
.c_ushort_type,
|
||||||
.c_int_type,
|
.c_int_type,
|
||||||
@ -950,8 +1022,14 @@ pub const Value = extern union {
|
|||||||
.ty,
|
.ty,
|
||||||
.u8_type,
|
.u8_type,
|
||||||
.i8_type,
|
.i8_type,
|
||||||
.isize_type,
|
.u16_type,
|
||||||
|
.i16_type,
|
||||||
|
.u32_type,
|
||||||
|
.i32_type,
|
||||||
|
.u64_type,
|
||||||
|
.i64_type,
|
||||||
.usize_type,
|
.usize_type,
|
||||||
|
.isize_type,
|
||||||
.c_short_type,
|
.c_short_type,
|
||||||
.c_ushort_type,
|
.c_ushort_type,
|
||||||
.c_int_type,
|
.c_int_type,
|
||||||
|
|||||||
@ -34,7 +34,13 @@ pub const Inst = struct {
|
|||||||
|
|
||||||
/// These names are used directly as the instruction names in the text format.
|
/// These names are used directly as the instruction names in the text format.
|
||||||
pub const Tag = enum {
|
pub const Tag = enum {
|
||||||
|
/// Function parameter value.
|
||||||
|
arg,
|
||||||
|
/// A labeled block of code, which can return a value.
|
||||||
|
block,
|
||||||
breakpoint,
|
breakpoint,
|
||||||
|
/// Same as `break` but without an operand; the operand is assumed to be the void value.
|
||||||
|
breakvoid,
|
||||||
call,
|
call,
|
||||||
compileerror,
|
compileerror,
|
||||||
/// Special case, has no textual representation.
|
/// Special case, has no textual representation.
|
||||||
@ -75,7 +81,10 @@ pub const Inst = struct {
|
|||||||
|
|
||||||
pub fn TagToType(tag: Tag) type {
|
pub fn TagToType(tag: Tag) type {
|
||||||
return switch (tag) {
|
return switch (tag) {
|
||||||
|
.arg => Arg,
|
||||||
|
.block => Block,
|
||||||
.breakpoint => Breakpoint,
|
.breakpoint => Breakpoint,
|
||||||
|
.breakvoid => BreakVoid,
|
||||||
.call => Call,
|
.call => Call,
|
||||||
.declref => DeclRef,
|
.declref => DeclRef,
|
||||||
.declref_str => DeclRefStr,
|
.declref_str => DeclRefStr,
|
||||||
@ -115,6 +124,27 @@ pub const Inst = struct {
|
|||||||
return @fieldParentPtr(T, "base", base);
|
return @fieldParentPtr(T, "base", base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const Arg = struct {
|
||||||
|
pub const base_tag = Tag.arg;
|
||||||
|
base: Inst,
|
||||||
|
|
||||||
|
positionals: struct {
|
||||||
|
index: usize,
|
||||||
|
},
|
||||||
|
kw_args: struct {},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Block = struct {
|
||||||
|
pub const base_tag = Tag.block;
|
||||||
|
base: Inst,
|
||||||
|
|
||||||
|
positionals: struct {
|
||||||
|
label: []const u8,
|
||||||
|
body: Module.Body,
|
||||||
|
},
|
||||||
|
kw_args: struct {},
|
||||||
|
};
|
||||||
|
|
||||||
pub const Breakpoint = struct {
|
pub const Breakpoint = struct {
|
||||||
pub const base_tag = Tag.breakpoint;
|
pub const base_tag = Tag.breakpoint;
|
||||||
base: Inst,
|
base: Inst,
|
||||||
@ -123,6 +153,16 @@ pub const Inst = struct {
|
|||||||
kw_args: struct {},
|
kw_args: struct {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const BreakVoid = struct {
|
||||||
|
pub const base_tag = Tag.breakvoid;
|
||||||
|
base: Inst,
|
||||||
|
|
||||||
|
positionals: struct {
|
||||||
|
label: []const u8,
|
||||||
|
},
|
||||||
|
kw_args: struct {},
|
||||||
|
};
|
||||||
|
|
||||||
pub const Call = struct {
|
pub const Call = struct {
|
||||||
pub const base_tag = Tag.call;
|
pub const base_tag = Tag.call;
|
||||||
base: Inst,
|
base: Inst,
|
||||||
@ -347,6 +387,14 @@ pub const Inst = struct {
|
|||||||
kw_args: struct {},
|
kw_args: struct {},
|
||||||
|
|
||||||
pub const Builtin = enum {
|
pub const Builtin = enum {
|
||||||
|
i8,
|
||||||
|
u8,
|
||||||
|
i16,
|
||||||
|
u16,
|
||||||
|
i32,
|
||||||
|
u32,
|
||||||
|
i64,
|
||||||
|
u64,
|
||||||
isize,
|
isize,
|
||||||
usize,
|
usize,
|
||||||
c_short,
|
c_short,
|
||||||
@ -378,6 +426,14 @@ pub const Inst = struct {
|
|||||||
|
|
||||||
pub fn toTypedValue(self: Builtin) TypedValue {
|
pub fn toTypedValue(self: Builtin) TypedValue {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
|
.i8 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.i8_type) },
|
||||||
|
.u8 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.u8_type) },
|
||||||
|
.i16 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.i16_type) },
|
||||||
|
.u16 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.u16_type) },
|
||||||
|
.i32 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.i32_type) },
|
||||||
|
.u32 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.u32_type) },
|
||||||
|
.i64 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.i64_type) },
|
||||||
|
.u64 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.u64_type) },
|
||||||
.isize => .{ .ty = Type.initTag(.type), .val = Value.initTag(.isize_type) },
|
.isize => .{ .ty = Type.initTag(.type), .val = Value.initTag(.isize_type) },
|
||||||
.usize => .{ .ty = Type.initTag(.type), .val = Value.initTag(.usize_type) },
|
.usize => .{ .ty = Type.initTag(.type), .val = Value.initTag(.usize_type) },
|
||||||
.c_short => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_short_type) },
|
.c_short => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_short_type) },
|
||||||
@ -591,7 +647,10 @@ pub const Module = struct {
|
|||||||
) @TypeOf(stream).Error!void {
|
) @TypeOf(stream).Error!void {
|
||||||
// TODO I tried implementing this with an inline for loop and hit a compiler bug
|
// TODO I tried implementing this with an inline for loop and hit a compiler bug
|
||||||
switch (inst.tag) {
|
switch (inst.tag) {
|
||||||
|
.arg => return self.writeInstToStreamGeneric(stream, .arg, inst, inst_table),
|
||||||
|
.block => return self.writeInstToStreamGeneric(stream, .block, inst, inst_table),
|
||||||
.breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, inst, inst_table),
|
.breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, inst, inst_table),
|
||||||
|
.breakvoid => return self.writeInstToStreamGeneric(stream, .breakvoid, inst, inst_table),
|
||||||
.call => return self.writeInstToStreamGeneric(stream, .call, inst, inst_table),
|
.call => return self.writeInstToStreamGeneric(stream, .call, inst, inst_table),
|
||||||
.declref => return self.writeInstToStreamGeneric(stream, .declref, inst, inst_table),
|
.declref => return self.writeInstToStreamGeneric(stream, .declref, inst, inst_table),
|
||||||
.declref_str => return self.writeInstToStreamGeneric(stream, .declref_str, inst, inst_table),
|
.declref_str => return self.writeInstToStreamGeneric(stream, .declref_str, inst, inst_table),
|
||||||
@ -691,7 +750,7 @@ pub const Module = struct {
|
|||||||
},
|
},
|
||||||
bool => return stream.writeByte("01"[@boolToInt(param)]),
|
bool => return stream.writeByte("01"[@boolToInt(param)]),
|
||||||
[]u8, []const u8 => return std.zig.renderStringLiteral(param, stream),
|
[]u8, []const u8 => return std.zig.renderStringLiteral(param, stream),
|
||||||
BigIntConst => return stream.print("{}", .{param}),
|
BigIntConst, usize => return stream.print("{}", .{param}),
|
||||||
TypedValue => unreachable, // this is a special case
|
TypedValue => unreachable, // this is a special case
|
||||||
*IrModule.Decl => unreachable, // this is a special case
|
*IrModule.Decl => unreachable, // this is a special case
|
||||||
else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
|
else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
|
||||||
@ -718,7 +777,7 @@ pub const Module = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module {
|
pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module {
|
||||||
var global_name_map = std.StringHashMap(usize).init(allocator);
|
var global_name_map = std.StringHashMap(*Inst).init(allocator);
|
||||||
defer global_name_map.deinit();
|
defer global_name_map.deinit();
|
||||||
|
|
||||||
var parser: Parser = .{
|
var parser: Parser = .{
|
||||||
@ -752,22 +811,24 @@ const Parser = struct {
|
|||||||
i: usize,
|
i: usize,
|
||||||
source: [:0]const u8,
|
source: [:0]const u8,
|
||||||
decls: std.ArrayListUnmanaged(*Decl),
|
decls: std.ArrayListUnmanaged(*Decl),
|
||||||
global_name_map: *std.StringHashMap(usize),
|
global_name_map: *std.StringHashMap(*Inst),
|
||||||
error_msg: ?ErrorMsg = null,
|
error_msg: ?ErrorMsg = null,
|
||||||
unnamed_index: usize,
|
unnamed_index: usize,
|
||||||
|
|
||||||
const Body = struct {
|
const Body = struct {
|
||||||
instructions: std.ArrayList(*Inst),
|
instructions: std.ArrayList(*Inst),
|
||||||
name_map: std.StringHashMap(usize),
|
name_map: *std.StringHashMap(*Inst),
|
||||||
};
|
};
|
||||||
|
|
||||||
fn parseBody(self: *Parser) !Module.Body {
|
fn parseBody(self: *Parser, body_ctx: ?*Body) !Module.Body {
|
||||||
|
var name_map = std.StringHashMap(*Inst).init(self.allocator);
|
||||||
|
defer name_map.deinit();
|
||||||
|
|
||||||
var body_context = Body{
|
var body_context = Body{
|
||||||
.instructions = std.ArrayList(*Inst).init(self.allocator),
|
.instructions = std.ArrayList(*Inst).init(self.allocator),
|
||||||
.name_map = std.StringHashMap(usize).init(self.allocator),
|
.name_map = if (body_ctx) |bctx| bctx.name_map else &name_map,
|
||||||
};
|
};
|
||||||
defer body_context.instructions.deinit();
|
defer body_context.instructions.deinit();
|
||||||
defer body_context.name_map.deinit();
|
|
||||||
|
|
||||||
try requireEatBytes(self, "{");
|
try requireEatBytes(self, "{");
|
||||||
skipSpace(self);
|
skipSpace(self);
|
||||||
@ -782,7 +843,7 @@ const Parser = struct {
|
|||||||
skipSpace(self);
|
skipSpace(self);
|
||||||
const decl = try parseInstruction(self, &body_context, ident);
|
const decl = try parseInstruction(self, &body_context, ident);
|
||||||
const ident_index = body_context.instructions.items.len;
|
const ident_index = body_context.instructions.items.len;
|
||||||
if (try body_context.name_map.put(ident, ident_index)) |_| {
|
if (try body_context.name_map.put(ident, decl.inst)) |_| {
|
||||||
return self.fail("redefinition of identifier '{}'", .{ident});
|
return self.fail("redefinition of identifier '{}'", .{ident});
|
||||||
}
|
}
|
||||||
try body_context.instructions.append(decl.inst);
|
try body_context.instructions.append(decl.inst);
|
||||||
@ -866,12 +927,12 @@ const Parser = struct {
|
|||||||
skipSpace(self);
|
skipSpace(self);
|
||||||
try requireEatBytes(self, "=");
|
try requireEatBytes(self, "=");
|
||||||
skipSpace(self);
|
skipSpace(self);
|
||||||
const inst = try parseInstruction(self, null, ident);
|
const decl = try parseInstruction(self, null, ident);
|
||||||
const ident_index = self.decls.items.len;
|
const ident_index = self.decls.items.len;
|
||||||
if (try self.global_name_map.put(ident, ident_index)) |_| {
|
if (try self.global_name_map.put(ident, decl.inst)) |_| {
|
||||||
return self.fail("redefinition of identifier '{}'", .{ident});
|
return self.fail("redefinition of identifier '{}'", .{ident});
|
||||||
}
|
}
|
||||||
try self.decls.append(self.allocator, inst);
|
try self.decls.append(self.allocator, decl);
|
||||||
},
|
},
|
||||||
' ', '\n' => self.i += 1,
|
' ', '\n' => self.i += 1,
|
||||||
0 => break,
|
0 => break,
|
||||||
@ -1032,7 +1093,7 @@ const Parser = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
switch (T) {
|
switch (T) {
|
||||||
Module.Body => return parseBody(self),
|
Module.Body => return parseBody(self, body_ctx),
|
||||||
bool => {
|
bool => {
|
||||||
const bool_value = switch (self.source[self.i]) {
|
const bool_value = switch (self.source[self.i]) {
|
||||||
'0' => false,
|
'0' => false,
|
||||||
@ -1060,6 +1121,10 @@ const Parser = struct {
|
|||||||
*Inst => return parseParameterInst(self, body_ctx),
|
*Inst => return parseParameterInst(self, body_ctx),
|
||||||
[]u8, []const u8 => return self.parseStringLiteral(),
|
[]u8, []const u8 => return self.parseStringLiteral(),
|
||||||
BigIntConst => return self.parseIntegerLiteral(),
|
BigIntConst => return self.parseIntegerLiteral(),
|
||||||
|
usize => {
|
||||||
|
const big_int = try self.parseIntegerLiteral();
|
||||||
|
return big_int.to(usize) catch |err| return self.fail("integer literal: {}", .{@errorName(err)});
|
||||||
|
},
|
||||||
TypedValue => return self.fail("'const' is a special instruction; not legal in ZIR text", .{}),
|
TypedValue => return self.fail("'const' is a special instruction; not legal in ZIR text", .{}),
|
||||||
*IrModule.Decl => return self.fail("'declval_in_module' is a special instruction; not legal in ZIR text", .{}),
|
*IrModule.Decl => return self.fail("'declval_in_module' is a special instruction; not legal in ZIR text", .{}),
|
||||||
else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
|
else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
|
||||||
@ -1075,7 +1140,7 @@ const Parser = struct {
|
|||||||
};
|
};
|
||||||
const map = if (local_ref)
|
const map = if (local_ref)
|
||||||
if (body_ctx) |bc|
|
if (body_ctx) |bc|
|
||||||
&bc.name_map
|
bc.name_map
|
||||||
else
|
else
|
||||||
return self.fail("referencing a % instruction in global scope", .{})
|
return self.fail("referencing a % instruction in global scope", .{})
|
||||||
else
|
else
|
||||||
@ -1107,11 +1172,7 @@ const Parser = struct {
|
|||||||
return &declval.base;
|
return &declval.base;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (local_ref) {
|
return kv.value;
|
||||||
return body_ctx.?.instructions.items[kv.value];
|
|
||||||
} else {
|
|
||||||
return self.decls.items[kv.value].inst;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generateName(self: *Parser) ![]u8 {
|
fn generateName(self: *Parser) ![]u8 {
|
||||||
@ -1456,7 +1517,7 @@ const EmitZIR = struct {
|
|||||||
|
|
||||||
fn emitBody(
|
fn emitBody(
|
||||||
self: *EmitZIR,
|
self: *EmitZIR,
|
||||||
body: IrModule.Body,
|
body: ir.Body,
|
||||||
inst_table: *std.AutoHashMap(*ir.Inst, *Inst),
|
inst_table: *std.AutoHashMap(*ir.Inst, *Inst),
|
||||||
instructions: *std.ArrayList(*Inst),
|
instructions: *std.ArrayList(*Inst),
|
||||||
) Allocator.Error!void {
|
) Allocator.Error!void {
|
||||||
@ -1466,6 +1527,57 @@ const EmitZIR = struct {
|
|||||||
};
|
};
|
||||||
for (body.instructions) |inst| {
|
for (body.instructions) |inst| {
|
||||||
const new_inst = switch (inst.tag) {
|
const new_inst = switch (inst.tag) {
|
||||||
|
.add => blk: {
|
||||||
|
const old_inst = inst.cast(ir.Inst.Add).?;
|
||||||
|
const new_inst = try self.arena.allocator.create(Inst.Add);
|
||||||
|
new_inst.* = .{
|
||||||
|
.base = .{
|
||||||
|
.src = inst.src,
|
||||||
|
.tag = Inst.Add.base_tag,
|
||||||
|
},
|
||||||
|
.positionals = .{
|
||||||
|
.lhs = try self.resolveInst(new_body, old_inst.args.lhs),
|
||||||
|
.rhs = try self.resolveInst(new_body, old_inst.args.rhs),
|
||||||
|
},
|
||||||
|
.kw_args = .{},
|
||||||
|
};
|
||||||
|
break :blk &new_inst.base;
|
||||||
|
},
|
||||||
|
.arg => blk: {
|
||||||
|
const old_inst = inst.cast(ir.Inst.Arg).?;
|
||||||
|
const new_inst = try self.arena.allocator.create(Inst.Arg);
|
||||||
|
new_inst.* = .{
|
||||||
|
.base = .{
|
||||||
|
.src = inst.src,
|
||||||
|
.tag = Inst.Arg.base_tag,
|
||||||
|
},
|
||||||
|
.positionals = .{ .index = old_inst.args.index },
|
||||||
|
.kw_args = .{},
|
||||||
|
};
|
||||||
|
break :blk &new_inst.base;
|
||||||
|
},
|
||||||
|
.block => blk: {
|
||||||
|
const old_inst = inst.cast(ir.Inst.Block).?;
|
||||||
|
const new_inst = try self.arena.allocator.create(Inst.Block);
|
||||||
|
|
||||||
|
var block_body = std.ArrayList(*Inst).init(self.allocator);
|
||||||
|
defer block_body.deinit();
|
||||||
|
|
||||||
|
try self.emitBody(old_inst.args.body, inst_table, &block_body);
|
||||||
|
|
||||||
|
new_inst.* = .{
|
||||||
|
.base = .{
|
||||||
|
.src = inst.src,
|
||||||
|
.tag = Inst.Block.base_tag,
|
||||||
|
},
|
||||||
|
.positionals = .{
|
||||||
|
.label = try self.autoName(),
|
||||||
|
.body = .{ .instructions = block_body.toOwnedSlice() },
|
||||||
|
},
|
||||||
|
.kw_args = .{},
|
||||||
|
};
|
||||||
|
break :blk &new_inst.base;
|
||||||
|
},
|
||||||
.breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),
|
.breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),
|
||||||
.call => blk: {
|
.call => blk: {
|
||||||
const old_inst = inst.cast(ir.Inst.Call).?;
|
const old_inst = inst.cast(ir.Inst.Call).?;
|
||||||
@ -1660,6 +1772,14 @@ const EmitZIR = struct {
|
|||||||
|
|
||||||
fn emitType(self: *EmitZIR, src: usize, ty: Type) Allocator.Error!*Decl {
|
fn emitType(self: *EmitZIR, src: usize, ty: Type) Allocator.Error!*Decl {
|
||||||
switch (ty.tag()) {
|
switch (ty.tag()) {
|
||||||
|
.i8 => return self.emitPrimitive(src, .i8),
|
||||||
|
.u8 => return self.emitPrimitive(src, .u8),
|
||||||
|
.i16 => return self.emitPrimitive(src, .i16),
|
||||||
|
.u16 => return self.emitPrimitive(src, .u16),
|
||||||
|
.i32 => return self.emitPrimitive(src, .i32),
|
||||||
|
.u32 => return self.emitPrimitive(src, .u32),
|
||||||
|
.i64 => return self.emitPrimitive(src, .i64),
|
||||||
|
.u64 => return self.emitPrimitive(src, .u64),
|
||||||
.isize => return self.emitPrimitive(src, .isize),
|
.isize => return self.emitPrimitive(src, .isize),
|
||||||
.usize => return self.emitPrimitive(src, .usize),
|
.usize => return self.emitPrimitive(src, .usize),
|
||||||
.c_short => return self.emitPrimitive(src, .c_short),
|
.c_short => return self.emitPrimitive(src, .c_short),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user