| author | |
| committer | |
| log | ec4953504a07f3025d5f32344180dd9b6a4de8ae |
| tree | bbf9a1aed1c8a160caffe68821f71ffd5c1d6fec |
| parent | 6b2ce9d1e99902d429d9946bcc57e8cb02f4d224 |
5 files changed, 91 insertions(+), 31 deletions(-)
src-self-hosted/Module.zig+67-5| ... | @@ -2219,11 +2219,6 @@ pub fn wantSafety(self: *Module, scope: *Scope) bool { | ... | @@ -2219,11 +2219,6 @@ pub fn wantSafety(self: *Module, scope: *Scope) bool { |
| 2219 | }; | 2219 | }; |
| 2220 | } | 2220 | } |
| 2221 | 2221 | ||
| 2222 | pub fn analyzeUnreach(self: *Module, scope: *Scope, src: usize) InnerError!*Inst { | ||
| 2223 | const b = try self.requireRuntimeBlock(scope, src); | ||
| 2224 | return self.addNoOp(b, src, Type.initTag(.noreturn), .unreach); | ||
| 2225 | } | ||
| 2226 | |||
| 2227 | pub fn analyzeIsNull( | 2222 | pub fn analyzeIsNull( |
| 2228 | self: *Module, | 2223 | self: *Module, |
| 2229 | scope: *Scope, | 2224 | scope: *Scope, |
| ... | @@ -2902,3 +2897,70 @@ pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void { | ... | @@ -2902,3 +2897,70 @@ pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void { |
| 2902 | }); | 2897 | }); |
| 2903 | } | 2898 | } |
| 2904 | } | 2899 | } |
| 2900 | |||
| 2901 | pub const PanicId = enum { | ||
| 2902 | unreach, | ||
| 2903 | unwrap_null, | ||
| 2904 | }; | ||
| 2905 | |||
| 2906 | pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic_id: PanicId) !void { | ||
| 2907 | const block_inst = try parent_block.arena.create(Inst.Block); | ||
| 2908 | block_inst.* = .{ | ||
| 2909 | .base = .{ | ||
| 2910 | .tag = Inst.Block.base_tag, | ||
| 2911 | .ty = Type.initTag(.void), | ||
| 2912 | .src = ok.src, | ||
| 2913 | }, | ||
| 2914 | .body = .{ | ||
| 2915 | .instructions = try parent_block.arena.alloc(*Inst, 1), // Only need space for the condbr. | ||
| 2916 | }, | ||
| 2917 | }; | ||
| 2918 | |||
| 2919 | const ok_body: ir.Body = .{ | ||
| 2920 | .instructions = try parent_block.arena.alloc(*Inst, 1), // Only need space for the brvoid. | ||
| 2921 | }; | ||
| 2922 | const brvoid = try parent_block.arena.create(Inst.BrVoid); | ||
| 2923 | brvoid.* = .{ | ||
| 2924 | .base = .{ | ||
| 2925 | .tag = .brvoid, | ||
| 2926 | .ty = Type.initTag(.noreturn), | ||
| 2927 | .src = ok.src, | ||
| 2928 | }, | ||
| 2929 | .block = block_inst, | ||
| 2930 | }; | ||
| 2931 | ok_body.instructions[0] = &brvoid.base; | ||
| 2932 | |||
| 2933 | var fail_block: Scope.Block = .{ | ||
| 2934 | .parent = parent_block, | ||
| 2935 | .func = parent_block.func, | ||
| 2936 | .decl = parent_block.decl, | ||
| 2937 | .instructions = .{}, | ||
| 2938 | .arena = parent_block.arena, | ||
| 2939 | }; | ||
| 2940 | defer fail_block.instructions.deinit(mod.gpa); | ||
| 2941 | |||
| 2942 | _ = try mod.safetyPanic(&fail_block, ok.src, panic_id); | ||
| 2943 | |||
| 2944 | const fail_body: ir.Body = .{ .instructions = try parent_block.arena.dupe(*Inst, fail_block.instructions.items) }; | ||
| 2945 | |||
| 2946 | const condbr = try parent_block.arena.create(Inst.CondBr); | ||
| 2947 | condbr.* = .{ | ||
| 2948 | .base = .{ | ||
| 2949 | .tag = .condbr, | ||
| 2950 | .ty = Type.initTag(.noreturn), | ||
| 2951 | .src = ok.src, | ||
| 2952 | }, | ||
| 2953 | .condition = ok, | ||
| 2954 | .then_body = ok_body, | ||
| 2955 | .else_body = fail_body, | ||
| 2956 | }; | ||
| 2957 | block_inst.body.instructions[0] = &condbr.base; | ||
| 2958 | |||
| 2959 | try parent_block.instructions.append(mod.gpa, &block_inst.base); | ||
| 2960 | } | ||
| 2961 | |||
| 2962 | pub fn safetyPanic(mod: *Module, block: *Scope.Block, src: usize, panic_id: PanicId) !*Inst { | ||
| 2963 | // TODO Once we have a panic function to call, call it here instead of breakpoint. | ||
| 2964 | _ = try mod.addNoOp(block, src, Type.initTag(.void), .breakpoint); | ||
| 2965 | return mod.addNoOp(block, src, Type.initTag(.noreturn), .unreach); | ||
| 2966 | } |
src-self-hosted/codegen.zig+2-3| ... | @@ -668,8 +668,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -668,8 +668,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 668 | .store => return self.genStore(inst.castTag(.store).?), | 668 | .store => return self.genStore(inst.castTag(.store).?), |
| 669 | .sub => return self.genSub(inst.castTag(.sub).?), | 669 | .sub => return self.genSub(inst.castTag(.sub).?), |
| 670 | .unreach => return MCValue{ .unreach = {} }, | 670 | .unreach => return MCValue{ .unreach = {} }, |
| 671 | .unwrap_optional_safe => return self.genUnwrapOptional(inst.castTag(.unwrap_optional_safe).?, true), | 671 | .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?), |
| 672 | .unwrap_optional_unsafe => return self.genUnwrapOptional(inst.castTag(.unwrap_optional_unsafe).?, false), | ||
| 673 | } | 672 | } |
| 674 | } | 673 | } |
| 675 | 674 | ||
| ... | @@ -819,7 +818,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -819,7 +818,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 819 | } | 818 | } |
| 820 | } | 819 | } |
| 821 | 820 | ||
| 822 | fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnOp, safety_check: bool) !MCValue { | 821 | fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnOp) !MCValue { |
| 823 | // No side effects, so if it's unreferenced, do nothing. | 822 | // No side effects, so if it's unreferenced, do nothing. |
| 824 | if (inst.base.isUnused()) | 823 | if (inst.base.isUnused()) |
| 825 | return MCValue.dead; | 824 | return MCValue.dead; |
src-self-hosted/ir.zig+2-4| ... | @@ -82,8 +82,7 @@ pub const Inst = struct { | ... | @@ -82,8 +82,7 @@ pub const Inst = struct { |
| 82 | not, | 82 | not, |
| 83 | floatcast, | 83 | floatcast, |
| 84 | intcast, | 84 | intcast, |
| 85 | unwrap_optional_safe, | 85 | unwrap_optional, |
| 86 | unwrap_optional_unsafe, | ||
| 87 | 86 | ||
| 88 | pub fn Type(tag: Tag) type { | 87 | pub fn Type(tag: Tag) type { |
| 89 | return switch (tag) { | 88 | return switch (tag) { |
| ... | @@ -104,8 +103,7 @@ pub const Inst = struct { | ... | @@ -104,8 +103,7 @@ pub const Inst = struct { |
| 104 | .floatcast, | 103 | .floatcast, |
| 105 | .intcast, | 104 | .intcast, |
| 106 | .load, | 105 | .load, |
| 107 | .unwrap_optional_safe, | 106 | .unwrap_optional, |
| 108 | .unwrap_optional_unsafe, | ||
| 109 | => UnOp, | 107 | => UnOp, |
| 110 | 108 | ||
| 111 | .add, | 109 | .add, |
src-self-hosted/zir.zig+1-2| ... | @@ -1927,8 +1927,7 @@ const EmitZIR = struct { | ... | @@ -1927,8 +1927,7 @@ const EmitZIR = struct { |
| 1927 | .isnonnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnonnull).?, .isnonnull), | 1927 | .isnonnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnonnull).?, .isnonnull), |
| 1928 | .load => try self.emitUnOp(inst.src, new_body, inst.castTag(.load).?, .deref), | 1928 | .load => try self.emitUnOp(inst.src, new_body, inst.castTag(.load).?, .deref), |
| 1929 | .ref => try self.emitUnOp(inst.src, new_body, inst.castTag(.ref).?, .ref), | 1929 | .ref => try self.emitUnOp(inst.src, new_body, inst.castTag(.ref).?, .ref), |
| 1930 | .unwrap_optional_safe => try self.emitUnOp(inst.src, new_body, inst.castTag(.unwrap_optional_safe).?, .unwrap_optional_safe), | 1930 | .unwrap_optional => try self.emitUnOp(inst.src, new_body, inst.castTag(.unwrap_optional).?, .unwrap_optional_unsafe), |
| 1931 | .unwrap_optional_unsafe => try self.emitUnOp(inst.src, new_body, inst.castTag(.unwrap_optional_unsafe).?, .unwrap_optional_unsafe), | ||
| 1932 | 1931 | ||
| 1933 | .add => try self.emitBinOp(inst.src, new_body, inst.castTag(.add).?, .add), | 1932 | .add => try self.emitBinOp(inst.src, new_body, inst.castTag(.add).?, .add), |
| 1934 | .sub => try self.emitBinOp(inst.src, new_body, inst.castTag(.sub).?, .sub), | 1933 | .sub => try self.emitBinOp(inst.src, new_body, inst.castTag(.sub).?, .sub), |
src-self-hosted/zir_sema.zig+19-17| ... | @@ -68,8 +68,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! | ... | @@ -68,8 +68,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 68 | .deref => return analyzeInstDeref(mod, scope, old_inst.castTag(.deref).?), | 68 | .deref => return analyzeInstDeref(mod, scope, old_inst.castTag(.deref).?), |
| 69 | .as => return analyzeInstAs(mod, scope, old_inst.castTag(.as).?), | 69 | .as => return analyzeInstAs(mod, scope, old_inst.castTag(.as).?), |
| 70 | .@"asm" => return analyzeInstAsm(mod, scope, old_inst.castTag(.@"asm").?), | 70 | .@"asm" => return analyzeInstAsm(mod, scope, old_inst.castTag(.@"asm").?), |
| 71 | .@"unreachable" => return analyzeInstUnreachable(mod, scope, old_inst.castTag(.@"unreachable").?), | 71 | .@"unreachable" => return analyzeInstUnreachable(mod, scope, old_inst.castTag(.@"unreachable").?, true), |
| 72 | .unreach_nocheck => return analyzeInstUnreachNoChk(mod, scope, old_inst.castTag(.unreach_nocheck).?), | 72 | .unreach_nocheck => return analyzeInstUnreachable(mod, scope, old_inst.castTag(.unreach_nocheck).?, false), |
| 73 | .@"return" => return analyzeInstRet(mod, scope, old_inst.castTag(.@"return").?), | 73 | .@"return" => return analyzeInstRet(mod, scope, old_inst.castTag(.@"return").?), |
| 74 | .returnvoid => return analyzeInstRetVoid(mod, scope, old_inst.castTag(.returnvoid).?), | 74 | .returnvoid => return analyzeInstRetVoid(mod, scope, old_inst.castTag(.returnvoid).?), |
| 75 | .@"fn" => return analyzeInstFn(mod, scope, old_inst.castTag(.@"fn").?), | 75 | .@"fn" => return analyzeInstFn(mod, scope, old_inst.castTag(.@"fn").?), |
| ... | @@ -313,7 +313,7 @@ fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError! | ... | @@ -313,7 +313,7 @@ fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError! |
| 313 | if (operand.value()) |val| { | 313 | if (operand.value()) |val| { |
| 314 | const ref_payload = try scope.arena().create(Value.Payload.RefVal); | 314 | const ref_payload = try scope.arena().create(Value.Payload.RefVal); |
| 315 | ref_payload.* = .{ .val = val }; | 315 | ref_payload.* = .{ .val = val }; |
| 316 | 316 | ||
| 317 | return mod.constInst(scope, inst.base.src, .{ | 317 | return mod.constInst(scope, inst.base.src, .{ |
| 318 | .ty = ptr_type, | 318 | .ty = ptr_type, |
| 319 | .val = Value.initPayload(&ref_payload.base), | 319 | .val = Value.initPayload(&ref_payload.base), |
| ... | @@ -677,7 +677,7 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp | ... | @@ -677,7 +677,7 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp |
| 677 | try mod.singleMutPtrType(scope, unwrap.base.src, child_type); | 677 | try mod.singleMutPtrType(scope, unwrap.base.src, child_type); |
| 678 | 678 | ||
| 679 | if (operand.value()) |val| { | 679 | if (operand.value()) |val| { |
| 680 | if (val.tag() == .null_value) { | 680 | if (val.isNull()) { |
| 681 | return mod.fail(scope, unwrap.base.src, "unable to unwrap null", .{}); | 681 | return mod.fail(scope, unwrap.base.src, "unable to unwrap null", .{}); |
| 682 | } | 682 | } |
| 683 | return mod.constInst(scope, unwrap.base.src, .{ | 683 | return mod.constInst(scope, unwrap.base.src, .{ |
| ... | @@ -687,10 +687,11 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp | ... | @@ -687,10 +687,11 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp |
| 687 | } | 687 | } |
| 688 | 688 | ||
| 689 | const b = try mod.requireRuntimeBlock(scope, unwrap.base.src); | 689 | const b = try mod.requireRuntimeBlock(scope, unwrap.base.src); |
| 690 | return if (safety_check) | 690 | if (safety_check and mod.wantSafety(scope)) { |
| 691 | mod.addUnOp(b, unwrap.base.src, child_pointer, .unwrap_optional_safe, operand) | 691 | const is_non_null = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .isnonnull, operand); |
| 692 | else | 692 | try mod.addSafetyCheck(b, is_non_null, .unwrap_null); |
| 693 | mod.addUnOp(b, unwrap.base.src, child_pointer, .unwrap_optional_unsafe, operand); | 693 | } |
| 694 | return mod.addUnOp(b, unwrap.base.src, child_pointer, .unwrap_optional, operand); | ||
| 694 | } | 695 | } |
| 695 | 696 | ||
| 696 | fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { | 697 | fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { |
| ... | @@ -1167,18 +1168,19 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE | ... | @@ -1167,18 +1168,19 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE |
| 1167 | return mod.addCondBr(parent_block, inst.base.src, cond, then_body, else_body); | 1168 | return mod.addCondBr(parent_block, inst.base.src, cond, then_body, else_body); |
| 1168 | } | 1169 | } |
| 1169 | 1170 | ||
| 1170 | fn analyzeInstUnreachNoChk(mod: *Module, scope: *Scope, unreach: *zir.Inst.NoOp) InnerError!*Inst { | 1171 | fn analyzeInstUnreachable( |
| 1171 | return mod.analyzeUnreach(scope, unreach.base.src); | 1172 | mod: *Module, |
| 1172 | } | 1173 | scope: *Scope, |
| 1173 | 1174 | unreach: *zir.Inst.NoOp, | |
| 1174 | fn analyzeInstUnreachable(mod: *Module, scope: *Scope, unreach: *zir.Inst.NoOp) InnerError!*Inst { | 1175 | safety_check: bool, |
| 1176 | ) InnerError!*Inst { | ||
| 1175 | const b = try mod.requireRuntimeBlock(scope, unreach.base.src); | 1177 | const b = try mod.requireRuntimeBlock(scope, unreach.base.src); |
| 1176 | // TODO Add compile error for @optimizeFor occurring too late in a scope. | 1178 | // TODO Add compile error for @optimizeFor occurring too late in a scope. |
| 1177 | if (mod.wantSafety(scope)) { | 1179 | if (safety_check and mod.wantSafety(scope)) { |
| 1178 | // TODO Once we have a panic function to call, call it here instead of this. | 1180 | return mod.safetyPanic(b, unreach.base.src, .unreach); |
| 1179 | _ = try mod.addNoOp(b, unreach.base.src, Type.initTag(.void), .breakpoint); | 1181 | } else { |
| 1182 | return mod.addNoOp(b, unreach.base.src, Type.initTag(.noreturn), .unreach); | ||
| 1180 | } | 1183 | } |
| 1181 | return mod.analyzeUnreach(scope, unreach.base.src); | ||
| 1182 | } | 1184 | } |
| 1183 | 1185 | ||
| 1184 | fn analyzeInstRet(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 1186 | fn analyzeInstRet(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |