authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-23 23:05:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-23 23:05:26-07:00
logaac6e8c4182b5d70de27b1f325151ac4233ed912
treec745097fb669f9b7f8c21f0bdc264a7d20656d7a
parentb4d383a47876b794b3f0950151c7cdcd5eddfc7a

self-hosted: AST flattening, astgen improvements, result locations, and more

* AST: flatten ControlFlowExpression into Continue, Break, and Return. * AST: unify identifiers and literals into the same AST type: OneToken * AST: ControlFlowExpression uses TrailerFlags to optimize storage space. * astgen: support `var` as well as `const` locals, and support explicitly typed locals. Corresponding Module and codegen code is not implemented yet. * astgen: support result locations. * ZIR: add the following instructions (see the corresponding doc comments for explanations of semantics): - alloc - alloc_inferred - bitcast_result_ptr - coerce_result_block_ptr - coerce_result_ptr - coerce_to_ptr_elem - ensure_result_used - ensure_result_non_error - ret_ptr - ret_type - store - param_type * the skeleton structure for result locations is set up. It's looking pretty clean so far. * add compile error for unused result and compile error for discarding errors. * astgen: split builtin calls up to implemented manually, and implement `@as`, `@bitCast` (and others) with respect to result locations. * add CLI support for hex and raw object formats. They are not supported by the self-hosted compiler yet, and emit errors. * rename `--c` CLI to `-ofmt=[objectformat]` which can be any of the object formats. Only ELF and C are supported so far. Also added missing help to the help text. * Remove hard tabs from C backend test cases. Shame on you Noam, you are grounded, you should know better, etc. Bad boy. * Delete C backend code and test case that relied on comptime_int incorrectly making it all the way to codegen.

12 files changed, 1177 insertions(+), 765 deletions(-)

lib/std/target.zig+2
......@@ -436,6 +436,8 @@ pub const Target = struct {
436436 macho,
437437 wasm,
438438 c,
439 hex,
440 raw,
439441 };
440442
441443 pub const SubSystem = enum {
lib/std/zig/ast.zig+85-217
......@@ -495,8 +495,10 @@ pub const Node = struct {
495495 While,
496496 For,
497497 If,
498 ControlFlowExpression,
499498 Suspend,
499 Continue,
500 Break,
501 Return,
500502
501503 // Type expressions
502504 AnyType,
......@@ -601,6 +603,24 @@ pub const Node = struct {
601603 .Try,
602604 => SimplePrefixOp,
603605
606 .Identifier,
607 .BoolLiteral,
608 .NullLiteral,
609 .UndefinedLiteral,
610 .Unreachable,
611 .AnyType,
612 .ErrorType,
613 .IntegerLiteral,
614 .FloatLiteral,
615 .StringLiteral,
616 .CharLiteral,
617 => OneToken,
618
619 .Continue,
620 .Break,
621 .Return,
622 => ControlFlowExpression,
623
604624 .ArrayType => ArrayType,
605625 .ArrayTypeSentinel => ArrayTypeSentinel,
606626
......@@ -621,23 +641,11 @@ pub const Node = struct {
621641 .While => While,
622642 .For => For,
623643 .If => If,
624 .ControlFlowExpression => ControlFlowExpression,
625644 .Suspend => Suspend,
626 .AnyType => AnyType,
627 .ErrorType => ErrorType,
628645 .FnProto => FnProto,
629646 .AnyFrameType => AnyFrameType,
630 .IntegerLiteral => IntegerLiteral,
631 .FloatLiteral => FloatLiteral,
632647 .EnumLiteral => EnumLiteral,
633 .StringLiteral => StringLiteral,
634648 .MultilineStringLiteral => MultilineStringLiteral,
635 .CharLiteral => CharLiteral,
636 .BoolLiteral => BoolLiteral,
637 .NullLiteral => NullLiteral,
638 .UndefinedLiteral => UndefinedLiteral,
639 .Unreachable => Unreachable,
640 .Identifier => Identifier,
641649 .GroupedExpression => GroupedExpression,
642650 .BuiltinCall => BuiltinCall,
643651 .ErrorSetDecl => ErrorSetDecl,
......@@ -1182,19 +1190,19 @@ pub const Node = struct {
11821190 }
11831191 };
11841192
1185 pub const Identifier = struct {
1186 base: Node = Node{ .tag = .Identifier },
1193 pub const OneToken = struct {
1194 base: Node,
11871195 token: TokenIndex,
11881196
1189 pub fn iterate(self: *const Identifier, index: usize) ?*Node {
1197 pub fn iterate(self: *const OneToken, index: usize) ?*Node {
11901198 return null;
11911199 }
11921200
1193 pub fn firstToken(self: *const Identifier) TokenIndex {
1201 pub fn firstToken(self: *const OneToken) TokenIndex {
11941202 return self.token;
11951203 }
11961204
1197 pub fn lastToken(self: *const Identifier) TokenIndex {
1205 pub fn lastToken(self: *const OneToken) TokenIndex {
11981206 return self.token;
11991207 }
12001208 };
......@@ -2569,34 +2577,65 @@ pub const Node = struct {
25692577 }
25702578 };
25712579
2572 /// TODO break this into separate Break, Continue, Return AST Nodes to save memory.
2573 /// Could be further broken into LabeledBreak, LabeledContinue, and ReturnVoid to save even more.
2580 /// Trailed in memory by possibly many things, with each optional thing
2581 /// determined by a bit in `trailer_flags`.
2582 /// Can be: return, break, continue
25742583 pub const ControlFlowExpression = struct {
2575 base: Node = Node{ .tag = .ControlFlowExpression },
2584 base: Node,
2585 trailer_flags: TrailerFlags,
25762586 ltoken: TokenIndex,
2577 kind: Kind,
2578 rhs: ?*Node,
25792587
2580 pub const Kind = union(enum) {
2581 Break: ?*Node,
2582 Continue: ?*Node,
2583 Return,
2588 pub const TrailerFlags = std.meta.TrailerFlags(struct {
2589 rhs: *Node,
2590 label: TokenIndex,
2591 });
2592
2593 pub const RequiredFields = struct {
2594 tag: Tag,
2595 ltoken: TokenIndex,
25842596 };
25852597
2598 pub fn getRHS(self: *const ControlFlowExpression) ?*Node {
2599 return self.getTrailer("rhs");
2600 }
2601
2602 pub fn getLabel(self: *const ControlFlowExpression) ?TokenIndex {
2603 return self.getTrailer("label");
2604 }
2605
2606 pub fn getTrailer(self: *const ControlFlowExpression, comptime name: []const u8) ?TrailerFlags.Field(name) {
2607 const trailers_start = @ptrCast([*]const u8, self) + @sizeOf(ControlFlowExpression);
2608 return self.trailer_flags.get(trailers_start, name);
2609 }
2610
2611 pub fn setTrailer(self: *ControlFlowExpression, comptime name: []const u8, value: TrailerFlags.Field(name)) void {
2612 const trailers_start = @ptrCast([*]u8, self) + @sizeOf(ControlFlowExpression);
2613 self.trailer_flags.set(trailers_start, name, value);
2614 }
2615
2616 pub fn create(allocator: *mem.Allocator, required: RequiredFields, trailers: anytype) !*ControlFlowExpression {
2617 const trailer_flags = TrailerFlags.init(trailers);
2618 const bytes = try allocator.alignedAlloc(u8, @alignOf(ControlFlowExpression), sizeInBytes(trailer_flags));
2619 const ctrl_flow_expr = @ptrCast(*ControlFlowExpression, bytes.ptr);
2620 ctrl_flow_expr.* = .{
2621 .base = .{ .tag = required.tag },
2622 .trailer_flags = trailer_flags,
2623 .ltoken = required.ltoken,
2624 };
2625 const trailers_start = bytes.ptr + @sizeOf(ControlFlowExpression);
2626 trailer_flags.setMany(trailers_start, trailers);
2627 return ctrl_flow_expr;
2628 }
2629
2630 pub fn destroy(self: *ControlFlowExpression, allocator: *mem.Allocator) void {
2631 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.trailer_flags)];
2632 allocator.free(bytes);
2633 }
2634
25862635 pub fn iterate(self: *const ControlFlowExpression, index: usize) ?*Node {
25872636 var i = index;
25882637
2589 switch (self.kind) {
2590 .Break, .Continue => |maybe_label| {
2591 if (maybe_label) |label| {
2592 if (i < 1) return label;
2593 i -= 1;
2594 }
2595 },
2596 .Return => {},
2597 }
2598
2599 if (self.rhs) |rhs| {
2638 if (self.getRHS()) |rhs| {
26002639 if (i < 1) return rhs;
26012640 i -= 1;
26022641 }
......@@ -2609,21 +2648,20 @@ pub const Node = struct {
26092648 }
26102649
26112650 pub fn lastToken(self: *const ControlFlowExpression) TokenIndex {
2612 if (self.rhs) |rhs| {
2651 if (self.getRHS()) |rhs| {
26132652 return rhs.lastToken();
26142653 }
26152654
2616 switch (self.kind) {
2617 .Break, .Continue => |maybe_label| {
2618 if (maybe_label) |label| {
2619 return label.lastToken();
2620 }
2621 },
2622 .Return => return self.ltoken,
2655 if (self.getLabel()) |label| {
2656 return label;
26232657 }
26242658
26252659 return self.ltoken;
26262660 }
2661
2662 fn sizeInBytes(trailer_flags: TrailerFlags) usize {
2663 return @sizeOf(ControlFlowExpression) + trailer_flags.sizeInBytes();
2664 }
26272665 };
26282666
26292667 pub const Suspend = struct {
......@@ -2655,23 +2693,6 @@ pub const Node = struct {
26552693 }
26562694 };
26572695
2658 pub const IntegerLiteral = struct {
2659 base: Node = Node{ .tag = .IntegerLiteral },
2660 token: TokenIndex,
2661
2662 pub fn iterate(self: *const IntegerLiteral, index: usize) ?*Node {
2663 return null;
2664 }
2665
2666 pub fn firstToken(self: *const IntegerLiteral) TokenIndex {
2667 return self.token;
2668 }
2669
2670 pub fn lastToken(self: *const IntegerLiteral) TokenIndex {
2671 return self.token;
2672 }
2673 };
2674
26752696 pub const EnumLiteral = struct {
26762697 base: Node = Node{ .tag = .EnumLiteral },
26772698 dot: TokenIndex,
......@@ -2690,23 +2711,6 @@ pub const Node = struct {
26902711 }
26912712 };
26922713
2693 pub const FloatLiteral = struct {
2694 base: Node = Node{ .tag = .FloatLiteral },
2695 token: TokenIndex,
2696
2697 pub fn iterate(self: *const FloatLiteral, index: usize) ?*Node {
2698 return null;
2699 }
2700
2701 pub fn firstToken(self: *const FloatLiteral) TokenIndex {
2702 return self.token;
2703 }
2704
2705 pub fn lastToken(self: *const FloatLiteral) TokenIndex {
2706 return self.token;
2707 }
2708 };
2709
27102714 /// Parameters are in memory following BuiltinCall.
27112715 pub const BuiltinCall = struct {
27122716 base: Node = Node{ .tag = .BuiltinCall },
......@@ -2757,23 +2761,6 @@ pub const Node = struct {
27572761 }
27582762 };
27592763
2760 pub const StringLiteral = struct {
2761 base: Node = Node{ .tag = .StringLiteral },
2762 token: TokenIndex,
2763
2764 pub fn iterate(self: *const StringLiteral, index: usize) ?*Node {
2765 return null;
2766 }
2767
2768 pub fn firstToken(self: *const StringLiteral) TokenIndex {
2769 return self.token;
2770 }
2771
2772 pub fn lastToken(self: *const StringLiteral) TokenIndex {
2773 return self.token;
2774 }
2775 };
2776
27772764 /// The string literal tokens appear directly in memory after MultilineStringLiteral.
27782765 pub const MultilineStringLiteral = struct {
27792766 base: Node = Node{ .tag = .MultilineStringLiteral },
......@@ -2817,74 +2804,6 @@ pub const Node = struct {
28172804 }
28182805 };
28192806
2820 pub const CharLiteral = struct {
2821 base: Node = Node{ .tag = .CharLiteral },
2822 token: TokenIndex,
2823
2824 pub fn iterate(self: *const CharLiteral, index: usize) ?*Node {
2825 return null;
2826 }
2827
2828 pub fn firstToken(self: *const CharLiteral) TokenIndex {
2829 return self.token;
2830 }
2831
2832 pub fn lastToken(self: *const CharLiteral) TokenIndex {
2833 return self.token;
2834 }
2835 };
2836
2837 pub const BoolLiteral = struct {
2838 base: Node = Node{ .tag = .BoolLiteral },
2839 token: TokenIndex,
2840
2841 pub fn iterate(self: *const BoolLiteral, index: usize) ?*Node {
2842 return null;
2843 }
2844
2845 pub fn firstToken(self: *const BoolLiteral) TokenIndex {
2846 return self.token;
2847 }
2848
2849 pub fn lastToken(self: *const BoolLiteral) TokenIndex {
2850 return self.token;
2851 }
2852 };
2853
2854 pub const NullLiteral = struct {
2855 base: Node = Node{ .tag = .NullLiteral },
2856 token: TokenIndex,
2857
2858 pub fn iterate(self: *const NullLiteral, index: usize) ?*Node {
2859 return null;
2860 }
2861
2862 pub fn firstToken(self: *const NullLiteral) TokenIndex {
2863 return self.token;
2864 }
2865
2866 pub fn lastToken(self: *const NullLiteral) TokenIndex {
2867 return self.token;
2868 }
2869 };
2870
2871 pub const UndefinedLiteral = struct {
2872 base: Node = Node{ .tag = .UndefinedLiteral },
2873 token: TokenIndex,
2874
2875 pub fn iterate(self: *const UndefinedLiteral, index: usize) ?*Node {
2876 return null;
2877 }
2878
2879 pub fn firstToken(self: *const UndefinedLiteral) TokenIndex {
2880 return self.token;
2881 }
2882
2883 pub fn lastToken(self: *const UndefinedLiteral) TokenIndex {
2884 return self.token;
2885 }
2886 };
2887
28882807 pub const Asm = struct {
28892808 base: Node = Node{ .tag = .Asm },
28902809 asm_token: TokenIndex,
......@@ -2904,7 +2823,7 @@ pub const Node = struct {
29042823 rparen: TokenIndex,
29052824
29062825 pub const Kind = union(enum) {
2907 Variable: *Identifier,
2826 Variable: *OneToken,
29082827 Return: *Node,
29092828 };
29102829
......@@ -3005,57 +2924,6 @@ pub const Node = struct {
30052924 }
30062925 };
30072926
3008 pub const Unreachable = struct {
3009 base: Node = Node{ .tag = .Unreachable },
3010 token: TokenIndex,
3011
3012 pub fn iterate(self: *const Unreachable, index: usize) ?*Node {
3013 return null;
3014 }
3015
3016 pub fn firstToken(self: *const Unreachable) TokenIndex {
3017 return self.token;
3018 }
3019
3020 pub fn lastToken(self: *const Unreachable) TokenIndex {
3021 return self.token;
3022 }
3023 };
3024
3025 pub const ErrorType = struct {
3026 base: Node = Node{ .tag = .ErrorType },
3027 token: TokenIndex,
3028
3029 pub fn iterate(self: *const ErrorType, index: usize) ?*Node {
3030 return null;
3031 }
3032
3033 pub fn firstToken(self: *const ErrorType) TokenIndex {
3034 return self.token;
3035 }
3036
3037 pub fn lastToken(self: *const ErrorType) TokenIndex {
3038 return self.token;
3039 }
3040 };
3041
3042 pub const AnyType = struct {
3043 base: Node = Node{ .tag = .AnyType },
3044 token: TokenIndex,
3045
3046 pub fn iterate(self: *const AnyType, index: usize) ?*Node {
3047 return null;
3048 }
3049
3050 pub fn firstToken(self: *const AnyType) TokenIndex {
3051 return self.token;
3052 }
3053
3054 pub fn lastToken(self: *const AnyType) TokenIndex {
3055 return self.token;
3056 }
3057 };
3058
30592927 /// TODO remove from the Node base struct
30602928 /// TODO actually maybe remove entirely in favor of iterating backward from Node.firstToken()
30612929 /// and forwards to find same-line doc comments.
lib/std/zig/parse.zig+47-35
......@@ -628,8 +628,11 @@ const Parser = struct {
628628 var type_expr: ?*Node = null;
629629 if (p.eatToken(.Colon)) |_| {
630630 if (p.eatToken(.Keyword_anytype) orelse p.eatToken(.Keyword_var)) |anytype_tok| {
631 const node = try p.arena.allocator.create(Node.AnyType);
632 node.* = .{ .token = anytype_tok };
631 const node = try p.arena.allocator.create(Node.OneToken);
632 node.* = .{
633 .base = .{ .tag = .AnyType },
634 .token = anytype_tok,
635 };
633636 type_expr = &node.base;
634637 } else {
635638 type_expr = try p.expectNode(parseTypeExpr, .{
......@@ -1079,12 +1082,13 @@ const Parser = struct {
10791082 if (p.eatToken(.Keyword_break)) |token| {
10801083 const label = try p.parseBreakLabel();
10811084 const expr_node = try p.parseExpr();
1082 const node = try p.arena.allocator.create(Node.ControlFlowExpression);
1083 node.* = .{
1085 const node = try Node.ControlFlowExpression.create(&p.arena.allocator, .{
1086 .tag = .Break,
10841087 .ltoken = token,
1085 .kind = .{ .Break = label },
1088 }, .{
1089 .label = label,
10861090 .rhs = expr_node,
1087 };
1091 });
10881092 return &node.base;
10891093 }
10901094
......@@ -1115,12 +1119,13 @@ const Parser = struct {
11151119
11161120 if (p.eatToken(.Keyword_continue)) |token| {
11171121 const label = try p.parseBreakLabel();
1118 const node = try p.arena.allocator.create(Node.ControlFlowExpression);
1119 node.* = .{
1122 const node = try Node.ControlFlowExpression.create(&p.arena.allocator, .{
1123 .tag = .Continue,
11201124 .ltoken = token,
1121 .kind = .{ .Continue = label },
1125 }, .{
1126 .label = label,
11221127 .rhs = null,
1123 };
1128 });
11241129 return &node.base;
11251130 }
11261131
......@@ -1139,12 +1144,12 @@ const Parser = struct {
11391144
11401145 if (p.eatToken(.Keyword_return)) |token| {
11411146 const expr_node = try p.parseExpr();
1142 const node = try p.arena.allocator.create(Node.ControlFlowExpression);
1143 node.* = .{
1147 const node = try Node.ControlFlowExpression.create(&p.arena.allocator, .{
1148 .tag = .Return,
11441149 .ltoken = token,
1145 .kind = .Return,
1150 }, .{
11461151 .rhs = expr_node,
1147 };
1152 });
11481153 return &node.base;
11491154 }
11501155
......@@ -1516,8 +1521,9 @@ const Parser = struct {
15161521 fn parsePrimaryTypeExpr(p: *Parser) !?*Node {
15171522 if (try p.parseBuiltinCall()) |node| return node;
15181523 if (p.eatToken(.CharLiteral)) |token| {
1519 const node = try p.arena.allocator.create(Node.CharLiteral);
1524 const node = try p.arena.allocator.create(Node.OneToken);
15201525 node.* = .{
1526 .base = .{ .tag = .CharLiteral },
15211527 .token = token,
15221528 };
15231529 return &node.base;
......@@ -1547,7 +1553,7 @@ const Parser = struct {
15471553 const identifier = try p.expectNodeRecoverable(parseIdentifier, .{
15481554 .ExpectedIdentifier = .{ .token = p.tok_i },
15491555 });
1550 const global_error_set = try p.createLiteral(Node.ErrorType, token);
1556 const global_error_set = try p.createLiteral(.ErrorType, token);
15511557 if (period == null or identifier == null) return global_error_set;
15521558
15531559 const node = try p.arena.allocator.create(Node.SimpleInfixOp);
......@@ -1559,8 +1565,8 @@ const Parser = struct {
15591565 };
15601566 return &node.base;
15611567 }
1562 if (p.eatToken(.Keyword_false)) |token| return p.createLiteral(Node.BoolLiteral, token);
1563 if (p.eatToken(.Keyword_null)) |token| return p.createLiteral(Node.NullLiteral, token);
1568 if (p.eatToken(.Keyword_false)) |token| return p.createLiteral(.BoolLiteral, token);
1569 if (p.eatToken(.Keyword_null)) |token| return p.createLiteral(.NullLiteral, token);
15641570 if (p.eatToken(.Keyword_anyframe)) |token| {
15651571 const node = try p.arena.allocator.create(Node.AnyFrameType);
15661572 node.* = .{
......@@ -1569,9 +1575,9 @@ const Parser = struct {
15691575 };
15701576 return &node.base;
15711577 }
1572 if (p.eatToken(.Keyword_true)) |token| return p.createLiteral(Node.BoolLiteral, token);
1573 if (p.eatToken(.Keyword_undefined)) |token| return p.createLiteral(Node.UndefinedLiteral, token);
1574 if (p.eatToken(.Keyword_unreachable)) |token| return p.createLiteral(Node.Unreachable, token);
1578 if (p.eatToken(.Keyword_true)) |token| return p.createLiteral(.BoolLiteral, token);
1579 if (p.eatToken(.Keyword_undefined)) |token| return p.createLiteral(.UndefinedLiteral, token);
1580 if (p.eatToken(.Keyword_unreachable)) |token| return p.createLiteral(.Unreachable, token);
15751581 if (try p.parseStringLiteral()) |node| return node;
15761582 if (try p.parseSwitchExpr()) |node| return node;
15771583
......@@ -1865,7 +1871,7 @@ const Parser = struct {
18651871 const variable = try p.expectNode(parseIdentifier, .{
18661872 .ExpectedIdentifier = .{ .token = p.tok_i },
18671873 });
1868 break :blk .{ .Variable = variable.cast(Node.Identifier).? };
1874 break :blk .{ .Variable = variable.castTag(.Identifier).? };
18691875 };
18701876 const rparen = try p.expectToken(.RParen);
18711877
......@@ -1906,11 +1912,10 @@ const Parser = struct {
19061912 }
19071913
19081914 /// BreakLabel <- COLON IDENTIFIER
1909 fn parseBreakLabel(p: *Parser) !?*Node {
1915 fn parseBreakLabel(p: *Parser) !?TokenIndex {
19101916 _ = p.eatToken(.Colon) orelse return null;
1911 return try p.expectNode(parseIdentifier, .{
1912 .ExpectedIdentifier = .{ .token = p.tok_i },
1913 });
1917 const ident = try p.expectToken(.Identifier);
1918 return ident;
19141919 }
19151920
19161921 /// BlockLabel <- IDENTIFIER COLON
......@@ -3022,8 +3027,9 @@ const Parser = struct {
30223027 });
30233028
30243029 // lets pretend this was an identifier so we can continue parsing
3025 const node = try p.arena.allocator.create(Node.Identifier);
3030 const node = try p.arena.allocator.create(Node.OneToken);
30263031 node.* = .{
3032 .base = .{ .tag = .Identifier },
30273033 .token = token,
30283034 };
30293035 return &node.base;
......@@ -3054,8 +3060,9 @@ const Parser = struct {
30543060
30553061 fn parseIdentifier(p: *Parser) !?*Node {
30563062 const token = p.eatToken(.Identifier) orelse return null;
3057 const node = try p.arena.allocator.create(Node.Identifier);
3063 const node = try p.arena.allocator.create(Node.OneToken);
30583064 node.* = .{
3065 .base = .{ .tag = .Identifier },
30593066 .token = token,
30603067 };
30613068 return &node.base;
......@@ -3064,16 +3071,18 @@ const Parser = struct {
30643071 fn parseAnyType(p: *Parser) !?*Node {
30653072 const token = p.eatToken(.Keyword_anytype) orelse
30663073 p.eatToken(.Keyword_var) orelse return null; // TODO remove in next release cycle
3067 const node = try p.arena.allocator.create(Node.AnyType);
3074 const node = try p.arena.allocator.create(Node.OneToken);
30683075 node.* = .{
3076 .base = .{ .tag = .AnyType },
30693077 .token = token,
30703078 };
30713079 return &node.base;
30723080 }
30733081
3074 fn createLiteral(p: *Parser, comptime T: type, token: TokenIndex) !*Node {
3075 const result = try p.arena.allocator.create(T);
3076 result.* = T{
3082 fn createLiteral(p: *Parser, tag: ast.Node.Tag, token: TokenIndex) !*Node {
3083 const result = try p.arena.allocator.create(Node.OneToken);
3084 result.* = .{
3085 .base = .{ .tag = tag },
30773086 .token = token,
30783087 };
30793088 return &result.base;
......@@ -3081,8 +3090,9 @@ const Parser = struct {
30813090
30823091 fn parseStringLiteralSingle(p: *Parser) !?*Node {
30833092 if (p.eatToken(.StringLiteral)) |token| {
3084 const node = try p.arena.allocator.create(Node.StringLiteral);
3093 const node = try p.arena.allocator.create(Node.OneToken);
30853094 node.* = .{
3095 .base = .{ .tag = .StringLiteral },
30863096 .token = token,
30873097 };
30883098 return &node.base;
......@@ -3131,8 +3141,9 @@ const Parser = struct {
31313141
31323142 fn parseIntegerLiteral(p: *Parser) !?*Node {
31333143 const token = p.eatToken(.IntegerLiteral) orelse return null;
3134 const node = try p.arena.allocator.create(Node.IntegerLiteral);
3144 const node = try p.arena.allocator.create(Node.OneToken);
31353145 node.* = .{
3146 .base = .{ .tag = .IntegerLiteral },
31363147 .token = token,
31373148 };
31383149 return &node.base;
......@@ -3140,8 +3151,9 @@ const Parser = struct {
31403151
31413152 fn parseFloatLiteral(p: *Parser) !?*Node {
31423153 const token = p.eatToken(.FloatLiteral) orelse return null;
3143 const node = try p.arena.allocator.create(Node.FloatLiteral);
3154 const node = try p.arena.allocator.create(Node.OneToken);
31443155 node.* = .{
3156 .base = .{ .tag = .FloatLiteral },
31453157 .token = token,
31463158 };
31473159 return &node.base;
lib/std/zig/render.zig+62-87
......@@ -366,10 +366,32 @@ fn renderExpression(
366366 space: Space,
367367) (@TypeOf(stream).Error || Error)!void {
368368 switch (base.tag) {
369 .Identifier => {
370 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
371 return renderToken(tree, stream, identifier.token, indent, start_col, space);
369 .Identifier,
370 .IntegerLiteral,
371 .FloatLiteral,
372 .StringLiteral,
373 .CharLiteral,
374 .BoolLiteral,
375 .NullLiteral,
376 .Unreachable,
377 .ErrorType,
378 .UndefinedLiteral,
379 => {
380 const casted_node = base.cast(ast.Node.OneToken).?;
381 return renderToken(tree, stream, casted_node.token, indent, start_col, space);
372382 },
383
384 .AnyType => {
385 const any_type = base.castTag(.AnyType).?;
386 if (mem.eql(u8, tree.tokenSlice(any_type.token), "var")) {
387 // TODO remove in next release cycle
388 try stream.writeAll("anytype");
389 if (space == .Comma) try stream.writeAll(",\n");
390 return;
391 }
392 return renderToken(tree, stream, any_type.token, indent, start_col, space);
393 },
394
373395 .Block => {
374396 const block = @fieldParentPtr(ast.Node.Block, "base", base);
375397
......@@ -399,6 +421,7 @@ fn renderExpression(
399421 return renderToken(tree, stream, block.rbrace, indent, start_col, space);
400422 }
401423 },
424
402425 .Defer => {
403426 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
404427
......@@ -1107,50 +1130,48 @@ fn renderExpression(
11071130 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?
11081131 },
11091132
1110 .ControlFlowExpression => {
1111 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
1133 .Break => {
1134 const flow_expr = base.castTag(.Break).?;
1135 const maybe_rhs = flow_expr.getRHS();
1136 const maybe_label = flow_expr.getLabel();
11121137
1113 switch (flow_expr.kind) {
1114 .Break => |maybe_label| {
1115 if (maybe_label == null and flow_expr.rhs == null) {
1116 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // break
1117 }
1118
1119 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // break
1120 if (maybe_label) |label| {
1121 const colon = tree.nextToken(flow_expr.ltoken);
1122 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
1123
1124 if (flow_expr.rhs == null) {
1125 return renderExpression(allocator, stream, tree, indent, start_col, label, space); // label
1126 }
1127 try renderExpression(allocator, stream, tree, indent, start_col, label, Space.Space); // label
1128 }
1129 },
1130 .Continue => |maybe_label| {
1131 assert(flow_expr.rhs == null);
1138 if (maybe_label == null and maybe_rhs == null) {
1139 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // break
1140 }
11321141
1133 if (maybe_label == null and flow_expr.rhs == null) {
1134 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // continue
1135 }
1142 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // break
1143 if (maybe_label) |label| {
1144 const colon = tree.nextToken(flow_expr.ltoken);
1145 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
11361146
1137 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // continue
1138 if (maybe_label) |label| {
1139 const colon = tree.nextToken(flow_expr.ltoken);
1140 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
1147 if (maybe_rhs == null) {
1148 return renderToken(tree, stream, label, indent, start_col, space); // label
1149 }
1150 try renderToken(tree, stream, label, indent, start_col, Space.Space); // label
1151 }
1152 return renderExpression(allocator, stream, tree, indent, start_col, maybe_rhs.?, space);
1153 },
11411154
1142 return renderExpression(allocator, stream, tree, indent, start_col, label, space);
1143 }
1144 },
1145 .Return => {
1146 if (flow_expr.rhs == null) {
1147 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space);
1148 }
1149 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space);
1150 },
1155 .Continue => {
1156 const flow_expr = base.castTag(.Continue).?;
1157 if (flow_expr.getLabel()) |label| {
1158 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // continue
1159 const colon = tree.nextToken(flow_expr.ltoken);
1160 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
1161 return renderToken(tree, stream, label, indent, start_col, space); // label
1162 } else {
1163 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // continue
11511164 }
1165 },
11521166
1153 return renderExpression(allocator, stream, tree, indent, start_col, flow_expr.rhs.?, space);
1167 .Return => {
1168 const flow_expr = base.castTag(.Return).?;
1169 if (flow_expr.getRHS()) |rhs| {
1170 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space);
1171 return renderExpression(allocator, stream, tree, indent, start_col, rhs, space);
1172 } else {
1173 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space);
1174 }
11541175 },
11551176
11561177 .Payload => {
......@@ -1208,48 +1229,6 @@ fn renderExpression(
12081229 return renderExpression(allocator, stream, tree, indent, start_col, field_init.expr, space);
12091230 },
12101231
1211 .IntegerLiteral => {
1212 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
1213 return renderToken(tree, stream, integer_literal.token, indent, start_col, space);
1214 },
1215 .FloatLiteral => {
1216 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
1217 return renderToken(tree, stream, float_literal.token, indent, start_col, space);
1218 },
1219 .StringLiteral => {
1220 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
1221 return renderToken(tree, stream, string_literal.token, indent, start_col, space);
1222 },
1223 .CharLiteral => {
1224 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
1225 return renderToken(tree, stream, char_literal.token, indent, start_col, space);
1226 },
1227 .BoolLiteral => {
1228 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
1229 return renderToken(tree, stream, bool_literal.token, indent, start_col, space);
1230 },
1231 .NullLiteral => {
1232 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
1233 return renderToken(tree, stream, null_literal.token, indent, start_col, space);
1234 },
1235 .Unreachable => {
1236 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
1237 return renderToken(tree, stream, unreachable_node.token, indent, start_col, space);
1238 },
1239 .ErrorType => {
1240 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
1241 return renderToken(tree, stream, error_type.token, indent, start_col, space);
1242 },
1243 .AnyType => {
1244 const any_type = @fieldParentPtr(ast.Node.AnyType, "base", base);
1245 if (mem.eql(u8, tree.tokenSlice(any_type.token), "var")) {
1246 // TODO remove in next release cycle
1247 try stream.writeAll("anytype");
1248 if (space == .Comma) try stream.writeAll(",\n");
1249 return;
1250 }
1251 return renderToken(tree, stream, any_type.token, indent, start_col, space);
1252 },
12531232 .ContainerDecl => {
12541233 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
12551234
......@@ -1468,10 +1447,6 @@ fn renderExpression(
14681447 }
14691448 try stream.writeByteNTimes(' ', indent);
14701449 },
1471 .UndefinedLiteral => {
1472 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
1473 return renderToken(tree, stream, undefined_literal.token, indent, start_col, space);
1474 },
14751450
14761451 .BuiltinCall => {
14771452 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
src-self-hosted/Module.zig+185-45
......@@ -212,7 +212,8 @@ pub const Decl = struct {
212212 },
213213 .block => unreachable,
214214 .gen_zir => unreachable,
215 .local_var => unreachable,
215 .local_val => unreachable,
216 .local_ptr => unreachable,
216217 .decl => unreachable,
217218 }
218219 }
......@@ -308,7 +309,8 @@ pub const Scope = struct {
308309 .block => return self.cast(Block).?.arena,
309310 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
310311 .gen_zir => return self.cast(GenZIR).?.arena,
311 .local_var => return self.cast(LocalVar).?.gen_zir.arena,
312 .local_val => return self.cast(LocalVal).?.gen_zir.arena,
313 .local_ptr => return self.cast(LocalPtr).?.gen_zir.arena,
312314 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
313315 .file => unreachable,
314316 }
......@@ -320,7 +322,8 @@ pub const Scope = struct {
320322 return switch (self.tag) {
321323 .block => self.cast(Block).?.decl,
322324 .gen_zir => self.cast(GenZIR).?.decl,
323 .local_var => return self.cast(LocalVar).?.gen_zir.decl,
325 .local_val => return self.cast(LocalVal).?.gen_zir.decl,
326 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl,
324327 .decl => self.cast(DeclAnalysis).?.decl,
325328 .zir_module => null,
326329 .file => null,
......@@ -333,7 +336,8 @@ pub const Scope = struct {
333336 switch (self.tag) {
334337 .block => return self.cast(Block).?.decl.scope,
335338 .gen_zir => return self.cast(GenZIR).?.decl.scope,
336 .local_var => return self.cast(LocalVar).?.gen_zir.decl.scope,
339 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope,
340 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope,
337341 .decl => return self.cast(DeclAnalysis).?.decl.scope,
338342 .zir_module, .file => return self,
339343 }
......@@ -346,7 +350,8 @@ pub const Scope = struct {
346350 switch (self.tag) {
347351 .block => unreachable,
348352 .gen_zir => unreachable,
349 .local_var => unreachable,
353 .local_val => unreachable,
354 .local_ptr => unreachable,
350355 .decl => unreachable,
351356 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),
352357 .file => return self.cast(File).?.fullyQualifiedNameHash(name),
......@@ -361,7 +366,8 @@ pub const Scope = struct {
361366 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(File).?.contents.tree,
362367 .block => return self.cast(Block).?.decl.scope.cast(File).?.contents.tree,
363368 .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(File).?.contents.tree,
364 .local_var => return self.cast(LocalVar).?.gen_zir.decl.scope.cast(File).?.contents.tree,
369 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope.cast(File).?.contents.tree,
370 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope.cast(File).?.contents.tree,
365371 }
366372 }
367373
......@@ -370,7 +376,8 @@ pub const Scope = struct {
370376 return switch (self.tag) {
371377 .block => unreachable,
372378 .gen_zir => self.cast(GenZIR).?,
373 .local_var => return self.cast(LocalVar).?.gen_zir,
379 .local_val => return self.cast(LocalVal).?.gen_zir,
380 .local_ptr => return self.cast(LocalPtr).?.gen_zir,
374381 .decl => unreachable,
375382 .zir_module => unreachable,
376383 .file => unreachable,
......@@ -397,7 +404,8 @@ pub const Scope = struct {
397404 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,
398405 .block => unreachable,
399406 .gen_zir => unreachable,
400 .local_var => unreachable,
407 .local_val => unreachable,
408 .local_ptr => unreachable,
401409 .decl => unreachable,
402410 }
403411 }
......@@ -408,7 +416,8 @@ pub const Scope = struct {
408416 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).unload(gpa),
409417 .block => unreachable,
410418 .gen_zir => unreachable,
411 .local_var => unreachable,
419 .local_val => unreachable,
420 .local_ptr => unreachable,
412421 .decl => unreachable,
413422 }
414423 }
......@@ -418,7 +427,8 @@ pub const Scope = struct {
418427 .file => return @fieldParentPtr(File, "base", base).getSource(module),
419428 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),
420429 .gen_zir => unreachable,
421 .local_var => unreachable,
430 .local_val => unreachable,
431 .local_ptr => unreachable,
422432 .block => unreachable,
423433 .decl => unreachable,
424434 }
......@@ -431,7 +441,8 @@ pub const Scope = struct {
431441 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),
432442 .block => unreachable,
433443 .gen_zir => unreachable,
434 .local_var => unreachable,
444 .local_val => unreachable,
445 .local_ptr => unreachable,
435446 .decl => unreachable,
436447 }
437448 }
......@@ -451,7 +462,8 @@ pub const Scope = struct {
451462 },
452463 .block => unreachable,
453464 .gen_zir => unreachable,
454 .local_var => unreachable,
465 .local_val => unreachable,
466 .local_ptr => unreachable,
455467 .decl => unreachable,
456468 }
457469 }
......@@ -472,7 +484,8 @@ pub const Scope = struct {
472484 block,
473485 decl,
474486 gen_zir,
475 local_var,
487 local_val,
488 local_ptr,
476489 };
477490
478491 pub const File = struct {
......@@ -708,17 +721,31 @@ pub const Scope = struct {
708721 instructions: std.ArrayListUnmanaged(*zir.Inst) = .{},
709722 };
710723
724 /// This is always a `const` local and importantly the `inst` is a value type, not a pointer.
711725 /// This structure lives as long as the AST generation of the Block
712726 /// node that contains the variable.
713 pub const LocalVar = struct {
714 pub const base_tag: Tag = .local_var;
727 pub const LocalVal = struct {
728 pub const base_tag: Tag = .local_val;
715729 base: Scope = Scope{ .tag = base_tag },
716 /// Parents can be: `LocalVar`, `GenZIR`.
730 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.
717731 parent: *Scope,
718732 gen_zir: *GenZIR,
719733 name: []const u8,
720734 inst: *zir.Inst,
721735 };
736
737 /// This could be a `const` or `var` local. It has a pointer instead of a value.
738 /// This structure lives as long as the AST generation of the Block
739 /// node that contains the variable.
740 pub const LocalPtr = struct {
741 pub const base_tag: Tag = .local_ptr;
742 base: Scope = Scope{ .tag = base_tag },
743 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.
744 parent: *Scope,
745 gen_zir: *GenZIR,
746 name: []const u8,
747 ptr: *zir.Inst,
748 };
722749};
723750
724751pub const AllErrors = struct {
......@@ -1176,12 +1203,19 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11761203
11771204 const param_decls = fn_proto.params();
11781205 const param_types = try fn_type_scope.arena.alloc(*zir.Inst, param_decls.len);
1206
1207 const fn_src = tree.token_locs[fn_proto.fn_token].start;
1208 const type_type = try self.addZIRInstConst(&fn_type_scope.base, fn_src, .{
1209 .ty = Type.initTag(.type),
1210 .val = Value.initTag(.type_type),
1211 });
1212 const type_type_rl: astgen.ResultLoc = .{ .ty = type_type };
11791213 for (param_decls) |param_decl, i| {
11801214 const param_type_node = switch (param_decl.param_type) {
11811215 .any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),
11821216 .type_expr => |node| node,
11831217 };
1184 param_types[i] = try astgen.expr(self, &fn_type_scope.base, param_type_node);
1218 param_types[i] = try astgen.expr(self, &fn_type_scope.base, type_type_rl, param_type_node);
11851219 }
11861220 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
11871221 return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{});
......@@ -1209,8 +1243,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
12091243 .Invalid => |tok| return self.failTok(&fn_type_scope.base, tok, "unable to parse return type", .{}),
12101244 };
12111245
1212 const return_type_inst = try astgen.expr(self, &fn_type_scope.base, return_type_expr);
1213 const fn_src = tree.token_locs[fn_proto.fn_token].start;
1246 const return_type_inst = try astgen.expr(self, &fn_type_scope.base, type_type_rl, return_type_expr);
12141247 const fn_type_inst = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.FnType, .{
12151248 .return_type = return_type_inst,
12161249 .param_types = param_types,
......@@ -1266,7 +1299,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
12661299 .kw_args = .{},
12671300 };
12681301 gen_scope.instructions.items[i] = &arg.base;
1269 const sub_scope = try gen_scope_arena.allocator.create(Scope.LocalVar);
1302 const sub_scope = try gen_scope_arena.allocator.create(Scope.LocalVal);
12701303 sub_scope.* = .{
12711304 .parent = params_scope,
12721305 .gen_zir = &gen_scope,
......@@ -1829,6 +1862,7 @@ fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
18291862 return self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src);
18301863}
18311864
1865/// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites.
18321866fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
18331867 return scope.cast(Scope.Block) orelse
18341868 return self.fail(scope, src, "instruction illegal outside function body", .{});
......@@ -2098,12 +2132,7 @@ pub fn addZIRInstSpecial(
20982132 return inst;
20992133}
21002134
2101pub fn addZIRNoOp(
2102 self: *Module,
2103 scope: *Scope,
2104 src: usize,
2105 tag: zir.Inst.Tag,
2106) !*zir.Inst {
2135pub fn addZIRNoOpT(self: *Module, scope: *Scope, src: usize, tag: zir.Inst.Tag) !*zir.Inst.NoOp {
21072136 const gen_zir = scope.getGenZIR();
21082137 try gen_zir.instructions.ensureCapacity(self.gpa, gen_zir.instructions.items.len + 1);
21092138 const inst = try gen_zir.arena.create(zir.Inst.NoOp);
......@@ -2116,6 +2145,11 @@ pub fn addZIRNoOp(
21162145 .kw_args = .{},
21172146 };
21182147 gen_zir.instructions.appendAssumeCapacity(&inst.base);
2148 return inst;
2149}
2150
2151pub fn addZIRNoOp(self: *Module, scope: *Scope, src: usize, tag: zir.Inst.Tag) !*zir.Inst {
2152 const inst = try self.addZIRNoOpT(scope, src, tag);
21192153 return &inst.base;
21202154}
21212155
......@@ -2320,24 +2354,36 @@ fn analyzeInstConst(self: *Module, scope: *Scope, const_inst: *zir.Inst.Const) I
23202354
23212355fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
23222356 switch (old_inst.tag) {
2357 .alloc => return self.analyzeInstAlloc(scope, old_inst.castTag(.alloc).?),
2358 .alloc_inferred => return self.analyzeInstAllocInferred(scope, old_inst.castTag(.alloc_inferred).?),
23232359 .arg => return self.analyzeInstArg(scope, old_inst.castTag(.arg).?),
2360 .bitcast_result_ptr => return self.analyzeInstBitCastResultPtr(scope, old_inst.castTag(.bitcast_result_ptr).?),
23242361 .block => return self.analyzeInstBlock(scope, old_inst.castTag(.block).?),
23252362 .@"break" => return self.analyzeInstBreak(scope, old_inst.castTag(.@"break").?),
23262363 .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.castTag(.breakpoint).?),
23272364 .breakvoid => return self.analyzeInstBreakVoid(scope, old_inst.castTag(.breakvoid).?),
23282365 .call => return self.analyzeInstCall(scope, old_inst.castTag(.call).?),
2366 .coerce_result_block_ptr => return self.analyzeInstCoerceResultBlockPtr(scope, old_inst.castTag(.coerce_result_block_ptr).?),
2367 .coerce_result_ptr => return self.analyzeInstCoerceResultPtr(scope, old_inst.castTag(.coerce_result_ptr).?),
2368 .coerce_to_ptr_elem => return self.analyzeInstCoerceToPtrElem(scope, old_inst.castTag(.coerce_to_ptr_elem).?),
23292369 .compileerror => return self.analyzeInstCompileError(scope, old_inst.castTag(.compileerror).?),
23302370 .@"const" => return self.analyzeInstConst(scope, old_inst.castTag(.@"const").?),
23312371 .declref => return self.analyzeInstDeclRef(scope, old_inst.castTag(.declref).?),
23322372 .declref_str => return self.analyzeInstDeclRefStr(scope, old_inst.castTag(.declref_str).?),
23332373 .declval => return self.analyzeInstDeclVal(scope, old_inst.castTag(.declval).?),
23342374 .declval_in_module => return self.analyzeInstDeclValInModule(scope, old_inst.castTag(.declval_in_module).?),
2375 .ensure_result_used => return self.analyzeInstEnsureResultUsed(scope, old_inst.castTag(.ensure_result_used).?),
2376 .ensure_result_non_error => return self.analyzeInstEnsureResultNonError(scope, old_inst.castTag(.ensure_result_non_error).?),
2377 .ret_ptr => return self.analyzeInstRetPtr(scope, old_inst.castTag(.ret_ptr).?),
2378 .ret_type => return self.analyzeInstRetType(scope, old_inst.castTag(.ret_type).?),
2379 .store => return self.analyzeInstStore(scope, old_inst.castTag(.store).?),
23352380 .str => return self.analyzeInstStr(scope, old_inst.castTag(.str).?),
23362381 .int => {
23372382 const big_int = old_inst.castTag(.int).?.positionals.int;
23382383 return self.constIntBig(scope, old_inst.src, Type.initTag(.comptime_int), big_int);
23392384 },
23402385 .inttype => return self.analyzeInstIntType(scope, old_inst.castTag(.inttype).?),
2386 .param_type => return self.analyzeInstParamType(scope, old_inst.castTag(.param_type).?),
23412387 .ptrtoint => return self.analyzeInstPtrToInt(scope, old_inst.castTag(.ptrtoint).?),
23422388 .fieldptr => return self.analyzeInstFieldPtr(scope, old_inst.castTag(.fieldptr).?),
23432389 .deref => return self.analyzeInstDeref(scope, old_inst.castTag(.deref).?),
......@@ -2369,6 +2415,94 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
23692415 }
23702416}
23712417
2418fn analyzeInstCoerceResultBlockPtr(
2419 self: *Module,
2420 scope: *Scope,
2421 inst: *zir.Inst.CoerceResultBlockPtr,
2422) InnerError!*Inst {
2423 return self.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{});
2424}
2425
2426fn analyzeInstBitCastResultPtr(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2427 return self.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastResultPtr", .{});
2428}
2429
2430fn analyzeInstCoerceResultPtr(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2431 return self.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultPtr", .{});
2432}
2433
2434fn analyzeInstCoerceToPtrElem(self: *Module, scope: *Scope, inst: *zir.Inst.CoerceToPtrElem) InnerError!*Inst {
2435 return self.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceToPtrElem", .{});
2436}
2437
2438fn analyzeInstRetPtr(self: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
2439 return self.fail(scope, inst.base.src, "TODO implement analyzeInstRetPtr", .{});
2440}
2441
2442fn analyzeInstRetType(self: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
2443 const b = try self.requireRuntimeBlock(scope, inst.base.src);
2444 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
2445 const ret_type = fn_ty.fnReturnType();
2446 return self.constType(scope, inst.base.src, ret_type);
2447}
2448
2449fn analyzeInstEnsureResultUsed(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2450 const operand = try self.resolveInst(scope, inst.positionals.operand);
2451 switch (operand.ty.zigTypeTag()) {
2452 .Void, .NoReturn => return self.constVoid(scope, operand.src),
2453 else => return self.fail(scope, operand.src, "expression value is ignored", .{}),
2454 }
2455}
2456
2457fn analyzeInstEnsureResultNonError(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2458 const operand = try self.resolveInst(scope, inst.positionals.operand);
2459 switch (operand.ty.zigTypeTag()) {
2460 .ErrorSet, .ErrorUnion => return self.fail(scope, operand.src, "error is discarded", .{}),
2461 else => return self.constVoid(scope, operand.src),
2462 }
2463}
2464
2465fn analyzeInstAlloc(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2466 return self.fail(scope, inst.base.src, "TODO implement analyzeInstAlloc", .{});
2467}
2468
2469fn analyzeInstAllocInferred(self: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
2470 return self.fail(scope, inst.base.src, "TODO implement analyzeInstAllocInferred", .{});
2471}
2472
2473fn analyzeInstStore(self: *Module, scope: *Scope, inst: *zir.Inst.Store) InnerError!*Inst {
2474 return self.fail(scope, inst.base.src, "TODO implement analyzeInstStore", .{});
2475}
2476
2477fn analyzeInstParamType(self: *Module, scope: *Scope, inst: *zir.Inst.ParamType) InnerError!*Inst {
2478 const fn_inst = try self.resolveInst(scope, inst.positionals.func);
2479 const arg_index = inst.positionals.arg_index;
2480
2481 const fn_ty: Type = switch (fn_inst.ty.zigTypeTag()) {
2482 .Fn => fn_inst.ty,
2483 .BoundFn => {
2484 return self.fail(scope, fn_inst.src, "TODO implement analyzeInstParamType for method call syntax", .{});
2485 },
2486 else => {
2487 return self.fail(scope, fn_inst.src, "expected function, found '{}'", .{fn_inst.ty});
2488 },
2489 };
2490
2491 // TODO support C-style var args
2492 const param_count = fn_ty.fnParamLen();
2493 if (arg_index >= param_count) {
2494 return self.fail(scope, inst.base.src, "arg index {} out of bounds; '{}' has {} arguments", .{
2495 arg_index,
2496 fn_ty,
2497 param_count,
2498 });
2499 }
2500
2501 // TODO support generic functions
2502 const param_type = fn_ty.fnParamType(arg_index);
2503 return self.constType(scope, inst.base.src, param_type);
2504}
2505
23722506fn analyzeInstStr(self: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerError!*Inst {
23732507 // The bytes references memory inside the ZIR module, which can get deallocated
23742508 // after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena.
......@@ -2746,13 +2880,13 @@ fn analyzeInstPrimitive(self: *Module, scope: *Scope, primitive: *zir.Inst.Primi
27462880 return self.constInst(scope, primitive.base.src, primitive.positionals.tag.toTypedValue());
27472881}
27482882
2749fn analyzeInstAs(self: *Module, scope: *Scope, as: *zir.Inst.As) InnerError!*Inst {
2750 const dest_type = try self.resolveType(scope, as.positionals.dest_type);
2751 const new_inst = try self.resolveInst(scope, as.positionals.value);
2883fn analyzeInstAs(self: *Module, scope: *Scope, as: *zir.Inst.BinOp) InnerError!*Inst {
2884 const dest_type = try self.resolveType(scope, as.positionals.lhs);
2885 const new_inst = try self.resolveInst(scope, as.positionals.rhs);
27522886 return self.coerce(scope, dest_type, new_inst);
27532887}
27542888
2755fn analyzeInstPtrToInt(self: *Module, scope: *Scope, ptrtoint: *zir.Inst.PtrToInt) InnerError!*Inst {
2889fn analyzeInstPtrToInt(self: *Module, scope: *Scope, ptrtoint: *zir.Inst.UnOp) InnerError!*Inst {
27562890 const ptr = try self.resolveInst(scope, ptrtoint.positionals.operand);
27572891 if (ptr.ty.zigTypeTag() != .Pointer) {
27582892 return self.fail(scope, ptrtoint.positionals.operand.src, "expected pointer, found '{}'", .{ptr.ty});
......@@ -2797,16 +2931,16 @@ fn analyzeInstFieldPtr(self: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPt
27972931 }
27982932}
27992933
2800fn analyzeInstIntCast(self: *Module, scope: *Scope, inst: *zir.Inst.IntCast) InnerError!*Inst {
2801 const dest_type = try self.resolveType(scope, inst.positionals.dest_type);
2802 const operand = try self.resolveInst(scope, inst.positionals.operand);
2934fn analyzeInstIntCast(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2935 const dest_type = try self.resolveType(scope, inst.positionals.lhs);
2936 const operand = try self.resolveInst(scope, inst.positionals.rhs);
28032937
28042938 const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {
28052939 .ComptimeInt => true,
28062940 .Int => false,
28072941 else => return self.fail(
28082942 scope,
2809 inst.positionals.dest_type.src,
2943 inst.positionals.lhs.src,
28102944 "expected integer type, found '{}'",
28112945 .{
28122946 dest_type,
......@@ -2818,7 +2952,7 @@ fn analyzeInstIntCast(self: *Module, scope: *Scope, inst: *zir.Inst.IntCast) Inn
28182952 .ComptimeInt, .Int => {},
28192953 else => return self.fail(
28202954 scope,
2821 inst.positionals.operand.src,
2955 inst.positionals.rhs.src,
28222956 "expected integer type, found '{}'",
28232957 .{operand.ty},
28242958 ),
......@@ -2833,22 +2967,22 @@ fn analyzeInstIntCast(self: *Module, scope: *Scope, inst: *zir.Inst.IntCast) Inn
28332967 return self.fail(scope, inst.base.src, "TODO implement analyze widen or shorten int", .{});
28342968}
28352969
2836fn analyzeInstBitCast(self: *Module, scope: *Scope, inst: *zir.Inst.BitCast) InnerError!*Inst {
2837 const dest_type = try self.resolveType(scope, inst.positionals.dest_type);
2838 const operand = try self.resolveInst(scope, inst.positionals.operand);
2970fn analyzeInstBitCast(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2971 const dest_type = try self.resolveType(scope, inst.positionals.lhs);
2972 const operand = try self.resolveInst(scope, inst.positionals.rhs);
28392973 return self.bitcast(scope, dest_type, operand);
28402974}
28412975
2842fn analyzeInstFloatCast(self: *Module, scope: *Scope, inst: *zir.Inst.FloatCast) InnerError!*Inst {
2843 const dest_type = try self.resolveType(scope, inst.positionals.dest_type);
2844 const operand = try self.resolveInst(scope, inst.positionals.operand);
2976fn analyzeInstFloatCast(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2977 const dest_type = try self.resolveType(scope, inst.positionals.lhs);
2978 const operand = try self.resolveInst(scope, inst.positionals.rhs);
28452979
28462980 const dest_is_comptime_float = switch (dest_type.zigTypeTag()) {
28472981 .ComptimeFloat => true,
28482982 .Float => false,
28492983 else => return self.fail(
28502984 scope,
2851 inst.positionals.dest_type.src,
2985 inst.positionals.lhs.src,
28522986 "expected float type, found '{}'",
28532987 .{
28542988 dest_type,
......@@ -2860,7 +2994,7 @@ fn analyzeInstFloatCast(self: *Module, scope: *Scope, inst: *zir.Inst.FloatCast)
28602994 .ComptimeFloat, .Float, .ComptimeInt => {},
28612995 else => return self.fail(
28622996 scope,
2863 inst.positionals.operand.src,
2997 inst.positionals.rhs.src,
28642998 "expected float type, found '{}'",
28652999 .{operand.ty},
28663000 ),
......@@ -3560,8 +3694,14 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err
35603694 gen_zir.decl.generation = self.generation;
35613695 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
35623696 },
3563 .local_var => {
3564 const gen_zir = scope.cast(Scope.LocalVar).?.gen_zir;
3697 .local_val => {
3698 const gen_zir = scope.cast(Scope.LocalVal).?.gen_zir;
3699 gen_zir.decl.analysis = .sema_failure;
3700 gen_zir.decl.generation = self.generation;
3701 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3702 },
3703 .local_ptr => {
3704 const gen_zir = scope.cast(Scope.LocalPtr).?.gen_zir;
35653705 gen_zir.decl.analysis = .sema_failure;
35663706 gen_zir.decl.generation = self.generation;
35673707 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
src-self-hosted/astgen.zig+457-153
......@@ -1,5 +1,6 @@
11const std = @import("std");
22const mem = std.mem;
3const Allocator = std.mem.Allocator;
34const Value = @import("value.zig").Value;
45const Type = @import("type.zig").Type;
56const TypedValue = @import("TypedValue.zig");
......@@ -11,35 +12,67 @@ const trace = @import("tracy.zig").trace;
1112const Scope = Module.Scope;
1213const InnerError = Module.InnerError;
1314
15pub const ResultLoc = union(enum) {
16 /// The expression is the right-hand side of assignment to `_`.
17 discard,
18 /// The expression has an inferred type, and it will be evaluated as an rvalue.
19 none,
20 /// The expression will be type coerced into this type, but it will be evaluated as an rvalue.
21 ty: *zir.Inst,
22 /// The expression must store its result into this typed pointer.
23 ptr: *zir.Inst,
24 /// The expression must store its result into this allocation, which has an inferred type.
25 inferred_ptr: *zir.Inst.Tag.alloc_inferred.Type(),
26 /// The expression must store its result into this pointer, which is a typed pointer that
27 /// has been bitcasted to whatever the expression's type is.
28 bitcasted_ptr: *zir.Inst.UnOp,
29 /// There is a pointer for the expression to store its result into, however, its type
30 /// is inferred based on peer type resolution for a `zir.Inst.Block`.
31 block_ptr: *zir.Inst.Block,
32};
33
34pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*zir.Inst {
35 const type_src = scope.tree().token_locs[type_node.firstToken()].start;
36 const type_type = try mod.addZIRInstConst(scope, type_src, .{
37 .ty = Type.initTag(.type),
38 .val = Value.initTag(.type_type),
39 });
40 const type_rl: ResultLoc = .{ .ty = type_type };
41 return expr(mod, scope, type_rl, type_node);
42}
43
1444/// Turn Zig AST into untyped ZIR istructions.
15pub fn expr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst {
45pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst {
1646 switch (node.tag) {
1747 .VarDecl => unreachable, // Handled in `blockExpr`.
18
19 .Add => return simpleInfixOp(mod, scope, node.castTag(.Add).?, .add),
20 .Sub => return simpleInfixOp(mod, scope, node.castTag(.Sub).?, .sub),
21 .BangEqual => return simpleInfixOp(mod, scope, node.castTag(.BangEqual).?, .cmp_neq),
22 .EqualEqual => return simpleInfixOp(mod, scope, node.castTag(.EqualEqual).?, .cmp_eq),
23 .GreaterThan => return simpleInfixOp(mod, scope, node.castTag(.GreaterThan).?, .cmp_gt),
24 .GreaterOrEqual => return simpleInfixOp(mod, scope, node.castTag(.GreaterOrEqual).?, .cmp_gte),
25 .LessThan => return simpleInfixOp(mod, scope, node.castTag(.LessThan).?, .cmp_lt),
26 .LessOrEqual => return simpleInfixOp(mod, scope, node.castTag(.LessOrEqual).?, .cmp_lte),
27
28 .Identifier => return identifier(mod, scope, node.castTag(.Identifier).?),
29 .Asm => return assembly(mod, scope, node.castTag(.Asm).?),
30 .StringLiteral => return stringLiteral(mod, scope, node.castTag(.StringLiteral).?),
31 .IntegerLiteral => return integerLiteral(mod, scope, node.castTag(.IntegerLiteral).?),
32 .BuiltinCall => return builtinCall(mod, scope, node.castTag(.BuiltinCall).?),
33 .Call => return callExpr(mod, scope, node.castTag(.Call).?),
48 .Assign => unreachable, // Handled in `blockExpr`.
49
50 .Add => return arithmetic(mod, scope, rl, node.castTag(.Add).?, .add),
51 .Sub => return arithmetic(mod, scope, rl, node.castTag(.Sub).?, .sub),
52
53 .BangEqual => return cmp(mod, scope, rl, node.castTag(.BangEqual).?, .cmp_neq),
54 .EqualEqual => return cmp(mod, scope, rl, node.castTag(.EqualEqual).?, .cmp_eq),
55 .GreaterThan => return cmp(mod, scope, rl, node.castTag(.GreaterThan).?, .cmp_gt),
56 .GreaterOrEqual => return cmp(mod, scope, rl, node.castTag(.GreaterOrEqual).?, .cmp_gte),
57 .LessThan => return cmp(mod, scope, rl, node.castTag(.LessThan).?, .cmp_lt),
58 .LessOrEqual => return cmp(mod, scope, rl, node.castTag(.LessOrEqual).?, .cmp_lte),
59
60 .Identifier => return rlWrap(mod, scope, rl, try identifier(mod, scope, node.castTag(.Identifier).?)),
61 .Asm => return rlWrap(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)),
62 .StringLiteral => return rlWrap(mod, scope, rl, try stringLiteral(mod, scope, node.castTag(.StringLiteral).?)),
63 .IntegerLiteral => return rlWrap(mod, scope, rl, try integerLiteral(mod, scope, node.castTag(.IntegerLiteral).?)),
64 .BuiltinCall => return builtinCall(mod, scope, rl, node.castTag(.BuiltinCall).?),
65 .Call => return callExpr(mod, scope, rl, node.castTag(.Call).?),
3466 .Unreachable => return unreach(mod, scope, node.castTag(.Unreachable).?),
35 .ControlFlowExpression => return controlFlowExpr(mod, scope, node.castTag(.ControlFlowExpression).?),
36 .If => return ifExpr(mod, scope, node.castTag(.If).?),
37 .Assign => return assign(mod, scope, node.castTag(.Assign).?),
38 .Period => return field(mod, scope, node.castTag(.Period).?),
39 .Deref => return deref(mod, scope, node.castTag(.Deref).?),
40 .BoolNot => return boolNot(mod, scope, node.castTag(.BoolNot).?),
41 .FloatLiteral => return floatLiteral(mod, scope, node.castTag(.FloatLiteral).?),
42 .UndefinedLiteral, .BoolLiteral, .NullLiteral => return primitiveLiteral(mod, scope, node),
67 .Return => return ret(mod, scope, node.castTag(.Return).?),
68 .If => return ifExpr(mod, scope, rl, node.castTag(.If).?),
69 .Period => return rlWrap(mod, scope, rl, try field(mod, scope, node.castTag(.Period).?)),
70 .Deref => return rlWrap(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)),
71 .BoolNot => return rlWrap(mod, scope, rl, try boolNot(mod, scope, node.castTag(.BoolNot).?)),
72 .FloatLiteral => return rlWrap(mod, scope, rl, try floatLiteral(mod, scope, node.castTag(.FloatLiteral).?)),
73 .UndefinedLiteral => return rlWrap(mod, scope, rl, try undefLiteral(mod, scope, node.castTag(.UndefinedLiteral).?)),
74 .BoolLiteral => return rlWrap(mod, scope, rl, try boolLiteral(mod, scope, node.castTag(.BoolLiteral).?)),
75 .NullLiteral => return rlWrap(mod, scope, rl, try nullLiteral(mod, scope, node.castTag(.NullLiteral).?)),
4376 else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}),
4477 }
4578}
......@@ -59,17 +92,28 @@ pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block
5992 for (block_node.statements()) |statement| {
6093 switch (statement.tag) {
6194 .VarDecl => {
62 const sub_scope = try block_arena.allocator.create(Scope.LocalVar);
63 const var_decl_node = @fieldParentPtr(ast.Node.VarDecl, "base", statement);
64 sub_scope.* = try varDecl(mod, scope, var_decl_node);
65 scope = &sub_scope.base;
95 const var_decl_node = statement.castTag(.VarDecl).?;
96 scope = try varDecl(mod, scope, var_decl_node, &block_arena.allocator);
97 },
98 .Assign => {
99 const ass = statement.castTag(.Assign).?;
100 try assign(mod, scope, ass);
101 },
102 else => {
103 const possibly_unused_result = try expr(mod, scope, .none, statement);
104 const src = scope.tree().token_locs[statement.firstToken()].start;
105 _ = try mod.addZIRUnOp(scope, src, .ensure_result_used, possibly_unused_result);
66106 },
67 else => _ = try expr(mod, scope, statement),
68107 }
69108 }
70109}
71110
72fn varDecl(mod: *Module, scope: *Scope, node: *ast.Node.VarDecl) InnerError!Scope.LocalVar {
111fn varDecl(
112 mod: *Module,
113 scope: *Scope,
114 node: *ast.Node.VarDecl,
115 block_arena: *Allocator,
116) InnerError!*Scope {
73117 // TODO implement detection of shadowing
74118 if (node.getTrailer("comptime_token")) |comptime_token| {
75119 return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{});
......@@ -78,48 +122,96 @@ fn varDecl(mod: *Module, scope: *Scope, node: *ast.Node.VarDecl) InnerError!Scop
78122 return mod.failNode(scope, align_node, "TODO implement alignment on locals", .{});
79123 }
80124 const tree = scope.tree();
125 const name_src = tree.token_locs[node.name_token].start;
126 const ident_name = try identifierTokenString(mod, scope, node.name_token);
127 const init_node = node.getTrailer("init_node").?;
81128 switch (tree.token_ids[node.mut_token]) {
82129 .Keyword_const => {
83 if (node.getTrailer("type_node")) |type_node| {
84 return mod.failNode(scope, type_node, "TODO implement typed const locals", .{});
85 }
86130 // Depending on the type of AST the initialization expression is, we may need an lvalue
87131 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as
88132 // the variable, no memory location needed.
89 const init_node = node.getTrailer("init_node").?;
90133 if (nodeMayNeedMemoryLocation(init_node)) {
91 return mod.failNode(scope, init_node, "TODO implement result locations", .{});
134 if (node.getTrailer("type_node")) |type_node| {
135 const type_inst = try typeExpr(mod, scope, type_node);
136 const alloc = try mod.addZIRUnOp(scope, name_src, .alloc, type_inst);
137 const result_loc: ResultLoc = .{ .ptr = alloc };
138 const init_inst = try expr(mod, scope, result_loc, init_node);
139 const sub_scope = try block_arena.create(Scope.LocalVal);
140 sub_scope.* = .{
141 .parent = scope,
142 .gen_zir = scope.getGenZIR(),
143 .name = ident_name,
144 .inst = init_inst,
145 };
146 return &sub_scope.base;
147 } else {
148 const alloc = try mod.addZIRNoOpT(scope, name_src, .alloc_inferred);
149 const result_loc: ResultLoc = .{ .inferred_ptr = alloc };
150 const init_inst = try expr(mod, scope, result_loc, init_node);
151 const sub_scope = try block_arena.create(Scope.LocalVal);
152 sub_scope.* = .{
153 .parent = scope,
154 .gen_zir = scope.getGenZIR(),
155 .name = ident_name,
156 .inst = init_inst,
157 };
158 return &sub_scope.base;
159 }
160 } else {
161 const result_loc: ResultLoc = if (node.getTrailer("type_node")) |type_node|
162 .{ .ty = try typeExpr(mod, scope, type_node) }
163 else
164 .none;
165 const init_inst = try expr(mod, scope, result_loc, init_node);
166 const sub_scope = try block_arena.create(Scope.LocalVal);
167 sub_scope.* = .{
168 .parent = scope,
169 .gen_zir = scope.getGenZIR(),
170 .name = ident_name,
171 .inst = init_inst,
172 };
173 return &sub_scope.base;
92174 }
93 const init_inst = try expr(mod, scope, init_node);
94 const ident_name = try identifierTokenString(mod, scope, node.name_token);
95 return Scope.LocalVar{
96 .parent = scope,
97 .gen_zir = scope.getGenZIR(),
98 .name = ident_name,
99 .inst = init_inst,
100 };
101175 },
102176 .Keyword_var => {
103 return mod.failNode(scope, &node.base, "TODO implement local vars", .{});
177 if (node.getTrailer("type_node")) |type_node| {
178 const type_inst = try typeExpr(mod, scope, type_node);
179 const alloc = try mod.addZIRUnOp(scope, name_src, .alloc, type_inst);
180 const result_loc: ResultLoc = .{ .ptr = alloc };
181 const init_inst = try expr(mod, scope, result_loc, init_node);
182 const sub_scope = try block_arena.create(Scope.LocalPtr);
183 sub_scope.* = .{
184 .parent = scope,
185 .gen_zir = scope.getGenZIR(),
186 .name = ident_name,
187 .ptr = alloc,
188 };
189 return &sub_scope.base;
190 } else {
191 const alloc = try mod.addZIRNoOp(scope, name_src, .alloc_inferred);
192 const result_loc = .{ .inferred_ptr = alloc.castTag(.alloc_inferred).? };
193 const init_inst = try expr(mod, scope, result_loc, init_node);
194 const sub_scope = try block_arena.create(Scope.LocalPtr);
195 sub_scope.* = .{
196 .parent = scope,
197 .gen_zir = scope.getGenZIR(),
198 .name = ident_name,
199 .ptr = alloc,
200 };
201 return &sub_scope.base;
202 }
104203 },
105204 else => unreachable,
106205 }
107206}
108207
109fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
110 const operand = try expr(mod, scope, node.rhs);
111 const tree = scope.tree();
112 const src = tree.token_locs[node.op_token].start;
113 return mod.addZIRUnOp(scope, src, .boolnot, operand);
114}
115
116fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
117 if (infix_node.lhs.tag == .Identifier) {
118 const ident = @fieldParentPtr(ast.Node.Identifier, "base", infix_node.lhs);
208fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!void {
209 if (infix_node.lhs.castTag(.Identifier)) |ident| {
119210 const tree = scope.tree();
120211 const ident_name = try identifierTokenString(mod, scope, ident.token);
121212 if (std.mem.eql(u8, ident_name, "_")) {
122 return expr(mod, scope, infix_node.rhs);
213 _ = try expr(mod, scope, .discard, infix_node.rhs);
214 return;
123215 } else {
124216 return mod.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{});
125217 }
......@@ -128,6 +220,17 @@ fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) Inne
128220 }
129221}
130222
223fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
224 const tree = scope.tree();
225 const src = tree.token_locs[node.op_token].start;
226 const bool_type = try mod.addZIRInstConst(scope, src, .{
227 .ty = Type.initTag(.type),
228 .val = Value.initTag(.bool_type),
229 });
230 const operand = try expr(mod, scope, .{ .ty = bool_type }, node.rhs);
231 return mod.addZIRUnOp(scope, src, .boolnot, operand);
232}
233
131234/// Identifier token -> String (allocated in scope.arena())
132235pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 {
133236 const tree = scope.tree();
......@@ -148,7 +251,7 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex)
148251 return ident_name;
149252}
150253
151pub fn identifierStringInst(mod: *Module, scope: *Scope, node: *ast.Node.Identifier) InnerError!*zir.Inst {
254pub fn identifierStringInst(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
152255 const tree = scope.tree();
153256 const src = tree.token_locs[node.token].start;
154257
......@@ -158,10 +261,11 @@ pub fn identifierStringInst(mod: *Module, scope: *Scope, node: *ast.Node.Identif
158261}
159262
160263fn field(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
264 // TODO introduce lvalues
161265 const tree = scope.tree();
162266 const src = tree.token_locs[node.op_token].start;
163267
164 const lhs = try expr(mod, scope, node.lhs);
268 const lhs = try expr(mod, scope, .none, node.lhs);
165269 const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?);
166270
167271 const pointer = try mod.addZIRInst(scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{});
......@@ -171,26 +275,44 @@ fn field(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp) InnerError!
171275fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
172276 const tree = scope.tree();
173277 const src = tree.token_locs[node.rtoken].start;
174 const lhs = try expr(mod, scope, node.lhs);
278 const lhs = try expr(mod, scope, .none, node.lhs);
175279 return mod.addZIRUnOp(scope, src, .deref, lhs);
176280}
177281
178fn simpleInfixOp(
282fn cmp(
283 mod: *Module,
284 scope: *Scope,
285 rl: ResultLoc,
286 infix_node: *ast.Node.SimpleInfixOp,
287 cmp_inst_tag: zir.Inst.Tag,
288) InnerError!*zir.Inst {
289 const tree = scope.tree();
290 const src = tree.token_locs[infix_node.op_token].start;
291
292 const lhs = try expr(mod, scope, .none, infix_node.lhs);
293 const rhs = try expr(mod, scope, .none, infix_node.rhs);
294 const result = try mod.addZIRBinOp(scope, src, cmp_inst_tag, lhs, rhs);
295 return rlWrap(mod, scope, rl, result);
296}
297
298fn arithmetic(
179299 mod: *Module,
180300 scope: *Scope,
301 rl: ResultLoc,
181302 infix_node: *ast.Node.SimpleInfixOp,
182303 op_inst_tag: zir.Inst.Tag,
183304) InnerError!*zir.Inst {
184 const lhs = try expr(mod, scope, infix_node.lhs);
185 const rhs = try expr(mod, scope, infix_node.rhs);
305 const lhs = try expr(mod, scope, .none, infix_node.lhs);
306 const rhs = try expr(mod, scope, .none, infix_node.rhs);
186307
187308 const tree = scope.tree();
188309 const src = tree.token_locs[infix_node.op_token].start;
189310
190 return mod.addZIRBinOp(scope, src, op_inst_tag, lhs, rhs);
311 const result = try mod.addZIRBinOp(scope, src, op_inst_tag, lhs, rhs);
312 return rlWrap(mod, scope, rl, result);
191313}
192314
193fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.Inst {
315fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst {
194316 if (if_node.payload) |payload| {
195317 return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for optionals", .{});
196318 }
......@@ -207,10 +329,14 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In
207329 };
208330 defer block_scope.instructions.deinit(mod.gpa);
209331
210 const cond = try expr(mod, &block_scope.base, if_node.condition);
211
212332 const tree = scope.tree();
213333 const if_src = tree.token_locs[if_node.if_token].start;
334 const bool_type = try mod.addZIRInstConst(scope, if_src, .{
335 .ty = Type.initTag(.type),
336 .val = Value.initTag(.bool_type),
337 });
338 const cond = try expr(mod, &block_scope.base, .{ .ty = bool_type }, if_node.condition);
339
214340 const condbr = try mod.addZIRInstSpecial(&block_scope.base, if_src, zir.Inst.CondBr, .{
215341 .condition = cond,
216342 .then_body = undefined, // populated below
......@@ -228,7 +354,16 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In
228354 };
229355 defer then_scope.instructions.deinit(mod.gpa);
230356
231 const then_result = try expr(mod, &then_scope.base, if_node.body);
357 // Most result location types can be forwarded directly; however
358 // if we need to write to a pointer which has an inferred type,
359 // proper type inference requires peer type resolution on the if's
360 // branches.
361 const branch_rl: ResultLoc = switch (rl) {
362 .discard, .none, .ty, .ptr => rl,
363 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
364 };
365
366 const then_result = try expr(mod, &then_scope.base, branch_rl, if_node.body);
232367 if (!then_result.tag.isNoReturn()) {
233368 const then_src = tree.token_locs[if_node.body.lastToken()].start;
234369 _ = try mod.addZIRInst(&then_scope.base, then_src, zir.Inst.Break, .{
......@@ -249,7 +384,7 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In
249384 defer else_scope.instructions.deinit(mod.gpa);
250385
251386 if (if_node.@"else") |else_node| {
252 const else_result = try expr(mod, &else_scope.base, else_node.body);
387 const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body);
253388 if (!else_result.tag.isNoReturn()) {
254389 const else_src = tree.token_locs[else_node.body.lastToken()].start;
255390 _ = try mod.addZIRInst(&else_scope.base, else_src, zir.Inst.Break, .{
......@@ -272,27 +407,25 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In
272407 return &block.base;
273408}
274409
275fn controlFlowExpr(
276 mod: *Module,
277 scope: *Scope,
278 cfe: *ast.Node.ControlFlowExpression,
279) InnerError!*zir.Inst {
280 switch (cfe.kind) {
281 .Break => return mod.failNode(scope, &cfe.base, "TODO implement astgen.Expr for Break", .{}),
282 .Continue => return mod.failNode(scope, &cfe.base, "TODO implement astgen.Expr for Continue", .{}),
283 .Return => {},
284 }
410fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst {
285411 const tree = scope.tree();
286412 const src = tree.token_locs[cfe.ltoken].start;
287 if (cfe.rhs) |rhs_node| {
288 const operand = try expr(mod, scope, rhs_node);
289 return mod.addZIRUnOp(scope, src, .@"return", operand);
413 if (cfe.getRHS()) |rhs_node| {
414 if (nodeMayNeedMemoryLocation(rhs_node)) {
415 const ret_ptr = try mod.addZIRNoOp(scope, src, .ret_ptr);
416 const operand = try expr(mod, scope, .{ .ptr = ret_ptr }, rhs_node);
417 return mod.addZIRUnOp(scope, src, .@"return", operand);
418 } else {
419 const fn_ret_ty = try mod.addZIRNoOp(scope, src, .ret_type);
420 const operand = try expr(mod, scope, .{ .ty = fn_ret_ty }, rhs_node);
421 return mod.addZIRUnOp(scope, src, .@"return", operand);
422 }
290423 } else {
291424 return mod.addZIRNoOp(scope, src, .returnvoid);
292425 }
293426}
294427
295fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst {
428fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.OneToken) InnerError!*zir.Inst {
296429 const tracy = trace(@src());
297430 defer tracy.end();
298431
......@@ -345,12 +478,19 @@ fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerErr
345478 {
346479 var s = scope;
347480 while (true) switch (s.tag) {
348 .local_var => {
349 const local_var = s.cast(Scope.LocalVar).?;
350 if (mem.eql(u8, local_var.name, ident_name)) {
351 return local_var.inst;
481 .local_val => {
482 const local_val = s.cast(Scope.LocalVal).?;
483 if (mem.eql(u8, local_val.name, ident_name)) {
484 return local_val.inst;
485 }
486 s = local_val.parent;
487 },
488 .local_ptr => {
489 const local_ptr = s.cast(Scope.LocalPtr).?;
490 if (mem.eql(u8, local_ptr.name, ident_name)) {
491 return try mod.addZIRUnOp(scope, src, .deref, local_ptr.ptr);
352492 }
353 s = local_var.parent;
493 s = local_ptr.parent;
354494 },
355495 .gen_zir => s = s.cast(Scope.GenZIR).?.parent,
356496 else => break,
......@@ -364,7 +504,7 @@ fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerErr
364504 return mod.failNode(scope, &ident.base, "use of undeclared identifier '{}'", .{ident_name});
365505}
366506
367fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral) InnerError!*zir.Inst {
507fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.OneToken) InnerError!*zir.Inst {
368508 const tree = scope.tree();
369509 const unparsed_bytes = tree.tokenSlice(str_lit.token);
370510 const arena = scope.arena();
......@@ -383,7 +523,7 @@ fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral)
383523 return mod.addZIRInst(scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
384524}
385525
386fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral) InnerError!*zir.Inst {
526fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) InnerError!*zir.Inst {
387527 const arena = scope.arena();
388528 const tree = scope.tree();
389529 const prefixed_bytes = tree.tokenSlice(int_lit.token);
......@@ -414,7 +554,7 @@ fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral
414554 }
415555}
416556
417fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.FloatLiteral) InnerError!*zir.Inst {
557fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.OneToken) InnerError!*zir.Inst {
418558 const arena = scope.arena();
419559 const tree = scope.tree();
420560 const bytes = tree.tokenSlice(float_lit.token);
......@@ -434,30 +574,38 @@ fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.FloatLiteral)
434574 });
435575}
436576
437fn primitiveLiteral(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst {
577fn undefLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
438578 const arena = scope.arena();
439579 const tree = scope.tree();
440 const src = tree.token_locs[node.firstToken()].start;
580 const src = tree.token_locs[node.token].start;
581 return mod.addZIRInstConst(scope, src, .{
582 .ty = Type.initTag(.@"undefined"),
583 .val = Value.initTag(.undef),
584 });
585}
441586
442 if (node.cast(ast.Node.BoolLiteral)) |bool_node| {
443 return mod.addZIRInstConst(scope, src, .{
444 .ty = Type.initTag(.bool),
445 .val = if (tree.token_ids[bool_node.token] == .Keyword_true)
446 Value.initTag(.bool_true)
447 else
448 Value.initTag(.bool_false),
449 });
450 } else if (node.tag == .UndefinedLiteral) {
451 return mod.addZIRInstConst(scope, src, .{
452 .ty = Type.initTag(.@"undefined"),
453 .val = Value.initTag(.undef),
454 });
455 } else if (node.tag == .NullLiteral) {
456 return mod.addZIRInstConst(scope, src, .{
457 .ty = Type.initTag(.@"null"),
458 .val = Value.initTag(.null_value),
459 });
460 } else unreachable;
587fn boolLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
588 const arena = scope.arena();
589 const tree = scope.tree();
590 const src = tree.token_locs[node.token].start;
591 return mod.addZIRInstConst(scope, src, .{
592 .ty = Type.initTag(.bool),
593 .val = switch (tree.token_ids[node.token]) {
594 .Keyword_true => Value.initTag(.bool_true),
595 .Keyword_false => Value.initTag(.bool_false),
596 else => unreachable,
597 },
598 });
599}
600
601fn nullLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
602 const arena = scope.arena();
603 const tree = scope.tree();
604 const src = tree.token_locs[node.token].start;
605 return mod.addZIRInstConst(scope, src, .{
606 .ty = Type.initTag(.@"null"),
607 .val = Value.initTag(.null_value),
608 });
461609}
462610
463611fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst {
......@@ -470,19 +618,26 @@ fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zi
470618 const inputs = try arena.alloc(*zir.Inst, asm_node.inputs.len);
471619 const args = try arena.alloc(*zir.Inst, asm_node.inputs.len);
472620
621 const src = tree.token_locs[asm_node.asm_token].start;
622
623 const str_type = try mod.addZIRInstConst(scope, src, .{
624 .ty = Type.initTag(.type),
625 .val = Value.initTag(.const_slice_u8_type),
626 });
627 const str_type_rl: ResultLoc = .{ .ty = str_type };
628
473629 for (asm_node.inputs) |input, i| {
474630 // TODO semantically analyze constraints
475 inputs[i] = try expr(mod, scope, input.constraint);
476 args[i] = try expr(mod, scope, input.expr);
631 inputs[i] = try expr(mod, scope, str_type_rl, input.constraint);
632 args[i] = try expr(mod, scope, .none, input.expr);
477633 }
478634
479 const src = tree.token_locs[asm_node.asm_token].start;
480635 const return_type = try mod.addZIRInstConst(scope, src, .{
481636 .ty = Type.initTag(.type),
482637 .val = Value.initTag(.void_type),
483638 });
484639 const asm_inst = try mod.addZIRInst(scope, src, zir.Inst.Asm, .{
485 .asm_source = try expr(mod, scope, asm_node.template),
640 .asm_source = try expr(mod, scope, str_type_rl, asm_node.template),
486641 .return_type = return_type,
487642 }, .{
488643 .@"volatile" = asm_node.volatile_token != null,
......@@ -493,63 +648,174 @@ fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zi
493648 return asm_inst;
494649}
495650
496fn builtinCall(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
651fn ensureBuiltinParamCount(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall, count: u32) !void {
652 if (call.params_len == count)
653 return;
654
655 const s = if (count == 1) "" else "s";
656 return mod.failTok(scope, call.builtin_token, "expected {} parameter{}, found {}", .{ count, s, call.params_len });
657}
658
659fn simpleCast(
660 mod: *Module,
661 scope: *Scope,
662 rl: ResultLoc,
663 call: *ast.Node.BuiltinCall,
664 inst_tag: zir.Inst.Tag,
665) InnerError!*zir.Inst {
666 try ensureBuiltinParamCount(mod, scope, call, 2);
497667 const tree = scope.tree();
498 const builtin_name = tree.tokenSlice(call.builtin_token);
499668 const src = tree.token_locs[call.builtin_token].start;
669 const type_type = try mod.addZIRInstConst(scope, src, .{
670 .ty = Type.initTag(.type),
671 .val = Value.initTag(.type_type),
672 });
673 const params = call.params();
674 const dest_type = try expr(mod, scope, .{ .ty = type_type }, params[0]);
675 const rhs = try expr(mod, scope, .none, params[1]);
676 const result = try mod.addZIRBinOp(scope, src, inst_tag, dest_type, rhs);
677 return rlWrap(mod, scope, rl, result);
678}
500679
501 inline for (std.meta.declarations(zir.Inst)) |inst| {
502 if (inst.data != .Type) continue;
503 const T = inst.data.Type;
504 if (!@hasDecl(T, "builtin_name")) continue;
505 if (std.mem.eql(u8, builtin_name, T.builtin_name)) {
506 var value: T = undefined;
507 const positionals = @typeInfo(std.meta.fieldInfo(T, "positionals").field_type).Struct;
508 if (positionals.fields.len == 0) {
509 return mod.addZIRInst(scope, src, T, value.positionals, value.kw_args);
510 }
511 const arg_count: ?usize = if (positionals.fields[0].field_type == []*zir.Inst) null else positionals.fields.len;
512 if (arg_count) |some| {
513 if (call.params_len != some) {
514 return mod.failTok(
515 scope,
516 call.builtin_token,
517 "expected {} parameter{}, found {}",
518 .{ some, if (some == 1) "" else "s", call.params_len },
519 );
520 }
521 const params = call.params();
522 inline for (positionals.fields) |p, i| {
523 @field(value.positionals, p.name) = try expr(mod, scope, params[i]);
524 }
525 } else {
526 return mod.failTok(scope, call.builtin_token, "TODO var args builtin '{}'", .{builtin_name});
527 }
680fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
681 try ensureBuiltinParamCount(mod, scope, call, 1);
682 const operand = try expr(mod, scope, .none, call.params()[0]);
683 const tree = scope.tree();
684 const src = tree.token_locs[call.builtin_token].start;
685 return mod.addZIRUnOp(scope, src, .ptrtoint, operand);
686}
528687
529 return mod.addZIRInst(scope, src, T, value.positionals, .{});
530 }
688fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
689 try ensureBuiltinParamCount(mod, scope, call, 2);
690 const tree = scope.tree();
691 const src = tree.token_locs[call.builtin_token].start;
692 const params = call.params();
693 const dest_type = try typeExpr(mod, scope, params[0]);
694 switch (rl) {
695 .none => return try expr(mod, scope, .{ .ty = dest_type }, params[1]),
696 .discard => {
697 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);
698 _ = try mod.addZIRUnOp(scope, result.src, .ensure_result_non_error, result);
699 return result;
700 },
701 .ty => |result_ty| {
702 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);
703 return mod.addZIRBinOp(scope, src, .as, result_ty, result);
704 },
705 .ptr => |result_ptr| {
706 const casted_result_ptr = try mod.addZIRBinOp(scope, src, .coerce_result_ptr, dest_type, result_ptr);
707 return expr(mod, scope, .{ .ptr = casted_result_ptr }, params[1]);
708 },
709 .bitcasted_ptr => |bitcasted_ptr| {
710 // TODO here we should be able to resolve the inference; we now have a type for the result.
711 return mod.failTok(scope, call.builtin_token, "TODO implement @as with result location @bitCast", .{});
712 },
713 .inferred_ptr => |result_alloc| {
714 // TODO here we should be able to resolve the inference; we now have a type for the result.
715 return mod.failTok(scope, call.builtin_token, "TODO implement @as with inferred-type result location pointer", .{});
716 },
717 .block_ptr => |block_ptr| {
718 const casted_block_ptr = try mod.addZIRInst(scope, src, zir.Inst.CoerceResultBlockPtr, .{
719 .dest_type = dest_type,
720 .block = block_ptr,
721 }, .{});
722 return expr(mod, scope, .{ .ptr = casted_block_ptr }, params[1]);
723 },
724 }
725}
726
727fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
728 try ensureBuiltinParamCount(mod, scope, call, 2);
729 const tree = scope.tree();
730 const src = tree.token_locs[call.builtin_token].start;
731 const type_type = try mod.addZIRInstConst(scope, src, .{
732 .ty = Type.initTag(.type),
733 .val = Value.initTag(.type_type),
734 });
735 const params = call.params();
736 const dest_type = try expr(mod, scope, .{ .ty = type_type }, params[0]);
737 switch (rl) {
738 .none => {
739 const operand = try expr(mod, scope, .none, params[1]);
740 return mod.addZIRBinOp(scope, src, .bitcast, dest_type, operand);
741 },
742 .discard => {
743 const operand = try expr(mod, scope, .none, params[1]);
744 const result = try mod.addZIRBinOp(scope, src, .bitcast, dest_type, operand);
745 _ = try mod.addZIRUnOp(scope, result.src, .ensure_result_non_error, result);
746 return result;
747 },
748 .ty => |result_ty| {
749 const result = try expr(mod, scope, .none, params[1]);
750 const bitcasted = try mod.addZIRBinOp(scope, src, .bitcast, dest_type, result);
751 return mod.addZIRBinOp(scope, src, .as, result_ty, bitcasted);
752 },
753 .ptr => |result_ptr| {
754 const casted_result_ptr = try mod.addZIRUnOp(scope, src, .bitcast_result_ptr, result_ptr);
755 return expr(mod, scope, .{ .bitcasted_ptr = casted_result_ptr.castTag(.bitcast_result_ptr).? }, params[1]);
756 },
757 .bitcasted_ptr => |bitcasted_ptr| {
758 return mod.failTok(scope, call.builtin_token, "TODO implement @bitCast with result location another @bitCast", .{});
759 },
760 .block_ptr => |block_ptr| {
761 return mod.failTok(scope, call.builtin_token, "TODO implement @bitCast with result location inferred peer types", .{});
762 },
763 .inferred_ptr => |result_alloc| {
764 // TODO here we should be able to resolve the inference; we now have a type for the result.
765 return mod.failTok(scope, call.builtin_token, "TODO implement @bitCast with inferred-type result location pointer", .{});
766 },
531767 }
532 return mod.failTok(scope, call.builtin_token, "TODO implement builtin call for '{}'", .{builtin_name});
533768}
534769
535fn callExpr(mod: *Module, scope: *Scope, node: *ast.Node.Call) InnerError!*zir.Inst {
770fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
536771 const tree = scope.tree();
537 const lhs = try expr(mod, scope, node.lhs);
772 const builtin_name = tree.tokenSlice(call.builtin_token);
773
774 // We handle the different builtins manually because they have different semantics depending
775 // on the function. For example, `@as` and others participate in result location semantics,
776 // and `@cImport` creates a special scope that collects a .c source code text buffer.
777 // Also, some builtins have a variable number of parameters.
778
779 if (mem.eql(u8, builtin_name, "@ptrToInt")) {
780 return rlWrap(mod, scope, rl, try ptrToInt(mod, scope, call));
781 } else if (mem.eql(u8, builtin_name, "@as")) {
782 return as(mod, scope, rl, call);
783 } else if (mem.eql(u8, builtin_name, "@floatCast")) {
784 return simpleCast(mod, scope, rl, call, .floatcast);
785 } else if (mem.eql(u8, builtin_name, "@intCast")) {
786 return simpleCast(mod, scope, rl, call, .intcast);
787 } else if (mem.eql(u8, builtin_name, "@bitCast")) {
788 return bitCast(mod, scope, rl, call);
789 } else {
790 return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{}'", .{builtin_name});
791 }
792}
793
794fn callExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Call) InnerError!*zir.Inst {
795 const tree = scope.tree();
796 const lhs = try expr(mod, scope, .none, node.lhs);
538797
539798 const param_nodes = node.params();
540799 const args = try scope.getGenZIR().arena.alloc(*zir.Inst, param_nodes.len);
541800 for (param_nodes) |param_node, i| {
542 args[i] = try expr(mod, scope, param_node);
801 const param_src = tree.token_locs[param_node.firstToken()].start;
802 const param_type = try mod.addZIRInst(scope, param_src, zir.Inst.ParamType, .{
803 .func = lhs,
804 .arg_index = i,
805 }, .{});
806 args[i] = try expr(mod, scope, .{ .ty = param_type }, param_node);
543807 }
544808
545809 const src = tree.token_locs[node.lhs.firstToken()].start;
546 return mod.addZIRInst(scope, src, zir.Inst.Call, .{
810 const result = try mod.addZIRInst(scope, src, zir.Inst.Call, .{
547811 .func = lhs,
548812 .args = args,
549813 }, .{});
814 // TODO function call with result location
815 return rlWrap(mod, scope, rl, result);
550816}
551817
552fn unreach(mod: *Module, scope: *Scope, unreach_node: *ast.Node.Unreachable) InnerError!*zir.Inst {
818fn unreach(mod: *Module, scope: *Scope, unreach_node: *ast.Node.OneToken) InnerError!*zir.Inst {
553819 const tree = scope.tree();
554820 const src = tree.token_locs[unreach_node.token].start;
555821 return mod.addZIRNoOp(scope, src, .@"unreachable");
......@@ -611,7 +877,9 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
611877 .FieldInitializer,
612878 => unreachable,
613879
614 .ControlFlowExpression,
880 .Return,
881 .Break,
882 .Continue,
615883 .BitNot,
616884 .BoolNot,
617885 .VarDecl,
......@@ -722,3 +990,39 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
722990 }
723991 }
724992}
993
994/// Applies `rl` semantics to `inst`. Expressions which do not do their own handling of
995/// result locations must call this function on their result.
996/// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.
997/// If the `ResultLoc` is `ty`, it will coerce the result to the type.
998fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerError!*zir.Inst {
999 switch (rl) {
1000 .none => return result,
1001 .discard => {
1002 // Emit a compile error for discarding error values.
1003 _ = try mod.addZIRUnOp(scope, result.src, .ensure_result_non_error, result);
1004 return result;
1005 },
1006 .ty => |ty_inst| return mod.addZIRBinOp(scope, result.src, .as, ty_inst, result),
1007 .ptr => |ptr_inst| {
1008 const casted_result = try mod.addZIRInst(scope, result.src, zir.Inst.CoerceToPtrElem, .{
1009 .ptr = ptr_inst,
1010 .value = result,
1011 }, .{});
1012 _ = try mod.addZIRInst(scope, result.src, zir.Inst.Store, .{
1013 .ptr = ptr_inst,
1014 .value = casted_result,
1015 }, .{});
1016 return casted_result;
1017 },
1018 .bitcasted_ptr => |bitcasted_ptr| {
1019 return mod.fail(scope, result.src, "TODO implement rlWrap .bitcasted_ptr", .{});
1020 },
1021 .inferred_ptr => |alloc| {
1022 return mod.fail(scope, result.src, "TODO implement rlWrap .inferred_ptr", .{});
1023 },
1024 .block_ptr => |block_ptr| {
1025 return mod.fail(scope, result.src, "TODO implement rlWrap .block_ptr", .{});
1026 },
1027 }
1028}
src-self-hosted/codegen/c.zig+3-17
......@@ -90,7 +90,7 @@ fn genFn(file: *C, decl: *Decl) !void {
9090 const instructions = func.analysis.success.instructions;
9191 if (instructions.len > 0) {
9292 for (instructions) |inst| {
93 try writer.writeAll("\n\t");
93 try writer.writeAll("\n ");
9494 switch (inst.tag) {
9595 .assembly => try genAsm(file, inst.castTag(.assembly).?, decl),
9696 .call => try genCall(file, inst.castTag(.call).?, decl),
......@@ -106,21 +106,7 @@ fn genFn(file: *C, decl: *Decl) !void {
106106}
107107
108108fn genRet(file: *C, inst: *Inst.UnOp, decl: *Decl, expected_return_type: Type) !void {
109 const writer = file.main.writer();
110 const ret_value = inst.operand;
111 const value = ret_value.value().?;
112 if (expected_return_type.eql(ret_value.ty))
113 return file.fail(decl.src(), "TODO return {}", .{expected_return_type})
114 else if (expected_return_type.isInt() and ret_value.ty.tag() == .comptime_int)
115 if (value.intFitsInType(expected_return_type, file.options.target))
116 if (expected_return_type.intInfo(file.options.target).bits <= 64)
117 try writer.print("return {};", .{value.toUnsignedInt()})
118 else
119 return file.fail(decl.src(), "TODO return ints > 64 bits", .{})
120 else
121 return file.fail(decl.src(), "comptime int {} does not fit in {}", .{ value.toUnsignedInt(), expected_return_type })
122 else
123 return file.fail(decl.src(), "return type mismatch: expected {}, found {}", .{ expected_return_type, ret_value.ty });
109 return file.fail(decl.src(), "TODO return {}", .{expected_return_type});
124110}
125111
126112fn genCall(file: *C, inst: *Inst.Call, decl: *Decl) !void {
......@@ -162,7 +148,7 @@ fn genAsm(file: *C, as: *Inst.Assembly, decl: *Decl) !void {
162148 if (c.val.tag() == .int_u64) {
163149 try writer.writeAll("register ");
164150 try renderType(file, writer, arg.ty, decl.src());
165 try writer.print(" {}_constant __asm__(\"{}\") = {};\n\t", .{ reg, reg, c.val.toUnsignedInt() });
151 try writer.print(" {}_constant __asm__(\"{}\") = {};\n ", .{ reg, reg, c.val.toUnsignedInt() });
166152 } else {
167153 return file.fail(decl.src(), "TODO inline asm {} args", .{c.val.tag()});
168154 }
src-self-hosted/link.zig+4
......@@ -1579,6 +1579,8 @@ pub fn createElfFile(allocator: *Allocator, file: fs.File, options: Options) !Fi
15791579 .elf => {},
15801580 .macho => return error.TODOImplementWritingMachO,
15811581 .wasm => return error.TODOImplementWritingWasmObjects,
1582 .hex => return error.TODOImplementWritingHex,
1583 .raw => return error.TODOImplementWritingRaw,
15821584 }
15831585
15841586 var self: File.Elf = .{
......@@ -1638,6 +1640,8 @@ fn openBinFileInner(allocator: *Allocator, file: fs.File, options: Options) !Fil
16381640 .elf => {},
16391641 .macho => return error.IncrFailed,
16401642 .wasm => return error.IncrFailed,
1643 .hex => return error.IncrFailed,
1644 .raw => return error.IncrFailed,
16411645 }
16421646 var self: File.Elf = .{
16431647 .allocator = allocator,
src-self-hosted/main.zig+38-10
......@@ -141,11 +141,19 @@ const usage_build_generic =
141141 \\ --name [name] Override output name
142142 \\ --mode [mode] Set the build mode
143143 \\ Debug (default) optimizations off, safety on
144 \\ ReleaseFast optimizations on, safety off
145 \\ ReleaseSafe optimizations on, safety on
146 \\ ReleaseSmall optimize for small binary, safety off
144 \\ ReleaseFast Optimizations on, safety off
145 \\ ReleaseSafe Optimizations on, safety on
146 \\ ReleaseSmall Optimize for small binary, safety off
147147 \\ --dynamic Force output to be dynamically linked
148148 \\ --strip Exclude debug symbols
149 \\ -ofmt=[mode] Override target object format
150 \\ elf Executable and Linking Format
151 \\ c Compile to C source code
152 \\ coff (planned) Common Object File Format (Windows)
153 \\ pe (planned) Portable Executable (Windows)
154 \\ macho (planned) macOS relocatables
155 \\ hex (planned) Intel IHEX
156 \\ raw (planned) Dump machine code directly
149157 \\
150158 \\Link Options:
151159 \\ -l[lib], --library [lib] Link against system library
......@@ -195,7 +203,7 @@ fn buildOutputType(
195203 var target_arch_os_abi: []const u8 = "native";
196204 var target_mcpu: ?[]const u8 = null;
197205 var target_dynamic_linker: ?[]const u8 = null;
198 var object_format: ?std.builtin.ObjectFormat = null;
206 var target_ofmt: ?[]const u8 = null;
199207
200208 var system_libs = std.ArrayList([]const u8).init(gpa);
201209 defer system_libs.deinit();
......@@ -282,12 +290,8 @@ fn buildOutputType(
282290 }
283291 i += 1;
284292 target_mcpu = args[i];
285 } else if (mem.eql(u8, arg, "--c")) {
286 if (object_format) |old| {
287 std.debug.print("attempted to override object format {} with C\n", .{old});
288 process.exit(1);
289 }
290 object_format = .c;
293 } else if (mem.startsWith(u8, arg, "-ofmt=")) {
294 target_ofmt = arg["-ofmt=".len..];
291295 } else if (mem.startsWith(u8, arg, "-mcpu=")) {
292296 target_mcpu = arg["-mcpu=".len..];
293297 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
......@@ -434,6 +438,30 @@ fn buildOutputType(
434438 process.exit(1);
435439 };
436440
441 const object_format: ?std.Target.ObjectFormat = blk: {
442 const ofmt = target_ofmt orelse break :blk null;
443 if (mem.eql(u8, ofmt, "elf")) {
444 break :blk .elf;
445 } else if (mem.eql(u8, ofmt, "c")) {
446 break :blk .c;
447 } else if (mem.eql(u8, ofmt, "coff")) {
448 break :blk .coff;
449 } else if (mem.eql(u8, ofmt, "pe")) {
450 break :blk .coff;
451 } else if (mem.eql(u8, ofmt, "macho")) {
452 break :blk .macho;
453 } else if (mem.eql(u8, ofmt, "wasm")) {
454 break :blk .wasm;
455 } else if (mem.eql(u8, ofmt, "hex")) {
456 break :blk .hex;
457 } else if (mem.eql(u8, ofmt, "raw")) {
458 break :blk .raw;
459 } else {
460 std.debug.print("unsupported object format: {}", .{ofmt});
461 process.exit(1);
462 }
463 };
464
437465 const bin_path = switch (emit_bin) {
438466 .no => {
439467 std.debug.print("-fno-emit-bin not supported yet", .{});
src-self-hosted/translate_c.zig+165-91
......@@ -1308,8 +1308,7 @@ fn transBinaryOperator(
13081308 const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
13091309 if (expr) {
13101310 _ = try appendToken(rp.c, .Semicolon, ";");
1311 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
1312 break_node.rhs = rhs;
1311 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label, rhs);
13131312 try block_scope.statements.append(&break_node.base);
13141313 const block_node = try block_scope.complete(rp.c);
13151314 const rparen = try appendToken(rp.c, .RParen, ")");
......@@ -1881,12 +1880,19 @@ fn transReturnStmt(
18811880 scope: *Scope,
18821881 expr: *const ZigClangReturnStmt,
18831882) TransError!*ast.Node {
1884 const node = try transCreateNodeReturnExpr(rp.c);
1885 if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {
1886 node.rhs = try transExprCoercing(rp, scope, val_expr, .used, .r_value);
1887 }
1883 const return_kw = try appendToken(rp.c, .Keyword_return, "return");
1884 const rhs: ?*ast.Node = if (ZigClangReturnStmt_getRetValue(expr)) |val_expr|
1885 try transExprCoercing(rp, scope, val_expr, .used, .r_value)
1886 else
1887 null;
1888 const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{
1889 .ltoken = return_kw,
1890 .tag = .Return,
1891 }, .{
1892 .rhs = rhs,
1893 });
18881894 _ = try appendToken(rp.c, .Semicolon, ";");
1889 return &node.base;
1895 return &return_expr.base;
18901896}
18911897
18921898fn transStringLiteral(
......@@ -1912,8 +1918,9 @@ fn transStringLiteral(
19121918 buf[buf.len - 1] = '"';
19131919
19141920 const token = try appendToken(rp.c, .StringLiteral, buf);
1915 const node = try rp.c.arena.create(ast.Node.StringLiteral);
1921 const node = try rp.c.arena.create(ast.Node.OneToken);
19161922 node.* = .{
1923 .base = .{ .tag = .StringLiteral },
19171924 .token = token,
19181925 };
19191926 return maybeSuppressResult(rp, scope, result_used, &node.base);
......@@ -2518,7 +2525,7 @@ fn transDoWhileLoop(
25182525 prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);
25192526 _ = try appendToken(rp.c, .RParen, ")");
25202527 if_node.condition = &prefix_op.base;
2521 if_node.body = &(try transCreateNodeBreak(rp.c, null)).base;
2528 if_node.body = &(try transCreateNodeBreak(rp.c, null, null)).base;
25222529 _ = try appendToken(rp.c, .Semicolon, ";");
25232530
25242531 const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: {
......@@ -2688,7 +2695,7 @@ fn transSwitch(
26882695 _ = try appendToken(rp.c, .Colon, ":");
26892696 if (!switch_scope.has_default) {
26902697 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
2691 else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch")).base;
2698 else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch", null)).base;
26922699 _ = try appendToken(rp.c, .Comma, ",");
26932700
26942701 if (switch_scope.case_index >= switch_scope.cases.len)
......@@ -2732,7 +2739,7 @@ fn transCase(
27322739 try transExpr(rp, scope, ZigClangCaseStmt_getLHS(stmt), .used, .r_value);
27332740
27342741 const switch_prong = try transCreateNodeSwitchCase(rp.c, expr);
2735 switch_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;
2742 switch_prong.expr = &(try transCreateNodeBreak(rp.c, label, null)).base;
27362743 _ = try appendToken(rp.c, .Comma, ",");
27372744
27382745 if (switch_scope.case_index >= switch_scope.cases.len)
......@@ -2768,7 +2775,7 @@ fn transDefault(
27682775 _ = try appendToken(rp.c, .Semicolon, ";");
27692776
27702777 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
2771 else_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;
2778 else_prong.expr = &(try transCreateNodeBreak(rp.c, label, null)).base;
27722779 _ = try appendToken(rp.c, .Comma, ",");
27732780
27742781 if (switch_scope.case_index >= switch_scope.cases.len)
......@@ -2843,8 +2850,9 @@ fn transCharLiteral(
28432850 }
28442851 var char_buf: [4]u8 = undefined;
28452852 const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)});
2846 const node = try rp.c.arena.create(ast.Node.CharLiteral);
2853 const node = try rp.c.arena.create(ast.Node.OneToken);
28472854 node.* = .{
2855 .base = .{ .tag = .CharLiteral },
28482856 .token = token,
28492857 };
28502858 break :blk &node.base;
......@@ -2889,8 +2897,11 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr,
28892897 const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value);
28902898 try block_scope.statements.append(result);
28912899 }
2892 const break_node = try transCreateNodeBreak(rp.c, "blk");
2893 break_node.rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value);
2900 const break_node = blk: {
2901 var tmp = try CtrlFlow.init(rp.c, .Break, "blk");
2902 const rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value);
2903 break :blk try tmp.finish(rhs);
2904 };
28942905 _ = try appendToken(rp.c, .Semicolon, ";");
28952906 try block_scope.statements.append(&break_node.base);
28962907 const block_node = try block_scope.complete(rp.c);
......@@ -3205,8 +3216,7 @@ fn transCreatePreCrement(
32053216 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);
32063217 try block_scope.statements.append(assign);
32073218
3208 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
3209 break_node.rhs = ref_node;
3219 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label, ref_node);
32103220 try block_scope.statements.append(&break_node.base);
32113221 const block_node = try block_scope.complete(rp.c);
32123222 // semicolon must immediately follow rbrace because it is the last token in a block
......@@ -3297,8 +3307,11 @@ fn transCreatePostCrement(
32973307 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);
32983308 try block_scope.statements.append(assign);
32993309
3300 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
3301 break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp);
3310 const break_node = blk: {
3311 var tmp_ctrl_flow = try CtrlFlow.initToken(rp.c, .Break, block_scope.label);
3312 const rhs = try transCreateNodeIdentifier(rp.c, tmp);
3313 break :blk try tmp_ctrl_flow.finish(rhs);
3314 };
33023315 try block_scope.statements.append(&break_node.base);
33033316 _ = try appendToken(rp.c, .Semicolon, ";");
33043317 const block_node = try block_scope.complete(rp.c);
......@@ -3490,8 +3503,7 @@ fn transCreateCompoundAssign(
34903503 try block_scope.statements.append(assign);
34913504 }
34923505
3493 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
3494 break_node.rhs = ref_node;
3506 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label, ref_node);
34953507 try block_scope.statements.append(&break_node.base);
34963508 const block_node = try block_scope.complete(rp.c);
34973509 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
......@@ -3567,10 +3579,8 @@ fn transCPtrCast(
35673579
35683580fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {
35693581 const break_scope = scope.getBreakableScope();
3570 const br = try transCreateNodeBreak(rp.c, if (break_scope.id == .Switch)
3571 "__switch"
3572 else
3573 null);
3582 const label_text: ?[]const u8 = if (break_scope.id == .Switch) "__switch" else null;
3583 const br = try transCreateNodeBreak(rp.c, label_text, null);
35743584 _ = try appendToken(rp.c, .Semicolon, ";");
35753585 return &br.base;
35763586}
......@@ -3578,8 +3588,9 @@ fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {
35783588fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFloatingLiteral, used: ResultUsed) TransError!*ast.Node {
35793589 // TODO use something more accurate
35803590 const dbl = ZigClangAPFloat_getValueAsApproximateDouble(stmt);
3581 const node = try rp.c.arena.create(ast.Node.FloatLiteral);
3591 const node = try rp.c.arena.create(ast.Node.OneToken);
35823592 node.* = .{
3593 .base = .{ .tag = .FloatLiteral },
35833594 .token = try appendTokenFmt(rp.c, .FloatLiteral, "{d}", .{dbl}),
35843595 };
35853596 return maybeSuppressResult(rp, scope, used, &node.base);
......@@ -3619,7 +3630,7 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
36193630 });
36203631 try block_scope.statements.append(&tmp_var.base);
36213632
3622 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);
3633 var break_node_tmp = try CtrlFlow.initToken(rp.c, .Break, block_scope.label);
36233634
36243635 const if_node = try transCreateNodeIf(rp.c);
36253636 var cond_scope = Scope.Condition{
......@@ -3641,7 +3652,7 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
36413652 if_node.@"else".?.body = try transExpr(rp, &block_scope.base, false_expr, .used, .r_value);
36423653 _ = try appendToken(rp.c, .Semicolon, ";");
36433654
3644 break_node.rhs = &if_node.base;
3655 const break_node = try break_node_tmp.finish(&if_node.base);
36453656 _ = try appendToken(rp.c, .Semicolon, ";");
36463657 try block_scope.statements.append(&break_node.base);
36473658 const block_node = try block_scope.complete(rp.c);
......@@ -3822,8 +3833,9 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC
38223833 if (int_bit_width != 0) {
38233834 // we can perform the log2 now.
38243835 const cast_bit_width = math.log2_int(u64, int_bit_width);
3825 const node = try rp.c.arena.create(ast.Node.IntegerLiteral);
3836 const node = try rp.c.arena.create(ast.Node.OneToken);
38263837 node.* = .{
3838 .base = .{ .tag = .IntegerLiteral },
38273839 .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),
38283840 };
38293841 return &node.base;
......@@ -3845,8 +3857,9 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC
38453857
38463858 const import_fn_call = try rp.c.createBuiltinCall("@import", 1);
38473859 const std_token = try appendToken(rp.c, .StringLiteral, "\"std\"");
3848 const std_node = try rp.c.arena.create(ast.Node.StringLiteral);
3860 const std_node = try rp.c.arena.create(ast.Node.OneToken);
38493861 std_node.* = .{
3862 .base = .{ .tag = .StringLiteral },
38503863 .token = std_token,
38513864 };
38523865 import_fn_call.params()[0] = &std_node.base;
......@@ -4081,8 +4094,11 @@ fn transCreateNodeAssign(
40814094 const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, lhs_eq_token, ident, .used, false);
40824095 try block_scope.statements.append(assign);
40834096
4084 const break_node = try transCreateNodeBreak(rp.c, label_name);
4085 break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp);
4097 const break_node = blk: {
4098 var tmp_ctrl_flow = try CtrlFlow.init(rp.c, .Break, label_name);
4099 const rhs_expr = try transCreateNodeIdentifier(rp.c, tmp);
4100 break :blk try tmp_ctrl_flow.finish(rhs_expr);
4101 };
40864102 _ = try appendToken(rp.c, .Semicolon, ";");
40874103 try block_scope.statements.append(&break_node.base);
40884104 const block_node = try block_scope.complete(rp.c);
......@@ -4255,28 +4271,19 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
42554271 };
42564272 defer c.arena.free(str);
42574273 const token = try appendToken(c, .IntegerLiteral, str);
4258 const node = try c.arena.create(ast.Node.IntegerLiteral);
4274 const node = try c.arena.create(ast.Node.OneToken);
42594275 node.* = .{
4276 .base = .{ .tag = .IntegerLiteral },
42604277 .token = token,
42614278 };
42624279 return &node.base;
42634280}
42644281
4265fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
4266 const ltoken = try appendToken(c, .Keyword_return, "return");
4267 const node = try c.arena.create(ast.Node.ControlFlowExpression);
4268 node.* = .{
4269 .ltoken = ltoken,
4270 .kind = .Return,
4271 .rhs = null,
4272 };
4273 return node;
4274}
4275
42764282fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
42774283 const token = try appendToken(c, .Keyword_undefined, "undefined");
4278 const node = try c.arena.create(ast.Node.UndefinedLiteral);
4284 const node = try c.arena.create(ast.Node.OneToken);
42794285 node.* = .{
4286 .base = .{ .tag = .UndefinedLiteral },
42804287 .token = token,
42814288 };
42824289 return &node.base;
......@@ -4284,8 +4291,9 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
42844291
42854292fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {
42864293 const token = try appendToken(c, .Keyword_null, "null");
4287 const node = try c.arena.create(ast.Node.NullLiteral);
4294 const node = try c.arena.create(ast.Node.OneToken);
42884295 node.* = .{
4296 .base = .{ .tag = .NullLiteral },
42894297 .token = token,
42904298 };
42914299 return &node.base;
......@@ -4296,8 +4304,9 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {
42964304 try appendToken(c, .Keyword_true, "true")
42974305 else
42984306 try appendToken(c, .Keyword_false, "false");
4299 const node = try c.arena.create(ast.Node.BoolLiteral);
4307 const node = try c.arena.create(ast.Node.OneToken);
43004308 node.* = .{
4309 .base = .{ .tag = .BoolLiteral },
43014310 .token = token,
43024311 };
43034312 return &node.base;
......@@ -4305,8 +4314,9 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {
43054314
43064315fn transCreateNodeInt(c: *Context, int: anytype) !*ast.Node {
43074316 const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int});
4308 const node = try c.arena.create(ast.Node.IntegerLiteral);
4317 const node = try c.arena.create(ast.Node.OneToken);
43094318 node.* = .{
4319 .base = .{ .tag = .IntegerLiteral },
43104320 .token = token,
43114321 };
43124322 return &node.base;
......@@ -4314,8 +4324,9 @@ fn transCreateNodeInt(c: *Context, int: anytype) !*ast.Node {
43144324
43154325fn transCreateNodeFloat(c: *Context, int: anytype) !*ast.Node {
43164326 const token = try appendTokenFmt(c, .FloatLiteral, "{}", .{int});
4317 const node = try c.arena.create(ast.Node.FloatLiteral);
4327 const node = try c.arena.create(ast.Node.OneToken);
43184328 node.* = .{
4329 .base = .{ .tag = .FloatLiteral },
43194330 .token = token,
43204331 };
43214332 return &node.base;
......@@ -4362,7 +4373,7 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
43624373
43634374 const block_lbrace = try appendToken(c, .LBrace, "{");
43644375
4365 const return_expr = try transCreateNodeReturnExpr(c);
4376 const return_kw = try appendToken(c, .Keyword_return, "return");
43664377 const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.getTrailer("init_node").?);
43674378
43684379 const call_expr = try c.createCall(unwrap_expr, fn_params.items.len);
......@@ -4376,7 +4387,12 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
43764387 }
43774388 call_expr.rtoken = try appendToken(c, .RParen, ")");
43784389
4379 return_expr.rhs = &call_expr.base;
4390 const return_expr = try ast.Node.ControlFlowExpression.create(c.arena, .{
4391 .ltoken = return_kw,
4392 .tag = .Return,
4393 }, .{
4394 .rhs = &call_expr.base,
4395 });
43804396 _ = try appendToken(c, .Semicolon, ";");
43814397
43824398 const block = try ast.Node.Block.alloc(c.arena, 1);
......@@ -4424,8 +4440,9 @@ fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node {
44244440}
44254441
44264442fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node {
4427 const node = try c.arena.create(ast.Node.StringLiteral);
4443 const node = try c.arena.create(ast.Node.OneToken);
44284444 node.* = .{
4445 .base = .{ .tag = .StringLiteral },
44294446 .token = try appendToken(c, .StringLiteral, str),
44304447 };
44314448 return &node.base;
......@@ -4455,28 +4472,77 @@ fn transCreateNodeElse(c: *Context) !*ast.Node.Else {
44554472 return node;
44564473}
44574474
4458fn transCreateNodeBreakToken(c: *Context, label: ?ast.TokenIndex) !*ast.Node.ControlFlowExpression {
4459 const other_token = label orelse return transCreateNodeBreak(c, null);
4475fn transCreateNodeBreakToken(
4476 c: *Context,
4477 label: ?ast.TokenIndex,
4478 rhs: ?*ast.Node,
4479) !*ast.Node.ControlFlowExpression {
4480 const other_token = label orelse return transCreateNodeBreak(c, null, rhs);
44604481 const loc = c.token_locs.items[other_token];
44614482 const label_name = c.source_buffer.items[loc.start..loc.end];
4462 return transCreateNodeBreak(c, label_name);
4483 return transCreateNodeBreak(c, label_name, rhs);
44634484}
44644485
4465fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowExpression {
4466 const ltoken = try appendToken(c, .Keyword_break, "break");
4467 const label_node = if (label) |l| blk: {
4468 _ = try appendToken(c, .Colon, ":");
4469 break :blk try transCreateNodeIdentifier(c, l);
4470 } else null;
4471 const node = try c.arena.create(ast.Node.ControlFlowExpression);
4472 node.* = .{
4473 .ltoken = ltoken,
4474 .kind = .{ .Break = label_node },
4475 .rhs = null,
4476 };
4477 return node;
4486fn transCreateNodeBreak(
4487 c: *Context,
4488 label: ?[]const u8,
4489 rhs: ?*ast.Node,
4490) !*ast.Node.ControlFlowExpression {
4491 var ctrl_flow = try CtrlFlow.init(c, .Break, label);
4492 return ctrl_flow.finish(rhs);
44784493}
44794494
4495const CtrlFlow = struct {
4496 c: *Context,
4497 ltoken: ast.TokenIndex,
4498 label_token: ?ast.TokenIndex,
4499 tag: ast.Node.Tag,
4500
4501 /// Does everything except the RHS.
4502 fn init(c: *Context, tag: ast.Node.Tag, label: ?[]const u8) !CtrlFlow {
4503 const kw: Token.Id = switch (tag) {
4504 .Break => .Keyword_break,
4505 .Continue => .Keyword_continue,
4506 .Return => .Keyword_return,
4507 else => unreachable,
4508 };
4509 const kw_text = switch (tag) {
4510 .Break => "break",
4511 .Continue => "continue",
4512 .Return => "return",
4513 else => unreachable,
4514 };
4515 const ltoken = try appendToken(c, kw, kw_text);
4516 const label_token = if (label) |l| blk: {
4517 _ = try appendToken(c, .Colon, ":");
4518 break :blk try appendToken(c, .Identifier, l);
4519 } else null;
4520 return CtrlFlow{
4521 .c = c,
4522 .ltoken = ltoken,
4523 .label_token = label_token,
4524 .tag = tag,
4525 };
4526 }
4527
4528 fn initToken(c: *Context, tag: ast.Node.Tag, label: ?ast.TokenIndex) !CtrlFlow {
4529 const other_token = label orelse return init(c, tag, null);
4530 const loc = c.token_locs.items[other_token];
4531 const label_name = c.source_buffer.items[loc.start..loc.end];
4532 return init(c, tag, label_name);
4533 }
4534
4535 fn finish(self: *CtrlFlow, rhs: ?*ast.Node) !*ast.Node.ControlFlowExpression {
4536 return ast.Node.ControlFlowExpression.create(self.c.arena, .{
4537 .ltoken = self.ltoken,
4538 .tag = self.tag,
4539 }, .{
4540 .label = self.label_token,
4541 .rhs = rhs,
4542 });
4543 }
4544};
4545
44804546fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
44814547 const while_tok = try appendToken(c, .Keyword_while, "while");
44824548 _ = try appendToken(c, .LParen, "(");
......@@ -4497,12 +4563,10 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
44974563
44984564fn transCreateNodeContinue(c: *Context) !*ast.Node {
44994565 const ltoken = try appendToken(c, .Keyword_continue, "continue");
4500 const node = try c.arena.create(ast.Node.ControlFlowExpression);
4501 node.* = .{
4566 const node = try ast.Node.ControlFlowExpression.create(c.arena, .{
45024567 .ltoken = ltoken,
4503 .kind = .{ .Continue = null },
4504 .rhs = null,
4505 };
4568 .tag = .Continue,
4569 }, .{});
45064570 _ = try appendToken(c, .Semicolon, ";");
45074571 return &node.base;
45084572}
......@@ -5006,8 +5070,9 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp
50065070 const semi_tok = try appendToken(c, .Semicolon, ";");
50075071 _ = try appendTokenFmt(c, .LineComment, "// {}", .{c.locStr(loc)});
50085072
5009 const msg_node = try c.arena.create(ast.Node.StringLiteral);
5073 const msg_node = try c.arena.create(ast.Node.OneToken);
50105074 msg_node.* = .{
5075 .base = .{ .tag = .StringLiteral },
50115076 .token = msg_tok,
50125077 };
50135078
......@@ -5110,8 +5175,9 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {
51105175
51115176fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
51125177 const token_index = try appendIdentifier(c, name);
5113 const identifier = try c.arena.create(ast.Node.Identifier);
5178 const identifier = try c.arena.create(ast.Node.OneToken);
51145179 identifier.* = .{
5180 .base = .{ .tag = .Identifier },
51155181 .token = token_index,
51165182 };
51175183 return &identifier.base;
......@@ -5119,8 +5185,9 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
51195185
51205186fn transCreateNodeIdentifierUnchecked(c: *Context, name: []const u8) !*ast.Node {
51215187 const token_index = try appendTokenFmt(c, .Identifier, "{}", .{name});
5122 const identifier = try c.arena.create(ast.Node.Identifier);
5188 const identifier = try c.arena.create(ast.Node.OneToken);
51235189 identifier.* = .{
5190 .base = .{ .tag = .Identifier },
51245191 .token = token_index,
51255192 };
51265193 return &identifier.base;
......@@ -5289,8 +5356,9 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
52895356 const param_name_tok = try appendIdentifier(c, mangled_name);
52905357 _ = try appendToken(c, .Colon, ":");
52915358
5292 const any_type = try c.arena.create(ast.Node.AnyType);
5359 const any_type = try c.arena.create(ast.Node.OneToken);
52935360 any_type.* = .{
5361 .base = .{ .tag = .AnyType },
52945362 .token = try appendToken(c, .Keyword_anytype, "anytype"),
52955363 };
52965364
......@@ -5322,7 +5390,7 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
53225390
53235391 const type_of = try c.createBuiltinCall("@TypeOf", 1);
53245392
5325 const return_expr = try transCreateNodeReturnExpr(c);
5393 const return_kw = try appendToken(c, .Keyword_return, "return");
53265394 const expr = try parseCExpr(c, it, source, source_loc, scope);
53275395 const last = it.next().?;
53285396 if (last.id != .Eof and last.id != .Nl)
......@@ -5337,13 +5405,17 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
53375405 const type_of_arg = if (expr.tag != .Block) expr else blk: {
53385406 const blk = @fieldParentPtr(ast.Node.Block, "base", expr);
53395407 const blk_last = blk.statements()[blk.statements_len - 1];
5340 std.debug.assert(blk_last.tag == .ControlFlowExpression);
5341 const br = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", blk_last);
5342 break :blk br.rhs.?;
5408 const br = blk_last.cast(ast.Node.ControlFlowExpression).?;
5409 break :blk br.getRHS().?;
53435410 };
53445411 type_of.params()[0] = type_of_arg;
53455412 type_of.rparen_token = try appendToken(c, .RParen, ")");
5346 return_expr.rhs = expr;
5413 const return_expr = try ast.Node.ControlFlowExpression.create(c.arena, .{
5414 .ltoken = return_kw,
5415 .tag = .Return,
5416 }, .{
5417 .rhs = expr,
5418 });
53475419
53485420 try block_scope.statements.append(&return_expr.base);
53495421 const block_node = try block_scope.complete(c);
......@@ -5416,8 +5488,7 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_
54165488 }
54175489 }
54185490
5419 const break_node = try transCreateNodeBreak(c, label_name);
5420 break_node.rhs = last;
5491 const break_node = try transCreateNodeBreak(c, label_name, last);
54215492 try block_scope.statements.append(&break_node.base);
54225493 const block_node = try block_scope.complete(c);
54235494 return &block_node.base;
......@@ -5656,15 +5727,17 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
56565727 const first_tok = it.list.at(0);
56575728 if (source[tok.start] != '\'' or source[tok.start + 1] == '\\' or tok.end - tok.start == 3) {
56585729 const token = try appendToken(c, .CharLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc));
5659 const node = try c.arena.create(ast.Node.CharLiteral);
5730 const node = try c.arena.create(ast.Node.OneToken);
56605731 node.* = .{
5732 .base = .{ .tag = .CharLiteral },
56615733 .token = token,
56625734 };
56635735 return &node.base;
56645736 } else {
56655737 const token = try appendTokenFmt(c, .IntegerLiteral, "0x{x}", .{source[tok.start + 1 .. tok.end - 1]});
5666 const node = try c.arena.create(ast.Node.IntegerLiteral);
5738 const node = try c.arena.create(ast.Node.OneToken);
56675739 node.* = .{
5740 .base = .{ .tag = .IntegerLiteral },
56685741 .token = token,
56695742 };
56705743 return &node.base;
......@@ -5673,8 +5746,9 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
56735746 .StringLiteral => {
56745747 const first_tok = it.list.at(0);
56755748 const token = try appendToken(c, .StringLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc));
5676 const node = try c.arena.create(ast.Node.StringLiteral);
5749 const node = try c.arena.create(ast.Node.OneToken);
56775750 node.* = .{
5751 .base = .{ .tag = .StringLiteral },
56785752 .token = token,
56795753 };
56805754 return &node.base;
......@@ -6224,7 +6298,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
62246298 => return node,
62256299
62266300 .Identifier => {
6227 const ident = node.cast(ast.Node.Identifier).?;
6301 const ident = node.castTag(.Identifier).?;
62286302 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
62296303 if (value.cast(ast.Node.VarDecl)) |var_decl|
62306304 return getContainer(c, var_decl.getTrailer("init_node").?);
......@@ -6238,7 +6312,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
62386312 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
62396313 for (container.fieldsAndDecls()) |field_ref| {
62406314 const field = field_ref.cast(ast.Node.ContainerField).?;
6241 const ident = infix.rhs.cast(ast.Node.Identifier).?;
6315 const ident = infix.rhs.castTag(.Identifier).?;
62426316 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
62436317 return getContainer(c, field.type_expr.?);
62446318 }
......@@ -6253,7 +6327,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
62536327}
62546328
62556329fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
6256 if (ref.cast(ast.Node.Identifier)) |ident| {
6330 if (ref.castTag(.Identifier)) |ident| {
62576331 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
62586332 if (value.cast(ast.Node.VarDecl)) |var_decl| {
62596333 if (var_decl.getTrailer("type_node")) |ty|
......@@ -6265,7 +6339,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
62656339 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
62666340 for (container.fieldsAndDecls()) |field_ref| {
62676341 const field = field_ref.cast(ast.Node.ContainerField).?;
6268 const ident = infix.rhs.cast(ast.Node.Identifier).?;
6342 const ident = infix.rhs.castTag(.Identifier).?;
62696343 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
62706344 return getContainer(c, field.type_expr.?);
62716345 }
src-self-hosted/zir.zig+116-75
......@@ -34,9 +34,17 @@ pub const Inst = struct {
3434
3535 /// These names are used directly as the instruction names in the text format.
3636 pub const Tag = enum {
37 /// Allocates stack local memory. Its lifetime ends when the block ends that contains
38 /// this instruction.
39 alloc,
40 /// Same as `alloc` except the type is inferred.
41 alloc_inferred,
3742 /// Function parameter value. These must be first in a function's main block,
3843 /// in respective order with the parameters.
3944 arg,
45 /// A typed result location pointer is bitcasted to a new result location pointer.
46 /// The new result location pointer has an inferred type.
47 bitcast_result_ptr,
4048 /// A labeled block of code, which can return a value.
4149 block,
4250 /// Return a value from a `Block`.
......@@ -45,6 +53,17 @@ pub const Inst = struct {
4553 /// Same as `break` but without an operand; the operand is assumed to be the void value.
4654 breakvoid,
4755 call,
56 /// Coerces a result location pointer to a new element type. It is evaluated "backwards"-
57 /// as type coercion from the new element type to the old element type.
58 /// LHS is destination element type, RHS is result pointer.
59 coerce_result_ptr,
60 /// This instruction does a `coerce_result_ptr` operation on a `Block`'s
61 /// result location pointer, whose type is inferred by peer type resolution on the
62 /// `Block`'s corresponding `break` instructions.
63 coerce_result_block_ptr,
64 /// Equivalent to `as(ptr_child_type(typeof(ptr)), value)`.
65 coerce_to_ptr_elem,
66 /// Emit an error message and fail compilation.
4867 compileerror,
4968 /// Special case, has no textual representation.
5069 @"const",
......@@ -57,7 +76,17 @@ pub const Inst = struct {
5776 declval,
5877 /// Same as declval but the parameter is a `*Module.Decl` rather than a name.
5978 declval_in_module,
79 /// Emits a compile error if the operand is not `void`.
80 ensure_result_used,
81 /// Emits a compile error if an error is ignored.
82 ensure_result_non_error,
6083 boolnot,
84 /// Obtains a pointer to the return value.
85 ret_ptr,
86 /// Obtains the return type of the in-scope function.
87 ret_type,
88 /// Write a value to a pointer.
89 store,
6190 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
6291 str,
6392 int,
......@@ -73,6 +102,9 @@ pub const Inst = struct {
73102 @"fn",
74103 fntype,
75104 @"export",
105 /// Given a reference to a function and a parameter index, returns the
106 /// type of the parameter. TODO what happens when the parameter is `anytype`?
107 param_type,
76108 primitive,
77109 intcast,
78110 bitcast,
......@@ -96,6 +128,9 @@ pub const Inst = struct {
96128 .breakpoint,
97129 .@"unreachable",
98130 .returnvoid,
131 .alloc_inferred,
132 .ret_ptr,
133 .ret_type,
99134 => NoOp,
100135
101136 .boolnot,
......@@ -103,6 +138,11 @@ pub const Inst = struct {
103138 .@"return",
104139 .isnull,
105140 .isnonnull,
141 .ptrtoint,
142 .alloc,
143 .ensure_result_used,
144 .ensure_result_non_error,
145 .bitcast_result_ptr,
106146 => UnOp,
107147
108148 .add,
......@@ -113,32 +153,36 @@ pub const Inst = struct {
113153 .cmp_gte,
114154 .cmp_gt,
115155 .cmp_neq,
156 .as,
157 .floatcast,
158 .intcast,
159 .bitcast,
160 .coerce_result_ptr,
116161 => BinOp,
117162
118163 .block => Block,
119164 .@"break" => Break,
120165 .breakvoid => BreakVoid,
121166 .call => Call,
167 .coerce_to_ptr_elem => CoerceToPtrElem,
122168 .declref => DeclRef,
123169 .declref_str => DeclRefStr,
124170 .declval => DeclVal,
125171 .declval_in_module => DeclValInModule,
172 .coerce_result_block_ptr => CoerceResultBlockPtr,
126173 .compileerror => CompileError,
127174 .@"const" => Const,
175 .store => Store,
128176 .str => Str,
129177 .int => Int,
130178 .inttype => IntType,
131 .ptrtoint => PtrToInt,
132179 .fieldptr => FieldPtr,
133 .as => As,
134180 .@"asm" => Asm,
135181 .@"fn" => Fn,
136182 .@"export" => Export,
183 .param_type => ParamType,
137184 .primitive => Primitive,
138185 .fntype => FnType,
139 .intcast => IntCast,
140 .bitcast => BitCast,
141 .floatcast => FloatCast,
142186 .elemptr => ElemPtr,
143187 .condbr => CondBr,
144188 };
......@@ -148,15 +192,26 @@ pub const Inst = struct {
148192 /// Function calls do not count.
149193 pub fn isNoReturn(tag: Tag) bool {
150194 return switch (tag) {
195 .alloc,
196 .alloc_inferred,
151197 .arg,
198 .bitcast_result_ptr,
152199 .block,
153200 .breakpoint,
154201 .call,
202 .coerce_result_ptr,
203 .coerce_result_block_ptr,
204 .coerce_to_ptr_elem,
155205 .@"const",
156206 .declref,
157207 .declref_str,
158208 .declval,
159209 .declval_in_module,
210 .ensure_result_used,
211 .ensure_result_non_error,
212 .ret_ptr,
213 .ret_type,
214 .store,
160215 .str,
161216 .int,
162217 .inttype,
......@@ -168,6 +223,7 @@ pub const Inst = struct {
168223 .@"fn",
169224 .fntype,
170225 .@"export",
226 .param_type,
171227 .primitive,
172228 .intcast,
173229 .bitcast,
......@@ -292,6 +348,17 @@ pub const Inst = struct {
292348 },
293349 };
294350
351 pub const CoerceToPtrElem = struct {
352 pub const base_tag = Tag.coerce_to_ptr_elem;
353 base: Inst,
354
355 positionals: struct {
356 ptr: *Inst,
357 value: *Inst,
358 },
359 kw_args: struct {},
360 };
361
295362 pub const DeclRef = struct {
296363 pub const base_tag = Tag.declref;
297364 base: Inst,
......@@ -332,6 +399,17 @@ pub const Inst = struct {
332399 kw_args: struct {},
333400 };
334401
402 pub const CoerceResultBlockPtr = struct {
403 pub const base_tag = Tag.coerce_result_block_ptr;
404 base: Inst,
405
406 positionals: struct {
407 dest_type: *Inst,
408 block: *Block,
409 },
410 kw_args: struct {},
411 };
412
335413 pub const CompileError = struct {
336414 pub const base_tag = Tag.compileerror;
337415 base: Inst,
......@@ -352,33 +430,33 @@ pub const Inst = struct {
352430 kw_args: struct {},
353431 };
354432
355 pub const Str = struct {
356 pub const base_tag = Tag.str;
433 pub const Store = struct {
434 pub const base_tag = Tag.store;
357435 base: Inst,
358436
359437 positionals: struct {
360 bytes: []const u8,
438 ptr: *Inst,
439 value: *Inst,
361440 },
362441 kw_args: struct {},
363442 };
364443
365 pub const Int = struct {
366 pub const base_tag = Tag.int;
444 pub const Str = struct {
445 pub const base_tag = Tag.str;
367446 base: Inst,
368447
369448 positionals: struct {
370 int: BigIntConst,
449 bytes: []const u8,
371450 },
372451 kw_args: struct {},
373452 };
374453
375 pub const PtrToInt = struct {
376 pub const builtin_name = "@ptrToInt";
377 pub const base_tag = Tag.ptrtoint;
454 pub const Int = struct {
455 pub const base_tag = Tag.int;
378456 base: Inst,
379457
380458 positionals: struct {
381 operand: *Inst,
459 int: BigIntConst,
382460 },
383461 kw_args: struct {},
384462 };
......@@ -394,18 +472,6 @@ pub const Inst = struct {
394472 kw_args: struct {},
395473 };
396474
397 pub const As = struct {
398 pub const base_tag = Tag.as;
399 pub const builtin_name = "@as";
400 base: Inst,
401
402 positionals: struct {
403 dest_type: *Inst,
404 value: *Inst,
405 },
406 kw_args: struct {},
407 };
408
409475 pub const Asm = struct {
410476 pub const base_tag = Tag.@"asm";
411477 base: Inst,
......@@ -469,6 +535,17 @@ pub const Inst = struct {
469535 kw_args: struct {},
470536 };
471537
538 pub const ParamType = struct {
539 pub const base_tag = Tag.param_type;
540 base: Inst,
541
542 positionals: struct {
543 func: *Inst,
544 arg_index: usize,
545 },
546 kw_args: struct {},
547 };
548
472549 pub const Primitive = struct {
473550 pub const base_tag = Tag.primitive;
474551 base: Inst,
......@@ -559,42 +636,6 @@ pub const Inst = struct {
559636 };
560637 };
561638
562 pub const FloatCast = struct {
563 pub const base_tag = Tag.floatcast;
564 pub const builtin_name = "@floatCast";
565 base: Inst,
566
567 positionals: struct {
568 dest_type: *Inst,
569 operand: *Inst,
570 },
571 kw_args: struct {},
572 };
573
574 pub const IntCast = struct {
575 pub const base_tag = Tag.intcast;
576 pub const builtin_name = "@intCast";
577 base: Inst,
578
579 positionals: struct {
580 dest_type: *Inst,
581 operand: *Inst,
582 },
583 kw_args: struct {},
584 };
585
586 pub const BitCast = struct {
587 pub const base_tag = Tag.bitcast;
588 pub const builtin_name = "@bitCast";
589 base: Inst,
590
591 positionals: struct {
592 dest_type: *Inst,
593 operand: *Inst,
594 },
595 kw_args: struct {},
596 };
597
598639 pub const ElemPtr = struct {
599640 pub const base_tag = Tag.elemptr;
600641 base: Inst,
......@@ -1467,15 +1508,15 @@ const EmitZIR = struct {
14671508 },
14681509 .ComptimeInt => return self.emitComptimeIntVal(src, typed_value.val),
14691510 .Int => {
1470 const as_inst = try self.arena.allocator.create(Inst.As);
1511 const as_inst = try self.arena.allocator.create(Inst.BinOp);
14711512 as_inst.* = .{
14721513 .base = .{
1514 .tag = .as,
14731515 .src = src,
1474 .tag = Inst.As.base_tag,
14751516 },
14761517 .positionals = .{
1477 .dest_type = (try self.emitType(src, typed_value.ty)).inst,
1478 .value = (try self.emitComptimeIntVal(src, typed_value.val)).inst,
1518 .lhs = (try self.emitType(src, typed_value.ty)).inst,
1519 .rhs = (try self.emitComptimeIntVal(src, typed_value.val)).inst,
14791520 },
14801521 .kw_args = .{},
14811522 };
......@@ -1640,17 +1681,17 @@ const EmitZIR = struct {
16401681 src: usize,
16411682 new_body: ZirBody,
16421683 old_inst: *ir.Inst.UnOp,
1643 comptime I: type,
1684 tag: Inst.Tag,
16441685 ) Allocator.Error!*Inst {
1645 const new_inst = try self.arena.allocator.create(I);
1686 const new_inst = try self.arena.allocator.create(Inst.BinOp);
16461687 new_inst.* = .{
16471688 .base = .{
16481689 .src = src,
1649 .tag = I.base_tag,
1690 .tag = tag,
16501691 },
16511692 .positionals = .{
1652 .dest_type = (try self.emitType(src, old_inst.base.ty)).inst,
1653 .operand = try self.resolveInst(new_body, old_inst.operand),
1693 .lhs = (try self.emitType(old_inst.base.src, old_inst.base.ty)).inst,
1694 .rhs = try self.resolveInst(new_body, old_inst.operand),
16541695 },
16551696 .kw_args = .{},
16561697 };
......@@ -1691,9 +1732,9 @@ const EmitZIR = struct {
16911732 .cmp_gt => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_gt).?, .cmp_gt),
16921733 .cmp_neq => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_neq).?, .cmp_neq),
16931734
1694 .bitcast => try self.emitCast(inst.src, new_body, inst.castTag(.bitcast).?, Inst.BitCast),
1695 .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, Inst.IntCast),
1696 .floatcast => try self.emitCast(inst.src, new_body, inst.castTag(.floatcast).?, Inst.FloatCast),
1735 .bitcast => try self.emitCast(inst.src, new_body, inst.castTag(.bitcast).?, .bitcast),
1736 .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, .intcast),
1737 .floatcast => try self.emitCast(inst.src, new_body, inst.castTag(.floatcast).?, .floatcast),
16971738
16981739 .block => blk: {
16991740 const old_inst = inst.castTag(.block).?;
test/stage2/cbe.zig+13-35
......@@ -19,13 +19,13 @@ pub fn addCases(ctx: *TestContext) !void {
1919 \\fn main() noreturn {}
2020 \\
2121 \\export fn _start() noreturn {
22 \\ main();
22 \\ main();
2323 \\}
2424 ,
2525 \\noreturn void main(void);
2626 \\
2727 \\noreturn void _start(void) {
28 \\ main();
28 \\ main();
2929 \\}
3030 \\
3131 \\noreturn void main(void) {}
......@@ -35,15 +35,15 @@ pub fn addCases(ctx: *TestContext) !void {
3535 // TODO: figure out a way to prevent asm constants from being generated
3636 ctx.c("inline asm", linux_x64,
3737 \\fn exitGood() void {
38 \\ asm volatile ("syscall"
39 \\ :
40 \\ : [number] "{rax}" (231),
41 \\ [arg1] "{rdi}" (0)
42 \\ );
38 \\ asm volatile ("syscall"
39 \\ :
40 \\ : [number] "{rax}" (231),
41 \\ [arg1] "{rdi}" (0)
42 \\ );
4343 \\}
4444 \\
4545 \\export fn _start() noreturn {
46 \\ exitGood();
46 \\ exitGood();
4747 \\}
4848 ,
4949 \\#include <stddef.h>
......@@ -55,36 +55,14 @@ pub fn addCases(ctx: *TestContext) !void {
5555 \\const char *const exitGood__anon_2 = "syscall";
5656 \\
5757 \\noreturn void _start(void) {
58 \\ exitGood();
58 \\ exitGood();
5959 \\}
6060 \\
6161 \\void exitGood(void) {
62 \\ register size_t rax_constant __asm__("rax") = 231;
63 \\ register size_t rdi_constant __asm__("rdi") = 0;
64 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
65 \\ return;
66 \\}
67 \\
68 );
69 ctx.c("basic return", linux_x64,
70 \\fn main() u8 {
71 \\ return 103;
72 \\}
73 \\
74 \\export fn _start() noreturn {
75 \\ _ = main();
76 \\}
77 ,
78 \\#include <stdint.h>
79 \\
80 \\uint8_t main(void);
81 \\
82 \\noreturn void _start(void) {
83 \\ (void)main();
84 \\}
85 \\
86 \\uint8_t main(void) {
87 \\ return 103;
62 \\ register size_t rax_constant __asm__("rax") = 231;
63 \\ register size_t rdi_constant __asm__("rdi") = 0;
64 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
65 \\ return;
8866 \\}
8967 \\
9068 );