| author | |
| committer | |
| log | 6bbb168f6667520dc106bc93c6e3761d5611fccb |
| tree | c12be20be24223f37ab9a3c6cfdb9db8e7d263b4 |
| parent | eef111fe78d7b246b634a07561082a6fcf947e09 |
| parent | 73d16d015e09c05aecba8a58881cbc429e8126fa |
closes #61079 files changed, 1295 insertions(+), 928 deletions(-)
src-self-hosted/Module.zig+100-10| ... | ... | @@ -1485,6 +1485,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1485 | 1485 | const type_node = var_decl.getTrailer("type_node") orelse |
| 1486 | 1486 | break :blk null; |
| 1487 | 1487 | |
| 1488 | // Temporary arena for the zir instructions. | |
| 1488 | 1489 | var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa); |
| 1489 | 1490 | defer type_scope_arena.deinit(); |
| 1490 | 1491 | var type_scope: Scope.GenZIR = .{ |
| ... | ... | @@ -1539,7 +1540,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1539 | 1540 | try self.coerce(&inner_block.base, some, ret.operand) |
| 1540 | 1541 | else |
| 1541 | 1542 | 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", .{}); | |
| 1543 | 1545 | |
| 1544 | 1546 | var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena); |
| 1545 | 1547 | break :blk try val.copy(block_scope.arena); |
| ... | ... | @@ -1603,7 +1605,41 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1603 | 1605 | } |
| 1604 | 1606 | return type_changed; |
| 1605 | 1607 | }, |
| 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 | }, | |
| 1607 | 1643 | .Use => @panic("TODO usingnamespace decl"), |
| 1608 | 1644 | else => unreachable, |
| 1609 | 1645 | } |
| ... | ... | @@ -1794,7 +1830,16 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { |
| 1794 | 1830 | } |
| 1795 | 1831 | } |
| 1796 | 1832 | } 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 }); | |
| 1798 | 1843 | } else if (src_decl.castTag(.ContainerField)) |container_field| { |
| 1799 | 1844 | log.err("TODO: analyze container field", .{}); |
| 1800 | 1845 | } else if (src_decl.castTag(.TestDecl)) |test_decl| { |
| ... | ... | @@ -2429,7 +2474,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn |
| 2429 | 2474 | if (decl_tv.val.tag() == .variable) { |
| 2430 | 2475 | return self.analyzeVarRef(scope, src, decl_tv); |
| 2431 | 2476 | } |
| 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); | |
| 2433 | 2478 | const val_payload = try scope.arena().create(Value.Payload.DeclRef); |
| 2434 | 2479 | val_payload.* = .{ .decl = decl }; |
| 2435 | 2480 | |
| ... | ... | @@ -2442,7 +2487,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn |
| 2442 | 2487 | fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { |
| 2443 | 2488 | const variable = tv.val.cast(Value.Payload.Variable).?.variable; |
| 2444 | 2489 | |
| 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); | |
| 2446 | 2491 | if (!variable.is_mutable and !variable.is_extern) { |
| 2447 | 2492 | const val_payload = try scope.arena().create(Value.Payload.RefVal); |
| 2448 | 2493 | val_payload.* = .{ .val = variable.init }; |
| ... | ... | @@ -2766,7 +2811,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst |
| 2766 | 2811 | |
| 2767 | 2812 | // T to ?T |
| 2768 | 2813 | if (dest_type.zigTypeTag() == .Optional) { |
| 2769 | var buf: Type.Payload.Pointer = undefined; | |
| 2814 | var buf: Type.Payload.PointerSimple = undefined; | |
| 2770 | 2815 | const child_type = dest_type.optionalChild(&buf); |
| 2771 | 2816 | if (child_type.eql(inst.ty)) { |
| 2772 | 2817 | return self.wrapOptional(scope, dest_type, inst); |
| ... | ... | @@ -3145,11 +3190,56 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: |
| 3145 | 3190 | return Value.initPayload(val_payload); |
| 3146 | 3191 | } |
| 3147 | 3192 | |
| 3148 | pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) Allocator.Error!Type { | |
| 3193 | pub 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 | ||
| 3215 | pub 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 | |
| 3149 | 3232 | const type_payload = try scope.arena().create(Type.Payload.Pointer); |
| 3150 | 3233 | type_payload.* = .{ |
| 3151 | .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer }, | |
| 3152 | 3234 | .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, | |
| 3153 | 3243 | }; |
| 3154 | 3244 | return Type.initPayload(&type_payload.base); |
| 3155 | 3245 | } |
| ... | ... | @@ -3157,7 +3247,7 @@ pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, el |
| 3157 | 3247 | pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type { |
| 3158 | 3248 | return Type.initPayload(switch (child_type.tag()) { |
| 3159 | 3249 | .single_const_pointer => blk: { |
| 3160 | const payload = try scope.arena().create(Type.Payload.Pointer); | |
| 3250 | const payload = try scope.arena().create(Type.Payload.PointerSimple); | |
| 3161 | 3251 | payload.* = .{ |
| 3162 | 3252 | .base = .{ .tag = .optional_single_const_pointer }, |
| 3163 | 3253 | .pointee_type = child_type.elemType(), |
| ... | ... | @@ -3165,7 +3255,7 @@ pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Er |
| 3165 | 3255 | break :blk &payload.base; |
| 3166 | 3256 | }, |
| 3167 | 3257 | .single_mut_pointer => blk: { |
| 3168 | const payload = try scope.arena().create(Type.Payload.Pointer); | |
| 3258 | const payload = try scope.arena().create(Type.Payload.PointerSimple); | |
| 3169 | 3259 | payload.* = .{ |
| 3170 | 3260 | .base = .{ .tag = .optional_single_mut_pointer }, |
| 3171 | 3261 | .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 |
| 262 | 262 | .EnumLiteral => return rlWrap(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)), |
| 263 | 263 | .MultilineStringLiteral => return rlWrap(mod, scope, rl, try multilineStrLiteral(mod, scope, node.castTag(.MultilineStringLiteral).?)), |
| 264 | 264 | .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).?)), | |
| 265 | 266 | |
| 266 | 267 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| 267 | 268 | .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 |
| 275 | 276 | .NegationWrap => return mod.failNode(scope, node, "TODO implement astgen.expr for .NegationWrap", .{}), |
| 276 | 277 | .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}), |
| 277 | 278 | .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", .{}), | |
| 279 | 279 | .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}), |
| 280 | 280 | .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}), |
| 281 | 281 | .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 |
| 569 | 569 | return addZIRUnOp(mod, scope, src, .optional_type, operand); |
| 570 | 570 | } |
| 571 | 571 | |
| 572 | fn 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 | ||
| 572 | 578 | fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst { |
| 573 | 579 | const tree = scope.tree(); |
| 574 | 580 | 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 | ||
| 592 | fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, rhs: *ast.Node, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*zir.Inst { | |
| 575 | 593 | const meta_type = try addZIRInstConst(mod, scope, src, .{ |
| 576 | 594 | .ty = Type.initTag(.type), |
| 577 | 595 | .val = Value.initTag(.type_type), |
| 578 | 596 | }); |
| 579 | 597 | |
| 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; | |
| 584 | 602 | |
| 585 | 603 | 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); | |
| 591 | 614 | } |
| 592 | 615 | |
| 593 | 616 | 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| { | |
| 596 | 620 | kw_args.@"align" = try expr(mod, scope, .none, some.node); |
| 597 | 621 | if (some.bit_range) |bit_range| { |
| 598 | 622 | kw_args.align_bit_start = try expr(mod, scope, .none, bit_range.start); |
| 599 | 623 | kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end); |
| 600 | 624 | } |
| 601 | 625 | } |
| 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| { | |
| 605 | 629 | kw_args.sentinel = try expr(mod, scope, .none, some); |
| 606 | 630 | } |
| 607 | 631 | |
| 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); | |
| 609 | 633 | if (kw_args.sentinel) |some| { |
| 610 | 634 | kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some); |
| 611 | 635 | } |
| ... | ... | @@ -1271,7 +1295,7 @@ fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStr |
| 1271 | 1295 | i += 1; |
| 1272 | 1296 | } |
| 1273 | 1297 | 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]); | |
| 1275 | 1299 | i += slice.len - 3; |
| 1276 | 1300 | } |
| 1277 | 1301 |
src-self-hosted/codegen.zig+1-1| ... | ... | @@ -2060,7 +2060,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2060 | 2060 | if (typed_value.val.isNull()) |
| 2061 | 2061 | return MCValue{ .immediate = 0 }; |
| 2062 | 2062 | |
| 2063 | var buf: Type.Payload.Pointer = undefined; | |
| 2063 | var buf: Type.Payload.PointerSimple = undefined; | |
| 2064 | 2064 | return self.genTypedValue(src, .{ |
| 2065 | 2065 | .ty = typed_value.ty.optionalChild(&buf), |
| 2066 | 2066 | .val = typed_value.val, |
src-self-hosted/type.zig+344-34| ... | ... | @@ -66,10 +66,18 @@ pub const Type = extern union { |
| 66 | 66 | .function => return .Fn, |
| 67 | 67 | |
| 68 | 68 | .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, | |
| 73 | 81 | |
| 74 | 82 | .optional, |
| 75 | 83 | .optional_single_const_pointer, |
| ... | ... | @@ -108,13 +116,19 @@ pub const Type = extern union { |
| 108 | 116 | return @fieldParentPtr(T, "base", self.ptr_otherwise); |
| 109 | 117 | } |
| 110 | 118 | |
| 111 | pub fn castPointer(self: Type) ?*Payload.Pointer { | |
| 119 | pub fn castPointer(self: Type) ?*Payload.PointerSimple { | |
| 112 | 120 | return switch (self.tag()) { |
| 113 | 121 | .single_const_pointer, |
| 114 | 122 | .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, | |
| 115 | 129 | .optional_single_const_pointer, |
| 116 | 130 | .optional_single_mut_pointer, |
| 117 | => @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise), | |
| 131 | => @fieldParentPtr(Payload.PointerSimple, "base", self.ptr_otherwise), | |
| 118 | 132 | else => null, |
| 119 | 133 | }; |
| 120 | 134 | } |
| ... | ... | @@ -198,8 +212,8 @@ pub const Type = extern union { |
| 198 | 212 | return true; |
| 199 | 213 | }, |
| 200 | 214 | .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; | |
| 203 | 217 | return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b)); |
| 204 | 218 | }, |
| 205 | 219 | .Float, |
| ... | ... | @@ -263,7 +277,7 @@ pub const Type = extern union { |
| 263 | 277 | } |
| 264 | 278 | }, |
| 265 | 279 | .Optional => { |
| 266 | var buf: Payload.Pointer = undefined; | |
| 280 | var buf: Payload.PointerSimple = undefined; | |
| 267 | 281 | std.hash.autoHash(&hasher, self.optionalChild(&buf).hash()); |
| 268 | 282 | }, |
| 269 | 283 | .Float, |
| ... | ... | @@ -374,9 +388,34 @@ pub const Type = extern union { |
| 374 | 388 | .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"), |
| 375 | 389 | .single_const_pointer, |
| 376 | 390 | .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, | |
| 377 | 397 | .optional_single_mut_pointer, |
| 378 | 398 | .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 | }, | |
| 380 | 419 | } |
| 381 | 420 | } |
| 382 | 421 | |
| ... | ... | @@ -482,17 +521,53 @@ pub const Type = extern union { |
| 482 | 521 | continue; |
| 483 | 522 | }, |
| 484 | 523 | .single_const_pointer => { |
| 485 | const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); | |
| 524 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 486 | 525 | try out_stream.writeAll("*const "); |
| 487 | 526 | ty = payload.pointee_type; |
| 488 | 527 | continue; |
| 489 | 528 | }, |
| 490 | 529 | .single_mut_pointer => { |
| 491 | const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); | |
| 530 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 492 | 531 | try out_stream.writeAll("*"); |
| 493 | 532 | ty = payload.pointee_type; |
| 494 | 533 | continue; |
| 495 | 534 | }, |
| 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 | }, | |
| 496 | 571 | .int_signed => { |
| 497 | 572 | const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise); |
| 498 | 573 | return out_stream.print("i{}", .{payload.bits}); |
| ... | ... | @@ -508,17 +583,45 @@ pub const Type = extern union { |
| 508 | 583 | continue; |
| 509 | 584 | }, |
| 510 | 585 | .optional_single_const_pointer => { |
| 511 | const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); | |
| 586 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 512 | 587 | try out_stream.writeAll("?*const "); |
| 513 | 588 | ty = payload.pointee_type; |
| 514 | 589 | continue; |
| 515 | 590 | }, |
| 516 | 591 | .optional_single_mut_pointer => { |
| 517 | const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); | |
| 592 | const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); | |
| 518 | 593 | try out_stream.writeAll("?*"); |
| 519 | 594 | ty = payload.pointee_type; |
| 520 | 595 | continue; |
| 521 | 596 | }, |
| 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 | }, | |
| 522 | 625 | } |
| 523 | 626 | unreachable; |
| 524 | 627 | } |
| ... | ... | @@ -616,9 +719,7 @@ pub const Type = extern union { |
| 616 | 719 | // TODO lazy types |
| 617 | 720 | .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, |
| 618 | 721 | .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(), | |
| 622 | 723 | .int_signed => self.cast(Payload.IntSigned).?.bits == 0, |
| 623 | 724 | .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, |
| 624 | 725 | |
| ... | ... | @@ -669,10 +770,23 @@ pub const Type = extern union { |
| 669 | 770 | .const_slice_u8, |
| 670 | 771 | .single_const_pointer, |
| 671 | 772 | .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, | |
| 672 | 779 | .optional_single_const_pointer, |
| 673 | 780 | .optional_single_mut_pointer, |
| 674 | 781 | => return @divExact(target.cpu.arch.ptrBitWidth(), 8), |
| 675 | 782 | |
| 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 | ||
| 676 | 790 | .c_short => return @divExact(CType.short.sizeInBits(target), 8), |
| 677 | 791 | .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), |
| 678 | 792 | .c_int => return @divExact(CType.int.sizeInBits(target), 8), |
| ... | ... | @@ -704,7 +818,7 @@ pub const Type = extern union { |
| 704 | 818 | }, |
| 705 | 819 | |
| 706 | 820 | .optional => { |
| 707 | var buf: Payload.Pointer = undefined; | |
| 821 | var buf: Payload.PointerSimple = undefined; | |
| 708 | 822 | const child_type = self.optionalChild(&buf); |
| 709 | 823 | if (!child_type.hasCodeGenBits()) return 1; |
| 710 | 824 | |
| ... | ... | @@ -744,6 +858,7 @@ pub const Type = extern union { |
| 744 | 858 | .@"null" => unreachable, |
| 745 | 859 | .@"undefined" => unreachable, |
| 746 | 860 | .enum_literal => unreachable, |
| 861 | .single_const_pointer_to_comptime_int => unreachable, | |
| 747 | 862 | |
| 748 | 863 | .u8, |
| 749 | 864 | .i8, |
| ... | ... | @@ -766,15 +881,31 @@ pub const Type = extern union { |
| 766 | 881 | .i32, .u32 => return 4, |
| 767 | 882 | .i64, .u64 => return 8, |
| 768 | 883 | |
| 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, | |
| 772 | 888 | .const_slice_u8, |
| 773 | .single_const_pointer, | |
| 774 | .single_mut_pointer, | |
| 889 | => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, | |
| 890 | ||
| 775 | 891 | .optional_single_const_pointer, |
| 776 | 892 | .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 | }, | |
| 778 | 909 | |
| 779 | 910 | .c_short => return @divExact(CType.short.sizeInBits(target), 8), |
| 780 | 911 | .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), |
| ... | ... | @@ -805,7 +936,7 @@ pub const Type = extern union { |
| 805 | 936 | }, |
| 806 | 937 | |
| 807 | 938 | .optional => { |
| 808 | var buf: Payload.Pointer = undefined; | |
| 939 | var buf: Payload.PointerSimple = undefined; | |
| 809 | 940 | const child_type = self.optionalChild(&buf); |
| 810 | 941 | if (!child_type.hasCodeGenBits()) return 1; |
| 811 | 942 | |
| ... | ... | @@ -872,12 +1003,20 @@ pub const Type = extern union { |
| 872 | 1003 | .optional_single_mut_pointer, |
| 873 | 1004 | .optional_single_const_pointer, |
| 874 | 1005 | .enum_literal, |
| 1006 | .many_const_pointer, | |
| 1007 | .many_mut_pointer, | |
| 1008 | .c_const_pointer, | |
| 1009 | .c_mut_pointer, | |
| 1010 | .const_slice, | |
| 1011 | .mut_slice, | |
| 875 | 1012 | => false, |
| 876 | 1013 | |
| 877 | 1014 | .single_const_pointer, |
| 878 | 1015 | .single_mut_pointer, |
| 879 | 1016 | .single_const_pointer_to_comptime_int, |
| 880 | 1017 | => true, |
| 1018 | ||
| 1019 | .pointer => self.cast(Payload.Pointer).?.size == .One, | |
| 881 | 1020 | }; |
| 882 | 1021 | } |
| 883 | 1022 | |
| ... | ... | @@ -922,6 +1061,10 @@ pub const Type = extern union { |
| 922 | 1061 | .array_u8_sentinel_0, |
| 923 | 1062 | .single_const_pointer, |
| 924 | 1063 | .single_mut_pointer, |
| 1064 | .many_const_pointer, | |
| 1065 | .many_mut_pointer, | |
| 1066 | .c_const_pointer, | |
| 1067 | .c_mut_pointer, | |
| 925 | 1068 | .single_const_pointer_to_comptime_int, |
| 926 | 1069 | .fn_noreturn_no_args, |
| 927 | 1070 | .fn_void_no_args, |
| ... | ... | @@ -936,7 +1079,12 @@ pub const Type = extern union { |
| 936 | 1079 | .enum_literal, |
| 937 | 1080 | => false, |
| 938 | 1081 | |
| 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, | |
| 940 | 1088 | }; |
| 941 | 1089 | } |
| 942 | 1090 | |
| ... | ... | @@ -987,16 +1135,24 @@ pub const Type = extern union { |
| 987 | 1135 | .int_unsigned, |
| 988 | 1136 | .int_signed, |
| 989 | 1137 | .single_mut_pointer, |
| 1138 | .many_mut_pointer, | |
| 1139 | .c_mut_pointer, | |
| 990 | 1140 | .optional, |
| 991 | 1141 | .optional_single_mut_pointer, |
| 992 | 1142 | .optional_single_const_pointer, |
| 993 | 1143 | .enum_literal, |
| 1144 | .mut_slice, | |
| 994 | 1145 | => false, |
| 995 | 1146 | |
| 996 | 1147 | .single_const_pointer, |
| 1148 | .many_const_pointer, | |
| 1149 | .c_const_pointer, | |
| 997 | 1150 | .single_const_pointer_to_comptime_int, |
| 998 | 1151 | .const_slice_u8, |
| 1152 | .const_slice, | |
| 999 | 1153 | => true, |
| 1154 | ||
| 1155 | .pointer => !self.cast(Payload.Pointer).?.mutable, | |
| 1000 | 1156 | }; |
| 1001 | 1157 | } |
| 1002 | 1158 | |
| ... | ... | @@ -1048,6 +1204,12 @@ pub const Type = extern union { |
| 1048 | 1204 | .int_signed, |
| 1049 | 1205 | .single_mut_pointer, |
| 1050 | 1206 | .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, | |
| 1051 | 1213 | .single_const_pointer_to_comptime_int, |
| 1052 | 1214 | .const_slice_u8, |
| 1053 | 1215 | .optional, |
| ... | ... | @@ -1055,6 +1217,11 @@ pub const Type = extern union { |
| 1055 | 1217 | .optional_single_const_pointer, |
| 1056 | 1218 | .enum_literal, |
| 1057 | 1219 | => false, |
| 1220 | ||
| 1221 | .pointer => { | |
| 1222 | const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); | |
| 1223 | return payload.@"volatile"; | |
| 1224 | }, | |
| 1058 | 1225 | }; |
| 1059 | 1226 | } |
| 1060 | 1227 | |
| ... | ... | @@ -1063,7 +1230,7 @@ pub const Type = extern union { |
| 1063 | 1230 | switch (self.tag()) { |
| 1064 | 1231 | .optional_single_const_pointer, .optional_single_mut_pointer => return true, |
| 1065 | 1232 | .optional => { |
| 1066 | var buf: Payload.Pointer = undefined; | |
| 1233 | var buf: Payload.PointerSimple = undefined; | |
| 1067 | 1234 | const child_type = self.optionalChild(&buf); |
| 1068 | 1235 | // optionals of zero sized pointers behave like bools |
| 1069 | 1236 | if (!child_type.hasCodeGenBits()) return false; |
| ... | ... | @@ -1101,7 +1268,7 @@ pub const Type = extern union { |
| 1101 | 1268 | => return false, |
| 1102 | 1269 | |
| 1103 | 1270 | .Optional => { |
| 1104 | var buf: Payload.Pointer = undefined; | |
| 1271 | var buf: Payload.PointerSimple = undefined; | |
| 1105 | 1272 | return ty.optionalChild(&buf).isValidVarType(is_extern); |
| 1106 | 1273 | }, |
| 1107 | 1274 | .Pointer, .Array => ty = ty.elemType(), |
| ... | ... | @@ -1164,15 +1331,23 @@ pub const Type = extern union { |
| 1164 | 1331 | |
| 1165 | 1332 | .array => self.cast(Payload.Array).?.elem_type, |
| 1166 | 1333 | .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, | |
| 1169 | 1343 | .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), |
| 1170 | 1344 | .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), |
| 1345 | .pointer => self.cast(Payload.Pointer).?.pointee_type, | |
| 1171 | 1346 | }; |
| 1172 | 1347 | } |
| 1173 | 1348 | |
| 1174 | 1349 | /// 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 { | |
| 1176 | 1351 | return switch (self.tag()) { |
| 1177 | 1352 | .optional => self.cast(Payload.Optional).?.child_type, |
| 1178 | 1353 | .optional_single_mut_pointer => { |
| ... | ... | @@ -1199,7 +1374,7 @@ pub const Type = extern union { |
| 1199 | 1374 | return switch (self.tag()) { |
| 1200 | 1375 | .optional => self.cast(Payload.Optional).?.child_type, |
| 1201 | 1376 | .optional_single_mut_pointer, .optional_single_const_pointer => { |
| 1202 | const payload = try allocator.create(Payload.Pointer); | |
| 1377 | const payload = try allocator.create(Payload.PointerSimple); | |
| 1203 | 1378 | payload.* = .{ |
| 1204 | 1379 | .base = .{ |
| 1205 | 1380 | .tag = if (self.tag() == .optional_single_const_pointer) |
| ... | ... | @@ -1256,8 +1431,15 @@ pub const Type = extern union { |
| 1256 | 1431 | .fn_naked_noreturn_no_args, |
| 1257 | 1432 | .fn_ccc_void_no_args, |
| 1258 | 1433 | .function, |
| 1434 | .pointer, | |
| 1259 | 1435 | .single_const_pointer, |
| 1260 | 1436 | .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, | |
| 1261 | 1443 | .single_const_pointer_to_comptime_int, |
| 1262 | 1444 | .const_slice_u8, |
| 1263 | 1445 | .int_unsigned, |
| ... | ... | @@ -1316,8 +1498,15 @@ pub const Type = extern union { |
| 1316 | 1498 | .fn_naked_noreturn_no_args, |
| 1317 | 1499 | .fn_ccc_void_no_args, |
| 1318 | 1500 | .function, |
| 1501 | .pointer, | |
| 1319 | 1502 | .single_const_pointer, |
| 1320 | 1503 | .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, | |
| 1321 | 1510 | .single_const_pointer_to_comptime_int, |
| 1322 | 1511 | .const_slice_u8, |
| 1323 | 1512 | .int_unsigned, |
| ... | ... | @@ -1366,8 +1555,15 @@ pub const Type = extern union { |
| 1366 | 1555 | .array_sentinel, |
| 1367 | 1556 | .array_u8, |
| 1368 | 1557 | .array_u8_sentinel_0, |
| 1558 | .pointer, | |
| 1369 | 1559 | .single_const_pointer, |
| 1370 | 1560 | .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, | |
| 1371 | 1567 | .single_const_pointer_to_comptime_int, |
| 1372 | 1568 | .const_slice_u8, |
| 1373 | 1569 | .int_unsigned, |
| ... | ... | @@ -1427,8 +1623,15 @@ pub const Type = extern union { |
| 1427 | 1623 | .array_sentinel, |
| 1428 | 1624 | .array_u8, |
| 1429 | 1625 | .array_u8_sentinel_0, |
| 1626 | .pointer, | |
| 1430 | 1627 | .single_const_pointer, |
| 1431 | 1628 | .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, | |
| 1432 | 1635 | .single_const_pointer_to_comptime_int, |
| 1433 | 1636 | .const_slice_u8, |
| 1434 | 1637 | .int_signed, |
| ... | ... | @@ -1488,8 +1691,15 @@ pub const Type = extern union { |
| 1488 | 1691 | .array_sentinel, |
| 1489 | 1692 | .array_u8, |
| 1490 | 1693 | .array_u8_sentinel_0, |
| 1694 | .pointer, | |
| 1491 | 1695 | .single_const_pointer, |
| 1492 | 1696 | .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, | |
| 1493 | 1703 | .single_const_pointer_to_comptime_int, |
| 1494 | 1704 | .const_slice_u8, |
| 1495 | 1705 | .optional, |
| ... | ... | @@ -1547,8 +1757,15 @@ pub const Type = extern union { |
| 1547 | 1757 | .array_sentinel, |
| 1548 | 1758 | .array_u8, |
| 1549 | 1759 | .array_u8_sentinel_0, |
| 1760 | .pointer, | |
| 1550 | 1761 | .single_const_pointer, |
| 1551 | 1762 | .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, | |
| 1552 | 1769 | .single_const_pointer_to_comptime_int, |
| 1553 | 1770 | .const_slice_u8, |
| 1554 | 1771 | .int_unsigned, |
| ... | ... | @@ -1635,8 +1852,15 @@ pub const Type = extern union { |
| 1635 | 1852 | .array_sentinel, |
| 1636 | 1853 | .array_u8, |
| 1637 | 1854 | .array_u8_sentinel_0, |
| 1855 | .pointer, | |
| 1638 | 1856 | .single_const_pointer, |
| 1639 | 1857 | .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, | |
| 1640 | 1864 | .single_const_pointer_to_comptime_int, |
| 1641 | 1865 | .const_slice_u8, |
| 1642 | 1866 | .u8, |
| ... | ... | @@ -1699,8 +1923,15 @@ pub const Type = extern union { |
| 1699 | 1923 | .array_sentinel, |
| 1700 | 1924 | .array_u8, |
| 1701 | 1925 | .array_u8_sentinel_0, |
| 1926 | .pointer, | |
| 1702 | 1927 | .single_const_pointer, |
| 1703 | 1928 | .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, | |
| 1704 | 1935 | .single_const_pointer_to_comptime_int, |
| 1705 | 1936 | .const_slice_u8, |
| 1706 | 1937 | .u8, |
| ... | ... | @@ -1762,8 +1993,15 @@ pub const Type = extern union { |
| 1762 | 1993 | .array_sentinel, |
| 1763 | 1994 | .array_u8, |
| 1764 | 1995 | .array_u8_sentinel_0, |
| 1996 | .pointer, | |
| 1765 | 1997 | .single_const_pointer, |
| 1766 | 1998 | .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, | |
| 1767 | 2005 | .single_const_pointer_to_comptime_int, |
| 1768 | 2006 | .const_slice_u8, |
| 1769 | 2007 | .u8, |
| ... | ... | @@ -1825,8 +2063,15 @@ pub const Type = extern union { |
| 1825 | 2063 | .array_sentinel, |
| 1826 | 2064 | .array_u8, |
| 1827 | 2065 | .array_u8_sentinel_0, |
| 2066 | .pointer, | |
| 1828 | 2067 | .single_const_pointer, |
| 1829 | 2068 | .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, | |
| 1830 | 2075 | .single_const_pointer_to_comptime_int, |
| 1831 | 2076 | .const_slice_u8, |
| 1832 | 2077 | .u8, |
| ... | ... | @@ -1885,8 +2130,15 @@ pub const Type = extern union { |
| 1885 | 2130 | .array_sentinel, |
| 1886 | 2131 | .array_u8, |
| 1887 | 2132 | .array_u8_sentinel_0, |
| 2133 | .pointer, | |
| 1888 | 2134 | .single_const_pointer, |
| 1889 | 2135 | .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, | |
| 1890 | 2142 | .single_const_pointer_to_comptime_int, |
| 1891 | 2143 | .const_slice_u8, |
| 1892 | 2144 | .u8, |
| ... | ... | @@ -1945,8 +2197,15 @@ pub const Type = extern union { |
| 1945 | 2197 | .array_sentinel, |
| 1946 | 2198 | .array_u8, |
| 1947 | 2199 | .array_u8_sentinel_0, |
| 2200 | .pointer, | |
| 1948 | 2201 | .single_const_pointer, |
| 1949 | 2202 | .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, | |
| 1950 | 2209 | .single_const_pointer_to_comptime_int, |
| 1951 | 2210 | .const_slice_u8, |
| 1952 | 2211 | .u8, |
| ... | ... | @@ -2025,8 +2284,15 @@ pub const Type = extern union { |
| 2025 | 2284 | .array_sentinel, |
| 2026 | 2285 | .array_u8, |
| 2027 | 2286 | .array_u8_sentinel_0, |
| 2287 | .pointer, | |
| 2028 | 2288 | .single_const_pointer, |
| 2029 | 2289 | .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, | |
| 2030 | 2296 | .single_const_pointer_to_comptime_int, |
| 2031 | 2297 | .const_slice_u8, |
| 2032 | 2298 | .optional, |
| ... | ... | @@ -2077,6 +2343,8 @@ pub const Type = extern union { |
| 2077 | 2343 | .array_sentinel, |
| 2078 | 2344 | .array_u8_sentinel_0, |
| 2079 | 2345 | .const_slice_u8, |
| 2346 | .const_slice, | |
| 2347 | .mut_slice, | |
| 2080 | 2348 | .c_void, |
| 2081 | 2349 | .optional, |
| 2082 | 2350 | .optional_single_mut_pointer, |
| ... | ... | @@ -2109,11 +2377,21 @@ pub const Type = extern union { |
| 2109 | 2377 | ty = ty.elemType(); |
| 2110 | 2378 | continue; |
| 2111 | 2379 | }, |
| 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 | => { | |
| 2113 | 2387 | const ptr = ty.castPointer().?; |
| 2114 | 2388 | ty = ptr.pointee_type; |
| 2115 | 2389 | continue; |
| 2116 | 2390 | }, |
| 2391 | .pointer => { | |
| 2392 | ty = ty.cast(Payload.Pointer).?.pointee_type; | |
| 2393 | continue; | |
| 2394 | }, | |
| 2117 | 2395 | }; |
| 2118 | 2396 | } |
| 2119 | 2397 | |
| ... | ... | @@ -2167,11 +2445,21 @@ pub const Type = extern union { |
| 2167 | 2445 | .array_u8_sentinel_0, |
| 2168 | 2446 | .single_const_pointer, |
| 2169 | 2447 | .single_mut_pointer, |
| 2448 | .many_const_pointer, | |
| 2449 | .many_mut_pointer, | |
| 2450 | .const_slice, | |
| 2451 | .mut_slice, | |
| 2170 | 2452 | .optional, |
| 2171 | 2453 | .optional_single_mut_pointer, |
| 2172 | 2454 | .optional_single_const_pointer, |
| 2173 | 2455 | .enum_literal, |
| 2174 | 2456 | => return false, |
| 2457 | ||
| 2458 | .c_const_pointer, | |
| 2459 | .c_mut_pointer, | |
| 2460 | => return true, | |
| 2461 | ||
| 2462 | .pointer => self.cast(Payload.Pointer).?.size == .C, | |
| 2175 | 2463 | }; |
| 2176 | 2464 | } |
| 2177 | 2465 | |
| ... | ... | @@ -2229,8 +2517,15 @@ pub const Type = extern union { |
| 2229 | 2517 | array_u8_sentinel_0, |
| 2230 | 2518 | array, |
| 2231 | 2519 | array_sentinel, |
| 2520 | pointer, | |
| 2232 | 2521 | single_const_pointer, |
| 2233 | 2522 | 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, | |
| 2234 | 2529 | int_signed, |
| 2235 | 2530 | int_unsigned, |
| 2236 | 2531 | function, |
| ... | ... | @@ -2272,7 +2567,7 @@ pub const Type = extern union { |
| 2272 | 2567 | elem_type: Type, |
| 2273 | 2568 | }; |
| 2274 | 2569 | |
| 2275 | pub const Pointer = struct { | |
| 2570 | pub const PointerSimple = struct { | |
| 2276 | 2571 | base: Payload, |
| 2277 | 2572 | |
| 2278 | 2573 | pointee_type: Type, |
| ... | ... | @@ -2303,6 +2598,21 @@ pub const Type = extern union { |
| 2303 | 2598 | |
| 2304 | 2599 | child_type: Type, |
| 2305 | 2600 | }; |
| 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 | }; | |
| 2306 | 2616 | }; |
| 2307 | 2617 | }; |
| 2308 | 2618 |
src-self-hosted/zir.zig+29-4| ... | ... | @@ -194,10 +194,22 @@ pub const Inst = struct { |
| 194 | 194 | shl, |
| 195 | 195 | /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type. |
| 196 | 196 | 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` | |
| 198 | 198 | 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` | |
| 200 | 200 | 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, | |
| 201 | 213 | /// Create a pointer type with attributes |
| 202 | 214 | ptr_type, |
| 203 | 215 | /// Write a value to a pointer. For loading, see `deref`. |
| ... | ... | @@ -262,6 +274,12 @@ pub const Inst = struct { |
| 262 | 274 | .typeof, |
| 263 | 275 | .single_const_ptr_type, |
| 264 | 276 | .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, | |
| 265 | 283 | .optional_type, |
| 266 | 284 | .unwrap_optional_safe, |
| 267 | 285 | .unwrap_optional_unsafe, |
| ... | ... | @@ -400,6 +418,12 @@ pub const Inst = struct { |
| 400 | 418 | .shr, |
| 401 | 419 | .single_const_ptr_type, |
| 402 | 420 | .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, | |
| 403 | 427 | .store, |
| 404 | 428 | .str, |
| 405 | 429 | .sub, |
| ... | ... | @@ -856,9 +880,10 @@ pub const Inst = struct { |
| 856 | 880 | @"align": ?*Inst = null, |
| 857 | 881 | align_bit_start: ?*Inst = null, |
| 858 | 882 | align_bit_end: ?*Inst = null, |
| 859 | @"const": bool = true, | |
| 883 | mutable: bool = true, | |
| 860 | 884 | @"volatile": bool = false, |
| 861 | 885 | sentinel: ?*Inst = null, |
| 886 | size: std.builtin.TypeInfo.Pointer.Size = .One, | |
| 862 | 887 | }, |
| 863 | 888 | }; |
| 864 | 889 | |
| ... | ... | @@ -2443,7 +2468,7 @@ const EmitZIR = struct { |
| 2443 | 2468 | } |
| 2444 | 2469 | }, |
| 2445 | 2470 | .Optional => { |
| 2446 | var buf: Type.Payload.Pointer = undefined; | |
| 2471 | var buf: Type.Payload.PointerSimple = undefined; | |
| 2447 | 2472 | const inst = try self.arena.allocator.create(Inst.UnOp); |
| 2448 | 2473 | inst.* = .{ |
| 2449 | 2474 | .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! |
| 51 | 51 | .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?), |
| 52 | 52 | .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?), |
| 53 | 53 | .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), | |
| 56 | 62 | .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?), |
| 57 | 63 | .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?), |
| 58 | 64 | .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?), |
| ... | ... | @@ -267,6 +273,14 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type { |
| 267 | 273 | return val.toType(); |
| 268 | 274 | } |
| 269 | 275 | |
| 276 | fn 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 | ||
| 270 | 284 | pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue { |
| 271 | 285 | const new_inst = try resolveInst(mod, scope, old_inst); |
| 272 | 286 | const val = try mod.resolveConstValue(scope, new_inst); |
| ... | ... | @@ -324,7 +338,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr |
| 324 | 338 | |
| 325 | 339 | fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { |
| 326 | 340 | 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); | |
| 328 | 342 | |
| 329 | 343 | if (operand.value()) |val| { |
| 330 | 344 | 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 |
| 369 | 383 | if (!var_type.isValidVarType(false)) { |
| 370 | 384 | return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type}); |
| 371 | 385 | } |
| 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); | |
| 373 | 387 | const b = try mod.requireRuntimeBlock(scope, inst.base.src); |
| 374 | 388 | return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); |
| 375 | 389 | } |
| ... | ... | @@ -723,7 +737,7 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp |
| 723 | 737 | } |
| 724 | 738 | |
| 725 | 739 | 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); | |
| 727 | 741 | |
| 728 | 742 | if (operand.value()) |val| { |
| 729 | 743 | if (val.isNull()) { |
| ... | ... | @@ -940,7 +954,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne |
| 940 | 954 | // required a larger index. |
| 941 | 955 | const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64)); |
| 942 | 956 | |
| 943 | const type_payload = try scope.arena().create(Type.Payload.Pointer); | |
| 957 | const type_payload = try scope.arena().create(Type.Payload.PointerSimple); | |
| 944 | 958 | type_payload.* = .{ |
| 945 | 959 | .base = .{ .tag = .single_const_pointer }, |
| 946 | 960 | .pointee_type = array_ptr.ty.elemType().elemType(), |
| ... | ... | @@ -1311,18 +1325,49 @@ fn analyzeDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerErr |
| 1311 | 1325 | return decl; |
| 1312 | 1326 | } |
| 1313 | 1327 | |
| 1314 | fn 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 | ||
| 1320 | fn analyzeInstSingleMutPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 1328 | fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*Inst { | |
| 1321 | 1329 | 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); | |
| 1323 | 1331 | return mod.constType(scope, inst.base.src, ty); |
| 1324 | 1332 | } |
| 1325 | 1333 | |
| 1326 | 1334 | fn 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); | |
| 1328 | 1373 | } |
test/stage2/compare_output.zig deleted-710| ... | ... | @@ -1,710 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const 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. | |
| 5 | const linux_x64 = std.zig.CrossTarget{ | |
| 6 | .cpu_arch = .x86_64, | |
| 7 | .os_tag = .linux, | |
| 8 | }; | |
| 9 | ||
| 10 | const linux_riscv64 = std.zig.CrossTarget{ | |
| 11 | .cpu_arch = .riscv64, | |
| 12 | .os_tag = .linux, | |
| 13 | }; | |
| 14 | ||
| 15 | const wasi = std.zig.CrossTarget{ | |
| 16 | .cpu_arch = .wasm32, | |
| 17 | .os_tag = .wasi, | |
| 18 | }; | |
| 19 | ||
| 20 | pub 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 @@ |
| 1 | const TestContext = @import("../../src-self-hosted/test.zig").TestContext; | |
| 2 | const std = @import("std"); | |
| 3 | ||
| 4 | const ErrorMsg = @import("../../src-self-hosted/Module.zig").ErrorMsg; | |
| 5 | ||
| 6 | const linux_x64 = std.zig.CrossTarget{ | |
| 7 | .cpu_arch = .x86_64, | |
| 8 | .os_tag = .linux, | |
| 9 | }; | |
| 10 | ||
| 11 | pub 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 @@ |
| 1 | const std = @import("std"); | |
| 1 | 2 | const TestContext = @import("../../src-self-hosted/test.zig").TestContext; |
| 2 | 3 | |
| 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. | |
| 6 | const linux_x64 = std.zig.CrossTarget{ | |
| 7 | .cpu_arch = .x86_64, | |
| 8 | .os_tag = .linux, | |
| 9 | }; | |
| 10 | ||
| 11 | const linux_riscv64 = std.zig.CrossTarget{ | |
| 12 | .cpu_arch = .riscv64, | |
| 13 | .os_tag = .linux, | |
| 14 | }; | |
| 15 | ||
| 16 | const wasi = std.zig.CrossTarget{ | |
| 17 | .cpu_arch = .wasm32, | |
| 18 | .os_tag = .wasi, | |
| 19 | }; | |
| 20 | ||
| 3 | 21 | pub fn addCases(ctx: *TestContext) !void { |
| 4 | try @import("compile_errors.zig").addCases(ctx); | |
| 5 | try @import("compare_output.zig").addCases(ctx); | |
| 6 | 22 | try @import("zir.zig").addCases(ctx); |
| 7 | 23 | 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"}); | |
| 8 | 726 | } |