authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-13 14:18:44+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-13 08:12:17-07:00
log6b2ce9d1e99902d429d9946bcc57e8cb02f4d224
tree0b02c162eb1fef9555746cf074961063cb4af62b
parent4a40282391f0b92a83a6a8c269c27a32be92884a

stage2: split unwrap_optional to safe and unsafe verions


8 files changed, 57 insertions(+), 93 deletions(-)

src-self-hosted/Module.zig+1-23
...@@ -2016,28 +2016,6 @@ pub fn addCall(...@@ -2016,28 +2016,6 @@ pub fn addCall(
2016 return &inst.base;2016 return &inst.base;
2017}2017}
20182018
2019pub fn addUnwrapOptional(
2020 self: *Module,
2021 block: *Scope.Block,
2022 src: usize,
2023 ty: Type,
2024 operand: *Inst,
2025 safety_check: bool,
2026) !*Inst {
2027 const inst = try block.arena.create(Inst.UnwrapOptional);
2028 inst.* = .{
2029 .base = .{
2030 .tag = .unwrap_optional,
2031 .ty = ty,
2032 .src = src,
2033 },
2034 .operand = operand,
2035 .safety_check = safety_check,
2036 };
2037 try block.instructions.append(self.gpa, &inst.base);
2038 return &inst.base;
2039}
2040
2041pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst {2019pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst {
2042 const const_inst = try scope.arena().create(Inst.Constant);2020 const const_inst = try scope.arena().create(Inst.Constant);
2043 const_inst.* = .{2021 const_inst.* = .{
...@@ -2500,7 +2478,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst...@@ -2500,7 +2478,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
25002478
2501 // null to ?T2479 // null to ?T
2502 if (dest_type.zigTypeTag() == .Optional and inst.ty.zigTypeTag() == .Null) {2480 if (dest_type.zigTypeTag() == .Optional and inst.ty.zigTypeTag() == .Null) {
2503 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = inst.ty.onePossibleValue().? });2481 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = Value.initTag(.null_value) });
2504 }2482 }
25052483
2506 // T to ?T2484 // T to ?T
src-self-hosted/astgen.zig+1-1
...@@ -311,7 +311,7 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si...@@ -311,7 +311,7 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si
311 const src = tree.token_locs[node.rtoken].start;311 const src = tree.token_locs[node.rtoken].start;
312312
313 const operand = try expr(mod, scope, .lvalue, node.lhs);313 const operand = try expr(mod, scope, .lvalue, node.lhs);
314 const unwrapped_ptr = try addZIRInst(mod, scope, src, zir.Inst.UnwrapOptional, .{ .operand = operand }, .{});314 const unwrapped_ptr = try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand);
315 if (rl == .lvalue) return unwrapped_ptr;315 if (rl == .lvalue) return unwrapped_ptr;
316316
317 return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr));317 return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr));
src-self-hosted/codegen.zig+3-2
...@@ -668,7 +668,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -668,7 +668,8 @@ 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 => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),671 .unwrap_optional_safe => return self.genUnwrapOptional(inst.castTag(.unwrap_optional_safe).?, true),
672 .unwrap_optional_unsafe => return self.genUnwrapOptional(inst.castTag(.unwrap_optional_unsafe).?, false),
672 }673 }
673 }674 }
674675
...@@ -818,7 +819,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -818,7 +819,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
818 }819 }
819 }820 }
820821
821 fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnwrapOptional) !MCValue {822 fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnOp, safety_check: bool) !MCValue {
822 // No side effects, so if it's unreferenced, do nothing.823 // No side effects, so if it's unreferenced, do nothing.
823 if (inst.base.isUnused())824 if (inst.base.isUnused())
824 return MCValue.dead;825 return MCValue.dead;
src-self-hosted/ir.zig+4-23
...@@ -82,7 +82,8 @@ pub const Inst = struct {...@@ -82,7 +82,8 @@ pub const Inst = struct {
82 not,82 not,
83 floatcast,83 floatcast,
84 intcast,84 intcast,
85 unwrap_optional,85 unwrap_optional_safe,
86 unwrap_optional_unsafe,
8687
87 pub fn Type(tag: Tag) type {88 pub fn Type(tag: Tag) type {
88 return switch (tag) {89 return switch (tag) {
...@@ -103,6 +104,8 @@ pub const Inst = struct {...@@ -103,6 +104,8 @@ pub const Inst = struct {
103 .floatcast,104 .floatcast,
104 .intcast,105 .intcast,
105 .load,106 .load,
107 .unwrap_optional_safe,
108 .unwrap_optional_unsafe,
106 => UnOp,109 => UnOp,
107110
108 .add,111 .add,
...@@ -125,7 +128,6 @@ pub const Inst = struct {...@@ -125,7 +128,6 @@ pub const Inst = struct {
125 .condbr => CondBr,128 .condbr => CondBr,
126 .constant => Constant,129 .constant => Constant,
127 .loop => Loop,130 .loop => Loop,
128 .unwrap_optional => UnwrapOptional,
129 };131 };
130 }132 }
131133
...@@ -421,27 +423,6 @@ pub const Inst = struct {...@@ -421,27 +423,6 @@ pub const Inst = struct {
421 return null;423 return null;
422 }424 }
423 };425 };
424
425 pub const UnwrapOptional = struct {
426 pub const base_tag = Tag.unwrap_optional;
427 base: Inst,
428
429 operand: *Inst,
430 safety_check: bool,
431
432 pub fn operandCount(self: *const UnwrapOptional) usize {
433 return 1;
434 }
435 pub fn getOperand(self: *const UnwrapOptional, index: usize) ?*Inst {
436 var i = index;
437
438 if (i < 1)
439 return self.operand;
440 i -= 1;
441
442 return null;
443 }
444 };
445};426};
446427
447pub const Body = struct {428pub const Body = struct {
src-self-hosted/type.zig+8-2
...@@ -185,8 +185,6 @@ pub const Type = extern union {...@@ -185,8 +185,6 @@ pub const Type = extern union {
185 return true;185 return true;
186 },186 },
187 .Optional => {187 .Optional => {
188 if (a.tag() != b.tag())
189 return false;
190 return a.elemType().eql(b.elemType());188 return a.elemType().eql(b.elemType());
191 },189 },
192 .Float,190 .Float,
...@@ -662,6 +660,10 @@ pub const Type = extern union {...@@ -662,6 +660,10 @@ pub const Type = extern union {
662 .optional => {660 .optional => {
663 const child_type = self.cast(Payload.Optional).?.child_type;661 const child_type = self.cast(Payload.Optional).?.child_type;
664 if (!child_type.hasCodeGenBits()) return 1;662 if (!child_type.hasCodeGenBits()) return 1;
663
664 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
665 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
666
665 return child_type.abiAlignment(target);667 return child_type.abiAlignment(target);
666 },668 },
667669
...@@ -750,6 +752,10 @@ pub const Type = extern union {...@@ -750,6 +752,10 @@ pub const Type = extern union {
750 .optional => {752 .optional => {
751 const child_type = self.cast(Payload.Optional).?.child_type;753 const child_type = self.cast(Payload.Optional).?.child_type;
752 if (!child_type.hasCodeGenBits()) return 1;754 if (!child_type.hasCodeGenBits()) return 1;
755
756 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
757 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
758
753 // Optional types are represented as a struct with the child type as the first759 // Optional types are represented as a struct with the child type as the first
754 // field and a boolean as the second. Since the child type's abi alignment is760 // field and a boolean as the second. Since the child type's abi alignment is
755 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal761 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
src-self-hosted/zir.zig+9-34
...@@ -215,7 +215,9 @@ pub const Inst = struct {...@@ -215,7 +215,9 @@ pub const Inst = struct {
215 /// Create an optional type '?T'215 /// Create an optional type '?T'
216 optional_type,216 optional_type,
217 /// Unwraps an optional value 'lhs.?'217 /// Unwraps an optional value 'lhs.?'
218 unwrap_optional,218 unwrap_optional_safe,
219 /// Same as previous, but without safety checks. Used for orelse, if and while
220 unwrap_optional_unsafe,
219221
220 pub fn Type(tag: Tag) type {222 pub fn Type(tag: Tag) type {
221 return switch (tag) {223 return switch (tag) {
...@@ -245,6 +247,8 @@ pub const Inst = struct {...@@ -245,6 +247,8 @@ pub const Inst = struct {
245 .single_const_ptr_type,247 .single_const_ptr_type,
246 .single_mut_ptr_type,248 .single_mut_ptr_type,
247 .optional_type,249 .optional_type,
250 .unwrap_optional_safe,
251 .unwrap_optional_unsafe,
248 => UnOp,252 => UnOp,
249253
250 .add,254 .add,
...@@ -303,7 +307,6 @@ pub const Inst = struct {...@@ -303,7 +307,6 @@ pub const Inst = struct {
303 .fntype => FnType,307 .fntype => FnType,
304 .elemptr => ElemPtr,308 .elemptr => ElemPtr,
305 .condbr => CondBr,309 .condbr => CondBr,
306 .unwrap_optional => UnwrapOptional,
307 };310 };
308 }311 }
309312
...@@ -379,7 +382,8 @@ pub const Inst = struct {...@@ -379,7 +382,8 @@ pub const Inst = struct {
379 .typeof,382 .typeof,
380 .xor,383 .xor,
381 .optional_type,384 .optional_type,
382 .unwrap_optional,385 .unwrap_optional_safe,
386 .unwrap_optional_unsafe,
383 => false,387 => false,
384388
385 .@"break",389 .@"break",
...@@ -820,18 +824,6 @@ pub const Inst = struct {...@@ -820,18 +824,6 @@ pub const Inst = struct {
820 },824 },
821 kw_args: struct {},825 kw_args: struct {},
822 };826 };
823
824 pub const UnwrapOptional = struct {
825 pub const base_tag = Tag.unwrap_optional;
826 base: Inst,
827
828 positionals: struct {
829 operand: *Inst,
830 },
831 kw_args: struct {
832 safety_check: bool = true,
833 },
834 };
835};827};
836828
837pub const ErrorMsg = struct {829pub const ErrorMsg = struct {
...@@ -1935,6 +1927,8 @@ const EmitZIR = struct {...@@ -1935,6 +1927,8 @@ const EmitZIR = struct {
1935 .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),
1936 .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),
1937 .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),
1931 .unwrap_optional_unsafe => try self.emitUnOp(inst.src, new_body, inst.castTag(.unwrap_optional_unsafe).?, .unwrap_optional_unsafe),
19381932
1939 .add => try self.emitBinOp(inst.src, new_body, inst.castTag(.add).?, .add),1933 .add => try self.emitBinOp(inst.src, new_body, inst.castTag(.add).?, .add),
1940 .sub => try self.emitBinOp(inst.src, new_body, inst.castTag(.sub).?, .sub),1934 .sub => try self.emitBinOp(inst.src, new_body, inst.castTag(.sub).?, .sub),
...@@ -2157,25 +2151,6 @@ const EmitZIR = struct {...@@ -2157,25 +2151,6 @@ const EmitZIR = struct {
2157 };2151 };
2158 break :blk &new_inst.base;2152 break :blk &new_inst.base;
2159 },2153 },
2160
2161 .unwrap_optional => blk: {
2162 const old_inst = inst.castTag(.unwrap_optional).?;
2163
2164 const new_inst = try self.arena.allocator.create(Inst.UnwrapOptional);
2165 new_inst.* = .{
2166 .base = .{
2167 .src = inst.src,
2168 .tag = Inst.UnwrapOptional.base_tag,
2169 },
2170 .positionals = .{
2171 .operand = try self.resolveInst(new_body, old_inst.operand),
2172 },
2173 .kw_args = .{
2174 .safety_check = old_inst.safety_check,
2175 },
2176 };
2177 break :blk &new_inst.base;
2178 },
2179 };2154 };
2180 try instructions.append(new_inst);2155 try instructions.append(new_inst);
2181 try inst_table.put(inst, new_inst);2156 try inst_table.put(inst, new_inst);
src-self-hosted/zir_sema.zig+7-3
...@@ -107,7 +107,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -107,7 +107,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
107 .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?),107 .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?),
108 .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?),108 .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?),
109 .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?),109 .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?),
110 .unwrap_optional => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional).?),110 .unwrap_optional_safe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_safe).?, true),
111 .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),
111 }112 }
112}113}
113114
...@@ -661,7 +662,7 @@ fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp...@@ -661,7 +662,7 @@ fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp
661 }));662 }));
662}663}
663664
664fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnwrapOptional) InnerError!*Inst {665fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst {
665 const operand = try resolveInst(mod, scope, unwrap.positionals.operand);666 const operand = try resolveInst(mod, scope, unwrap.positionals.operand);
666 assert(operand.ty.zigTypeTag() == .Pointer);667 assert(operand.ty.zigTypeTag() == .Pointer);
667668
...@@ -686,7 +687,10 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.Unwr...@@ -686,7 +687,10 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.Unwr
686 }687 }
687688
688 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);689 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);
689 return mod.addUnwrapOptional(b, unwrap.base.src, child_pointer, operand, unwrap.kw_args.safety_check);690 return if (safety_check)
691 mod.addUnOp(b, unwrap.base.src, child_pointer, .unwrap_optional_safe, operand)
692 else
693 mod.addUnOp(b, unwrap.base.src, child_pointer, .unwrap_optional_unsafe, operand);
690}694}
691695
692fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {696fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
test/stage2/compare_output.zig+24-5
...@@ -31,11 +31,6 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -31,11 +31,6 @@ pub fn addCases(ctx: *TestContext) !void {
31 \\export fn _start() noreturn {31 \\export fn _start() noreturn {
32 \\ print();32 \\ print();
33 \\33 \\
34 \\ const a: u32 = 2;
35 \\ const b: ?u32 = a;
36 \\ const c = b.?;
37 \\ if (c != 2) unreachable;
38 \\
39 \\ exit();34 \\ exit();
40 \\}35 \\}
41 \\36 \\
...@@ -446,5 +441,29 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -446,5 +441,29 @@ pub fn addCases(ctx: *TestContext) !void {
446 ,441 ,
447 "",442 "",
448 );443 );
444
445 // Optionals
446 case.addCompareOutput(
447 \\export fn _start() noreturn {
448 \\ const a: u32 = 2;
449 \\ const b: ?u32 = a;
450 \\ const c = b.?;
451 \\ if (c != 2) unreachable;
452 \\
453 \\ exit();
454 \\}
455 \\
456 \\fn exit() noreturn {
457 \\ asm volatile ("syscall"
458 \\ :
459 \\ : [number] "{rax}" (231),
460 \\ [arg1] "{rdi}" (0)
461 \\ : "rcx", "r11", "memory"
462 \\ );
463 \\ unreachable;
464 \\}
465 ,
466 "",
467 );
449 }468 }
450}469}