ir: analyze as instruction

This commit is contained in:
Andrew Kelley 2020-04-21 17:33:41 -04:00
parent 25679b63eb
commit 69878207e7

View File

@ -141,7 +141,8 @@ const Analyze = struct {
}; };
const NewInst = struct { const NewInst = struct {
ptr: *Inst, /// null means a semantic analysis error happened
ptr: ?*Inst,
}; };
const Fn = struct { const Fn = struct {
@ -163,9 +164,12 @@ const Analyze = struct {
fn resolveInst(self: *Analyze, opt_func: ?*Fn, old_inst: *text.Inst) InnerError!*Inst { fn resolveInst(self: *Analyze, opt_func: ?*Fn, old_inst: *text.Inst) InnerError!*Inst {
if (opt_func) |func| { if (opt_func) |func| {
const kv = func.inst_table.get(old_inst) orelse return error.AnalysisFail; if (func.inst_table.get(old_inst)) |kv| {
return kv.value.ptr; return kv.value.ptr orelse return error.AnalysisFail;
} else if (self.decl_table.get(old_inst)) |kv| { }
}
if (self.decl_table.get(old_inst)) |kv| {
return kv.value.ptr orelse return error.AnalysisFail; return kv.value.ptr orelse return error.AnalysisFail;
} else { } else {
const new_inst = self.analyzeInst(null, old_inst) catch |err| switch (err) { const new_inst = self.analyzeInst(null, old_inst) catch |err| switch (err) {
@ -275,7 +279,7 @@ const Analyze = struct {
.ptrtoint => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), .ptrtoint => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
.fieldptr => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), .fieldptr => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
.deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), .deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
.as => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?),
.@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), .@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
.@"unreachable" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), .@"unreachable" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
.@"fn" => return self.analyzeInstFn(func, old_inst.cast(text.Inst.Fn).?), .@"fn" => return self.analyzeInstFn(func, old_inst.cast(text.Inst.Fn).?),
@ -305,6 +309,7 @@ const Analyze = struct {
for (fn_inst.positionals.body.instructions) |src_inst| { for (fn_inst.positionals.body.instructions) |src_inst| {
const new_inst = self.analyzeInst(&new_func, src_inst) catch |err| { const new_inst = self.analyzeInst(&new_func, src_inst) catch |err| {
self.fns.items[new_func.fn_index].analysis_status = .failure; self.fns.items[new_func.fn_index].analysis_status = .failure;
try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = null });
return err; return err;
}; };
try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst }); try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst });
@ -324,8 +329,8 @@ const Analyze = struct {
}); });
} }
fn analyzeInstFnType(self: *Analyze, opt_func: ?*Fn, fntype: *text.Inst.FnType) InnerError!*Inst { fn analyzeInstFnType(self: *Analyze, func: ?*Fn, fntype: *text.Inst.FnType) InnerError!*Inst {
const return_type = try self.resolveType(opt_func, fntype.positionals.return_type); const return_type = try self.resolveType(func, fntype.positionals.return_type);
if (return_type.zigTypeTag() == .NoReturn and if (return_type.zigTypeTag() == .NoReturn and
fntype.positionals.param_types.len == 0 and fntype.positionals.param_types.len == 0 and
@ -337,10 +342,16 @@ const Analyze = struct {
return self.fail(fntype.base.src, "TODO implement fntype instruction more", .{}); return self.fail(fntype.base.src, "TODO implement fntype instruction more", .{});
} }
fn analyzeInstPrimitive(self: *Analyze, opt_func: ?*Fn, primitive: *text.Inst.Primitive) InnerError!*Inst { fn analyzeInstPrimitive(self: *Analyze, func: ?*Fn, primitive: *text.Inst.Primitive) InnerError!*Inst {
return self.constType(primitive.base.src, primitive.positionals.tag.toType()); return self.constType(primitive.base.src, primitive.positionals.tag.toType());
} }
fn analyzeInstAs(self: *Analyze, func: ?*Fn, as: *text.Inst.As) InnerError!*Inst {
const dest_type = try self.resolveType(func, as.positionals.dest_type);
const new_inst = try self.resolveInst(func, as.positionals.value);
return self.coerce(dest_type, new_inst);
}
fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty); const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);
if (in_memory_result == .ok) { if (in_memory_result == .ok) {
@ -363,7 +374,11 @@ const Analyze = struct {
} }
fn bitcast(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { fn bitcast(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
return self.fail(inst.src, "TODO implement bitcast analysis", .{}); if (inst.value()) |val| {
// Keep the comptime Value representation; take the new type.
return self.constInst(inst.src, .{ .ty = dest_type, .val = val });
}
return self.fail(inst.src, "TODO implement runtime bitcast", .{});
} }
fn coerceArrayPtrToSlice(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst { fn coerceArrayPtrToSlice(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {