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(
20162016 return &inst.base;
20172017}
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
20412019pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst {
20422020 const const_inst = try scope.arena().create(Inst.Constant);
20432021 const_inst.* = .{
......@@ -2500,7 +2478,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
25002478
25012479 // null to ?T
25022480 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) });
25042482 }
25052483
25062484 // 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
311311 const src = tree.token_locs[node.rtoken].start;
312312
313313 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);
315315 if (rl == .lvalue) return unwrapped_ptr;
316316
317317 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 {
668668 .store => return self.genStore(inst.castTag(.store).?),
669669 .sub => return self.genSub(inst.castTag(.sub).?),
670670 .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),
672673 }
673674 }
674675
......@@ -818,7 +819,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
818819 }
819820 }
820821
821 fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnwrapOptional) !MCValue {
822 fn genUnwrapOptional(self: *Self, inst: *ir.Inst.UnOp, safety_check: bool) !MCValue {
822823 // No side effects, so if it's unreferenced, do nothing.
823824 if (inst.base.isUnused())
824825 return MCValue.dead;
src-self-hosted/ir.zig+4-23
......@@ -82,7 +82,8 @@ pub const Inst = struct {
8282 not,
8383 floatcast,
8484 intcast,
85 unwrap_optional,
85 unwrap_optional_safe,
86 unwrap_optional_unsafe,
8687
8788 pub fn Type(tag: Tag) type {
8889 return switch (tag) {
......@@ -103,6 +104,8 @@ pub const Inst = struct {
103104 .floatcast,
104105 .intcast,
105106 .load,
107 .unwrap_optional_safe,
108 .unwrap_optional_unsafe,
106109 => UnOp,
107110
108111 .add,
......@@ -125,7 +128,6 @@ pub const Inst = struct {
125128 .condbr => CondBr,
126129 .constant => Constant,
127130 .loop => Loop,
128 .unwrap_optional => UnwrapOptional,
129131 };
130132 }
131133
......@@ -421,27 +423,6 @@ pub const Inst = struct {
421423 return null;
422424 }
423425 };
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 };
445426};
446427
447428pub const Body = struct {
src-self-hosted/type.zig+8-2
......@@ -185,8 +185,6 @@ pub const Type = extern union {
185185 return true;
186186 },
187187 .Optional => {
188 if (a.tag() != b.tag())
189 return false;
190188 return a.elemType().eql(b.elemType());
191189 },
192190 .Float,
......@@ -662,6 +660,10 @@ pub const Type = extern union {
662660 .optional => {
663661 const child_type = self.cast(Payload.Optional).?.child_type;
664662 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
665667 return child_type.abiAlignment(target);
666668 },
667669
......@@ -750,6 +752,10 @@ pub const Type = extern union {
750752 .optional => {
751753 const child_type = self.cast(Payload.Optional).?.child_type;
752754 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
753759 // Optional types are represented as a struct with the child type as the first
754760 // field and a boolean as the second. Since the child type's abi alignment is
755761 // 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 {
215215 /// Create an optional type '?T'
216216 optional_type,
217217 /// 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
220222 pub fn Type(tag: Tag) type {
221223 return switch (tag) {
......@@ -245,6 +247,8 @@ pub const Inst = struct {
245247 .single_const_ptr_type,
246248 .single_mut_ptr_type,
247249 .optional_type,
250 .unwrap_optional_safe,
251 .unwrap_optional_unsafe,
248252 => UnOp,
249253
250254 .add,
......@@ -303,7 +307,6 @@ pub const Inst = struct {
303307 .fntype => FnType,
304308 .elemptr => ElemPtr,
305309 .condbr => CondBr,
306 .unwrap_optional => UnwrapOptional,
307310 };
308311 }
309312
......@@ -379,7 +382,8 @@ pub const Inst = struct {
379382 .typeof,
380383 .xor,
381384 .optional_type,
382 .unwrap_optional,
385 .unwrap_optional_safe,
386 .unwrap_optional_unsafe,
383387 => false,
384388
385389 .@"break",
......@@ -820,18 +824,6 @@ pub const Inst = struct {
820824 },
821825 kw_args: struct {},
822826 };
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 };
835827};
836828
837829pub const ErrorMsg = struct {
......@@ -1935,6 +1927,8 @@ const EmitZIR = struct {
19351927 .isnonnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnonnull).?, .isnonnull),
19361928 .load => try self.emitUnOp(inst.src, new_body, inst.castTag(.load).?, .deref),
19371929 .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
19391933 .add => try self.emitBinOp(inst.src, new_body, inst.castTag(.add).?, .add),
19401934 .sub => try self.emitBinOp(inst.src, new_body, inst.castTag(.sub).?, .sub),
......@@ -2157,25 +2151,6 @@ const EmitZIR = struct {
21572151 };
21582152 break :blk &new_inst.base;
21592153 },
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 },
21792154 };
21802155 try instructions.append(new_inst);
21812156 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!
107107 .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?),
108108 .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?),
109109 .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),
111112 }
112113}
113114
......@@ -661,7 +662,7 @@ fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp
661662 }));
662663}
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 {
665666 const operand = try resolveInst(mod, scope, unwrap.positionals.operand);
666667 assert(operand.ty.zigTypeTag() == .Pointer);
667668
......@@ -686,7 +687,10 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.Unwr
686687 }
687688
688689 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);
690694}
691695
692696fn 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 {
3131 \\export fn _start() noreturn {
3232 \\ print();
3333 \\
34 \\ const a: u32 = 2;
35 \\ const b: ?u32 = a;
36 \\ const c = b.?;
37 \\ if (c != 2) unreachable;
38 \\
3934 \\ exit();
4035 \\}
4136 \\
......@@ -446,5 +441,29 @@ pub fn addCases(ctx: *TestContext) !void {
446441 ,
447442 "",
448443 );
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 );
449468 }
450469}