authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-20 17:26:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-20 17:26:05-07:00
log6bbb168f6667520dc106bc93c6e3761d5611fccb
treec12be20be24223f37ab9a3c6cfdb9db8e7d263b4
parenteef111fe78d7b246b634a07561082a6fcf947e09
parent73d16d015e09c05aecba8a58881cbc429e8126fa

Merge branch 'Vexu-stage2'

closes #6107

9 files changed, 1295 insertions(+), 928 deletions(-)

src-self-hosted/Module.zig+100-10
......@@ -1485,6 +1485,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
14851485 const type_node = var_decl.getTrailer("type_node") orelse
14861486 break :blk null;
14871487
1488 // Temporary arena for the zir instructions.
14881489 var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
14891490 defer type_scope_arena.deinit();
14901491 var type_scope: Scope.GenZIR = .{
......@@ -1539,7 +1540,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
15391540 try self.coerce(&inner_block.base, some, ret.operand)
15401541 else
15411542 ret.operand;
1542 const val = try self.resolveConstValue(&inner_block.base, coerced);
1543 const val = coerced.value() orelse
1544 return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{});
15431545
15441546 var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena);
15451547 break :blk try val.copy(block_scope.arena);
......@@ -1603,7 +1605,41 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
16031605 }
16041606 return type_changed;
16051607 },
1606 .Comptime => @panic("TODO comptime decl"),
1608 .Comptime => {
1609 const comptime_decl = @fieldParentPtr(ast.Node.Comptime, "base", ast_node);
1610
1611 decl.analysis = .in_progress;
1612
1613 // A comptime decl does not store any value so we can just deinit this arena after analysis is done.
1614 var analysis_arena = std.heap.ArenaAllocator.init(self.gpa);
1615 defer analysis_arena.deinit();
1616 var gen_scope: Scope.GenZIR = .{
1617 .decl = decl,
1618 .arena = &analysis_arena.allocator,
1619 .parent = decl.scope,
1620 };
1621 defer gen_scope.instructions.deinit(self.gpa);
1622
1623 // TODO comptime scope here
1624 _ = try astgen.expr(self, &gen_scope.base, .none, comptime_decl.expr);
1625
1626 var block_scope: Scope.Block = .{
1627 .parent = null,
1628 .func = null,
1629 .decl = decl,
1630 .instructions = .{},
1631 .arena = &analysis_arena.allocator,
1632 };
1633 defer block_scope.instructions.deinit(self.gpa);
1634
1635 _ = try zir_sema.analyzeBody(self, &block_scope.base, .{
1636 .instructions = gen_scope.instructions.items,
1637 });
1638
1639 decl.analysis = .complete;
1640 decl.generation = self.generation;
1641 return true;
1642 },
16071643 .Use => @panic("TODO usingnamespace decl"),
16081644 else => unreachable,
16091645 }
......@@ -1794,7 +1830,16 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
17941830 }
17951831 }
17961832 } else if (src_decl.castTag(.Comptime)) |comptime_node| {
1797 log.err("TODO: analyze comptime decl", .{});
1833 const name_index = self.getNextAnonNameIndex();
1834 const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index});
1835 defer self.gpa.free(name);
1836
1837 const name_hash = root_scope.fullyQualifiedNameHash(name);
1838 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1839
1840 const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash);
1841 root_scope.decls.appendAssumeCapacity(new_decl);
1842 self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
17981843 } else if (src_decl.castTag(.ContainerField)) |container_field| {
17991844 log.err("TODO: analyze container field", .{});
18001845 } else if (src_decl.castTag(.TestDecl)) |test_decl| {
......@@ -2429,7 +2474,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn
24292474 if (decl_tv.val.tag() == .variable) {
24302475 return self.analyzeVarRef(scope, src, decl_tv);
24312476 }
2432 const ty = try self.singlePtrType(scope, src, false, decl_tv.ty);
2477 const ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One);
24332478 const val_payload = try scope.arena().create(Value.Payload.DeclRef);
24342479 val_payload.* = .{ .decl = decl };
24352480
......@@ -2442,7 +2487,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn
24422487fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst {
24432488 const variable = tv.val.cast(Value.Payload.Variable).?.variable;
24442489
2445 const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty);
2490 const ty = try self.simplePtrType(scope, src, tv.ty, variable.is_mutable, .One);
24462491 if (!variable.is_mutable and !variable.is_extern) {
24472492 const val_payload = try scope.arena().create(Value.Payload.RefVal);
24482493 val_payload.* = .{ .val = variable.init };
......@@ -2766,7 +2811,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
27662811
27672812 // T to ?T
27682813 if (dest_type.zigTypeTag() == .Optional) {
2769 var buf: Type.Payload.Pointer = undefined;
2814 var buf: Type.Payload.PointerSimple = undefined;
27702815 const child_type = dest_type.optionalChild(&buf);
27712816 if (child_type.eql(inst.ty)) {
27722817 return self.wrapOptional(scope, dest_type, inst);
......@@ -3145,11 +3190,56 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
31453190 return Value.initPayload(val_payload);
31463191}
31473192
3148pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) Allocator.Error!Type {
3193pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type {
3194 if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) {
3195 return Type.initTag(.const_slice_u8);
3196 }
3197 // TODO stage1 type inference bug
3198 const T = Type.Tag;
3199
3200 const type_payload = try scope.arena().create(Type.Payload.PointerSimple);
3201 type_payload.* = .{
3202 .base = .{
3203 .tag = switch (size) {
3204 .One => if (mutable) T.single_mut_pointer else T.single_const_pointer,
3205 .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer,
3206 .C => if (mutable) T.c_mut_pointer else T.c_const_pointer,
3207 .Slice => if (mutable) T.mut_slice else T.const_slice,
3208 },
3209 },
3210 .pointee_type = elem_ty,
3211 };
3212 return Type.initPayload(&type_payload.base);
3213}
3214
3215pub fn ptrType(
3216 self: *Module,
3217 scope: *Scope,
3218 src: usize,
3219 elem_ty: Type,
3220 sentinel: ?Value,
3221 @"align": u32,
3222 bit_offset: u16,
3223 host_size: u16,
3224 mutable: bool,
3225 @"allowzero": bool,
3226 @"volatile": bool,
3227 size: std.builtin.TypeInfo.Pointer.Size,
3228) Allocator.Error!Type {
3229 assert(host_size == 0 or bit_offset < host_size * 8);
3230
3231 // TODO check if type can be represented by simplePtrType
31493232 const type_payload = try scope.arena().create(Type.Payload.Pointer);
31503233 type_payload.* = .{
3151 .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer },
31523234 .pointee_type = elem_ty,
3235 .sentinel = sentinel,
3236 .@"align" = @"align",
3237 .bit_offset = bit_offset,
3238 .host_size = host_size,
3239 .@"allowzero" = @"allowzero",
3240 .mutable = mutable,
3241 .@"volatile" = @"volatile",
3242 .size = size,
31533243 };
31543244 return Type.initPayload(&type_payload.base);
31553245}
......@@ -3157,7 +3247,7 @@ pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, el
31573247pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type {
31583248 return Type.initPayload(switch (child_type.tag()) {
31593249 .single_const_pointer => blk: {
3160 const payload = try scope.arena().create(Type.Payload.Pointer);
3250 const payload = try scope.arena().create(Type.Payload.PointerSimple);
31613251 payload.* = .{
31623252 .base = .{ .tag = .optional_single_const_pointer },
31633253 .pointee_type = child_type.elemType(),
......@@ -3165,7 +3255,7 @@ pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Er
31653255 break :blk &payload.base;
31663256 },
31673257 .single_mut_pointer => blk: {
3168 const payload = try scope.arena().create(Type.Payload.Pointer);
3258 const payload = try scope.arena().create(Type.Payload.PointerSimple);
31693259 payload.* = .{
31703260 .base = .{ .tag = .optional_single_mut_pointer },
31713261 .pointee_type = child_type.elemType(),
src-self-hosted/astgen.zig+41-17
......@@ -262,6 +262,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
262262 .EnumLiteral => return rlWrap(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)),
263263 .MultilineStringLiteral => return rlWrap(mod, scope, rl, try multilineStrLiteral(mod, scope, node.castTag(.MultilineStringLiteral).?)),
264264 .CharLiteral => return rlWrap(mod, scope, rl, try charLiteral(mod, scope, node.castTag(.CharLiteral).?)),
265 .SliceType => return rlWrap(mod, scope, rl, try sliceType(mod, scope, node.castTag(.SliceType).?)),
265266
266267 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
267268 .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}),
......@@ -275,7 +276,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
275276 .NegationWrap => return mod.failNode(scope, node, "TODO implement astgen.expr for .NegationWrap", .{}),
276277 .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),
277278 .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
278 .SliceType => return mod.failNode(scope, node, "TODO implement astgen.expr for .SliceType", .{}),
279279 .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),
280280 .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}),
281281 .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}),
......@@ -569,43 +569,67 @@ fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) Inn
569569 return addZIRUnOp(mod, scope, src, .optional_type, operand);
570570}
571571
572fn sliceType(mod: *Module, scope: *Scope, node: *ast.Node.SliceType) InnerError!*zir.Inst {
573 const tree = scope.tree();
574 const src = tree.token_locs[node.op_token].start;
575 return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, .Slice);
576}
577
572578fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst {
573579 const tree = scope.tree();
574580 const src = tree.token_locs[node.op_token].start;
581 return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, switch (tree.token_ids[node.op_token]) {
582 .Asterisk, .AsteriskAsterisk => .One,
583 // TODO stage1 type inference bug
584 .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) {
585 .Identifier => .C,
586 else => .Many,
587 }),
588 else => unreachable,
589 });
590}
591
592fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, rhs: *ast.Node, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*zir.Inst {
575593 const meta_type = try addZIRInstConst(mod, scope, src, .{
576594 .ty = Type.initTag(.type),
577595 .val = Value.initTag(.type_type),
578596 });
579597
580 const simple = node.ptr_info.allowzero_token == null and
581 node.ptr_info.align_info == null and
582 node.ptr_info.volatile_token == null and
583 node.ptr_info.sentinel == null;
598 const simple = ptr_info.allowzero_token == null and
599 ptr_info.align_info == null and
600 ptr_info.volatile_token == null and
601 ptr_info.sentinel == null;
584602
585603 if (simple) {
586 const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
587 return addZIRUnOp(mod, scope, src, if (node.ptr_info.const_token == null)
588 .single_mut_ptr_type
589 else
590 .single_const_ptr_type, child_type);
604 const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs);
605 const mutable = ptr_info.const_token == null;
606 // TODO stage1 type inference bug
607 const T = zir.Inst.Tag;
608 return addZIRUnOp(mod, scope, src, switch (size) {
609 .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type,
610 .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type,
611 .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type,
612 .Slice => if (mutable) T.mut_slice_type else T.mut_slice_type,
613 }, child_type);
591614 }
592615
593616 var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, "kw_args").field_type = .{};
594 kw_args.@"allowzero" = node.ptr_info.allowzero_token != null;
595 if (node.ptr_info.align_info) |some| {
617 kw_args.size = size;
618 kw_args.@"allowzero" = ptr_info.allowzero_token != null;
619 if (ptr_info.align_info) |some| {
596620 kw_args.@"align" = try expr(mod, scope, .none, some.node);
597621 if (some.bit_range) |bit_range| {
598622 kw_args.align_bit_start = try expr(mod, scope, .none, bit_range.start);
599623 kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end);
600624 }
601625 }
602 kw_args.@"const" = node.ptr_info.const_token != null;
603 kw_args.@"volatile" = node.ptr_info.volatile_token != null;
604 if (node.ptr_info.sentinel) |some| {
626 kw_args.mutable = ptr_info.const_token == null;
627 kw_args.@"volatile" = ptr_info.volatile_token != null;
628 if (ptr_info.sentinel) |some| {
605629 kw_args.sentinel = try expr(mod, scope, .none, some);
606630 }
607631
608 const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
632 const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs);
609633 if (kw_args.sentinel) |some| {
610634 kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some);
611635 }
......@@ -1271,7 +1295,7 @@ fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStr
12711295 i += 1;
12721296 }
12731297 const slice = tree.tokenSlice(line);
1274 mem.copy(u8, bytes[i..], slice[2..slice.len - 1]);
1298 mem.copy(u8, bytes[i..], slice[2 .. slice.len - 1]);
12751299 i += slice.len - 3;
12761300 }
12771301
src-self-hosted/codegen.zig+1-1
......@@ -2060,7 +2060,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
20602060 if (typed_value.val.isNull())
20612061 return MCValue{ .immediate = 0 };
20622062
2063 var buf: Type.Payload.Pointer = undefined;
2063 var buf: Type.Payload.PointerSimple = undefined;
20642064 return self.genTypedValue(src, .{
20652065 .ty = typed_value.ty.optionalChild(&buf),
20662066 .val = typed_value.val,
src-self-hosted/type.zig+344-34
......@@ -66,10 +66,18 @@ pub const Type = extern union {
6666 .function => return .Fn,
6767
6868 .array, .array_u8_sentinel_0, .array_u8, .array_sentinel => return .Array,
69 .single_const_pointer => return .Pointer,
70 .single_mut_pointer => return .Pointer,
71 .single_const_pointer_to_comptime_int => return .Pointer,
72 .const_slice_u8 => return .Pointer,
69 .single_const_pointer_to_comptime_int,
70 .const_slice_u8,
71 .single_const_pointer,
72 .single_mut_pointer,
73 .many_const_pointer,
74 .many_mut_pointer,
75 .c_const_pointer,
76 .c_mut_pointer,
77 .const_slice,
78 .mut_slice,
79 .pointer,
80 => return .Pointer,
7381
7482 .optional,
7583 .optional_single_const_pointer,
......@@ -108,13 +116,19 @@ pub const Type = extern union {
108116 return @fieldParentPtr(T, "base", self.ptr_otherwise);
109117 }
110118
111 pub fn castPointer(self: Type) ?*Payload.Pointer {
119 pub fn castPointer(self: Type) ?*Payload.PointerSimple {
112120 return switch (self.tag()) {
113121 .single_const_pointer,
114122 .single_mut_pointer,
123 .many_const_pointer,
124 .many_mut_pointer,
125 .c_const_pointer,
126 .c_mut_pointer,
127 .const_slice,
128 .mut_slice,
115129 .optional_single_const_pointer,
116130 .optional_single_mut_pointer,
117 => @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise),
131 => @fieldParentPtr(Payload.PointerSimple, "base", self.ptr_otherwise),
118132 else => null,
119133 };
120134 }
......@@ -198,8 +212,8 @@ pub const Type = extern union {
198212 return true;
199213 },
200214 .Optional => {
201 var buf_a: Payload.Pointer = undefined;
202 var buf_b: Payload.Pointer = undefined;
215 var buf_a: Payload.PointerSimple = undefined;
216 var buf_b: Payload.PointerSimple = undefined;
203217 return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b));
204218 },
205219 .Float,
......@@ -263,7 +277,7 @@ pub const Type = extern union {
263277 }
264278 },
265279 .Optional => {
266 var buf: Payload.Pointer = undefined;
280 var buf: Payload.PointerSimple = undefined;
267281 std.hash.autoHash(&hasher, self.optionalChild(&buf).hash());
268282 },
269283 .Float,
......@@ -374,9 +388,34 @@ pub const Type = extern union {
374388 .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"),
375389 .single_const_pointer,
376390 .single_mut_pointer,
391 .many_const_pointer,
392 .many_mut_pointer,
393 .c_const_pointer,
394 .c_mut_pointer,
395 .const_slice,
396 .mut_slice,
377397 .optional_single_mut_pointer,
378398 .optional_single_const_pointer,
379 => return self.copyPayloadSingleField(allocator, Payload.Pointer, "pointee_type"),
399 => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"),
400
401 .pointer => {
402 const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise);
403 const new_payload = try allocator.create(Payload.Pointer);
404 new_payload.* = .{
405 .base = payload.base,
406
407 .pointee_type = try payload.pointee_type.copy(allocator),
408 .sentinel = if (payload.sentinel) |some| try some.copy(allocator) else null,
409 .@"align" = payload.@"align",
410 .bit_offset = payload.bit_offset,
411 .host_size = payload.host_size,
412 .@"allowzero" = payload.@"allowzero",
413 .mutable = payload.mutable,
414 .@"volatile" = payload.@"volatile",
415 .size = payload.size,
416 };
417 return Type{ .ptr_otherwise = &new_payload.base };
418 },
380419 }
381420 }
382421
......@@ -482,17 +521,53 @@ pub const Type = extern union {
482521 continue;
483522 },
484523 .single_const_pointer => {
485 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
524 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
486525 try out_stream.writeAll("*const ");
487526 ty = payload.pointee_type;
488527 continue;
489528 },
490529 .single_mut_pointer => {
491 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
530 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
492531 try out_stream.writeAll("*");
493532 ty = payload.pointee_type;
494533 continue;
495534 },
535 .many_const_pointer => {
536 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
537 try out_stream.writeAll("[*]const ");
538 ty = payload.pointee_type;
539 continue;
540 },
541 .many_mut_pointer => {
542 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
543 try out_stream.writeAll("[*]");
544 ty = payload.pointee_type;
545 continue;
546 },
547 .c_const_pointer => {
548 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
549 try out_stream.writeAll("[*c]const ");
550 ty = payload.pointee_type;
551 continue;
552 },
553 .c_mut_pointer => {
554 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
555 try out_stream.writeAll("[*c]");
556 ty = payload.pointee_type;
557 continue;
558 },
559 .const_slice => {
560 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
561 try out_stream.writeAll("[]const ");
562 ty = payload.pointee_type;
563 continue;
564 },
565 .mut_slice => {
566 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
567 try out_stream.writeAll("[]");
568 ty = payload.pointee_type;
569 continue;
570 },
496571 .int_signed => {
497572 const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise);
498573 return out_stream.print("i{}", .{payload.bits});
......@@ -508,17 +583,45 @@ pub const Type = extern union {
508583 continue;
509584 },
510585 .optional_single_const_pointer => {
511 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
586 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
512587 try out_stream.writeAll("?*const ");
513588 ty = payload.pointee_type;
514589 continue;
515590 },
516591 .optional_single_mut_pointer => {
517 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
592 const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise);
518593 try out_stream.writeAll("?*");
519594 ty = payload.pointee_type;
520595 continue;
521596 },
597
598 .pointer => {
599 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
600 if (payload.sentinel) |some| switch (payload.size) {
601 .One, .C => unreachable,
602 .Many => try out_stream.writeAll("[*:{}]"),
603 .Slice => try out_stream.writeAll("[:{}]"),
604 } else switch (payload.size) {
605 .One => try out_stream.writeAll("*"),
606 .Many => try out_stream.writeAll("[*]"),
607 .C => try out_stream.writeAll("[*c]"),
608 .Slice => try out_stream.writeAll("[]"),
609 }
610 if (payload.@"align" != 0) {
611 try out_stream.print("align({}", .{payload.@"align"});
612
613 if (payload.bit_offset != 0) {
614 try out_stream.print(":{}:{}", .{ payload.bit_offset, payload.host_size });
615 }
616 try out_stream.writeAll(") ");
617 }
618 if (!payload.mutable) try out_stream.writeAll("const ");
619 if (payload.@"volatile") try out_stream.writeAll("volatile ");
620 if (payload.@"allowzero") try out_stream.writeAll("allowzero ");
621
622 ty = payload.pointee_type;
623 continue;
624 },
522625 }
523626 unreachable;
524627 }
......@@ -616,9 +719,7 @@ pub const Type = extern union {
616719 // TODO lazy types
617720 .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
618721 .array_u8 => self.arrayLen() != 0,
619 .array_sentinel => self.elemType().hasCodeGenBits(),
620 .single_const_pointer => self.elemType().hasCodeGenBits(),
621 .single_mut_pointer => self.elemType().hasCodeGenBits(),
722 .array_sentinel, .single_const_pointer, .single_mut_pointer, .many_const_pointer, .many_mut_pointer, .c_const_pointer, .c_mut_pointer, .const_slice, .mut_slice, .pointer => self.elemType().hasCodeGenBits(),
622723 .int_signed => self.cast(Payload.IntSigned).?.bits == 0,
623724 .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0,
624725
......@@ -669,10 +770,23 @@ pub const Type = extern union {
669770 .const_slice_u8,
670771 .single_const_pointer,
671772 .single_mut_pointer,
773 .many_const_pointer,
774 .many_mut_pointer,
775 .c_const_pointer,
776 .c_mut_pointer,
777 .const_slice,
778 .mut_slice,
672779 .optional_single_const_pointer,
673780 .optional_single_mut_pointer,
674781 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
675782
783 .pointer => {
784 const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise);
785
786 if (payload.@"align" != 0) return payload.@"align";
787 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
788 },
789
676790 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
677791 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
678792 .c_int => return @divExact(CType.int.sizeInBits(target), 8),
......@@ -704,7 +818,7 @@ pub const Type = extern union {
704818 },
705819
706820 .optional => {
707 var buf: Payload.Pointer = undefined;
821 var buf: Payload.PointerSimple = undefined;
708822 const child_type = self.optionalChild(&buf);
709823 if (!child_type.hasCodeGenBits()) return 1;
710824
......@@ -744,6 +858,7 @@ pub const Type = extern union {
744858 .@"null" => unreachable,
745859 .@"undefined" => unreachable,
746860 .enum_literal => unreachable,
861 .single_const_pointer_to_comptime_int => unreachable,
747862
748863 .u8,
749864 .i8,
......@@ -766,15 +881,31 @@ pub const Type = extern union {
766881 .i32, .u32 => return 4,
767882 .i64, .u64 => return 8,
768883
769 .isize,
770 .usize,
771 .single_const_pointer_to_comptime_int,
884 .isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
885
886 .const_slice,
887 .mut_slice,
772888 .const_slice_u8,
773 .single_const_pointer,
774 .single_mut_pointer,
889 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
890
775891 .optional_single_const_pointer,
776892 .optional_single_mut_pointer,
777 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
893 => {
894 if (self.elemType().hasCodeGenBits()) return 1;
895 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
896 },
897
898 .single_const_pointer,
899 .single_mut_pointer,
900 .many_const_pointer,
901 .many_mut_pointer,
902 .c_const_pointer,
903 .c_mut_pointer,
904 .pointer,
905 => {
906 if (self.elemType().hasCodeGenBits()) return 0;
907 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
908 },
778909
779910 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
780911 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
......@@ -805,7 +936,7 @@ pub const Type = extern union {
805936 },
806937
807938 .optional => {
808 var buf: Payload.Pointer = undefined;
939 var buf: Payload.PointerSimple = undefined;
809940 const child_type = self.optionalChild(&buf);
810941 if (!child_type.hasCodeGenBits()) return 1;
811942
......@@ -872,12 +1003,20 @@ pub const Type = extern union {
8721003 .optional_single_mut_pointer,
8731004 .optional_single_const_pointer,
8741005 .enum_literal,
1006 .many_const_pointer,
1007 .many_mut_pointer,
1008 .c_const_pointer,
1009 .c_mut_pointer,
1010 .const_slice,
1011 .mut_slice,
8751012 => false,
8761013
8771014 .single_const_pointer,
8781015 .single_mut_pointer,
8791016 .single_const_pointer_to_comptime_int,
8801017 => true,
1018
1019 .pointer => self.cast(Payload.Pointer).?.size == .One,
8811020 };
8821021 }
8831022
......@@ -922,6 +1061,10 @@ pub const Type = extern union {
9221061 .array_u8_sentinel_0,
9231062 .single_const_pointer,
9241063 .single_mut_pointer,
1064 .many_const_pointer,
1065 .many_mut_pointer,
1066 .c_const_pointer,
1067 .c_mut_pointer,
9251068 .single_const_pointer_to_comptime_int,
9261069 .fn_noreturn_no_args,
9271070 .fn_void_no_args,
......@@ -936,7 +1079,12 @@ pub const Type = extern union {
9361079 .enum_literal,
9371080 => false,
9381081
939 .const_slice_u8 => true,
1082 .const_slice,
1083 .mut_slice,
1084 .const_slice_u8,
1085 => true,
1086
1087 .pointer => self.cast(Payload.Pointer).?.size == .Slice,
9401088 };
9411089 }
9421090
......@@ -987,16 +1135,24 @@ pub const Type = extern union {
9871135 .int_unsigned,
9881136 .int_signed,
9891137 .single_mut_pointer,
1138 .many_mut_pointer,
1139 .c_mut_pointer,
9901140 .optional,
9911141 .optional_single_mut_pointer,
9921142 .optional_single_const_pointer,
9931143 .enum_literal,
1144 .mut_slice,
9941145 => false,
9951146
9961147 .single_const_pointer,
1148 .many_const_pointer,
1149 .c_const_pointer,
9971150 .single_const_pointer_to_comptime_int,
9981151 .const_slice_u8,
1152 .const_slice,
9991153 => true,
1154
1155 .pointer => !self.cast(Payload.Pointer).?.mutable,
10001156 };
10011157 }
10021158
......@@ -1048,6 +1204,12 @@ pub const Type = extern union {
10481204 .int_signed,
10491205 .single_mut_pointer,
10501206 .single_const_pointer,
1207 .many_const_pointer,
1208 .many_mut_pointer,
1209 .c_const_pointer,
1210 .c_mut_pointer,
1211 .const_slice,
1212 .mut_slice,
10511213 .single_const_pointer_to_comptime_int,
10521214 .const_slice_u8,
10531215 .optional,
......@@ -1055,6 +1217,11 @@ pub const Type = extern union {
10551217 .optional_single_const_pointer,
10561218 .enum_literal,
10571219 => false,
1220
1221 .pointer => {
1222 const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise);
1223 return payload.@"volatile";
1224 },
10581225 };
10591226 }
10601227
......@@ -1063,7 +1230,7 @@ pub const Type = extern union {
10631230 switch (self.tag()) {
10641231 .optional_single_const_pointer, .optional_single_mut_pointer => return true,
10651232 .optional => {
1066 var buf: Payload.Pointer = undefined;
1233 var buf: Payload.PointerSimple = undefined;
10671234 const child_type = self.optionalChild(&buf);
10681235 // optionals of zero sized pointers behave like bools
10691236 if (!child_type.hasCodeGenBits()) return false;
......@@ -1101,7 +1268,7 @@ pub const Type = extern union {
11011268 => return false,
11021269
11031270 .Optional => {
1104 var buf: Payload.Pointer = undefined;
1271 var buf: Payload.PointerSimple = undefined;
11051272 return ty.optionalChild(&buf).isValidVarType(is_extern);
11061273 },
11071274 .Pointer, .Array => ty = ty.elemType(),
......@@ -1164,15 +1331,23 @@ pub const Type = extern union {
11641331
11651332 .array => self.cast(Payload.Array).?.elem_type,
11661333 .array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type,
1167 .single_const_pointer => self.castPointer().?.pointee_type,
1168 .single_mut_pointer => self.castPointer().?.pointee_type,
1334 .single_const_pointer,
1335 .single_mut_pointer,
1336 .many_const_pointer,
1337 .many_mut_pointer,
1338 .c_const_pointer,
1339 .c_mut_pointer,
1340 .const_slice,
1341 .mut_slice,
1342 => self.castPointer().?.pointee_type,
11691343 .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
11701344 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
1345 .pointer => self.cast(Payload.Pointer).?.pointee_type,
11711346 };
11721347 }
11731348
11741349 /// Asserts that the type is an optional.
1175 pub fn optionalChild(self: Type, buf: *Payload.Pointer) Type {
1350 pub fn optionalChild(self: Type, buf: *Payload.PointerSimple) Type {
11761351 return switch (self.tag()) {
11771352 .optional => self.cast(Payload.Optional).?.child_type,
11781353 .optional_single_mut_pointer => {
......@@ -1199,7 +1374,7 @@ pub const Type = extern union {
11991374 return switch (self.tag()) {
12001375 .optional => self.cast(Payload.Optional).?.child_type,
12011376 .optional_single_mut_pointer, .optional_single_const_pointer => {
1202 const payload = try allocator.create(Payload.Pointer);
1377 const payload = try allocator.create(Payload.PointerSimple);
12031378 payload.* = .{
12041379 .base = .{
12051380 .tag = if (self.tag() == .optional_single_const_pointer)
......@@ -1256,8 +1431,15 @@ pub const Type = extern union {
12561431 .fn_naked_noreturn_no_args,
12571432 .fn_ccc_void_no_args,
12581433 .function,
1434 .pointer,
12591435 .single_const_pointer,
12601436 .single_mut_pointer,
1437 .many_const_pointer,
1438 .many_mut_pointer,
1439 .c_const_pointer,
1440 .c_mut_pointer,
1441 .const_slice,
1442 .mut_slice,
12611443 .single_const_pointer_to_comptime_int,
12621444 .const_slice_u8,
12631445 .int_unsigned,
......@@ -1316,8 +1498,15 @@ pub const Type = extern union {
13161498 .fn_naked_noreturn_no_args,
13171499 .fn_ccc_void_no_args,
13181500 .function,
1501 .pointer,
13191502 .single_const_pointer,
13201503 .single_mut_pointer,
1504 .many_const_pointer,
1505 .many_mut_pointer,
1506 .c_const_pointer,
1507 .c_mut_pointer,
1508 .const_slice,
1509 .mut_slice,
13211510 .single_const_pointer_to_comptime_int,
13221511 .const_slice_u8,
13231512 .int_unsigned,
......@@ -1366,8 +1555,15 @@ pub const Type = extern union {
13661555 .array_sentinel,
13671556 .array_u8,
13681557 .array_u8_sentinel_0,
1558 .pointer,
13691559 .single_const_pointer,
13701560 .single_mut_pointer,
1561 .many_const_pointer,
1562 .many_mut_pointer,
1563 .c_const_pointer,
1564 .c_mut_pointer,
1565 .const_slice,
1566 .mut_slice,
13711567 .single_const_pointer_to_comptime_int,
13721568 .const_slice_u8,
13731569 .int_unsigned,
......@@ -1427,8 +1623,15 @@ pub const Type = extern union {
14271623 .array_sentinel,
14281624 .array_u8,
14291625 .array_u8_sentinel_0,
1626 .pointer,
14301627 .single_const_pointer,
14311628 .single_mut_pointer,
1629 .many_const_pointer,
1630 .many_mut_pointer,
1631 .c_const_pointer,
1632 .c_mut_pointer,
1633 .const_slice,
1634 .mut_slice,
14321635 .single_const_pointer_to_comptime_int,
14331636 .const_slice_u8,
14341637 .int_signed,
......@@ -1488,8 +1691,15 @@ pub const Type = extern union {
14881691 .array_sentinel,
14891692 .array_u8,
14901693 .array_u8_sentinel_0,
1694 .pointer,
14911695 .single_const_pointer,
14921696 .single_mut_pointer,
1697 .many_const_pointer,
1698 .many_mut_pointer,
1699 .c_const_pointer,
1700 .c_mut_pointer,
1701 .const_slice,
1702 .mut_slice,
14931703 .single_const_pointer_to_comptime_int,
14941704 .const_slice_u8,
14951705 .optional,
......@@ -1547,8 +1757,15 @@ pub const Type = extern union {
15471757 .array_sentinel,
15481758 .array_u8,
15491759 .array_u8_sentinel_0,
1760 .pointer,
15501761 .single_const_pointer,
15511762 .single_mut_pointer,
1763 .many_const_pointer,
1764 .many_mut_pointer,
1765 .c_const_pointer,
1766 .c_mut_pointer,
1767 .const_slice,
1768 .mut_slice,
15521769 .single_const_pointer_to_comptime_int,
15531770 .const_slice_u8,
15541771 .int_unsigned,
......@@ -1635,8 +1852,15 @@ pub const Type = extern union {
16351852 .array_sentinel,
16361853 .array_u8,
16371854 .array_u8_sentinel_0,
1855 .pointer,
16381856 .single_const_pointer,
16391857 .single_mut_pointer,
1858 .many_const_pointer,
1859 .many_mut_pointer,
1860 .c_const_pointer,
1861 .c_mut_pointer,
1862 .const_slice,
1863 .mut_slice,
16401864 .single_const_pointer_to_comptime_int,
16411865 .const_slice_u8,
16421866 .u8,
......@@ -1699,8 +1923,15 @@ pub const Type = extern union {
16991923 .array_sentinel,
17001924 .array_u8,
17011925 .array_u8_sentinel_0,
1926 .pointer,
17021927 .single_const_pointer,
17031928 .single_mut_pointer,
1929 .many_const_pointer,
1930 .many_mut_pointer,
1931 .c_const_pointer,
1932 .c_mut_pointer,
1933 .const_slice,
1934 .mut_slice,
17041935 .single_const_pointer_to_comptime_int,
17051936 .const_slice_u8,
17061937 .u8,
......@@ -1762,8 +1993,15 @@ pub const Type = extern union {
17621993 .array_sentinel,
17631994 .array_u8,
17641995 .array_u8_sentinel_0,
1996 .pointer,
17651997 .single_const_pointer,
17661998 .single_mut_pointer,
1999 .many_const_pointer,
2000 .many_mut_pointer,
2001 .c_const_pointer,
2002 .c_mut_pointer,
2003 .const_slice,
2004 .mut_slice,
17672005 .single_const_pointer_to_comptime_int,
17682006 .const_slice_u8,
17692007 .u8,
......@@ -1825,8 +2063,15 @@ pub const Type = extern union {
18252063 .array_sentinel,
18262064 .array_u8,
18272065 .array_u8_sentinel_0,
2066 .pointer,
18282067 .single_const_pointer,
18292068 .single_mut_pointer,
2069 .many_const_pointer,
2070 .many_mut_pointer,
2071 .c_const_pointer,
2072 .c_mut_pointer,
2073 .const_slice,
2074 .mut_slice,
18302075 .single_const_pointer_to_comptime_int,
18312076 .const_slice_u8,
18322077 .u8,
......@@ -1885,8 +2130,15 @@ pub const Type = extern union {
18852130 .array_sentinel,
18862131 .array_u8,
18872132 .array_u8_sentinel_0,
2133 .pointer,
18882134 .single_const_pointer,
18892135 .single_mut_pointer,
2136 .many_const_pointer,
2137 .many_mut_pointer,
2138 .c_const_pointer,
2139 .c_mut_pointer,
2140 .const_slice,
2141 .mut_slice,
18902142 .single_const_pointer_to_comptime_int,
18912143 .const_slice_u8,
18922144 .u8,
......@@ -1945,8 +2197,15 @@ pub const Type = extern union {
19452197 .array_sentinel,
19462198 .array_u8,
19472199 .array_u8_sentinel_0,
2200 .pointer,
19482201 .single_const_pointer,
19492202 .single_mut_pointer,
2203 .many_const_pointer,
2204 .many_mut_pointer,
2205 .c_const_pointer,
2206 .c_mut_pointer,
2207 .const_slice,
2208 .mut_slice,
19502209 .single_const_pointer_to_comptime_int,
19512210 .const_slice_u8,
19522211 .u8,
......@@ -2025,8 +2284,15 @@ pub const Type = extern union {
20252284 .array_sentinel,
20262285 .array_u8,
20272286 .array_u8_sentinel_0,
2287 .pointer,
20282288 .single_const_pointer,
20292289 .single_mut_pointer,
2290 .many_const_pointer,
2291 .many_mut_pointer,
2292 .c_const_pointer,
2293 .c_mut_pointer,
2294 .const_slice,
2295 .mut_slice,
20302296 .single_const_pointer_to_comptime_int,
20312297 .const_slice_u8,
20322298 .optional,
......@@ -2077,6 +2343,8 @@ pub const Type = extern union {
20772343 .array_sentinel,
20782344 .array_u8_sentinel_0,
20792345 .const_slice_u8,
2346 .const_slice,
2347 .mut_slice,
20802348 .c_void,
20812349 .optional,
20822350 .optional_single_mut_pointer,
......@@ -2109,11 +2377,21 @@ pub const Type = extern union {
21092377 ty = ty.elemType();
21102378 continue;
21112379 },
2112 .single_const_pointer, .single_mut_pointer => {
2380 .many_const_pointer,
2381 .many_mut_pointer,
2382 .c_const_pointer,
2383 .c_mut_pointer,
2384 .single_const_pointer,
2385 .single_mut_pointer,
2386 => {
21132387 const ptr = ty.castPointer().?;
21142388 ty = ptr.pointee_type;
21152389 continue;
21162390 },
2391 .pointer => {
2392 ty = ty.cast(Payload.Pointer).?.pointee_type;
2393 continue;
2394 },
21172395 };
21182396 }
21192397
......@@ -2167,11 +2445,21 @@ pub const Type = extern union {
21672445 .array_u8_sentinel_0,
21682446 .single_const_pointer,
21692447 .single_mut_pointer,
2448 .many_const_pointer,
2449 .many_mut_pointer,
2450 .const_slice,
2451 .mut_slice,
21702452 .optional,
21712453 .optional_single_mut_pointer,
21722454 .optional_single_const_pointer,
21732455 .enum_literal,
21742456 => return false,
2457
2458 .c_const_pointer,
2459 .c_mut_pointer,
2460 => return true,
2461
2462 .pointer => self.cast(Payload.Pointer).?.size == .C,
21752463 };
21762464 }
21772465
......@@ -2229,8 +2517,15 @@ pub const Type = extern union {
22292517 array_u8_sentinel_0,
22302518 array,
22312519 array_sentinel,
2520 pointer,
22322521 single_const_pointer,
22332522 single_mut_pointer,
2523 many_const_pointer,
2524 many_mut_pointer,
2525 c_const_pointer,
2526 c_mut_pointer,
2527 const_slice,
2528 mut_slice,
22342529 int_signed,
22352530 int_unsigned,
22362531 function,
......@@ -2272,7 +2567,7 @@ pub const Type = extern union {
22722567 elem_type: Type,
22732568 };
22742569
2275 pub const Pointer = struct {
2570 pub const PointerSimple = struct {
22762571 base: Payload,
22772572
22782573 pointee_type: Type,
......@@ -2303,6 +2598,21 @@ pub const Type = extern union {
23032598
23042599 child_type: Type,
23052600 };
2601
2602 pub const Pointer = struct {
2603 base: Payload = .{ .tag = .pointer },
2604
2605 pointee_type: Type,
2606 sentinel: ?Value,
2607 /// If zero use pointee_type.AbiAlign()
2608 @"align": u32,
2609 bit_offset: u16,
2610 host_size: u16,
2611 @"allowzero": bool,
2612 mutable: bool,
2613 @"volatile": bool,
2614 size: std.builtin.TypeInfo.Pointer.Size,
2615 };
23062616 };
23072617};
23082618
src-self-hosted/zir.zig+29-4
......@@ -194,10 +194,22 @@ pub const Inst = struct {
194194 shl,
195195 /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type.
196196 shr,
197 /// Create a const pointer type based on the element type. `*const T`
197 /// Create a const pointer type with element type T. `*const T`
198198 single_const_ptr_type,
199 /// Create a mutable pointer type based on the element type. `*T`
199 /// Create a mutable pointer type with element type T. `*T`
200200 single_mut_ptr_type,
201 /// Create a const pointer type with element type T. `[*]const T`
202 many_const_ptr_type,
203 /// Create a mutable pointer type with element type T. `[*]T`
204 many_mut_ptr_type,
205 /// Create a const pointer type with element type T. `[*c]const T`
206 c_const_ptr_type,
207 /// Create a mutable pointer type with element type T. `[*c]T`
208 c_mut_ptr_type,
209 /// Create a mutable slice type with element type T. `[]T`
210 mut_slice_type,
211 /// Create a const slice type with element type T. `[]T`
212 const_slice_type,
201213 /// Create a pointer type with attributes
202214 ptr_type,
203215 /// Write a value to a pointer. For loading, see `deref`.
......@@ -262,6 +274,12 @@ pub const Inst = struct {
262274 .typeof,
263275 .single_const_ptr_type,
264276 .single_mut_ptr_type,
277 .many_const_ptr_type,
278 .many_mut_ptr_type,
279 .c_const_ptr_type,
280 .c_mut_ptr_type,
281 .mut_slice_type,
282 .const_slice_type,
265283 .optional_type,
266284 .unwrap_optional_safe,
267285 .unwrap_optional_unsafe,
......@@ -400,6 +418,12 @@ pub const Inst = struct {
400418 .shr,
401419 .single_const_ptr_type,
402420 .single_mut_ptr_type,
421 .many_const_ptr_type,
422 .many_mut_ptr_type,
423 .c_const_ptr_type,
424 .c_mut_ptr_type,
425 .mut_slice_type,
426 .const_slice_type,
403427 .store,
404428 .str,
405429 .sub,
......@@ -856,9 +880,10 @@ pub const Inst = struct {
856880 @"align": ?*Inst = null,
857881 align_bit_start: ?*Inst = null,
858882 align_bit_end: ?*Inst = null,
859 @"const": bool = true,
883 mutable: bool = true,
860884 @"volatile": bool = false,
861885 sentinel: ?*Inst = null,
886 size: std.builtin.TypeInfo.Pointer.Size = .One,
862887 },
863888 };
864889
......@@ -2443,7 +2468,7 @@ const EmitZIR = struct {
24432468 }
24442469 },
24452470 .Optional => {
2446 var buf: Type.Payload.Pointer = undefined;
2471 var buf: Type.Payload.PointerSimple = undefined;
24472472 const inst = try self.arena.allocator.create(Inst.UnOp);
24482473 inst.* = .{
24492474 .base = .{
src-self-hosted/zir_sema.zig+60-15
......@@ -51,8 +51,14 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
5151 .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?),
5252 .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?),
5353 .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?),
54 .single_const_ptr_type => return analyzeInstSingleConstPtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?),
55 .single_mut_ptr_type => return analyzeInstSingleMutPtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?),
54 .single_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?, false, .One),
55 .single_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?, true, .One),
56 .many_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_const_ptr_type).?, false, .Many),
57 .many_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_mut_ptr_type).?, true, .Many),
58 .c_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_const_ptr_type).?, false, .C),
59 .c_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_mut_ptr_type).?, true, .C),
60 .const_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.const_slice_type).?, false, .Slice),
61 .mut_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.mut_slice_type).?, true, .Slice),
5662 .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?),
5763 .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?),
5864 .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?),
......@@ -267,6 +273,14 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type {
267273 return val.toType();
268274}
269275
276fn resolveInt(mod: *Module, scope: *Scope, old_inst: *zir.Inst, dest_type: Type) !u64 {
277 const new_inst = try resolveInst(mod, scope, old_inst);
278 const coerced = try mod.coerce(scope, dest_type, new_inst);
279 const val = try mod.resolveConstValue(scope, coerced);
280
281 return val.toUnsignedInt();
282}
283
270284pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue {
271285 const new_inst = try resolveInst(mod, scope, old_inst);
272286 const val = try mod.resolveConstValue(scope, new_inst);
......@@ -324,7 +338,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr
324338
325339fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
326340 const operand = try resolveInst(mod, scope, inst.positionals.operand);
327 const ptr_type = try mod.singlePtrType(scope, inst.base.src, false, operand.ty);
341 const ptr_type = try mod.simplePtrType(scope, inst.base.src, operand.ty, false, .One);
328342
329343 if (operand.value()) |val| {
330344 const ref_payload = try scope.arena().create(Value.Payload.RefVal);
......@@ -369,7 +383,7 @@ fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerErro
369383 if (!var_type.isValidVarType(false)) {
370384 return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type});
371385 }
372 const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type);
386 const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One);
373387 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
374388 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
375389}
......@@ -723,7 +737,7 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp
723737 }
724738
725739 const child_type = try operand.ty.elemType().optionalChildAlloc(scope.arena());
726 const child_pointer = try mod.singlePtrType(scope, unwrap.base.src, operand.ty.isConstPtr(), child_type);
740 const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, operand.ty.isConstPtr(), .One);
727741
728742 if (operand.value()) |val| {
729743 if (val.isNull()) {
......@@ -940,7 +954,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
940954 // required a larger index.
941955 const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64));
942956
943 const type_payload = try scope.arena().create(Type.Payload.Pointer);
957 const type_payload = try scope.arena().create(Type.Payload.PointerSimple);
944958 type_payload.* = .{
945959 .base = .{ .tag = .single_const_pointer },
946960 .pointee_type = array_ptr.ty.elemType().elemType(),
......@@ -1311,18 +1325,49 @@ fn analyzeDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerErr
13111325 return decl;
13121326}
13131327
1314fn analyzeInstSingleConstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1315 const elem_type = try resolveType(mod, scope, inst.positionals.operand);
1316 const ty = try mod.singlePtrType(scope, inst.base.src, false, elem_type);
1317 return mod.constType(scope, inst.base.src, ty);
1318}
1319
1320fn analyzeInstSingleMutPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1328fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*Inst {
13211329 const elem_type = try resolveType(mod, scope, inst.positionals.operand);
1322 const ty = try mod.singlePtrType(scope, inst.base.src, true, elem_type);
1330 const ty = try mod.simplePtrType(scope, inst.base.src, elem_type, mutable, size);
13231331 return mod.constType(scope, inst.base.src, ty);
13241332}
13251333
13261334fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) InnerError!*Inst {
1327 return mod.fail(scope, inst.base.src, "TODO implement ptr_type", .{});
1335 // TODO lazy values
1336 const @"align" = if (inst.kw_args.@"align") |some|
1337 @truncate(u32, try resolveInt(mod, scope, some, Type.initTag(.u32)))
1338 else
1339 0;
1340 const bit_offset = if (inst.kw_args.align_bit_start) |some|
1341 @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16)))
1342 else
1343 0;
1344 const host_size = if (inst.kw_args.align_bit_end) |some|
1345 @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16)))
1346 else
1347 0;
1348
1349 if (host_size != 0 and bit_offset >= host_size * 8)
1350 return mod.fail(scope, inst.base.src, "bit offset starts after end of host integer", .{});
1351
1352 const sentinel = if (inst.kw_args.sentinel) |some|
1353 (try resolveInstConst(mod, scope, some)).val
1354 else
1355 null;
1356
1357 const elem_type = try resolveType(mod, scope, inst.positionals.child_type);
1358
1359 const ty = try mod.ptrType(
1360 scope,
1361 inst.base.src,
1362 elem_type,
1363 sentinel,
1364 @"align",
1365 bit_offset,
1366 host_size,
1367 inst.kw_args.mutable,
1368 inst.kw_args.@"allowzero",
1369 inst.kw_args.@"volatile",
1370 inst.kw_args.size,
1371 );
1372 return mod.constType(scope, inst.base.src, ty);
13281373}
test/stage2/compare_output.zig deleted-710
......@@ -1,710 +0,0 @@
1const std = @import("std");
2const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
3// self-hosted does not yet support PE executable files / COFF object files
4// or mach-o files. So we do these test cases cross compiling for x86_64-linux.
5const linux_x64 = std.zig.CrossTarget{
6 .cpu_arch = .x86_64,
7 .os_tag = .linux,
8};
9
10const linux_riscv64 = std.zig.CrossTarget{
11 .cpu_arch = .riscv64,
12 .os_tag = .linux,
13};
14
15const wasi = std.zig.CrossTarget{
16 .cpu_arch = .wasm32,
17 .os_tag = .wasi,
18};
19
20pub fn addCases(ctx: *TestContext) !void {
21 {
22 var case = ctx.exe("hello world with updates", linux_x64);
23
24 case.addError("", &[_][]const u8{":1:1: error: no entry point found"});
25
26 case.addError(
27 \\export fn _start() noreturn {
28 \\}
29 , &[_][]const u8{":2:1: error: expected noreturn, found void"});
30
31 // Regular old hello world
32 case.addCompareOutput(
33 \\export fn _start() noreturn {
34 \\ print();
35 \\
36 \\ exit();
37 \\}
38 \\
39 \\fn print() void {
40 \\ asm volatile ("syscall"
41 \\ :
42 \\ : [number] "{rax}" (1),
43 \\ [arg1] "{rdi}" (1),
44 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
45 \\ [arg3] "{rdx}" (14)
46 \\ : "rcx", "r11", "memory"
47 \\ );
48 \\ return;
49 \\}
50 \\
51 \\fn exit() noreturn {
52 \\ asm volatile ("syscall"
53 \\ :
54 \\ : [number] "{rax}" (231),
55 \\ [arg1] "{rdi}" (0)
56 \\ : "rcx", "r11", "memory"
57 \\ );
58 \\ unreachable;
59 \\}
60 ,
61 "Hello, World!\n",
62 );
63 // Now change the message only
64 case.addCompareOutput(
65 \\export fn _start() noreturn {
66 \\ print();
67 \\
68 \\ exit();
69 \\}
70 \\
71 \\fn print() void {
72 \\ asm volatile ("syscall"
73 \\ :
74 \\ : [number] "{rax}" (1),
75 \\ [arg1] "{rdi}" (1),
76 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
77 \\ [arg3] "{rdx}" (104)
78 \\ : "rcx", "r11", "memory"
79 \\ );
80 \\ return;
81 \\}
82 \\
83 \\fn exit() noreturn {
84 \\ asm volatile ("syscall"
85 \\ :
86 \\ : [number] "{rax}" (231),
87 \\ [arg1] "{rdi}" (0)
88 \\ : "rcx", "r11", "memory"
89 \\ );
90 \\ unreachable;
91 \\}
92 ,
93 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
94 );
95 // Now we print it twice.
96 case.addCompareOutput(
97 \\export fn _start() noreturn {
98 \\ print();
99 \\ print();
100 \\
101 \\ exit();
102 \\}
103 \\
104 \\fn print() void {
105 \\ asm volatile ("syscall"
106 \\ :
107 \\ : [number] "{rax}" (1),
108 \\ [arg1] "{rdi}" (1),
109 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
110 \\ [arg3] "{rdx}" (104)
111 \\ : "rcx", "r11", "memory"
112 \\ );
113 \\ return;
114 \\}
115 \\
116 \\fn exit() noreturn {
117 \\ asm volatile ("syscall"
118 \\ :
119 \\ : [number] "{rax}" (231),
120 \\ [arg1] "{rdi}" (0)
121 \\ : "rcx", "r11", "memory"
122 \\ );
123 \\ unreachable;
124 \\}
125 ,
126 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
127 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
128 \\
129 );
130 }
131
132 {
133 var case = ctx.exe("hello world", linux_riscv64);
134 // Regular old hello world
135 case.addCompareOutput(
136 \\export fn _start() noreturn {
137 \\ print();
138 \\
139 \\ exit();
140 \\}
141 \\
142 \\fn print() void {
143 \\ asm volatile ("ecall"
144 \\ :
145 \\ : [number] "{a7}" (64),
146 \\ [arg1] "{a0}" (1),
147 \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")),
148 \\ [arg3] "{a2}" ("Hello, World!\n".len)
149 \\ : "rcx", "r11", "memory"
150 \\ );
151 \\ return;
152 \\}
153 \\
154 \\fn exit() noreturn {
155 \\ asm volatile ("ecall"
156 \\ :
157 \\ : [number] "{a7}" (94),
158 \\ [arg1] "{a0}" (0)
159 \\ : "rcx", "r11", "memory"
160 \\ );
161 \\ unreachable;
162 \\}
163 ,
164 "Hello, World!\n",
165 );
166 }
167
168 {
169 var case = ctx.exe("adding numbers at comptime", linux_x64);
170 case.addCompareOutput(
171 \\export fn _start() noreturn {
172 \\ asm volatile ("syscall"
173 \\ :
174 \\ : [number] "{rax}" (1),
175 \\ [arg1] "{rdi}" (1),
176 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
177 \\ [arg3] "{rdx}" (10 + 4)
178 \\ : "rcx", "r11", "memory"
179 \\ );
180 \\ asm volatile ("syscall"
181 \\ :
182 \\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)),
183 \\ [arg1] "{rdi}" (0)
184 \\ : "rcx", "r11", "memory"
185 \\ );
186 \\ unreachable;
187 \\}
188 ,
189 "Hello, World!\n",
190 );
191 }
192
193 {
194 var case = ctx.exe("adding numbers at runtime", linux_x64);
195 case.addCompareOutput(
196 \\export fn _start() noreturn {
197 \\ add(3, 4);
198 \\
199 \\ exit();
200 \\}
201 \\
202 \\fn add(a: u32, b: u32) void {
203 \\ if (a + b != 7) unreachable;
204 \\}
205 \\
206 \\fn exit() noreturn {
207 \\ asm volatile ("syscall"
208 \\ :
209 \\ : [number] "{rax}" (231),
210 \\ [arg1] "{rdi}" (0)
211 \\ : "rcx", "r11", "memory"
212 \\ );
213 \\ unreachable;
214 \\}
215 ,
216 "",
217 );
218 }
219
220 {
221 var case = ctx.exe("substracting numbers at runtime", linux_x64);
222 case.addCompareOutput(
223 \\export fn _start() noreturn {
224 \\ sub(7, 4);
225 \\
226 \\ exit();
227 \\}
228 \\
229 \\fn sub(a: u32, b: u32) void {
230 \\ if (a - b != 3) unreachable;
231 \\}
232 \\
233 \\fn exit() noreturn {
234 \\ asm volatile ("syscall"
235 \\ :
236 \\ : [number] "{rax}" (231),
237 \\ [arg1] "{rdi}" (0)
238 \\ : "rcx", "r11", "memory"
239 \\ );
240 \\ unreachable;
241 \\}
242 ,
243 "",
244 );
245 }
246
247 {
248 var case = ctx.exe("assert function", linux_x64);
249 case.addCompareOutput(
250 \\export fn _start() noreturn {
251 \\ add(3, 4);
252 \\
253 \\ exit();
254 \\}
255 \\
256 \\fn add(a: u32, b: u32) void {
257 \\ assert(a + b == 7);
258 \\}
259 \\
260 \\pub fn assert(ok: bool) void {
261 \\ if (!ok) unreachable; // assertion failure
262 \\}
263 \\
264 \\fn exit() noreturn {
265 \\ asm volatile ("syscall"
266 \\ :
267 \\ : [number] "{rax}" (231),
268 \\ [arg1] "{rdi}" (0)
269 \\ : "rcx", "r11", "memory"
270 \\ );
271 \\ unreachable;
272 \\}
273 ,
274 "",
275 );
276
277 // Tests copying a register. For the `c = a + b`, it has to
278 // preserve both a and b, because they are both used later.
279 case.addCompareOutput(
280 \\export fn _start() noreturn {
281 \\ add(3, 4);
282 \\
283 \\ exit();
284 \\}
285 \\
286 \\fn add(a: u32, b: u32) void {
287 \\ const c = a + b; // 7
288 \\ const d = a + c; // 10
289 \\ const e = d + b; // 14
290 \\ assert(e == 14);
291 \\}
292 \\
293 \\pub fn assert(ok: bool) void {
294 \\ if (!ok) unreachable; // assertion failure
295 \\}
296 \\
297 \\fn exit() noreturn {
298 \\ asm volatile ("syscall"
299 \\ :
300 \\ : [number] "{rax}" (231),
301 \\ [arg1] "{rdi}" (0)
302 \\ : "rcx", "r11", "memory"
303 \\ );
304 \\ unreachable;
305 \\}
306 ,
307 "",
308 );
309
310 // More stress on the liveness detection.
311 case.addCompareOutput(
312 \\export fn _start() noreturn {
313 \\ add(3, 4);
314 \\
315 \\ exit();
316 \\}
317 \\
318 \\fn add(a: u32, b: u32) void {
319 \\ const c = a + b; // 7
320 \\ const d = a + c; // 10
321 \\ const e = d + b; // 14
322 \\ const f = d + e; // 24
323 \\ const g = e + f; // 38
324 \\ const h = f + g; // 62
325 \\ const i = g + h; // 100
326 \\ assert(i == 100);
327 \\}
328 \\
329 \\pub fn assert(ok: bool) void {
330 \\ if (!ok) unreachable; // assertion failure
331 \\}
332 \\
333 \\fn exit() noreturn {
334 \\ asm volatile ("syscall"
335 \\ :
336 \\ : [number] "{rax}" (231),
337 \\ [arg1] "{rdi}" (0)
338 \\ : "rcx", "r11", "memory"
339 \\ );
340 \\ unreachable;
341 \\}
342 ,
343 "",
344 );
345
346 // Requires a second move. The register allocator should figure out to re-use rax.
347 case.addCompareOutput(
348 \\export fn _start() noreturn {
349 \\ add(3, 4);
350 \\
351 \\ exit();
352 \\}
353 \\
354 \\fn add(a: u32, b: u32) void {
355 \\ const c = a + b; // 7
356 \\ const d = a + c; // 10
357 \\ const e = d + b; // 14
358 \\ const f = d + e; // 24
359 \\ const g = e + f; // 38
360 \\ const h = f + g; // 62
361 \\ const i = g + h; // 100
362 \\ const j = i + d; // 110
363 \\ assert(j == 110);
364 \\}
365 \\
366 \\pub fn assert(ok: bool) void {
367 \\ if (!ok) unreachable; // assertion failure
368 \\}
369 \\
370 \\fn exit() noreturn {
371 \\ asm volatile ("syscall"
372 \\ :
373 \\ : [number] "{rax}" (231),
374 \\ [arg1] "{rdi}" (0)
375 \\ : "rcx", "r11", "memory"
376 \\ );
377 \\ unreachable;
378 \\}
379 ,
380 "",
381 );
382
383 // Now we test integer return values.
384 case.addCompareOutput(
385 \\export fn _start() noreturn {
386 \\ assert(add(3, 4) == 7);
387 \\ assert(add(20, 10) == 30);
388 \\
389 \\ exit();
390 \\}
391 \\
392 \\fn add(a: u32, b: u32) u32 {
393 \\ return a + b;
394 \\}
395 \\
396 \\pub fn assert(ok: bool) void {
397 \\ if (!ok) unreachable; // assertion failure
398 \\}
399 \\
400 \\fn exit() noreturn {
401 \\ asm volatile ("syscall"
402 \\ :
403 \\ : [number] "{rax}" (231),
404 \\ [arg1] "{rdi}" (0)
405 \\ : "rcx", "r11", "memory"
406 \\ );
407 \\ unreachable;
408 \\}
409 ,
410 "",
411 );
412
413 // Local mutable variables.
414 case.addCompareOutput(
415 \\export fn _start() noreturn {
416 \\ assert(add(3, 4) == 7);
417 \\ assert(add(20, 10) == 30);
418 \\
419 \\ exit();
420 \\}
421 \\
422 \\fn add(a: u32, b: u32) u32 {
423 \\ var x: u32 = undefined;
424 \\ x = 0;
425 \\ x += a;
426 \\ x += b;
427 \\ return x;
428 \\}
429 \\
430 \\pub fn assert(ok: bool) void {
431 \\ if (!ok) unreachable; // assertion failure
432 \\}
433 \\
434 \\fn exit() noreturn {
435 \\ asm volatile ("syscall"
436 \\ :
437 \\ : [number] "{rax}" (231),
438 \\ [arg1] "{rdi}" (0)
439 \\ : "rcx", "r11", "memory"
440 \\ );
441 \\ unreachable;
442 \\}
443 ,
444 "",
445 );
446
447 // Optionals
448 case.addCompareOutput(
449 \\export fn _start() noreturn {
450 \\ const a: u32 = 2;
451 \\ const b: ?u32 = a;
452 \\ const c = b.?;
453 \\ if (c != 2) unreachable;
454 \\
455 \\ exit();
456 \\}
457 \\
458 \\fn exit() noreturn {
459 \\ asm volatile ("syscall"
460 \\ :
461 \\ : [number] "{rax}" (231),
462 \\ [arg1] "{rdi}" (0)
463 \\ : "rcx", "r11", "memory"
464 \\ );
465 \\ unreachable;
466 \\}
467 ,
468 "",
469 );
470
471 // While loops
472 case.addCompareOutput(
473 \\export fn _start() noreturn {
474 \\ var i: u32 = 0;
475 \\ while (i < 4) : (i += 1) print();
476 \\ assert(i == 4);
477 \\
478 \\ exit();
479 \\}
480 \\
481 \\fn print() void {
482 \\ asm volatile ("syscall"
483 \\ :
484 \\ : [number] "{rax}" (1),
485 \\ [arg1] "{rdi}" (1),
486 \\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
487 \\ [arg3] "{rdx}" (6)
488 \\ : "rcx", "r11", "memory"
489 \\ );
490 \\ return;
491 \\}
492 \\
493 \\pub fn assert(ok: bool) void {
494 \\ if (!ok) unreachable; // assertion failure
495 \\}
496 \\
497 \\fn exit() noreturn {
498 \\ asm volatile ("syscall"
499 \\ :
500 \\ : [number] "{rax}" (231),
501 \\ [arg1] "{rdi}" (0)
502 \\ : "rcx", "r11", "memory"
503 \\ );
504 \\ unreachable;
505 \\}
506 ,
507 "hello\nhello\nhello\nhello\n",
508 );
509
510 // Labeled blocks (no conditional branch)
511 case.addCompareOutput(
512 \\export fn _start() noreturn {
513 \\ assert(add(3, 4) == 20);
514 \\
515 \\ exit();
516 \\}
517 \\
518 \\fn add(a: u32, b: u32) u32 {
519 \\ const x: u32 = blk: {
520 \\ const c = a + b; // 7
521 \\ const d = a + c; // 10
522 \\ const e = d + b; // 14
523 \\ break :blk e;
524 \\ };
525 \\ const y = x + a; // 17
526 \\ const z = y + a; // 20
527 \\ return z;
528 \\}
529 \\
530 \\pub fn assert(ok: bool) void {
531 \\ if (!ok) unreachable; // assertion failure
532 \\}
533 \\
534 \\fn exit() noreturn {
535 \\ asm volatile ("syscall"
536 \\ :
537 \\ : [number] "{rax}" (231),
538 \\ [arg1] "{rdi}" (0)
539 \\ : "rcx", "r11", "memory"
540 \\ );
541 \\ unreachable;
542 \\}
543 ,
544 "",
545 );
546
547 // This catches a possible bug in the logic for re-using dying operands.
548 case.addCompareOutput(
549 \\export fn _start() noreturn {
550 \\ assert(add(3, 4) == 116);
551 \\
552 \\ exit();
553 \\}
554 \\
555 \\fn add(a: u32, b: u32) u32 {
556 \\ const x: u32 = blk: {
557 \\ const c = a + b; // 7
558 \\ const d = a + c; // 10
559 \\ const e = d + b; // 14
560 \\ const f = d + e; // 24
561 \\ const g = e + f; // 38
562 \\ const h = f + g; // 62
563 \\ const i = g + h; // 100
564 \\ const j = i + d; // 110
565 \\ break :blk j;
566 \\ };
567 \\ const y = x + a; // 113
568 \\ const z = y + a; // 116
569 \\ return z;
570 \\}
571 \\
572 \\pub fn assert(ok: bool) void {
573 \\ if (!ok) unreachable; // assertion failure
574 \\}
575 \\
576 \\fn exit() noreturn {
577 \\ asm volatile ("syscall"
578 \\ :
579 \\ : [number] "{rax}" (231),
580 \\ [arg1] "{rdi}" (0)
581 \\ : "rcx", "r11", "memory"
582 \\ );
583 \\ unreachable;
584 \\}
585 ,
586 "",
587 );
588
589 // Character literals and multiline strings.
590 case.addCompareOutput(
591 \\export fn _start() noreturn {
592 \\ const ignore =
593 \\ \\ cool thx
594 \\ \\
595 \\ ;
596 \\ add('ぁ', '\x03');
597 \\
598 \\ exit();
599 \\}
600 \\
601 \\fn add(a: u32, b: u32) void {
602 \\ assert(a + b == 12356);
603 \\}
604 \\
605 \\pub fn assert(ok: bool) void {
606 \\ if (!ok) unreachable; // assertion failure
607 \\}
608 \\
609 \\fn exit() noreturn {
610 \\ asm volatile ("syscall"
611 \\ :
612 \\ : [number] "{rax}" (231),
613 \\ [arg1] "{rdi}" (0)
614 \\ : "rcx", "r11", "memory"
615 \\ );
616 \\ unreachable;
617 \\}
618 ,
619 "",
620 );
621
622 // Global const.
623 case.addCompareOutput(
624 \\export fn _start() noreturn {
625 \\ add(aa, bb);
626 \\
627 \\ exit();
628 \\}
629 \\
630 \\const aa = 'ぁ';
631 \\const bb = '\x03';
632 \\
633 \\fn add(a: u32, b: u32) void {
634 \\ assert(a + b == 12356);
635 \\}
636 \\
637 \\pub fn assert(ok: bool) void {
638 \\ if (!ok) unreachable; // assertion failure
639 \\}
640 \\
641 \\fn exit() noreturn {
642 \\ asm volatile ("syscall"
643 \\ :
644 \\ : [number] "{rax}" (231),
645 \\ [arg1] "{rdi}" (0)
646 \\ : "rcx", "r11", "memory"
647 \\ );
648 \\ unreachable;
649 \\}
650 ,
651 "",
652 );
653 }
654
655 {
656 var case = ctx.exe("wasm function calls", wasi);
657
658 case.addCompareOutput(
659 \\export fn _start() u32 {
660 \\ foo();
661 \\ bar();
662 \\ return 42;
663 \\}
664 \\fn foo() void {
665 \\ bar();
666 \\ bar();
667 \\}
668 \\fn bar() void {}
669 ,
670 "42\n",
671 );
672
673 case.addCompareOutput(
674 \\export fn _start() i64 {
675 \\ bar();
676 \\ foo();
677 \\ foo();
678 \\ bar();
679 \\ foo();
680 \\ bar();
681 \\ return 42;
682 \\}
683 \\fn foo() void {
684 \\ bar();
685 \\}
686 \\fn bar() void {}
687 ,
688 "42\n",
689 );
690
691 case.addCompareOutput(
692 \\export fn _start() f32 {
693 \\ bar();
694 \\ foo();
695 \\ return 42.0;
696 \\}
697 \\fn foo() void {
698 \\ bar();
699 \\ bar();
700 \\ bar();
701 \\}
702 \\fn bar() void {}
703 ,
704 // This is what you get when you take the bits of the IEE-754
705 // representation of 42.0 and reinterpret them as an unsigned
706 // integer. Guess that's a bug in wasmtime.
707 "1109917696\n",
708 );
709 }
710}
test/stage2/compile_errors.zig deleted-135
......@@ -1,135 +0,0 @@
1const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
2const std = @import("std");
3
4const ErrorMsg = @import("../../src-self-hosted/Module.zig").ErrorMsg;
5
6const linux_x64 = std.zig.CrossTarget{
7 .cpu_arch = .x86_64,
8 .os_tag = .linux,
9};
10
11pub fn addCases(ctx: *TestContext) !void {
12 ctx.compileErrorZIR("call undefined local", linux_x64,
13 \\@noreturn = primitive(noreturn)
14 \\
15 \\@start_fnty = fntype([], @noreturn, cc=Naked)
16 \\@start = fn(@start_fnty, {
17 \\ %0 = call(%test, [])
18 \\})
19 // TODO: address inconsistency in this message and the one in the next test
20 , &[_][]const u8{":5:13: error: unrecognized identifier: %test"});
21
22 ctx.compileErrorZIR("call with non-existent target", linux_x64,
23 \\@noreturn = primitive(noreturn)
24 \\
25 \\@start_fnty = fntype([], @noreturn, cc=Naked)
26 \\@start = fn(@start_fnty, {
27 \\ %0 = call(@notafunc, [])
28 \\})
29 \\@0 = str("_start")
30 \\@1 = export(@0, "start")
31 , &[_][]const u8{":5:13: error: decl 'notafunc' not found"});
32
33 // TODO: this error should occur at the call site, not the fntype decl
34 ctx.compileErrorZIR("call naked function", linux_x64,
35 \\@noreturn = primitive(noreturn)
36 \\
37 \\@start_fnty = fntype([], @noreturn, cc=Naked)
38 \\@s = fn(@start_fnty, {})
39 \\@start = fn(@start_fnty, {
40 \\ %0 = call(@s, [])
41 \\})
42 \\@0 = str("_start")
43 \\@1 = export(@0, "start")
44 , &[_][]const u8{":4:9: error: unable to call function with naked calling convention"});
45
46 ctx.incrementalFailureZIR("exported symbol collision", linux_x64,
47 \\@noreturn = primitive(noreturn)
48 \\
49 \\@start_fnty = fntype([], @noreturn)
50 \\@start = fn(@start_fnty, {})
51 \\
52 \\@0 = str("_start")
53 \\@1 = export(@0, "start")
54 \\@2 = export(@0, "start")
55 , &[_][]const u8{":8:13: error: exported symbol collision: _start"},
56 \\@noreturn = primitive(noreturn)
57 \\
58 \\@start_fnty = fntype([], @noreturn)
59 \\@start = fn(@start_fnty, {})
60 \\
61 \\@0 = str("_start")
62 \\@1 = export(@0, "start")
63 );
64
65 ctx.compileError("function redefinition", linux_x64,
66 \\fn entry() void {}
67 \\fn entry() void {}
68 , &[_][]const u8{":2:4: error: redefinition of 'entry'"});
69
70 //ctx.incrementalFailure("function redefinition", linux_x64,
71 // \\fn entry() void {}
72 // \\fn entry() void {}
73 //, &[_][]const u8{":2:4: error: redefinition of 'entry'"},
74 // \\fn entry() void {}
75 //);
76
77 //// TODO: need to make sure this works with other variants of export.
78 //ctx.incrementalFailure("exported symbol collision", linux_x64,
79 // \\export fn entry() void {}
80 // \\export fn entry() void {}
81 //, &[_][]const u8{":2:11: error: redefinition of 'entry'"},
82 // \\export fn entry() void {}
83 //);
84
85 // ctx.incrementalFailure("missing function name", linux_x64,
86 // \\fn() void {}
87 // , &[_][]const u8{":1:3: error: missing function name"},
88 // \\fn a() void {}
89 // );
90
91 // TODO: re-enable these tests.
92 // https://github.com/ziglang/zig/issues/1364
93
94 //ctx.testCompileError(
95 // \\comptime {
96 // \\ return;
97 // \\}
98 //, "1.zig", 2, 5, "return expression outside function definition");
99
100 //ctx.testCompileError(
101 // \\export fn entry() void {
102 // \\ defer return;
103 // \\}
104 //, "1.zig", 2, 11, "cannot return from defer expression");
105
106 //ctx.testCompileError(
107 // \\export fn entry() c_int {
108 // \\ return 36893488147419103232;
109 // \\}
110 //, "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'");
111
112 //ctx.testCompileError(
113 // \\comptime {
114 // \\ var a: *align(4) align(4) i32 = 0;
115 // \\}
116 //, "1.zig", 2, 22, "Extra align qualifier");
117
118 //ctx.testCompileError(
119 // \\comptime {
120 // \\ var b: *const const i32 = 0;
121 // \\}
122 //, "1.zig", 2, 19, "Extra align qualifier");
123
124 //ctx.testCompileError(
125 // \\comptime {
126 // \\ var c: *volatile volatile i32 = 0;
127 // \\}
128 //, "1.zig", 2, 22, "Extra align qualifier");
129
130 //ctx.testCompileError(
131 // \\comptime {
132 // \\ var d: *allowzero allowzero i32 = 0;
133 // \\}
134 //, "1.zig", 2, 23, "Extra align qualifier");
135}
test/stage2/test.zig+720-2
......@@ -1,8 +1,726 @@
1const std = @import("std");
12const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
23
4// self-hosted does not yet support PE executable files / COFF object files
5// or mach-o files. So we do these test cases cross compiling for x86_64-linux.
6const linux_x64 = std.zig.CrossTarget{
7 .cpu_arch = .x86_64,
8 .os_tag = .linux,
9};
10
11const linux_riscv64 = std.zig.CrossTarget{
12 .cpu_arch = .riscv64,
13 .os_tag = .linux,
14};
15
16const wasi = std.zig.CrossTarget{
17 .cpu_arch = .wasm32,
18 .os_tag = .wasi,
19};
20
321pub fn addCases(ctx: *TestContext) !void {
4 try @import("compile_errors.zig").addCases(ctx);
5 try @import("compare_output.zig").addCases(ctx);
622 try @import("zir.zig").addCases(ctx);
723 try @import("cbe.zig").addCases(ctx);
24 {
25 var case = ctx.exe("hello world with updates", linux_x64);
26
27 case.addError("", &[_][]const u8{":1:1: error: no entry point found"});
28
29 // Incorrect return type
30 case.addError(
31 \\export fn _start() noreturn {
32 \\}
33 , &[_][]const u8{":2:1: error: expected noreturn, found void"});
34
35 // Regular old hello world
36 case.addCompareOutput(
37 \\export fn _start() noreturn {
38 \\ print();
39 \\
40 \\ exit();
41 \\}
42 \\
43 \\fn print() void {
44 \\ asm volatile ("syscall"
45 \\ :
46 \\ : [number] "{rax}" (1),
47 \\ [arg1] "{rdi}" (1),
48 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
49 \\ [arg3] "{rdx}" (14)
50 \\ : "rcx", "r11", "memory"
51 \\ );
52 \\ return;
53 \\}
54 \\
55 \\fn exit() noreturn {
56 \\ asm volatile ("syscall"
57 \\ :
58 \\ : [number] "{rax}" (231),
59 \\ [arg1] "{rdi}" (0)
60 \\ : "rcx", "r11", "memory"
61 \\ );
62 \\ unreachable;
63 \\}
64 ,
65 "Hello, World!\n",
66 );
67 // Now change the message only
68 case.addCompareOutput(
69 \\export fn _start() noreturn {
70 \\ print();
71 \\
72 \\ exit();
73 \\}
74 \\
75 \\fn print() void {
76 \\ asm volatile ("syscall"
77 \\ :
78 \\ : [number] "{rax}" (1),
79 \\ [arg1] "{rdi}" (1),
80 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
81 \\ [arg3] "{rdx}" (104)
82 \\ : "rcx", "r11", "memory"
83 \\ );
84 \\ return;
85 \\}
86 \\
87 \\fn exit() noreturn {
88 \\ asm volatile ("syscall"
89 \\ :
90 \\ : [number] "{rax}" (231),
91 \\ [arg1] "{rdi}" (0)
92 \\ : "rcx", "r11", "memory"
93 \\ );
94 \\ unreachable;
95 \\}
96 ,
97 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
98 );
99 // Now we print it twice.
100 case.addCompareOutput(
101 \\export fn _start() noreturn {
102 \\ print();
103 \\ print();
104 \\
105 \\ exit();
106 \\}
107 \\
108 \\fn print() void {
109 \\ asm volatile ("syscall"
110 \\ :
111 \\ : [number] "{rax}" (1),
112 \\ [arg1] "{rdi}" (1),
113 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
114 \\ [arg3] "{rdx}" (104)
115 \\ : "rcx", "r11", "memory"
116 \\ );
117 \\ return;
118 \\}
119 \\
120 \\fn exit() noreturn {
121 \\ asm volatile ("syscall"
122 \\ :
123 \\ : [number] "{rax}" (231),
124 \\ [arg1] "{rdi}" (0)
125 \\ : "rcx", "r11", "memory"
126 \\ );
127 \\ unreachable;
128 \\}
129 ,
130 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
131 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
132 \\
133 );
134 }
135
136 {
137 var case = ctx.exe("hello world", linux_riscv64);
138 // Regular old hello world
139 case.addCompareOutput(
140 \\export fn _start() noreturn {
141 \\ print();
142 \\
143 \\ exit();
144 \\}
145 \\
146 \\fn print() void {
147 \\ asm volatile ("ecall"
148 \\ :
149 \\ : [number] "{a7}" (64),
150 \\ [arg1] "{a0}" (1),
151 \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")),
152 \\ [arg3] "{a2}" ("Hello, World!\n".len)
153 \\ : "rcx", "r11", "memory"
154 \\ );
155 \\ return;
156 \\}
157 \\
158 \\fn exit() noreturn {
159 \\ asm volatile ("ecall"
160 \\ :
161 \\ : [number] "{a7}" (94),
162 \\ [arg1] "{a0}" (0)
163 \\ : "rcx", "r11", "memory"
164 \\ );
165 \\ unreachable;
166 \\}
167 ,
168 "Hello, World!\n",
169 );
170 }
171
172 {
173 var case = ctx.exe("adding numbers at comptime", linux_x64);
174 case.addCompareOutput(
175 \\export fn _start() noreturn {
176 \\ asm volatile ("syscall"
177 \\ :
178 \\ : [number] "{rax}" (1),
179 \\ [arg1] "{rdi}" (1),
180 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
181 \\ [arg3] "{rdx}" (10 + 4)
182 \\ : "rcx", "r11", "memory"
183 \\ );
184 \\ asm volatile ("syscall"
185 \\ :
186 \\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)),
187 \\ [arg1] "{rdi}" (0)
188 \\ : "rcx", "r11", "memory"
189 \\ );
190 \\ unreachable;
191 \\}
192 ,
193 "Hello, World!\n",
194 );
195 }
196
197 {
198 var case = ctx.exe("adding numbers at runtime", linux_x64);
199 case.addCompareOutput(
200 \\export fn _start() noreturn {
201 \\ add(3, 4);
202 \\
203 \\ exit();
204 \\}
205 \\
206 \\fn add(a: u32, b: u32) void {
207 \\ if (a + b != 7) unreachable;
208 \\}
209 \\
210 \\fn exit() noreturn {
211 \\ asm volatile ("syscall"
212 \\ :
213 \\ : [number] "{rax}" (231),
214 \\ [arg1] "{rdi}" (0)
215 \\ : "rcx", "r11", "memory"
216 \\ );
217 \\ unreachable;
218 \\}
219 ,
220 "",
221 );
222 }
223
224 {
225 var case = ctx.exe("substracting numbers at runtime", linux_x64);
226 case.addCompareOutput(
227 \\export fn _start() noreturn {
228 \\ sub(7, 4);
229 \\
230 \\ exit();
231 \\}
232 \\
233 \\fn sub(a: u32, b: u32) void {
234 \\ if (a - b != 3) unreachable;
235 \\}
236 \\
237 \\fn exit() noreturn {
238 \\ asm volatile ("syscall"
239 \\ :
240 \\ : [number] "{rax}" (231),
241 \\ [arg1] "{rdi}" (0)
242 \\ : "rcx", "r11", "memory"
243 \\ );
244 \\ unreachable;
245 \\}
246 ,
247 "",
248 );
249 }
250
251 {
252 var case = ctx.exe("assert function", linux_x64);
253 case.addCompareOutput(
254 \\export fn _start() noreturn {
255 \\ add(3, 4);
256 \\
257 \\ exit();
258 \\}
259 \\
260 \\fn add(a: u32, b: u32) void {
261 \\ assert(a + b == 7);
262 \\}
263 \\
264 \\pub fn assert(ok: bool) void {
265 \\ if (!ok) unreachable; // assertion failure
266 \\}
267 \\
268 \\fn exit() noreturn {
269 \\ asm volatile ("syscall"
270 \\ :
271 \\ : [number] "{rax}" (231),
272 \\ [arg1] "{rdi}" (0)
273 \\ : "rcx", "r11", "memory"
274 \\ );
275 \\ unreachable;
276 \\}
277 ,
278 "",
279 );
280
281 // Tests copying a register. For the `c = a + b`, it has to
282 // preserve both a and b, because they are both used later.
283 case.addCompareOutput(
284 \\export fn _start() noreturn {
285 \\ add(3, 4);
286 \\
287 \\ exit();
288 \\}
289 \\
290 \\fn add(a: u32, b: u32) void {
291 \\ const c = a + b; // 7
292 \\ const d = a + c; // 10
293 \\ const e = d + b; // 14
294 \\ assert(e == 14);
295 \\}
296 \\
297 \\pub fn assert(ok: bool) void {
298 \\ if (!ok) unreachable; // assertion failure
299 \\}
300 \\
301 \\fn exit() noreturn {
302 \\ asm volatile ("syscall"
303 \\ :
304 \\ : [number] "{rax}" (231),
305 \\ [arg1] "{rdi}" (0)
306 \\ : "rcx", "r11", "memory"
307 \\ );
308 \\ unreachable;
309 \\}
310 ,
311 "",
312 );
313
314 // More stress on the liveness detection.
315 case.addCompareOutput(
316 \\export fn _start() noreturn {
317 \\ add(3, 4);
318 \\
319 \\ exit();
320 \\}
321 \\
322 \\fn add(a: u32, b: u32) void {
323 \\ const c = a + b; // 7
324 \\ const d = a + c; // 10
325 \\ const e = d + b; // 14
326 \\ const f = d + e; // 24
327 \\ const g = e + f; // 38
328 \\ const h = f + g; // 62
329 \\ const i = g + h; // 100
330 \\ assert(i == 100);
331 \\}
332 \\
333 \\pub fn assert(ok: bool) void {
334 \\ if (!ok) unreachable; // assertion failure
335 \\}
336 \\
337 \\fn exit() noreturn {
338 \\ asm volatile ("syscall"
339 \\ :
340 \\ : [number] "{rax}" (231),
341 \\ [arg1] "{rdi}" (0)
342 \\ : "rcx", "r11", "memory"
343 \\ );
344 \\ unreachable;
345 \\}
346 ,
347 "",
348 );
349
350 // Requires a second move. The register allocator should figure out to re-use rax.
351 case.addCompareOutput(
352 \\export fn _start() noreturn {
353 \\ add(3, 4);
354 \\
355 \\ exit();
356 \\}
357 \\
358 \\fn add(a: u32, b: u32) void {
359 \\ const c = a + b; // 7
360 \\ const d = a + c; // 10
361 \\ const e = d + b; // 14
362 \\ const f = d + e; // 24
363 \\ const g = e + f; // 38
364 \\ const h = f + g; // 62
365 \\ const i = g + h; // 100
366 \\ const j = i + d; // 110
367 \\ assert(j == 110);
368 \\}
369 \\
370 \\pub fn assert(ok: bool) void {
371 \\ if (!ok) unreachable; // assertion failure
372 \\}
373 \\
374 \\fn exit() noreturn {
375 \\ asm volatile ("syscall"
376 \\ :
377 \\ : [number] "{rax}" (231),
378 \\ [arg1] "{rdi}" (0)
379 \\ : "rcx", "r11", "memory"
380 \\ );
381 \\ unreachable;
382 \\}
383 ,
384 "",
385 );
386
387 // Now we test integer return values.
388 case.addCompareOutput(
389 \\export fn _start() noreturn {
390 \\ assert(add(3, 4) == 7);
391 \\ assert(add(20, 10) == 30);
392 \\
393 \\ exit();
394 \\}
395 \\
396 \\fn add(a: u32, b: u32) u32 {
397 \\ return a + b;
398 \\}
399 \\
400 \\pub fn assert(ok: bool) void {
401 \\ if (!ok) unreachable; // assertion failure
402 \\}
403 \\
404 \\fn exit() noreturn {
405 \\ asm volatile ("syscall"
406 \\ :
407 \\ : [number] "{rax}" (231),
408 \\ [arg1] "{rdi}" (0)
409 \\ : "rcx", "r11", "memory"
410 \\ );
411 \\ unreachable;
412 \\}
413 ,
414 "",
415 );
416
417 // Local mutable variables.
418 case.addCompareOutput(
419 \\export fn _start() noreturn {
420 \\ assert(add(3, 4) == 7);
421 \\ assert(add(20, 10) == 30);
422 \\
423 \\ exit();
424 \\}
425 \\
426 \\fn add(a: u32, b: u32) u32 {
427 \\ var x: u32 = undefined;
428 \\ x = 0;
429 \\ x += a;
430 \\ x += b;
431 \\ return x;
432 \\}
433 \\
434 \\pub fn assert(ok: bool) void {
435 \\ if (!ok) unreachable; // assertion failure
436 \\}
437 \\
438 \\fn exit() noreturn {
439 \\ asm volatile ("syscall"
440 \\ :
441 \\ : [number] "{rax}" (231),
442 \\ [arg1] "{rdi}" (0)
443 \\ : "rcx", "r11", "memory"
444 \\ );
445 \\ unreachable;
446 \\}
447 ,
448 "",
449 );
450
451 // Optionals
452 case.addCompareOutput(
453 \\export fn _start() noreturn {
454 \\ const a: u32 = 2;
455 \\ const b: ?u32 = a;
456 \\ const c = b.?;
457 \\ if (c != 2) unreachable;
458 \\
459 \\ exit();
460 \\}
461 \\
462 \\fn exit() noreturn {
463 \\ asm volatile ("syscall"
464 \\ :
465 \\ : [number] "{rax}" (231),
466 \\ [arg1] "{rdi}" (0)
467 \\ : "rcx", "r11", "memory"
468 \\ );
469 \\ unreachable;
470 \\}
471 ,
472 "",
473 );
474
475 // While loops
476 case.addCompareOutput(
477 \\export fn _start() noreturn {
478 \\ var i: u32 = 0;
479 \\ while (i < 4) : (i += 1) print();
480 \\ assert(i == 4);
481 \\
482 \\ exit();
483 \\}
484 \\
485 \\fn print() void {
486 \\ asm volatile ("syscall"
487 \\ :
488 \\ : [number] "{rax}" (1),
489 \\ [arg1] "{rdi}" (1),
490 \\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
491 \\ [arg3] "{rdx}" (6)
492 \\ : "rcx", "r11", "memory"
493 \\ );
494 \\ return;
495 \\}
496 \\
497 \\pub fn assert(ok: bool) void {
498 \\ if (!ok) unreachable; // assertion failure
499 \\}
500 \\
501 \\fn exit() noreturn {
502 \\ asm volatile ("syscall"
503 \\ :
504 \\ : [number] "{rax}" (231),
505 \\ [arg1] "{rdi}" (0)
506 \\ : "rcx", "r11", "memory"
507 \\ );
508 \\ unreachable;
509 \\}
510 ,
511 "hello\nhello\nhello\nhello\n",
512 );
513
514 // Labeled blocks (no conditional branch)
515 case.addCompareOutput(
516 \\export fn _start() noreturn {
517 \\ assert(add(3, 4) == 20);
518 \\
519 \\ exit();
520 \\}
521 \\
522 \\fn add(a: u32, b: u32) u32 {
523 \\ const x: u32 = blk: {
524 \\ const c = a + b; // 7
525 \\ const d = a + c; // 10
526 \\ const e = d + b; // 14
527 \\ break :blk e;
528 \\ };
529 \\ const y = x + a; // 17
530 \\ const z = y + a; // 20
531 \\ return z;
532 \\}
533 \\
534 \\pub fn assert(ok: bool) void {
535 \\ if (!ok) unreachable; // assertion failure
536 \\}
537 \\
538 \\fn exit() noreturn {
539 \\ asm volatile ("syscall"
540 \\ :
541 \\ : [number] "{rax}" (231),
542 \\ [arg1] "{rdi}" (0)
543 \\ : "rcx", "r11", "memory"
544 \\ );
545 \\ unreachable;
546 \\}
547 ,
548 "",
549 );
550
551 // This catches a possible bug in the logic for re-using dying operands.
552 case.addCompareOutput(
553 \\export fn _start() noreturn {
554 \\ assert(add(3, 4) == 116);
555 \\
556 \\ exit();
557 \\}
558 \\
559 \\fn add(a: u32, b: u32) u32 {
560 \\ const x: u32 = blk: {
561 \\ const c = a + b; // 7
562 \\ const d = a + c; // 10
563 \\ const e = d + b; // 14
564 \\ const f = d + e; // 24
565 \\ const g = e + f; // 38
566 \\ const h = f + g; // 62
567 \\ const i = g + h; // 100
568 \\ const j = i + d; // 110
569 \\ break :blk j;
570 \\ };
571 \\ const y = x + a; // 113
572 \\ const z = y + a; // 116
573 \\ return z;
574 \\}
575 \\
576 \\pub fn assert(ok: bool) void {
577 \\ if (!ok) unreachable; // assertion failure
578 \\}
579 \\
580 \\fn exit() noreturn {
581 \\ asm volatile ("syscall"
582 \\ :
583 \\ : [number] "{rax}" (231),
584 \\ [arg1] "{rdi}" (0)
585 \\ : "rcx", "r11", "memory"
586 \\ );
587 \\ unreachable;
588 \\}
589 ,
590 "",
591 );
592
593 // Character literals and multiline strings.
594 case.addCompareOutput(
595 \\export fn _start() noreturn {
596 \\ const ignore =
597 \\ \\ cool thx
598 \\ \\
599 \\ ;
600 \\ add('ぁ', '\x03');
601 \\
602 \\ exit();
603 \\}
604 \\
605 \\fn add(a: u32, b: u32) void {
606 \\ assert(a + b == 12356);
607 \\}
608 \\
609 \\pub fn assert(ok: bool) void {
610 \\ if (!ok) unreachable; // assertion failure
611 \\}
612 \\
613 \\fn exit() noreturn {
614 \\ asm volatile ("syscall"
615 \\ :
616 \\ : [number] "{rax}" (231),
617 \\ [arg1] "{rdi}" (0)
618 \\ : "rcx", "r11", "memory"
619 \\ );
620 \\ unreachable;
621 \\}
622 ,
623 "",
624 );
625
626 // Global const.
627 case.addCompareOutput(
628 \\export fn _start() noreturn {
629 \\ add(aa, bb);
630 \\
631 \\ exit();
632 \\}
633 \\
634 \\const aa = 'ぁ';
635 \\const bb = '\x03';
636 \\
637 \\fn add(a: u32, b: u32) void {
638 \\ assert(a + b == 12356);
639 \\}
640 \\
641 \\pub fn assert(ok: bool) void {
642 \\ if (!ok) unreachable; // assertion failure
643 \\}
644 \\
645 \\fn exit() noreturn {
646 \\ asm volatile ("syscall"
647 \\ :
648 \\ : [number] "{rax}" (231),
649 \\ [arg1] "{rdi}" (0)
650 \\ : "rcx", "r11", "memory"
651 \\ );
652 \\ unreachable;
653 \\}
654 ,
655 "",
656 );
657 }
658
659 {
660 var case = ctx.exe("wasm function calls", wasi);
661
662 case.addCompareOutput(
663 \\export fn _start() u32 {
664 \\ foo();
665 \\ bar();
666 \\ return 42;
667 \\}
668 \\fn foo() void {
669 \\ bar();
670 \\ bar();
671 \\}
672 \\fn bar() void {}
673 ,
674 "42\n",
675 );
676
677 case.addCompareOutput(
678 \\export fn _start() i64 {
679 \\ bar();
680 \\ foo();
681 \\ foo();
682 \\ bar();
683 \\ foo();
684 \\ bar();
685 \\ return 42;
686 \\}
687 \\fn foo() void {
688 \\ bar();
689 \\}
690 \\fn bar() void {}
691 ,
692 "42\n",
693 );
694
695 case.addCompareOutput(
696 \\export fn _start() f32 {
697 \\ bar();
698 \\ foo();
699 \\ return 42.0;
700 \\}
701 \\fn foo() void {
702 \\ bar();
703 \\ bar();
704 \\ bar();
705 \\}
706 \\fn bar() void {}
707 ,
708 // This is what you get when you take the bits of the IEE-754
709 // representation of 42.0 and reinterpret them as an unsigned
710 // integer. Guess that's a bug in wasmtime.
711 "1109917696\n",
712 );
713 }
714
715 ctx.compileError("function redefinition", linux_x64,
716 \\fn entry() void {}
717 \\fn entry() void {}
718 , &[_][]const u8{":2:4: error: redefinition of 'entry'"});
719
720 ctx.compileError("extern variable has no type", linux_x64,
721 \\comptime {
722 \\ _ = foo;
723 \\}
724 \\extern var foo;
725 , &[_][]const u8{":4:1: error: unable to infer variable type"});
8726}