From ccc7f9987debd2112d1432f7aa58a81a0814e81d Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Thu, 2 Sep 2021 14:45:00 +0200 Subject: [PATCH 01/30] Address spaces: addrspace(A) parsing The grammar for function prototypes, (global) variable declarations, and pointer types now accepts an optional addrspace(A) modifier. --- lib/std/zig/Ast.zig | 54 ++++++++++++++++-- lib/std/zig/parse.zig | 115 ++++++++++++++++++++++++++++---------- lib/std/zig/tokenizer.zig | 3 + src/translate_c/ast.zig | 1 + 4 files changed, 139 insertions(+), 34 deletions(-) diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index 35e75f4db2..a62e9c105d 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -262,6 +262,9 @@ pub fn renderError(tree: Tree, parse_error: Error, stream: anytype) !void { token_tags[parse_error.token].symbol(), }); }, + .extra_addrspace_qualifier => { + return stream.writeAll("extra addrspace qualifier"); + }, .extra_align_qualifier => { return stream.writeAll("extra align qualifier"); }, @@ -1021,7 +1024,7 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex { }, .fn_proto_one => { const extra = tree.extraData(datas[n].lhs, Node.FnProtoOne); - // linksection, callconv, align can appear in any order, so we + // addrspace, linksection, callconv, align can appear in any order, so we // find the last one here. var max_node: Node.Index = datas[n].rhs; var max_start = token_starts[main_tokens[max_node]]; @@ -1034,6 +1037,14 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex { max_offset = 1; // for the rparen } } + if (extra.addrspace_expr != 0) { + const start = token_starts[main_tokens[extra.addrspace_expr]]; + if (start > max_start) { + max_node = extra.addrspace_expr; + max_start = start; + max_offset = 1; // for the rparen + } + } if (extra.section_expr != 0) { const start = token_starts[main_tokens[extra.section_expr]]; if (start > max_start) { @@ -1055,7 +1066,7 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex { }, .fn_proto => { const extra = tree.extraData(datas[n].lhs, Node.FnProto); - // linksection, callconv, align can appear in any order, so we + // addrspace, linksection, callconv, align can appear in any order, so we // find the last one here. var max_node: Node.Index = datas[n].rhs; var max_start = token_starts[main_tokens[max_node]]; @@ -1068,6 +1079,14 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex { max_offset = 1; // for the rparen } } + if (extra.addrspace_expr != 0) { + const start = token_starts[main_tokens[extra.addrspace_expr]]; + if (start > max_start) { + max_node = extra.addrspace_expr; + max_start = start; + max_offset = 1; // for the rparen + } + } if (extra.section_expr != 0) { const start = token_starts[main_tokens[extra.section_expr]]; if (start > max_start) { @@ -1138,6 +1157,7 @@ pub fn globalVarDecl(tree: Tree, node: Node.Index) full.VarDecl { return tree.fullVarDecl(.{ .type_node = extra.type_node, .align_node = extra.align_node, + .addrspace_node = extra.addrspace_node, .section_node = extra.section_node, .init_node = data.rhs, .mut_token = tree.nodes.items(.main_token)[node], @@ -1151,6 +1171,7 @@ pub fn localVarDecl(tree: Tree, node: Node.Index) full.VarDecl { return tree.fullVarDecl(.{ .type_node = extra.type_node, .align_node = extra.align_node, + .addrspace_node = 0, .section_node = 0, .init_node = data.rhs, .mut_token = tree.nodes.items(.main_token)[node], @@ -1163,6 +1184,7 @@ pub fn simpleVarDecl(tree: Tree, node: Node.Index) full.VarDecl { return tree.fullVarDecl(.{ .type_node = data.lhs, .align_node = 0, + .addrspace_node = 0, .section_node = 0, .init_node = data.rhs, .mut_token = tree.nodes.items(.main_token)[node], @@ -1175,6 +1197,7 @@ pub fn alignedVarDecl(tree: Tree, node: Node.Index) full.VarDecl { return tree.fullVarDecl(.{ .type_node = 0, .align_node = data.lhs, + .addrspace_node = 0, .section_node = 0, .init_node = data.rhs, .mut_token = tree.nodes.items(.main_token)[node], @@ -1249,6 +1272,7 @@ pub fn fnProtoSimple(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full. .return_type = data.rhs, .params = params, .align_expr = 0, + .addrspace_expr = 0, .section_expr = 0, .callconv_expr = 0, }); @@ -1265,6 +1289,7 @@ pub fn fnProtoMulti(tree: Tree, node: Node.Index) full.FnProto { .return_type = data.rhs, .params = params, .align_expr = 0, + .addrspace_expr = 0, .section_expr = 0, .callconv_expr = 0, }); @@ -1282,6 +1307,7 @@ pub fn fnProtoOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.FnP .return_type = data.rhs, .params = params, .align_expr = extra.align_expr, + .addrspace_expr = extra.addrspace_expr, .section_expr = extra.section_expr, .callconv_expr = extra.callconv_expr, }); @@ -1298,6 +1324,7 @@ pub fn fnProto(tree: Tree, node: Node.Index) full.FnProto { .return_type = data.rhs, .params = params, .align_expr = extra.align_expr, + .addrspace_expr = extra.addrspace_expr, .section_expr = extra.section_expr, .callconv_expr = extra.callconv_expr, }); @@ -1453,6 +1480,7 @@ pub fn ptrTypeAligned(tree: Tree, node: Node.Index) full.PtrType { return tree.fullPtrType(.{ .main_token = tree.nodes.items(.main_token)[node], .align_node = data.lhs, + .addrspace_node = 0, .sentinel = 0, .bit_range_start = 0, .bit_range_end = 0, @@ -1466,6 +1494,7 @@ pub fn ptrTypeSentinel(tree: Tree, node: Node.Index) full.PtrType { return tree.fullPtrType(.{ .main_token = tree.nodes.items(.main_token)[node], .align_node = 0, + .addrspace_node = 0, .sentinel = data.lhs, .bit_range_start = 0, .bit_range_end = 0, @@ -1480,6 +1509,7 @@ pub fn ptrType(tree: Tree, node: Node.Index) full.PtrType { return tree.fullPtrType(.{ .main_token = tree.nodes.items(.main_token)[node], .align_node = extra.align_node, + .addrspace_node = extra.addrspace_node, .sentinel = extra.sentinel, .bit_range_start = 0, .bit_range_end = 0, @@ -1494,6 +1524,7 @@ pub fn ptrTypeBitRange(tree: Tree, node: Node.Index) full.PtrType { return tree.fullPtrType(.{ .main_token = tree.nodes.items(.main_token)[node], .align_node = extra.align_node, + .addrspace_node = extra.addrspace_node, .sentinel = extra.sentinel, .bit_range_start = extra.bit_range_start, .bit_range_end = extra.bit_range_end, @@ -2063,6 +2094,7 @@ pub const full = struct { mut_token: TokenIndex, type_node: Node.Index, align_node: Node.Index, + addrspace_node: Node.Index, section_node: Node.Index, init_node: Node.Index, }; @@ -2130,6 +2162,7 @@ pub const full = struct { return_type: Node.Index, params: []const Node.Index, align_expr: Node.Index, + addrspace_expr: Node.Index, section_expr: Node.Index, callconv_expr: Node.Index, }; @@ -2288,6 +2321,7 @@ pub const full = struct { pub const Components = struct { main_token: TokenIndex, align_node: Node.Index, + addrspace_node: Node.Index, sentinel: Node.Index, bit_range_start: Node.Index, bit_range_end: Node.Index, @@ -2397,6 +2431,7 @@ pub const Error = struct { expected_var_decl_or_fn, expected_loop_payload, expected_container, + extra_addrspace_qualifier, extra_align_qualifier, extra_allowzero_qualifier, extra_const_qualifier, @@ -2723,13 +2758,13 @@ pub const Node = struct { /// main_token is the `fn` keyword. /// extern function declarations use this tag. fn_proto_multi, - /// `fn(a: b) rhs linksection(e) callconv(f)`. `FnProtoOne[lhs]`. + /// `fn(a: b) rhs addrspace(e) linksection(f) callconv(g)`. `FnProtoOne[lhs]`. /// zero or one parameters. /// anytype and ... parameters are omitted from the AST tree. /// main_token is the `fn` keyword. /// extern function declarations use this tag. fn_proto_one, - /// `fn(a: b, c: d) rhs linksection(e) callconv(f)`. `FnProto[lhs]`. + /// `fn(a: b, c: d) rhs addrspace(e) linksection(f) callconv(g)`. `FnProto[lhs]`. /// anytype and ... parameters are omitted from the AST tree. /// main_token is the `fn` keyword. /// extern function declarations use this tag. @@ -2893,11 +2928,13 @@ pub const Node = struct { pub const PtrType = struct { sentinel: Index, align_node: Index, + addrspace_node: Index, }; pub const PtrTypeBitRange = struct { sentinel: Index, align_node: Index, + addrspace_node: Index, bit_range_start: Index, bit_range_end: Index, }; @@ -2920,8 +2957,13 @@ pub const Node = struct { }; pub const GlobalVarDecl = struct { + /// Populated if there is an explicit type ascription. type_node: Index, + /// Populated if align(A) is present. align_node: Index, + /// Populated if linksection(A) is present. + addrspace_node: Index, + /// Populated if addrspace(A) is present. section_node: Index, }; @@ -2954,6 +2996,8 @@ pub const Node = struct { /// Populated if align(A) is present. align_expr: Index, /// Populated if linksection(A) is present. + addrspace_expr: Index, + /// Populated if addrspace(A) is present. section_expr: Index, /// Populated if callconv(A) is present. callconv_expr: Index, @@ -2964,6 +3008,8 @@ pub const Node = struct { params_end: Index, /// Populated if align(A) is present. align_expr: Index, + /// Populated if addrspace(A) is present. + addrspace_expr: Index, /// Populated if linksection(A) is present. section_expr: Index, /// Populated if callconv(A) is present. diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 5bd5a6dfeb..f7697027a3 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -629,7 +629,7 @@ const Parser = struct { }; } - /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr + /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr fn parseFnProto(p: *Parser) !Node.Index { const fn_token = p.eatToken(.keyword_fn) orelse return null_node; @@ -639,6 +639,7 @@ const Parser = struct { _ = p.eatToken(.identifier); const params = try p.parseParamDeclList(); const align_expr = try p.parseByteAlign(); + const addrspace_expr = try p.parseAddrSpace(); const section_expr = try p.parseLinkSection(); const callconv_expr = try p.parseCallconv(); _ = p.eatToken(.bang); @@ -650,7 +651,7 @@ const Parser = struct { try p.warn(.expected_return_type); } - if (align_expr == 0 and section_expr == 0 and callconv_expr == 0) { + if (align_expr == 0 and section_expr == 0 and callconv_expr == 0 and addrspace_expr == 0) { switch (params) { .zero_or_one => |param| return p.setNode(fn_proto_index, .{ .tag = .fn_proto_simple, @@ -683,6 +684,7 @@ const Parser = struct { .lhs = try p.addExtra(Node.FnProtoOne{ .param = param, .align_expr = align_expr, + .addrspace_expr = addrspace_expr, .section_expr = section_expr, .callconv_expr = callconv_expr, }), @@ -698,6 +700,7 @@ const Parser = struct { .params_start = span.start, .params_end = span.end, .align_expr = align_expr, + .addrspace_expr = addrspace_expr, .section_expr = section_expr, .callconv_expr = callconv_expr, }), @@ -708,7 +711,7 @@ const Parser = struct { } } - /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON + /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? (EQUAL Expr)? SEMICOLON fn parseVarDecl(p: *Parser) !Node.Index { const mut_token = p.eatToken(.keyword_const) orelse p.eatToken(.keyword_var) orelse @@ -717,9 +720,10 @@ const Parser = struct { _ = try p.expectToken(.identifier); const type_node: Node.Index = if (p.eatToken(.colon) == null) 0 else try p.expectTypeExpr(); const align_node = try p.parseByteAlign(); + const addrspace_node = try p.parseAddrSpace(); const section_node = try p.parseLinkSection(); const init_node: Node.Index = if (p.eatToken(.equal) == null) 0 else try p.expectExpr(); - if (section_node == 0) { + if (section_node == 0 and addrspace_node == 0) { if (align_node == 0) { return p.addNode(.{ .tag = .simple_var_decl, @@ -759,6 +763,7 @@ const Parser = struct { .lhs = try p.addExtra(Node.GlobalVarDecl{ .type_node = type_node, .align_node = align_node, + .addrspace_node = addrspace_node, .section_node = section_node, }), .rhs = init_node, @@ -1440,8 +1445,8 @@ const Parser = struct { /// PrefixTypeOp /// <- QUESTIONMARK /// / KEYWORD_anyframe MINUSRARROW - /// / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* - /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* + /// / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* + /// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* /// / ArrayTypeStart /// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET /// PtrTypeStart @@ -1474,16 +1479,7 @@ const Parser = struct { const asterisk = p.nextToken(); const mods = try p.parsePtrModifiers(); const elem_type = try p.expectTypeExpr(); - if (mods.bit_range_start == 0) { - return p.addNode(.{ - .tag = .ptr_type_aligned, - .main_token = asterisk, - .data = .{ - .lhs = mods.align_node, - .rhs = elem_type, - }, - }); - } else { + if (mods.bit_range_start != 0) { return p.addNode(.{ .tag = .ptr_type_bit_range, .main_token = asterisk, @@ -1491,12 +1487,35 @@ const Parser = struct { .lhs = try p.addExtra(Node.PtrTypeBitRange{ .sentinel = 0, .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, .bit_range_start = mods.bit_range_start, .bit_range_end = mods.bit_range_end, }), .rhs = elem_type, }, }); + } else if (mods.addrspace_node != 0) { + return p.addNode(.{ + .tag = .ptr_type, + .main_token = asterisk, + .data = .{ + .lhs = try p.addExtra(Node.PtrType{ + .sentinel = 0, + .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, + }), + .rhs = elem_type, + }, + }); + } else { + return p.addNode(.{ + .tag = .ptr_type_aligned, + .main_token = asterisk, + .data = .{ + .lhs = mods.align_node, + .rhs = elem_type, + }, + }); } }, .asterisk_asterisk => { @@ -1504,16 +1523,7 @@ const Parser = struct { const mods = try p.parsePtrModifiers(); const elem_type = try p.expectTypeExpr(); const inner: Node.Index = inner: { - if (mods.bit_range_start == 0) { - break :inner try p.addNode(.{ - .tag = .ptr_type_aligned, - .main_token = asterisk, - .data = .{ - .lhs = mods.align_node, - .rhs = elem_type, - }, - }); - } else { + if (mods.bit_range_start != 0) { break :inner try p.addNode(.{ .tag = .ptr_type_bit_range, .main_token = asterisk, @@ -1521,12 +1531,35 @@ const Parser = struct { .lhs = try p.addExtra(Node.PtrTypeBitRange{ .sentinel = 0, .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, .bit_range_start = mods.bit_range_start, .bit_range_end = mods.bit_range_end, }), .rhs = elem_type, }, }); + } else if (mods.addrspace_node != 0) { + break :inner try p.addNode(.{ + .tag = .ptr_type, + .main_token = asterisk, + .data = .{ + .lhs = try p.addExtra(Node.PtrType{ + .sentinel = 0, + .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, + }), + .rhs = elem_type, + }, + }); + } else { + break :inner try p.addNode(.{ + .tag = .ptr_type_aligned, + .main_token = asterisk, + .data = .{ + .lhs = mods.align_node, + .rhs = elem_type, + }, + }); } }; return p.addNode(.{ @@ -1560,7 +1593,7 @@ const Parser = struct { const mods = try p.parsePtrModifiers(); const elem_type = try p.expectTypeExpr(); if (mods.bit_range_start == 0) { - if (sentinel == 0) { + if (sentinel == 0 and mods.addrspace_node == 0) { return p.addNode(.{ .tag = .ptr_type_aligned, .main_token = asterisk, @@ -1569,7 +1602,7 @@ const Parser = struct { .rhs = elem_type, }, }); - } else if (mods.align_node == 0) { + } else if (mods.align_node == 0 and mods.addrspace_node == 0) { return p.addNode(.{ .tag = .ptr_type_sentinel, .main_token = asterisk, @@ -1586,6 +1619,7 @@ const Parser = struct { .lhs = try p.addExtra(Node.PtrType{ .sentinel = sentinel, .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, }), .rhs = elem_type, }, @@ -1599,6 +1633,7 @@ const Parser = struct { .lhs = try p.addExtra(Node.PtrTypeBitRange{ .sentinel = sentinel, .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, .bit_range_start = mods.bit_range_start, .bit_range_end = mods.bit_range_end, }), @@ -1624,7 +1659,7 @@ const Parser = struct { .token = p.nodes.items(.main_token)[mods.bit_range_start], }); } - if (sentinel == 0) { + if (sentinel == 0 and mods.addrspace_node == 0) { return p.addNode(.{ .tag = .ptr_type_aligned, .main_token = lbracket, @@ -1633,7 +1668,7 @@ const Parser = struct { .rhs = elem_type, }, }); - } else if (mods.align_node == 0) { + } else if (mods.align_node == 0 and mods.addrspace_node == 0) { return p.addNode(.{ .tag = .ptr_type_sentinel, .main_token = lbracket, @@ -1650,6 +1685,7 @@ const Parser = struct { .lhs = try p.addExtra(Node.PtrType{ .sentinel = sentinel, .align_node = mods.align_node, + .addrspace_node = mods.addrspace_node, }), .rhs = elem_type, }, @@ -1661,6 +1697,7 @@ const Parser = struct { .keyword_const, .keyword_volatile, .keyword_allowzero, + .keyword_addrspace, => return p.fail(.ptr_mod_on_array_child_type), else => {}, } @@ -2879,6 +2916,15 @@ const Parser = struct { return expr_node; } + /// AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN + fn parseAddrSpace(p: *Parser) !Node.Index { + _ = p.eatToken(.keyword_addrspace) orelse return null_node; + _ = try p.expectToken(.l_paren); + const expr_node = try p.expectExpr(); + _ = try p.expectToken(.r_paren); + return expr_node; + } + /// ParamDecl /// <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType /// / DOT3 @@ -3011,6 +3057,7 @@ const Parser = struct { const PtrModifiers = struct { align_node: Node.Index, + addrspace_node: Node.Index, bit_range_start: Node.Index, bit_range_end: Node.Index, }; @@ -3018,12 +3065,14 @@ const Parser = struct { fn parsePtrModifiers(p: *Parser) !PtrModifiers { var result: PtrModifiers = .{ .align_node = 0, + .addrspace_node = 0, .bit_range_start = 0, .bit_range_end = 0, }; var saw_const = false; var saw_volatile = false; var saw_allowzero = false; + var saw_addrspace = false; while (true) { switch (p.token_tags[p.tok_i]) { .keyword_align => { @@ -3063,6 +3112,12 @@ const Parser = struct { p.tok_i += 1; saw_allowzero = true; }, + .keyword_addrspace => { + if (saw_addrspace) { + try p.warn(.extra_addrspace_qualifier); + } + result.addrspace_node = try p.parseAddrSpace(); + }, else => return result, } } diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index 3fdbb3ec7b..c64d740b01 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -11,6 +11,7 @@ pub const Token = struct { }; pub const keywords = std.ComptimeStringMap(Tag, .{ + .{ "addrspace", .keyword_addrspace }, .{ "align", .keyword_align }, .{ "allowzero", .keyword_allowzero }, .{ "and", .keyword_and }, @@ -132,6 +133,7 @@ pub const Token = struct { float_literal, doc_comment, container_doc_comment, + keyword_addrspace, keyword_align, keyword_allowzero, keyword_and, @@ -251,6 +253,7 @@ pub const Token = struct { .angle_bracket_angle_bracket_right => ">>", .angle_bracket_angle_bracket_right_equal => ">>=", .tilde => "~", + .keyword_addrspace => "addrspace", .keyword_align => "align", .keyword_allowzero => "allowzero", .keyword_and => "and", diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 93acd464f4..bafaebfea0 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -2614,6 +2614,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex { .type_node = type_node, .align_node = align_node, .section_node = section_node, + .addrspace_node = 0, }), .rhs = init_node, }, From 7da9fa6fe2e982d10ebc9c3844d1249a4eb1d514 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Tue, 17 Aug 2021 01:38:22 +0200 Subject: [PATCH 02/30] Address spaces: AstGen Adds AST generation for address spaces on pointers, function prototypes, function declarations and variable declarations. In the latter two cases, declaration properties were already stored more efficiently in a declaration structure. To accomodate these for address spaces, the bit indicating presence of a linksection attribute has been extended to include either linksection, address space, or both. --- lib/std/builtin.zig | 6 ++++ src/AstGen.zig | 50 ++++++++++++++++++++++---- src/Sema.zig | 3 ++ src/Zir.zig | 77 +++++++++++++++++++++++++++++++---------- src/translate_c/ast.zig | 2 ++ src/type.zig | 19 ++++++++++ src/value.zig | 5 +++ 7 files changed, 137 insertions(+), 25 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 7f6c40c6f5..724b069a34 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -166,6 +166,12 @@ pub const CallingConvention = enum { SysV, }; +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const AddressSpace = enum { + generic, +}; + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const SourceLocation = struct { diff --git a/src/AstGen.zig b/src/AstGen.zig index be3613dfb9..bfb7a0b10f 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1116,6 +1116,11 @@ fn fnProtoExpr( const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { break :inst try expr(gz, scope, align_rl, fn_proto.ast.align_expr); }; + + const addrspace_inst: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: { + break :inst try expr(gz, scope, .{ .ty = .address_space_type }, fn_proto.ast.addrspace_expr); + }; + if (fn_proto.ast.section_expr != 0) { return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{}); } @@ -1148,6 +1153,7 @@ fn fnProtoExpr( .body = &[0]Zir.Inst.Index{}, .cc = cc, .align_inst = align_inst, + .addrspace_inst = addrspace_inst, .lib_name = 0, .is_var_args = is_var_args, .is_inferred_error = false, @@ -2714,6 +2720,7 @@ fn ptrType( const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type); const simple = ptr_info.ast.align_node == 0 and + ptr_info.ast.addrspace_node == 0 and ptr_info.ast.sentinel == 0 and ptr_info.ast.bit_range_start == 0; @@ -2732,6 +2739,7 @@ fn ptrType( var sentinel_ref: Zir.Inst.Ref = .none; var align_ref: Zir.Inst.Ref = .none; + var addrspace_ref: Zir.Inst.Ref = .none; var bit_start_ref: Zir.Inst.Ref = .none; var bit_end_ref: Zir.Inst.Ref = .none; var trailing_count: u32 = 0; @@ -2744,6 +2752,10 @@ fn ptrType( align_ref = try expr(gz, scope, align_rl, ptr_info.ast.align_node); trailing_count += 1; } + if (ptr_info.ast.addrspace_node != 0) { + addrspace_ref = try expr(gz, scope, .{ .ty = .address_space_type }, ptr_info.ast.addrspace_node); + trailing_count += 1; + } if (ptr_info.ast.bit_range_start != 0) { assert(ptr_info.ast.bit_range_end != 0); bit_start_ref = try expr(gz, scope, .none, ptr_info.ast.bit_range_start); @@ -2764,6 +2776,9 @@ fn ptrType( if (align_ref != .none) { gz.astgen.extra.appendAssumeCapacity(@enumToInt(align_ref)); } + if (addrspace_ref != .none) { + gz.astgen.extra.appendAssumeCapacity(@enumToInt(addrspace_ref)); + } if (bit_start_ref != .none) { gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_start_ref)); gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_end_ref)); @@ -2779,6 +2794,7 @@ fn ptrType( .is_volatile = ptr_info.volatile_token != null, .has_sentinel = sentinel_ref != .none, .has_align = align_ref != .none, + .has_addrspace = addrspace_ref != .none, .has_bit_range = bit_start_ref != .none, }, .size = ptr_info.size, @@ -2847,7 +2863,7 @@ const WipDecls = struct { is_pub: bool, is_export: bool, has_align: bool, - has_section: bool, + has_section_or_addrspace: bool, ) Allocator.Error!void { if (wip_decls.decl_index % fields_per_u32 == 0 and wip_decls.decl_index != 0) { try wip_decls.bit_bag.append(gpa, wip_decls.cur_bit_bag); @@ -2857,7 +2873,7 @@ const WipDecls = struct { (@as(u32, @boolToInt(is_pub)) << 28) | (@as(u32, @boolToInt(is_export)) << 29) | (@as(u32, @boolToInt(has_align)) << 30) | - (@as(u32, @boolToInt(has_section)) << 31); + (@as(u32, @boolToInt(has_section_or_addrspace)) << 31); wip_decls.decl_index += 1; } @@ -2922,7 +2938,8 @@ fn fnDecl( const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false; break :blk token_tags[maybe_inline_token] == .keyword_inline; }; - try wip_decls.next(gpa, is_pub, is_export, fn_proto.ast.align_expr != 0, fn_proto.ast.section_expr != 0); + const has_section_or_addrspace = fn_proto.ast.section_expr != 0 or fn_proto.ast.addrspace_expr != 0; + try wip_decls.next(gpa, is_pub, is_export, fn_proto.ast.align_expr != 0, has_section_or_addrspace); var params_scope = &fn_gz.base; const is_var_args = is_var_args: { @@ -3011,6 +3028,9 @@ fn fnDecl( const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { break :inst try expr(&decl_gz, params_scope, align_rl, fn_proto.ast.align_expr); }; + const addrspace_inst: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: { + break :inst try expr(&decl_gz, params_scope, .{ .ty = .address_space_type }, fn_proto.ast.addrspace_expr); + }; const section_inst: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: { break :inst try comptimeExpr(&decl_gz, params_scope, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr); }; @@ -3060,6 +3080,7 @@ fn fnDecl( .body = &[0]Zir.Inst.Index{}, .cc = cc, .align_inst = .none, // passed in the per-decl data + .addrspace_inst = .none, // passed in the per-decl data .lib_name = lib_name, .is_var_args = is_var_args, .is_inferred_error = false, @@ -3099,6 +3120,7 @@ fn fnDecl( .body = fn_gz.instructions.items, .cc = cc, .align_inst = .none, // passed in the per-decl data + .addrspace_inst = .none, // passed in the per-decl data .lib_name = lib_name, .is_var_args = is_var_args, .is_inferred_error = is_inferred_error, @@ -3127,8 +3149,10 @@ fn fnDecl( if (align_inst != .none) { wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst)); } - if (section_inst != .none) { + + if (has_section_or_addrspace) { wip_decls.payload.appendAssumeCapacity(@enumToInt(section_inst)); + wip_decls.payload.appendAssumeCapacity(@enumToInt(addrspace_inst)); } } @@ -3175,10 +3199,14 @@ fn globalVarDecl( const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node == 0) .none else inst: { break :inst try expr(&block_scope, &block_scope.base, align_rl, var_decl.ast.align_node); }; + const addrspace_inst: Zir.Inst.Ref = if (var_decl.ast.addrspace_node == 0) .none else inst: { + break :inst try expr(&block_scope, &block_scope.base, .{ .ty = .address_space_type }, var_decl.ast.addrspace_node); + }; const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: { break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .ty = .const_slice_u8_type }, var_decl.ast.section_node); }; - try wip_decls.next(gpa, is_pub, is_export, align_inst != .none, section_inst != .none); + const has_section_or_addrspace = section_inst != .none or addrspace_inst != .none; + try wip_decls.next(gpa, is_pub, is_export, align_inst != .none, has_section_or_addrspace); const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: { if (!is_mutable) { @@ -3271,8 +3299,9 @@ fn globalVarDecl( if (align_inst != .none) { wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst)); } - if (section_inst != .none) { + if (has_section_or_addrspace) { wip_decls.payload.appendAssumeCapacity(@enumToInt(section_inst)); + wip_decls.payload.appendAssumeCapacity(@enumToInt(addrspace_inst)); } } @@ -3443,6 +3472,7 @@ fn testDecl( .body = fn_block.instructions.items, .cc = .none, .align_inst = .none, + .addrspace_inst = .none, .lib_name = 0, .is_var_args = false, .is_inferred_error = true, @@ -9178,6 +9208,7 @@ const GenZir = struct { ret_br: Zir.Inst.Index, cc: Zir.Inst.Ref, align_inst: Zir.Inst.Ref, + addrspace_inst: Zir.Inst.Ref, lib_name: u32, is_var_args: bool, is_inferred_error: bool, @@ -9221,7 +9252,7 @@ const GenZir = struct { if (args.cc != .none or args.lib_name != 0 or args.is_var_args or args.is_test or args.align_inst != .none or - args.is_extern) + args.addrspace_inst != .none or args.is_extern) { try astgen.extra.ensureUnusedCapacity( gpa, @@ -9229,6 +9260,7 @@ const GenZir = struct { args.ret_ty.len + args.body.len + src_locs.len + @boolToInt(args.lib_name != 0) + @boolToInt(args.align_inst != .none) + + @boolToInt(args.addrspace_inst != .none) + @boolToInt(args.cc != .none), ); const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{ @@ -9246,6 +9278,9 @@ const GenZir = struct { if (args.align_inst != .none) { astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); } + if (args.addrspace_inst != .none) { + astgen.extra.appendAssumeCapacity(@enumToInt(args.addrspace_inst)); + } astgen.extra.appendSliceAssumeCapacity(args.ret_ty); astgen.extra.appendSliceAssumeCapacity(args.body); astgen.extra.appendSliceAssumeCapacity(src_locs); @@ -9264,6 +9299,7 @@ const GenZir = struct { .has_lib_name = args.lib_name != 0, .has_cc = args.cc != .none, .has_align = args.align_inst != .none, + .has_addrspace = args.addrspace_inst != .none, .is_test = args.is_test, .is_extern = args.is_extern, }), diff --git a/src/Sema.zig b/src/Sema.zig index 5471795317..8200e95aa5 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -10200,6 +10200,7 @@ fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type .atomic_order => return sema.resolveBuiltinTypeFields(block, src, "AtomicOrder"), .atomic_rmw_op => return sema.resolveBuiltinTypeFields(block, src, "AtomicRmwOp"), .calling_convention => return sema.resolveBuiltinTypeFields(block, src, "CallingConvention"), + .address_space => return sema.resolveBuiltinTypeFields(block, src, "AddressSpace"), .float_mode => return sema.resolveBuiltinTypeFields(block, src, "FloatMode"), .reduce_op => return sema.resolveBuiltinTypeFields(block, src, "ReduceOp"), .call_options => return sema.resolveBuiltinTypeFields(block, src, "CallOptions"), @@ -10594,6 +10595,7 @@ fn typeHasOnePossibleValue( .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -10779,6 +10781,7 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref { .atomic_order => return .atomic_order_type, .atomic_rmw_op => return .atomic_rmw_op_type, .calling_convention => return .calling_convention_type, + .address_space => return .address_space_type, .float_mode => return .float_mode_type, .reduce_op => return .reduce_op_type, .call_options => return .call_options_type, diff --git a/src/Zir.zig b/src/Zir.zig index f8dbef2534..0e50f8c256 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -488,10 +488,10 @@ pub const Inst = struct { /// this instruction; a following 'ret' instruction will do the diversion. /// Uses the `str_tok` union field. ret_err_value_code, - /// Create a pointer type that does not have a sentinel, alignment, or bit range specified. + /// Create a pointer type that does not have a sentinel, alignment, address space, or bit range specified. /// Uses the `ptr_type_simple` union field. ptr_type_simple, - /// Create a pointer type which can have a sentinel, alignment, and/or bit range. + /// Create a pointer type which can have a sentinel, alignment, address space, and/or bit range. /// Uses the `ptr_type` union field. ptr_type, /// Slice operation `lhs[rhs..]`. No sentinel and no end offset. @@ -1717,6 +1717,7 @@ pub const Inst = struct { atomic_order_type, atomic_rmw_op_type, calling_convention_type, + address_space_type, float_mode_type, reduce_op_type, call_options_type, @@ -1973,6 +1974,10 @@ pub const Inst = struct { .ty = Type.initTag(.type), .val = Value.initTag(.calling_convention_type), }, + .address_space_type = .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.address_space_type), + }, .float_mode_type = .{ .ty = Type.initTag(.type), .val = Value.initTag(.float_mode_type), @@ -2174,8 +2179,9 @@ pub const Inst = struct { is_volatile: bool, has_sentinel: bool, has_align: bool, + has_addrspace: bool, has_bit_range: bool, - _: u2 = undefined, + _: u1 = undefined, }, size: std.builtin.TypeInfo.Pointer.Size, /// Index into extra. See `PtrType`. @@ -2303,6 +2309,7 @@ pub const Inst = struct { /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set /// 1. cc: Ref, // if has_cc is set /// 2. align: Ref, // if has_align is set + /// 3. addrspace: Ref, // if has_addrspace is set /// 3. return_type: Index // for each ret_body_len /// 4. body: Index // for each body_len /// 5. src_locs: Func.SrcLocs // if body_len != 0 @@ -2320,9 +2327,10 @@ pub const Inst = struct { has_lib_name: bool, has_cc: bool, has_align: bool, + has_addrspace: bool, is_test: bool, is_extern: bool, - _: u9 = undefined, + _: u8 = undefined, }; }; @@ -2405,12 +2413,13 @@ pub const Inst = struct { else_body_len: u32, }; - /// Stored in extra. Depending on the flags in Data, there will be up to 4 + /// Stored in extra. Depending on the flags in Data, there will be up to 5 /// trailing Ref fields: /// 0. sentinel: Ref // if `has_sentinel` flag is set /// 1. align: Ref // if `has_align` flag is set - /// 2. bit_start: Ref // if `has_bit_range` flag is set - /// 3. bit_end: Ref // if `has_bit_range` flag is set + /// 2. address_space: Ref // if `has_addrspace` flag is set + /// 3. bit_start: Ref // if `has_bit_range` flag is set + /// 4. bit_end: Ref // if `has_bit_range` flag is set pub const PtrType = struct { elem_type: Ref, }; @@ -2528,7 +2537,7 @@ pub const Inst = struct { /// 0b000X: whether corresponding decl is pub /// 0b00X0: whether corresponding decl is exported /// 0b0X00: whether corresponding decl has an align expression - /// 0bX000: whether corresponding decl has a linksection expression + /// 0bX000: whether corresponding decl has a linksection or an address space expression /// 5. decl: { // for every decls_len /// src_hash: [4]u32, // hash of source bytes /// line: u32, // line number of decl, relative to parent @@ -2540,7 +2549,10 @@ pub const Inst = struct { /// this is a test decl, and the name starts at `name+1`. /// value: Index, /// align: Ref, // if corresponding bit is set - /// link_section: Ref, // if corresponding bit is set + /// link_section_or_address_space: { // if corresponding bit is set. + /// link_section: Ref, + /// address_space: Ref, + /// } /// } /// 6. inst: Index // for every body_len /// 7. flags: u32 // for every 8 fields @@ -2592,7 +2604,7 @@ pub const Inst = struct { /// 0b000X: whether corresponding decl is pub /// 0b00X0: whether corresponding decl is exported /// 0b0X00: whether corresponding decl has an align expression - /// 0bX000: whether corresponding decl has a linksection expression + /// 0bX000: whether corresponding decl has a linksection or an address space expression /// 6. decl: { // for every decls_len /// src_hash: [4]u32, // hash of source bytes /// line: u32, // line number of decl, relative to parent @@ -2604,7 +2616,10 @@ pub const Inst = struct { /// this is a test decl, and the name starts at `name+1`. /// value: Index, /// align: Ref, // if corresponding bit is set - /// link_section: Ref, // if corresponding bit is set + /// link_section_or_address_space: { // if corresponding bit is set. + /// link_section: Ref, + /// address_space: Ref, + /// } /// } /// 7. inst: Index // for every body_len /// 8. has_bits: u32 // for every 32 fields @@ -2637,7 +2652,7 @@ pub const Inst = struct { /// 0b000X: whether corresponding decl is pub /// 0b00X0: whether corresponding decl is exported /// 0b0X00: whether corresponding decl has an align expression - /// 0bX000: whether corresponding decl has a linksection expression + /// 0bX000: whether corresponding decl has a linksection or an address space expression /// 6. decl: { // for every decls_len /// src_hash: [4]u32, // hash of source bytes /// line: u32, // line number of decl, relative to parent @@ -2649,7 +2664,10 @@ pub const Inst = struct { /// this is a test decl, and the name starts at `name+1`. /// value: Index, /// align: Ref, // if corresponding bit is set - /// link_section: Ref, // if corresponding bit is set + /// link_section_or_address_space: { // if corresponding bit is set. + /// link_section: Ref, + /// address_space: Ref, + /// } /// } /// 7. inst: Index // for every body_len /// 8. has_bits: u32 // for every 8 fields @@ -2686,7 +2704,7 @@ pub const Inst = struct { /// 0b000X: whether corresponding decl is pub /// 0b00X0: whether corresponding decl is exported /// 0b0X00: whether corresponding decl has an align expression - /// 0bX000: whether corresponding decl has a linksection expression + /// 0bX000: whether corresponding decl has a linksection or an address space expression /// 1. decl: { // for every decls_len /// src_hash: [4]u32, // hash of source bytes /// line: u32, // line number of decl, relative to parent @@ -2698,7 +2716,10 @@ pub const Inst = struct { /// this is a test decl, and the name starts at `name+1`. /// value: Index, /// align: Ref, // if corresponding bit is set - /// link_section: Ref, // if corresponding bit is set + /// link_section_or_address_space: { // if corresponding bit is set. + /// link_section: Ref, + /// address_space: Ref, + /// } /// } pub const OpaqueDecl = struct { decls_len: u32, @@ -3983,7 +4004,7 @@ const Writer = struct { cur_bit_bag >>= 1; const has_align = @truncate(u1, cur_bit_bag) != 0; cur_bit_bag >>= 1; - const has_section = @truncate(u1, cur_bit_bag) != 0; + const has_section_or_addrspace = @truncate(u1, cur_bit_bag) != 0; cur_bit_bag >>= 1; const sub_index = extra_index; @@ -4001,12 +4022,16 @@ const Writer = struct { extra_index += 1; break :inst inst; }; - const section_inst: Inst.Ref = if (!has_section) .none else inst: { + const section_inst: Inst.Ref = if (!has_section_or_addrspace) .none else inst: { const inst = @intToEnum(Inst.Ref, self.code.extra[extra_index]); extra_index += 1; break :inst inst; }; - + const addrspace_inst: Inst.Ref = if (!has_section_or_addrspace) .none else inst: { + const inst = @intToEnum(Inst.Ref, self.code.extra[extra_index]); + extra_index +=1; + break :inst inst; + }; const pub_str = if (is_pub) "pub " else ""; const hash_bytes = @bitCast([16]u8, hash_u32s.*); try stream.writeByteNTimes(' ', self.indent); @@ -4032,6 +4057,11 @@ const Writer = struct { try self.writeInstRef(stream, align_inst); try stream.writeAll(")"); } + if (addrspace_inst != .none) { + try stream.writeAll(" addrspace("); + try self.writeInstRef(stream, addrspace_inst); + try stream.writeAll(")"); + } if (section_inst != .none) { try stream.writeAll(" linksection("); try self.writeInstRef(stream, section_inst); @@ -4453,6 +4483,7 @@ const Writer = struct { false, .none, .none, + .none, body, src, src_locs, @@ -4481,6 +4512,11 @@ const Writer = struct { extra_index += 1; break :blk align_inst; }; + const addrspace_inst: Inst.Ref = if (!small.has_addrspace) .none else blk: { + const addrspace_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :blk addrspace_inst; + }; const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len]; extra_index += ret_ty_body.len; @@ -4500,6 +4536,7 @@ const Writer = struct { small.is_extern, cc, align_inst, + addrspace_inst, body, src, src_locs, @@ -4582,6 +4619,7 @@ const Writer = struct { is_extern: bool, cc: Inst.Ref, align_inst: Inst.Ref, + addrspace_inst: Inst.Ref, body: []const Inst.Index, src: LazySrcLoc, src_locs: Zir.Inst.Func.SrcLocs, @@ -4599,6 +4637,7 @@ const Writer = struct { try self.writeOptionalInstRef(stream, ", cc=", cc); try self.writeOptionalInstRef(stream, ", align=", align_inst); + try self.writeOptionalInstRef(stream, ", addrspace=", addrspace_inst); try self.writeFlag(stream, ", vargs", var_args); try self.writeFlag(stream, ", extern", is_extern); try self.writeFlag(stream, ", inferror", inferred_error_set); @@ -4876,6 +4915,7 @@ fn findDeclsInner( extra_index += @boolToInt(small.has_lib_name); extra_index += @boolToInt(small.has_cc); extra_index += @boolToInt(small.has_align); + extra_index += @boolToInt(small.has_addrspace); const body = zir.extra[extra_index..][0..extra.data.body_len]; return zir.findDeclsBody(list, body); }, @@ -5079,6 +5119,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { extra_index += @boolToInt(small.has_lib_name); extra_index += @boolToInt(small.has_cc); extra_index += @boolToInt(small.has_align); + extra_index += @boolToInt(small.has_addrspace); const ret_ty_body = zir.extra[extra_index..][0..extra.data.ret_body_len]; extra_index += ret_ty_body.len; const body = zir.extra[extra_index..][0..extra.data.body_len]; diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index bafaebfea0..d0fe6d1b31 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -2706,6 +2706,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex { .lhs = try c.addExtra(std.zig.Ast.Node.FnProtoOne{ .param = params.items[0], .align_expr = align_expr, + .addrspace_expr = 0, // TODO .section_expr = section_expr, .callconv_expr = callconv_expr, }), @@ -2721,6 +2722,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex { .params_start = span.start, .params_end = span.end, .align_expr = align_expr, + .addrspace_expr = 0, // TODO .section_expr = section_expr, .callconv_expr = callconv_expr, }), diff --git a/src/type.zig b/src/type.zig index ec73ae1196..8eca352eac 100644 --- a/src/type.zig +++ b/src/type.zig @@ -127,6 +127,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, => return .Enum, @@ -746,6 +747,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -958,6 +960,7 @@ pub const Type = extern union { .atomic_order => return writer.writeAll("std.builtin.AtomicOrder"), .atomic_rmw_op => return writer.writeAll("std.builtin.AtomicRmwOp"), .calling_convention => return writer.writeAll("std.builtin.CallingConvention"), + .address_space => return writer.writeAll("std.builtin.AddressSpace"), .float_mode => return writer.writeAll("std.builtin.FloatMode"), .reduce_op => return writer.writeAll("std.builtin.ReduceOp"), .call_options => return writer.writeAll("std.builtin.CallOptions"), @@ -1186,6 +1189,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -1301,6 +1305,7 @@ pub const Type = extern union { .atomic_order => return Value.initTag(.atomic_order_type), .atomic_rmw_op => return Value.initTag(.atomic_rmw_op_type), .calling_convention => return Value.initTag(.calling_convention_type), + .address_space => return Value.initTag(.address_space_type), .float_mode => return Value.initTag(.float_mode_type), .reduce_op => return Value.initTag(.reduce_op_type), .call_options => return Value.initTag(.call_options_type), @@ -1362,6 +1367,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -1508,6 +1514,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -1734,6 +1741,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -2018,6 +2026,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -2775,6 +2784,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -2982,6 +2992,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -3006,6 +3017,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -3029,6 +3041,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -3082,6 +3095,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -3137,6 +3151,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -3174,6 +3189,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -3224,6 +3240,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, @@ -3284,6 +3301,7 @@ pub const Type = extern union { atomic_order, atomic_rmw_op, calling_convention, + address_space, float_mode, reduce_op, call_options, @@ -3407,6 +3425,7 @@ pub const Type = extern union { .atomic_order, .atomic_rmw_op, .calling_convention, + .address_space, .float_mode, .reduce_op, .call_options, diff --git a/src/value.zig b/src/value.zig index 88d0d04086..9fa42d3008 100644 --- a/src/value.zig +++ b/src/value.zig @@ -63,6 +63,7 @@ pub const Value = extern union { atomic_order_type, atomic_rmw_op_type, calling_convention_type, + address_space_type, float_mode_type, reduce_op_type, call_options_type, @@ -226,6 +227,7 @@ pub const Value = extern union { .atomic_order_type, .atomic_rmw_op_type, .calling_convention_type, + .address_space_type, .float_mode_type, .reduce_op_type, .call_options_type, @@ -412,6 +414,7 @@ pub const Value = extern union { .atomic_order_type, .atomic_rmw_op_type, .calling_convention_type, + .address_space_type, .float_mode_type, .reduce_op_type, .call_options_type, @@ -625,6 +628,7 @@ pub const Value = extern union { .atomic_order_type => return out_stream.writeAll("std.builtin.AtomicOrder"), .atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"), .calling_convention_type => return out_stream.writeAll("std.builtin.CallingConvention"), + .address_space_type => return out_stream.writeAll("std.builtin.AddressSpace"), .float_mode_type => return out_stream.writeAll("std.builtin.FloatMode"), .reduce_op_type => return out_stream.writeAll("std.builtin.ReduceOp"), .call_options_type => return out_stream.writeAll("std.builtin.CallOptions"), @@ -792,6 +796,7 @@ pub const Value = extern union { .atomic_order_type => Type.initTag(.atomic_order), .atomic_rmw_op_type => Type.initTag(.atomic_rmw_op), .calling_convention_type => Type.initTag(.calling_convention), + .address_space_type => Type.initTag(.address_space), .float_mode_type => Type.initTag(.float_mode), .reduce_op_type => Type.initTag(.reduce_op), .call_options_type => Type.initTag(.call_options), From 805e1bffbdcab84717356fb1a7b375369407d9c2 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Thu, 2 Sep 2021 14:46:31 +0200 Subject: [PATCH 03/30] Address Spaces: Sema basics --- lib/std/builtin.zig | 1 + src/AstGen.zig | 4 ++-- src/Module.zig | 53 +++++++++++++++++++++++++++++++-------------- src/Sema.zig | 28 ++++++++++++++++++++++-- src/type.zig | 42 +++++++++++++++++++++++++++++++++++ 5 files changed, 108 insertions(+), 20 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 724b069a34..b9176794c6 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -170,6 +170,7 @@ pub const CallingConvention = enum { /// therefore must be kept in sync with the compiler implementation. pub const AddressSpace = enum { generic, + special, }; /// This data structure is used by the Zig language code generation and diff --git a/src/AstGen.zig b/src/AstGen.zig index bfb7a0b10f..443834485f 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -3134,7 +3134,7 @@ fn fnDecl( _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst); try decl_gz.setBlockBody(block_inst); - try wip_decls.payload.ensureUnusedCapacity(gpa, 9); + try wip_decls.payload.ensureUnusedCapacity(gpa, 10); { const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); const casted = @bitCast([4]u32, contents_hash); @@ -3284,7 +3284,7 @@ fn globalVarDecl( _ = try block_scope.addBreak(.break_inline, block_inst, var_inst); try block_scope.setBlockBody(block_inst); - try wip_decls.payload.ensureUnusedCapacity(gpa, 9); + try wip_decls.payload.ensureUnusedCapacity(gpa, 10); { const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); const casted = @bitCast([4]u32, contents_hash); diff --git a/src/Module.zig b/src/Module.zig index add0562d93..957987b895 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -288,6 +288,8 @@ pub const Decl = struct { align_val: Value, /// Populated when `has_tv`. linksection_val: Value, + /// Populated when `has_tv`. + @"addrspace": std.builtin.AddressSpace, /// The memory for ty, val, align_val, linksection_val. /// If this is `null` then there is no memory management needed. value_arena: ?*std.heap.ArenaAllocator.State = null, @@ -351,7 +353,7 @@ pub const Decl = struct { /// to require re-analysis. outdated, }, - /// Whether `typed_value`, `align_val`, and `linksection_val` are populated. + /// Whether `typed_value`, `align_val`, `linksection_val` and `has_addrspace` are populated. has_tv: bool, /// If `true` it means the `Decl` is the resource owner of the type/value associated /// with it. That means when `Decl` is destroyed, the cleanup code should additionally @@ -366,8 +368,8 @@ pub const Decl = struct { is_exported: bool, /// Whether the ZIR code provides an align instruction. has_align: bool, - /// Whether the ZIR code provides a linksection instruction. - has_linksection: bool, + /// Whether the ZIR code provides a linksection and address space instruction. + has_linksection_or_addrspace: bool, /// Flag used by garbage collection to mark and sweep. /// Decls which correspond to an AST node always have this field set to `true`. /// Anonymous Decls are initialized with this field set to `false` and then it @@ -489,14 +491,22 @@ pub const Decl = struct { if (!decl.has_align) return .none; assert(decl.zir_decl_index != 0); const zir = decl.namespace.file_scope.zir; - return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 6]); + return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 7]); } pub fn zirLinksectionRef(decl: Decl) Zir.Inst.Ref { - if (!decl.has_linksection) return .none; + if (!decl.has_linksection_or_addrspace) return .none; assert(decl.zir_decl_index != 0); const zir = decl.namespace.file_scope.zir; - const extra_index = decl.zir_decl_index + 6 + @boolToInt(decl.has_align); + const extra_index = decl.zir_decl_index + 7 + @boolToInt(decl.has_align); + return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); + } + + pub fn zirAddrspaceRef(decl: Decl) Zir.Inst.Ref { + if (!decl.has_linksection_or_addrspace) return .none; + assert(decl.zir_decl_index != 0); + const zir = decl.namespace.file_scope.zir; + const extra_index = decl.zir_decl_index + 7 + @boolToInt(decl.has_align) + 1; return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); } @@ -3072,7 +3082,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void { new_decl.is_pub = true; new_decl.is_exported = false; new_decl.has_align = false; - new_decl.has_linksection = false; + new_decl.has_linksection_or_addrspace = false; new_decl.ty = struct_ty; new_decl.val = struct_val; new_decl.has_tv = true; @@ -3202,6 +3212,12 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { if (linksection_ref == .none) break :blk Value.initTag(.null_value); break :blk (try sema.resolveInstConst(&block_scope, src, linksection_ref)).val; }; + const address_space = blk: { + const addrspace_ref = decl.zirAddrspaceRef(); + if (addrspace_ref == .none) break :blk .generic; + const addrspace_tv = try sema.resolveInstConst(&block_scope, src, addrspace_ref); + break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace); + }; // Note this resolves the type of the Decl, not the value; if this Decl // is a struct, for example, this resolves `type` (which needs no resolution), // not the struct itself. @@ -3258,6 +3274,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { decl.val = try decl_tv.val.copy(&decl_arena.allocator); decl.align_val = try align_val.copy(&decl_arena.allocator); decl.linksection_val = try linksection_val.copy(&decl_arena.allocator); + decl.@"addrspace" = address_space; decl.has_tv = true; decl.owns_tv = owns_tv; decl_arena_state.* = decl_arena.state; @@ -3319,6 +3336,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { decl.val = try decl_tv.val.copy(&decl_arena.allocator); decl.align_val = try align_val.copy(&decl_arena.allocator); decl.linksection_val = try linksection_val.copy(&decl_arena.allocator); + decl.@"addrspace" = address_space; decl.has_tv = true; decl_arena_state.* = decl_arena.state; decl.value_arena = decl_arena_state; @@ -3526,8 +3544,8 @@ pub fn scanNamespace( const decl_sub_index = extra_index; extra_index += 7; // src_hash(4) + line(1) + name(1) + value(1) - extra_index += @truncate(u1, flags >> 2); - extra_index += @truncate(u1, flags >> 3); + extra_index += @truncate(u1, flags >> 2); // Align + extra_index += @as(u2, @truncate(u1, flags >> 3)) * 2; // Link section or address space, consists of 2 Refs try scanDecl(&scan_decl_iter, decl_sub_index, flags); } @@ -3553,10 +3571,10 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi const zir = namespace.file_scope.zir; // zig fmt: off - const is_pub = (flags & 0b0001) != 0; - const export_bit = (flags & 0b0010) != 0; - const has_align = (flags & 0b0100) != 0; - const has_linksection = (flags & 0b1000) != 0; + const is_pub = (flags & 0b0001) != 0; + const export_bit = (flags & 0b0010) != 0; + const has_align = (flags & 0b0100) != 0; + const has_linksection_or_addrspace = (flags & 0b1000) != 0; // zig fmt: on const line = iter.parent_decl.relativeToLine(zir.extra[decl_sub_index + 4]); @@ -3639,7 +3657,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi new_decl.is_exported = is_exported; new_decl.is_usingnamespace = is_usingnamespace; new_decl.has_align = has_align; - new_decl.has_linksection = has_linksection; + new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace; new_decl.zir_decl_index = @intCast(u32, decl_sub_index); new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive. return; @@ -3656,7 +3674,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi decl.is_exported = is_exported; decl.is_usingnamespace = is_usingnamespace; decl.has_align = has_align; - decl.has_linksection = has_linksection; + decl.has_linksection_or_addrspace = has_linksection_or_addrspace; decl.zir_decl_index = @intCast(u32, decl_sub_index); if (decl.getFunction()) |_| { switch (mod.comp.bin_file.tag) { @@ -4028,6 +4046,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast. .val = undefined, .align_val = undefined, .linksection_val = undefined, + .@"addrspace" = undefined, .analysis = .unreferenced, .deletion_flag = false, .zir_decl_index = 0, @@ -4052,7 +4071,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast. .generation = 0, .is_pub = false, .is_exported = false, - .has_linksection = false, + .has_linksection_or_addrspace = false, .has_align = false, .alive = false, .is_usingnamespace = false, @@ -4357,6 +4376,7 @@ pub fn ptrType( elem_ty: Type, sentinel: ?Value, @"align": u32, + @"addrspace": std.builtin.AddressSpace, bit_offset: u16, host_size: u16, mutable: bool, @@ -4371,6 +4391,7 @@ pub fn ptrType( .pointee_type = elem_ty, .sentinel = sentinel, .@"align" = @"align", + .@"addrspace" = @"addrspace", .bit_offset = bit_offset, .host_size = host_size, .@"allowzero" = @"allowzero", diff --git a/src/Sema.zig b/src/Sema.zig index 8200e95aa5..b1145bab99 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3004,7 +3004,7 @@ fn analyzeCall( new_decl.is_pub = module_fn.owner_decl.is_pub; new_decl.is_exported = module_fn.owner_decl.is_exported; new_decl.has_align = module_fn.owner_decl.has_align; - new_decl.has_linksection = module_fn.owner_decl.has_linksection; + new_decl.has_linksection_or_addrspace = module_fn.owner_decl.has_linksection_or_addrspace; new_decl.zir_decl_index = module_fn.owner_decl.zir_decl_index; new_decl.alive = true; // This Decl is called at runtime. new_decl.has_tv = true; @@ -3895,6 +3895,7 @@ fn zirFunc( ret_ty_body, cc, Value.initTag(.null_value), + .generic, false, inferred_error_set, false, @@ -3911,6 +3912,7 @@ fn funcCommon( ret_ty_body: []const Zir.Inst.Index, cc: std.builtin.CallingConvention, align_val: Value, + address_space: std.builtin.AddressSpace, var_args: bool, inferred_error_set: bool, is_extern: bool, @@ -3968,7 +3970,7 @@ fn funcCommon( // Hot path for some common function types. // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated. if (!is_generic and block.params.items.len == 0 and !var_args and - align_val.tag() == .null_value and !inferred_error_set) + align_val.tag() == .null_value and !inferred_error_set and address_space == .generic) { if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) { break :fn_ty Type.initTag(.fn_noreturn_no_args); @@ -4020,6 +4022,7 @@ fn funcCommon( .comptime_params = comptime_params.ptr, .return_type = return_type, .cc = cc, + .@"addrspace" = address_space, .is_var_args = var_args, .is_generic = is_generic, }); @@ -6876,6 +6879,7 @@ fn zirPtrTypeSimple(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp elem_type, null, 0, + .generic, 0, 0, inst_data.is_mutable, @@ -6908,6 +6912,13 @@ fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u32); } else 0; + const address_space = if (inst_data.flags.has_addrspace) blk: { + const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); + extra_i += 1; + const addrspace_tv = try sema.resolveInstConst(block, .unneeded, ref); + break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace); + } else .generic; + const bit_start = if (inst_data.flags.has_bit_range) blk: { const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); extra_i += 1; @@ -6930,6 +6941,7 @@ fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr elem_type, sentinel, abi_align, + address_space, bit_start, bit_end, inst_data.flags.is_mutable, @@ -8035,6 +8047,7 @@ fn zirFuncExtended( const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = extra.data.src_node }; const align_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at align + const addrspace_src: LazySrcLoc = src; // TODO(Snektron) add a LazySrcLoc that points at addrspace const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small); var extra_index: usize = extra.end; @@ -8059,6 +8072,13 @@ fn zirFuncExtended( break :blk align_tv.val; } else Value.initTag(.null_value); + const address_space: std.builtin.AddressSpace = if (small.has_addrspace) blk: { + const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); + extra_index += 1; + const addrspace_tv = try sema.resolveInstConst(block, addrspace_src, addrspace_ref); + break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace); + } else .generic; + const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len]; extra_index += ret_ty_body.len; @@ -8081,6 +8101,7 @@ fn zirFuncExtended( ret_ty_body, cc, align_val, + address_space, is_var_args, is_inferred_error, is_extern, @@ -9693,6 +9714,9 @@ fn analyzeSlice( return_elem_type, if (end_opt == .none) slice_sentinel else null, 0, // TODO alignment + // TODO(Snektron) address space, should be inferred from the pointer type. + // TODO(Snektron) address space for slicing a local, should compute address space from context and architecture. + .generic, 0, 0, !ptr_child.isConstPtr(), diff --git a/src/type.zig b/src/type.zig index 8eca352eac..647d88c60f 100644 --- a/src/type.zig +++ b/src/type.zig @@ -289,6 +289,7 @@ pub const Type = extern union { .pointee_type = Type.initTag(.comptime_int), .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -300,6 +301,7 @@ pub const Type = extern union { .pointee_type = Type.initTag(.u8), .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -311,6 +313,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -322,6 +325,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -333,6 +337,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -344,6 +349,7 @@ pub const Type = extern union { .pointee_type = Type.initTag(.u8), .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -355,6 +361,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -366,6 +373,7 @@ pub const Type = extern union { .pointee_type = Type.initTag(.u8), .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -377,6 +385,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -388,6 +397,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -399,6 +409,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -410,6 +421,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -462,6 +474,8 @@ pub const Type = extern union { return false; if (info_a.host_size != info_b.host_size) return false; + if (info_a.@"addrspace" != info_b.@"addrspace") + return false; const sentinel_a = info_a.sentinel; const sentinel_b = info_b.sentinel; @@ -516,6 +530,8 @@ pub const Type = extern union { return false; if (a.fnCallingConvention() != b.fnCallingConvention()) return false; + if (a.fnAddressSpace() != b.fnAddressSpace()) + return false; const a_param_len = a.fnParamLen(); const b_param_len = b.fnParamLen(); if (a_param_len != b_param_len) @@ -822,6 +838,7 @@ pub const Type = extern union { .return_type = try payload.return_type.copy(allocator), .param_types = param_types, .cc = payload.cc, + .@"addrspace" = payload.@"addrspace", .is_var_args = payload.is_var_args, .is_generic = payload.is_generic, .comptime_params = comptime_params.ptr, @@ -837,6 +854,7 @@ pub const Type = extern union { .pointee_type = try payload.pointee_type.copy(allocator), .sentinel = sent, .@"align" = payload.@"align", + .@"addrspace" = payload.@"addrspace", .bit_offset = payload.bit_offset, .host_size = payload.host_size, .@"allowzero" = payload.@"allowzero", @@ -983,6 +1001,9 @@ pub const Type = extern union { try writer.writeAll(") callconv(."); try writer.writeAll(@tagName(payload.cc)); try writer.writeAll(") "); + if (payload.@"addrspace" != .generic) { + try writer.print("addrspace(.{s}) ", .{ @tagName(payload.@"addrspace") }); + } ty = payload.return_type; continue; }, @@ -1114,6 +1135,9 @@ pub const Type = extern union { } try writer.writeAll(") "); } + if (payload.@"addrspace" != .generic) { + try writer.print("addrspace(.{s}) ", .{ @tagName(payload.@"addrspace") }); + } if (!payload.mutable) try writer.writeAll("const "); if (payload.@"volatile") try writer.writeAll("volatile "); if (payload.@"allowzero") try writer.writeAll("allowzero "); @@ -2642,6 +2666,18 @@ pub const Type = extern union { }; } + pub fn fnAddressSpace(self: Type) std.builtin.AddressSpace { + return switch (self.tag()) { + .fn_noreturn_no_args => .generic, + .fn_void_no_args => .generic, + .fn_naked_noreturn_no_args => .generic, + .fn_ccc_void_no_args => .generic, + .function => self.castTag(.function).?.data.@"addrspace", + + else => unreachable, + }; + } + pub fn fnInfo(ty: Type) Payload.Function.Data { return switch (ty.tag()) { .fn_noreturn_no_args => .{ @@ -2649,6 +2685,7 @@ pub const Type = extern union { .comptime_params = undefined, .return_type = initTag(.noreturn), .cc = .Unspecified, + .@"addrspace" = .generic, .is_var_args = false, .is_generic = false, }, @@ -2657,6 +2694,7 @@ pub const Type = extern union { .comptime_params = undefined, .return_type = initTag(.void), .cc = .Unspecified, + .@"addrspace" = .generic, .is_var_args = false, .is_generic = false, }, @@ -2665,6 +2703,7 @@ pub const Type = extern union { .comptime_params = undefined, .return_type = initTag(.noreturn), .cc = .Naked, + .@"addrspace" = .generic, .is_var_args = false, .is_generic = false, }, @@ -2673,6 +2712,7 @@ pub const Type = extern union { .comptime_params = undefined, .return_type = initTag(.void), .cc = .C, + .@"addrspace" = .generic, .is_var_args = false, .is_generic = false, }, @@ -3544,6 +3584,7 @@ pub const Type = extern union { comptime_params: [*]bool, return_type: Type, cc: std.builtin.CallingConvention, + @"addrspace": std.builtin.AddressSpace, is_var_args: bool, is_generic: bool, @@ -3581,6 +3622,7 @@ pub const Type = extern union { sentinel: ?Value, /// If zero use pointee_type.AbiAlign() @"align": u32, + @"addrspace": std.builtin.AddressSpace, bit_offset: u16, host_size: u16, @"allowzero": bool, From cfbe9a6f61c98cb1b18e18aa6a4acf7785590953 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Thu, 2 Sep 2021 14:49:24 +0200 Subject: [PATCH 04/30] Address spaces: Forbid addrspace and linksection for local variables --- src/AstGen.zig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/AstGen.zig b/src/AstGen.zig index 443834485f..cffc626a1e 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -2377,6 +2377,7 @@ fn varDecl( const gpa = astgen.gpa; const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); + const main_tokens = tree.nodes.items(.main_token); const name_token = var_decl.ast.mut_token + 1; const ident_name_raw = tree.tokenSlice(name_token); @@ -2391,6 +2392,14 @@ fn varDecl( return astgen.failNode(node, "variables must be initialized", .{}); } + if (var_decl.ast.addrspace_node != 0) { + return astgen.failTok(main_tokens[var_decl.ast.addrspace_node], "cannot set address space of local variable '{s}'", .{ ident_name_raw }); + } + + if (var_decl.ast.section_node != 0) { + return astgen.failTok(main_tokens[var_decl.ast.section_node], "cannot set section of local variable '{s}'", .{ ident_name_raw }); + } + const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node != 0) try expr(gz, scope, align_rl, var_decl.ast.align_node) else From 60231086508d26689d53b8bc545e8fe98cad966d Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Fri, 20 Aug 2021 01:22:44 +0200 Subject: [PATCH 05/30] Address Spaces: x86 segment address spaces in builtin --- lib/std/builtin.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index b9176794c6..09d93d5d21 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -170,7 +170,9 @@ pub const CallingConvention = enum { /// therefore must be kept in sync with the compiler implementation. pub const AddressSpace = enum { generic, - special, + gs, + fs, + ss, }; /// This data structure is used by the Zig language code generation and From cd9f6001af407a6961281cbe9c658cfe94b81ecb Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Fri, 20 Aug 2021 02:53:29 +0200 Subject: [PATCH 06/30] Address Spaces: decl_ref, *?T => *T, and *(E!T) -> *T --- src/Module.zig | 30 +++++++++++++++++++++++++++++- src/Sema.zig | 20 ++++++++++++++++---- src/type.zig | 24 ++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 957987b895..83b9a600d0 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -353,7 +353,7 @@ pub const Decl = struct { /// to require re-analysis. outdated, }, - /// Whether `typed_value`, `align_val`, `linksection_val` and `has_addrspace` are populated. + /// Whether `typed_value`, `align_val`, `linksection_val` and `addrspace` are populated. has_tv: bool, /// If `true` it means the `Decl` is the resource owner of the type/value associated /// with it. That means when `Decl` is destroyed, the cleanup code should additionally @@ -4401,6 +4401,34 @@ pub fn ptrType( }); } +/// Create a pointer type with an explicit address space. This function might return results +/// of either simplePtrType or ptrType, depending on the address space. +/// TODO(Snektron) unify ptrType functions. +pub fn simplePtrTypeWithAddressSpace( + arena: *Allocator, + elem_ty: Type, + mutable: bool, + size: std.builtin.TypeInfo.Pointer.Size, + address_space: std.builtin.AddressSpace, +) Allocator.Error!Type { + switch (address_space) { + .generic => return simplePtrType(arena, elem_ty, mutable, size), + else => return ptrType( + arena, + elem_ty, + null, + 0, + address_space, + 0, + 0, + mutable, + false, + false, + size, + ), + } +} + pub fn optionalType(arena: *Allocator, child_type: Type) Allocator.Error!Type { switch (child_type.tag()) { .single_const_pointer => return Type.Tag.optional_single_const_pointer.create( diff --git a/src/Sema.zig b/src/Sema.zig index b1145bab99..14f43ccf9e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3658,7 +3658,13 @@ fn zirOptionalPayloadPtr( } const child_type = try opt_type.optionalChildAlloc(sema.arena); - const child_pointer = try Module.simplePtrType(sema.arena, child_type, !optional_ptr_ty.isConstPtr(), .One); + const child_pointer = try Module.simplePtrTypeWithAddressSpace( + sema.arena, + child_type, + !optional_ptr_ty.isConstPtr(), + .One, + optional_ptr_ty.ptrAddressSpace(), + ); if (try sema.resolveDefinedValue(block, src, optional_ptr)) |pointer_val| { if (try pointer_val.pointerDeref(sema.arena)) |val| { @@ -3773,7 +3779,13 @@ fn zirErrUnionPayloadPtr( return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand_ty.elemType()}); const payload_ty = operand_ty.elemType().errorUnionPayload(); - const operand_pointer_ty = try Module.simplePtrType(sema.arena, payload_ty, !operand_ty.isConstPtr(), .One); + const operand_pointer_ty = try Module.simplePtrTypeWithAddressSpace( + sema.arena, + payload_ty, + !operand_ty.isConstPtr(), + .One, + operand_ty.ptrAddressSpace(), + ); if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| { if (try pointer_val.pointerDeref(sema.arena)) |val| { @@ -9525,11 +9537,11 @@ fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref { const decl_tv = try decl.typedValue(); if (decl_tv.val.castTag(.variable)) |payload| { const variable = payload.data; - const ty = try Module.simplePtrType(sema.arena, decl_tv.ty, variable.is_mutable, .One); + const ty = try Module.simplePtrTypeWithAddressSpace(sema.arena, decl_tv.ty, variable.is_mutable, .One, decl.@"addrspace"); return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl)); } return sema.addConstant( - try Module.simplePtrType(sema.arena, decl_tv.ty, false, .One), + try Module.simplePtrTypeWithAddressSpace(sema.arena, decl_tv.ty, false, .One, decl.@"addrspace"), try Value.Tag.decl_ref.create(sema.arena, decl), ); } diff --git a/src/type.zig b/src/type.zig index 647d88c60f..b15026b595 100644 --- a/src/type.zig +++ b/src/type.zig @@ -1526,6 +1526,30 @@ pub const Type = extern union { } } + pub fn ptrAddressSpace(self: Type) std.builtin.AddressSpace { + return switch (self.tag()) { + .single_const_pointer_to_comptime_int, + .const_slice_u8, + .single_const_pointer, + .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .const_slice, + .mut_slice, + .inferred_alloc_const, + .inferred_alloc_mut, + .manyptr_u8, + .manyptr_const_u8, + => .generic, + + .pointer => self.castTag(.pointer).?.data.@"addrspace", + + else => unreachable, + }; + } + /// Asserts that hasCodeGenBits() is true. pub fn abiAlignment(self: Type, target: Target) u32 { return switch (self.tag()) { From 0e6dc64a6fa173ae92197f692cf907fdc8bbf811 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Thu, 26 Aug 2021 03:29:31 +0200 Subject: [PATCH 07/30] Address Spaces: Return proper address space for &x[y] --- src/Sema.zig | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 14f43ccf9e..a782cb2472 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -9035,10 +9035,13 @@ fn elemPtrArray( ) CompileError!Air.Inst.Ref { const array_ptr_ty = sema.typeOf(array_ptr); const pointee_type = array_ptr_ty.elemType().elemType(); - const result_ty = if (array_ptr_ty.ptrIsMutable()) - try Type.Tag.single_mut_pointer.create(sema.arena, pointee_type) - else - try Type.Tag.single_const_pointer.create(sema.arena, pointee_type); + const result_ty = try Module.simplePtrTypeWithAddressSpace( + sema.arena, + pointee_type, + array_ptr_ty.ptrIsMutable(), + .One, + array_ptr_ty.ptrAddressSpace(), + ); if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| { if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| { From e182c17187c12cfb448cf47a04a156caaf9e3fc9 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Thu, 26 Aug 2021 03:31:03 +0200 Subject: [PATCH 08/30] Address Spaces: Disallow coercing pointers to different address spaces --- src/Sema.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Sema.zig b/src/Sema.zig index a782cb2472..e0a085a010 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -9132,6 +9132,7 @@ fn coerce( const dest_is_mut = !dest_type.isConstPtr(); if (inst_ty.isConstPtr() and dest_is_mut) break :src_array_ptr; if (inst_ty.isVolatilePtr() and !dest_type.isVolatilePtr()) break :src_array_ptr; + if (inst_ty.ptrAddressSpace() != dest_type.ptrAddressSpace()) break :src_array_ptr; const dst_elem_type = dest_type.elemType(); switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type, dest_is_mut)) { From 64c328a71700608b4cf5a19644f96fe99fbac4dd Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Thu, 26 Aug 2021 03:51:22 +0200 Subject: [PATCH 09/30] Address Spaces: Default align, linksection & addrspace for anon decls --- src/Module.zig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Module.zig b/src/Module.zig index 83b9a600d0..b2cef0792a 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4204,6 +4204,9 @@ pub fn createAnonymousDeclFromDeclNamed( new_decl.src_line = owner_decl.src_line; new_decl.ty = typed_value.ty; new_decl.val = typed_value.val; + new_decl.align_val = Value.initTag(.null_value); + new_decl.linksection_val = Value.initTag(.null_value); + new_decl.@"addrspace" = .generic; // default global addrspace new_decl.has_tv = true; new_decl.analysis = .complete; new_decl.generation = mod.generation; From 497c0d3783c6a11cc64eaff72be050ce09a0ac13 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Thu, 26 Aug 2021 04:11:04 +0200 Subject: [PATCH 10/30] Allow x.y when x is a pointer --- src/Sema.zig | 99 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 38 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index e0a085a010..9426c0caec 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8424,21 +8424,32 @@ fn fieldVal( } }, .One => { - const elem_ty = object_ty.elemType(); - if (elem_ty.zigTypeTag() == .Array) { - if (mem.eql(u8, field_name, "len")) { - return sema.addConstant( - Type.initTag(.comptime_int), - try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()), - ); - } else { - return mod.fail( - &block.base, - field_name_src, - "no member named '{s}' in '{}'", - .{ field_name, object_ty }, - ); - } + const ptr_child = object_ty.elemType(); + switch (ptr_child.zigTypeTag()) { + .Array => { + if (mem.eql(u8, field_name, "len")) { + return sema.addConstant( + Type.initTag(.comptime_int), + try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()), + ); + } else { + return mod.fail( + &block.base, + field_name_src, + "no member named '{s}' in '{}'", + .{ field_name, object_ty }, + ); + } + }, + .Struct => { + const struct_ptr_deref = try sema.analyzeLoad(block, src, object, object_src); + return sema.unionFieldVal(block, src, struct_ptr_deref, field_name, field_name_src, ptr_child); + }, + .Union => { + const union_ptr_deref = try sema.analyzeLoad(block, src, object, object_src); + return sema.unionFieldVal(block, src, union_ptr_deref, field_name, field_name_src, ptr_child); + }, + else => {}, } }, .Many, .C => {}, @@ -8562,9 +8573,8 @@ fn fieldPtr( ); } }, - .Pointer => { - const ptr_child = object_ty.elemType(); - if (ptr_child.isSlice()) { + .Pointer => switch (object_ty.ptrSize()) { + .Slice => { // Here for the ptr and len fields what we need to do is the situation // when a temporary has its address taken, e.g. `&a[c..d].len`. // This value may be known at compile-time or runtime. In the former @@ -8594,26 +8604,39 @@ fn fieldPtr( .{ field_name, object_ty }, ); } - } else switch (ptr_child.zigTypeTag()) { - .Array => { - if (mem.eql(u8, field_name, "len")) { - var anon_decl = try block.startAnonDecl(); - defer anon_decl.deinit(); - return sema.analyzeDeclRef(try anon_decl.finish( - Type.initTag(.comptime_int), - try Value.Tag.int_u64.create(anon_decl.arena(), ptr_child.arrayLen()), - )); - } else { - return mod.fail( - &block.base, - field_name_src, - "no member named '{s}' in '{}'", - .{ field_name, object_ty }, - ); - } - }, - else => {}, - } + }, + .One => { + const ptr_child = object_ty.elemType(); + switch (ptr_child.zigTypeTag()) { + .Array => { + if (mem.eql(u8, field_name, "len")) { + var anon_decl = try block.startAnonDecl(); + defer anon_decl.deinit(); + return sema.analyzeDeclRef(try anon_decl.finish( + Type.initTag(.comptime_int), + try Value.Tag.int_u64.create(anon_decl.arena(), ptr_child.arrayLen()), + )); + } else { + return mod.fail( + &block.base, + field_name_src, + "no member named '{s}' in '{}'", + .{ field_name, object_ty }, + ); + } + }, + .Struct => { + const struct_ptr_deref = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src); + return sema.structFieldPtr(block, src, struct_ptr_deref, field_name, field_name_src, ptr_child); + }, + .Union => { + const union_ptr_deref = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src); + return sema.unionFieldPtr(block, src, union_ptr_deref, field_name, field_name_src, ptr_child); + }, + else => {}, + } + }, + .Many, .C => {}, }, .Type => { _ = try sema.resolveConstValue(block, object_ptr_src, object_ptr); From 538f1bbcb35c10fb0aa633adbac64932cc89d034 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Thu, 26 Aug 2021 04:16:36 +0200 Subject: [PATCH 11/30] Address Spaces: Return proper address space for &x.y --- src/Sema.zig | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 9426c0caec..dfcfde71cc 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8778,13 +8778,20 @@ fn structFieldPtr( const arena = sema.arena; assert(unresolved_struct_ty.zigTypeTag() == .Struct); + const struct_ptr_ty = sema.typeOf(struct_ptr); const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty); const struct_obj = struct_ty.castTag(.@"struct").?.data; const field_index = struct_obj.fields.getIndex(field_name) orelse return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name); const field = struct_obj.fields.values()[field_index]; - const ptr_field_ty = try Module.simplePtrType(arena, field.ty, true, .One); + const ptr_field_ty = try Module.simplePtrTypeWithAddressSpace( + arena, + field.ty, + struct_ptr_ty.ptrIsMutable(), + .One, + struct_ptr_ty.ptrAddressSpace(), + ); if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| { return sema.addConstant( @@ -8875,6 +8882,7 @@ fn unionFieldPtr( const arena = sema.arena; assert(unresolved_union_ty.zigTypeTag() == .Union); + const union_ptr_ty = sema.typeOf(union_ptr); const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty); const union_obj = union_ty.cast(Type.Payload.Union).?.data; @@ -8882,7 +8890,13 @@ fn unionFieldPtr( return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name); const field = union_obj.fields.values()[field_index]; - const ptr_field_ty = try Module.simplePtrType(arena, field.ty, true, .One); + const ptr_field_ty = try Module.simplePtrTypeWithAddressSpace( + arena, + field.ty, + union_ptr_ty.ptrIsMutable(), + .One, + union_ptr_ty.ptrAddressSpace(), + ); if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| { // TODO detect inactive union field and emit compile error From 8672f2696f20e8989d42f69adbe09edfe5cd9332 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Thu, 2 Sep 2021 14:50:40 +0200 Subject: [PATCH 12/30] Address Spaces: zig fmt + tests --- lib/std/zig/parser_test.zig | 34 +++++++++++++++++++-------- lib/std/zig/render.zig | 47 +++++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 615648d1ad..2f79cc175c 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -404,6 +404,10 @@ test "zig fmt: trailing comma in fn parameter list" { \\pub fn f( \\ a: i32, \\ b: i32, + \\) addrspace(.generic) i32 {} + \\pub fn f( + \\ a: i32, + \\ b: i32, \\) linksection(".text") i32 {} \\pub fn f( \\ a: i32, @@ -553,8 +557,8 @@ test "zig fmt: sentinel-terminated slice type" { test "zig fmt: pointer-to-one with modifiers" { try testCanonical( \\const x: *u32 = undefined; - \\const y: *allowzero align(8) const volatile u32 = undefined; - \\const z: *allowzero align(8:4:2) const volatile u32 = undefined; + \\const y: *allowzero align(8) addrspace(.generic) const volatile u32 = undefined; + \\const z: *allowzero align(8:4:2) addrspace(.generic) const volatile u32 = undefined; \\ ); } @@ -562,8 +566,8 @@ test "zig fmt: pointer-to-one with modifiers" { test "zig fmt: pointer-to-many with modifiers" { try testCanonical( \\const x: [*]u32 = undefined; - \\const y: [*]allowzero align(8) const volatile u32 = undefined; - \\const z: [*]allowzero align(8:4:2) const volatile u32 = undefined; + \\const y: [*]allowzero align(8) addrspace(.generic) const volatile u32 = undefined; + \\const z: [*]allowzero align(8:4:2) addrspace(.generic) const volatile u32 = undefined; \\ ); } @@ -571,8 +575,8 @@ test "zig fmt: pointer-to-many with modifiers" { test "zig fmt: sentinel pointer with modifiers" { try testCanonical( \\const x: [*:42]u32 = undefined; - \\const y: [*:42]allowzero align(8) const volatile u32 = undefined; - \\const y: [*:42]allowzero align(8:4:2) const volatile u32 = undefined; + \\const y: [*:42]allowzero align(8) addrspace(.generic) const volatile u32 = undefined; + \\const y: [*:42]allowzero align(8:4:2) addrspace(.generic) const volatile u32 = undefined; \\ ); } @@ -580,8 +584,8 @@ test "zig fmt: sentinel pointer with modifiers" { test "zig fmt: c pointer with modifiers" { try testCanonical( \\const x: [*c]u32 = undefined; - \\const y: [*c]allowzero align(8) const volatile u32 = undefined; - \\const z: [*c]allowzero align(8:4:2) const volatile u32 = undefined; + \\const y: [*c]allowzero align(8) addrspace(.generic) const volatile u32 = undefined; + \\const z: [*c]allowzero align(8:4:2) addrspace(.generic) const volatile u32 = undefined; \\ ); } @@ -589,7 +593,7 @@ test "zig fmt: c pointer with modifiers" { test "zig fmt: slice with modifiers" { try testCanonical( \\const x: []u32 = undefined; - \\const y: []allowzero align(8) const volatile u32 = undefined; + \\const y: []allowzero align(8) addrspace(.generic) const volatile u32 = undefined; \\ ); } @@ -597,7 +601,7 @@ test "zig fmt: slice with modifiers" { test "zig fmt: sentinel slice with modifiers" { try testCanonical( \\const x: [:42]u32 = undefined; - \\const y: [:42]allowzero align(8) const volatile u32 = undefined; + \\const y: [:42]allowzero align(8) addrspace(.generic) const volatile u32 = undefined; \\ ); } @@ -1129,6 +1133,16 @@ test "zig fmt: linksection" { ); } +test "zig fmt: addrspace" { + try testCanonical( + \\export var python_length: u64 align(1) addrspace(.generic); + \\export var python_color: Color addrspace(.generic) = .green; + \\export var python_legs: u0 align(8) addrspace(.generic) linksection(".python") = 0; + \\export fn python_hiss() align(8) addrspace(.generic) linksection(".python") void; + \\ + ); +} + test "zig fmt: correctly space struct fields with doc comments" { try testTransform( \\pub const S = struct { diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 265049e1f9..0703b5bbfa 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -797,6 +797,14 @@ fn renderPtrType( } } + if (ptr_type.ast.addrspace_node != 0) { + const addrspace_first = tree.firstToken(ptr_type.ast.addrspace_node); + try renderToken(ais, tree, addrspace_first - 2, .none); // addrspace + try renderToken(ais, tree, addrspace_first - 1, .none); // lparen + try renderExpression(gpa, ais, tree, ptr_type.ast.addrspace_node, .none); + try renderToken(ais, tree, tree.lastToken(ptr_type.ast.addrspace_node) + 1, .space); // rparen + } + if (ptr_type.const_token) |const_token| { try renderToken(ais, tree, const_token, .space); } @@ -921,6 +929,7 @@ fn renderVarDecl(gpa: *Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDe const name_space = if (var_decl.ast.type_node == 0 and (var_decl.ast.align_node != 0 or + var_decl.ast.addrspace_node != 0 or var_decl.ast.section_node != 0 or var_decl.ast.init_node != 0)) Space.space @@ -930,8 +939,8 @@ fn renderVarDecl(gpa: *Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDe if (var_decl.ast.type_node != 0) { try renderToken(ais, tree, var_decl.ast.mut_token + 2, Space.space); // : - if (var_decl.ast.align_node != 0 or var_decl.ast.section_node != 0 or - var_decl.ast.init_node != 0) + if (var_decl.ast.align_node != 0 or var_decl.ast.addrspace_node != 0 or + var_decl.ast.section_node != 0 or var_decl.ast.init_node != 0) { try renderExpression(gpa, ais, tree, var_decl.ast.type_node, .space); } else { @@ -948,6 +957,22 @@ fn renderVarDecl(gpa: *Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDe try renderToken(ais, tree, align_kw, Space.none); // align try renderToken(ais, tree, lparen, Space.none); // ( try renderExpression(gpa, ais, tree, var_decl.ast.align_node, Space.none); + if (var_decl.ast.addrspace_node != 0 or var_decl.ast.section_node != 0 or + var_decl.ast.init_node != 0) { + try renderToken(ais, tree, rparen, .space); // ) + } else { + try renderToken(ais, tree, rparen, .none); // ) + return renderToken(ais, tree, rparen + 1, Space.newline); // ; + } + } + + if (var_decl.ast.addrspace_node != 0) { + const lparen = tree.firstToken(var_decl.ast.addrspace_node) - 1; + const addrspace_kw = lparen - 1; + const rparen = tree.lastToken(var_decl.ast.addrspace_node) + 1; + try renderToken(ais, tree, addrspace_kw, Space.none); // addrspace + try renderToken(ais, tree, lparen, Space.none); // ( + try renderExpression(gpa, ais, tree, var_decl.ast.addrspace_node, Space.none); if (var_decl.ast.section_node != 0 or var_decl.ast.init_node != 0) { try renderToken(ais, tree, rparen, .space); // ) } else { @@ -1267,6 +1292,14 @@ fn renderFnProto(gpa: *Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnPro smallest_start = start; } } + if (fn_proto.ast.addrspace_expr != 0) { + const tok = tree.firstToken(fn_proto.ast.addrspace_expr) - 3; + const start = token_starts[tok]; + if (start < smallest_start) { + rparen = tok; + smallest_start = start; + } + } if (fn_proto.ast.section_expr != 0) { const tok = tree.firstToken(fn_proto.ast.section_expr) - 3; const start = token_starts[tok]; @@ -1407,6 +1440,16 @@ fn renderFnProto(gpa: *Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnPro try renderToken(ais, tree, align_rparen, .space); // ) } + if (fn_proto.ast.addrspace_expr != 0) { + const align_lparen = tree.firstToken(fn_proto.ast.addrspace_expr) - 1; + const align_rparen = tree.lastToken(fn_proto.ast.addrspace_expr) + 1; + + try renderToken(ais, tree, align_lparen - 1, .none); // addrspace + try renderToken(ais, tree, align_lparen, .none); // ( + try renderExpression(gpa, ais, tree, fn_proto.ast.addrspace_expr, .none); + try renderToken(ais, tree, align_rparen, .space); // ) + } + if (fn_proto.ast.section_expr != 0) { const section_lparen = tree.firstToken(fn_proto.ast.section_expr) - 1; const section_rparen = tree.lastToken(fn_proto.ast.section_expr) + 1; From e77fcf17301ad5a68e84cb598984a526cc356621 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Fri, 27 Aug 2021 02:48:29 +0200 Subject: [PATCH 13/30] Address Spaces: Implement right address space for slicing --- src/Sema.zig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index dfcfde71cc..4b75cc4c43 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -9767,9 +9767,7 @@ fn analyzeSlice( return_elem_type, if (end_opt == .none) slice_sentinel else null, 0, // TODO alignment - // TODO(Snektron) address space, should be inferred from the pointer type. - // TODO(Snektron) address space for slicing a local, should compute address space from context and architecture. - .generic, + if (ptr_child.zigTypeTag() == .Pointer) ptr_child.ptrAddressSpace() else .generic, 0, 0, !ptr_child.isConstPtr(), From 6336f08c2122faf712cb4b5096555e2617ce3936 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Fri, 27 Aug 2021 04:26:05 +0200 Subject: [PATCH 14/30] Address Spaces: Address space on local variable test --- test/cases.zig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/cases.zig b/test/cases.zig index 59f0ef7146..33fa5b19e2 100644 --- a/test/cases.zig +++ b/test/cases.zig @@ -1807,4 +1807,16 @@ pub fn addCases(ctx: *TestContext) !void { \\} , ""); } + + { + var case = ctx.exe("setting an address space on a local variable", linux_x64); + case.addError( + \\export fn entry() i32 { + \\ var foo: i32 addrspace(".general") = 1234; + \\ return foo; + \\} + , &[_][]const u8{ + ":2:28: error: cannot set address space of local variable 'foo'", + }); + } } From 7686165c8265cebfb7a3d7d4fd4f00a46dc4743a Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Fri, 27 Aug 2021 05:04:13 +0200 Subject: [PATCH 15/30] Address Spaces: Pointer coercion errors tests --- test/cases.zig | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/test/cases.zig b/test/cases.zig index 33fa5b19e2..1a92f20262 100644 --- a/test/cases.zig +++ b/test/cases.zig @@ -861,7 +861,7 @@ pub fn addCases(ctx: *TestContext) !void { "Hello, World!\n", ); try case.files.append(.{ - .src = + .src = \\pub fn print() void { \\ asm volatile ("syscall" \\ : @@ -924,7 +924,7 @@ pub fn addCases(ctx: *TestContext) !void { }, ); try case.files.append(.{ - .src = + .src = \\// dummy comment to make print be on line 2 \\fn print() void { \\ asm volatile ("syscall" @@ -1819,4 +1819,43 @@ pub fn addCases(ctx: *TestContext) !void { ":2:28: error: cannot set address space of local variable 'foo'", }); } + + { + var case = ctx.exe("address space pointer coercions", linux_x64); + case.addError( + \\fn entry(a: *addrspace(.gs) i32) *i32 { + \\ return a; + \\} + \\pub fn main() void { _ = entry; } + , &[_][]const u8{ + ":2:12: error: expected *i32, found *addrspace(.gs) i32", + }); + + case.addError( + \\fn entry(a: *addrspace(.gs) i32) *addrspace(.fs) i32 { + \\ return a; + \\} + \\pub fn main() void { _ = entry; } + , &[_][]const u8{ + ":2:12: error: expected *addrspace(.fs) i32, found *addrspace(.gs) i32", + }); + + case.addError( + \\fn entry(a: ?*addrspace(.gs) i32) *i32 { + \\ return a.?; + \\} + \\pub fn main() void { _ = entry; } + , &[_][]const u8{ + ":2:13: error: expected *i32, found *addrspace(.gs) i32", + }); + + case.addError( + \\fn entry(a: *addrspace(.gs) i32) *i32 { + \\ return &a.*; + \\} + \\pub fn main() void { _ = entry; } + , &[_][]const u8{ + ":2:12: error: expected *i32, found *addrspace(.gs) i32", + }); + } } From 8f28c5875911c663541dd4fd1a48fecfe412e8bf Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 29 Aug 2021 02:19:58 +0200 Subject: [PATCH 16/30] Address Spaces: compiles() test cases --- test/cases.zig | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/cases.zig b/test/cases.zig index 1a92f20262..e36bb368c8 100644 --- a/test/cases.zig +++ b/test/cases.zig @@ -1831,6 +1831,20 @@ pub fn addCases(ctx: *TestContext) !void { ":2:12: error: expected *i32, found *addrspace(.gs) i32", }); + case.compiles( + \\fn entry(a: *addrspace(.gs) i32) *addrspace(.gs) i32 { + \\ return a; + \\} + \\pub fn main() void { _ = entry; } + ); + + case.compiles( + \\fn entry(a: *addrspace(.generic) i32) *i32 { + \\ return a; + \\} + \\pub fn main() void { _ = entry; } + ); + case.addError( \\fn entry(a: *addrspace(.gs) i32) *addrspace(.fs) i32 { \\ return a; @@ -1857,5 +1871,12 @@ pub fn addCases(ctx: *TestContext) !void { , &[_][]const u8{ ":2:12: error: expected *i32, found *addrspace(.gs) i32", }); + + case.compiles( + \\fn entry(a: *addrspace(.gs) i32) *addrspace(.gs) i32 { + \\ return &a.*; + \\} + \\pub fn main() void { _ = entry; } + ); } } From 2f43749c2b48b1ef3e59663f3e7033500a4b0c0c Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Wed, 1 Sep 2021 17:03:41 +0200 Subject: [PATCH 17/30] Address Spaces: Move stage 2 tests to stage2/llvm.zig --- test/cases.zig | 60 -------------------------------------------- test/stage2/llvm.zig | 60 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/test/cases.zig b/test/cases.zig index e36bb368c8..62677b8424 100644 --- a/test/cases.zig +++ b/test/cases.zig @@ -1819,64 +1819,4 @@ pub fn addCases(ctx: *TestContext) !void { ":2:28: error: cannot set address space of local variable 'foo'", }); } - - { - var case = ctx.exe("address space pointer coercions", linux_x64); - case.addError( - \\fn entry(a: *addrspace(.gs) i32) *i32 { - \\ return a; - \\} - \\pub fn main() void { _ = entry; } - , &[_][]const u8{ - ":2:12: error: expected *i32, found *addrspace(.gs) i32", - }); - - case.compiles( - \\fn entry(a: *addrspace(.gs) i32) *addrspace(.gs) i32 { - \\ return a; - \\} - \\pub fn main() void { _ = entry; } - ); - - case.compiles( - \\fn entry(a: *addrspace(.generic) i32) *i32 { - \\ return a; - \\} - \\pub fn main() void { _ = entry; } - ); - - case.addError( - \\fn entry(a: *addrspace(.gs) i32) *addrspace(.fs) i32 { - \\ return a; - \\} - \\pub fn main() void { _ = entry; } - , &[_][]const u8{ - ":2:12: error: expected *addrspace(.fs) i32, found *addrspace(.gs) i32", - }); - - case.addError( - \\fn entry(a: ?*addrspace(.gs) i32) *i32 { - \\ return a.?; - \\} - \\pub fn main() void { _ = entry; } - , &[_][]const u8{ - ":2:13: error: expected *i32, found *addrspace(.gs) i32", - }); - - case.addError( - \\fn entry(a: *addrspace(.gs) i32) *i32 { - \\ return &a.*; - \\} - \\pub fn main() void { _ = entry; } - , &[_][]const u8{ - ":2:12: error: expected *i32, found *addrspace(.gs) i32", - }); - - case.compiles( - \\fn entry(a: *addrspace(.gs) i32) *addrspace(.gs) i32 { - \\ return &a.*; - \\} - \\pub fn main() void { _ = entry; } - ); - } } diff --git a/test/stage2/llvm.zig b/test/stage2/llvm.zig index 34f73b01c7..b5ec47c5de 100644 --- a/test/stage2/llvm.zig +++ b/test/stage2/llvm.zig @@ -242,4 +242,64 @@ pub fn addCases(ctx: *TestContext) !void { \\} , ""); } + + { + var case = ctx.exeUsingLlvmBackend("address space pointer coercions", linux_x64); + case.addError( + \\fn entry(a: *addrspace(.gs) i32) *i32 { + \\ return a; + \\} + \\pub export fn main() void { _ = entry; } + , &[_][]const u8{ + ":2:12: error: expected *i32, found *addrspace(.gs) i32", + }); + + case.compiles( + \\fn entry(a: *addrspace(.gs) i32) *addrspace(.gs) i32 { + \\ return a; + \\} + \\pub export fn main() void { _ = entry; } + ); + + case.compiles( + \\fn entry(a: *addrspace(.generic) i32) *i32 { + \\ return a; + \\} + \\pub export fn main() void { _ = entry; } + ); + + case.addError( + \\fn entry(a: *addrspace(.gs) i32) *addrspace(.fs) i32 { + \\ return a; + \\} + \\pub export fn main() void { _ = entry; } + , &[_][]const u8{ + ":2:12: error: expected *addrspace(.fs) i32, found *addrspace(.gs) i32", + }); + + case.addError( + \\fn entry(a: ?*addrspace(.gs) i32) *i32 { + \\ return a.?; + \\} + \\pub export fn main() void { _ = entry; } + , &[_][]const u8{ + ":2:13: error: expected *i32, found *addrspace(.gs) i32", + }); + + case.addError( + \\fn entry(a: *addrspace(.gs) i32) *i32 { + \\ return &a.*; + \\} + \\pub export fn main() void { _ = entry; } + , &[_][]const u8{ + ":2:12: error: expected *i32, found *addrspace(.gs) i32", + }); + + case.compiles( + \\fn entry(a: *addrspace(.gs) i32) *addrspace(.gs) i32 { + \\ return &a.*; + \\} + \\pub export fn main() void { _ = entry; } + ); + } } From e09465fc49d86cc4aa9338106862d3e059ae3303 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 29 Aug 2021 03:18:23 +0200 Subject: [PATCH 18/30] Address Spaces: Chaining tests --- src/codegen/llvm/bindings.zig | 59 +++++++++++++++++++++++++++++++++++ test/stage2/llvm.zig | 52 ++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index db1dcd22f2..67b39784b1 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -973,3 +973,62 @@ pub const TypeKind = enum(c_int) { BFloat, X86_AMX, }; + +pub const address_space = struct { + // See llvm/lib/Target/X86/X86.h + pub const x86_64 = x86; + pub const x86 = struct { + pub const gs = 256; + pub const fs = 257; + pub const ss = 258; + + pub const ptr32_sptr = 270; + pub const ptr32_uptr = 271; + pub const ptr64 = 272; + }; + + // See llvm/lib/Target/AVR/AVR.h + pub const avr = struct { + pub const data_memory = 0; + pub const program_memory = 1; + }; + + // See llvm/lib/Target/NVPTX/NVPTX.h + pub const nvptx = struct { + pub const generic = 0; + pub const global = 1; + pub const constant = 2; + pub const shared = 3; + pub const param = 4; + pub const local = 5; + }; + + // See llvm/lib/Target/AMDGPU/AMDGPU.h + pub const amdgpu = struct { + pub const flat = 0; + pub const global = 1; + pub const region = 2; + pub const local = 3; + pub const constant = 4; + pub const constant_32bit = 6; + pub const buffer_fat_pointer = 7; + pub const param_d = 6; + pub const param_i = 7; + pub const constant_buffer_0 = 8; + pub const constant_buffer_1 = 9; + pub const constant_buffer_2 = 10; + pub const constant_buffer_3 = 11; + pub const constant_buffer_4 = 12; + pub const constant_buffer_5 = 13; + pub const constant_buffer_6 = 14; + pub const constant_buffer_7 = 15; + pub const constant_buffer_8 = 16; + pub const constant_buffer_9 = 17; + pub const constant_buffer_10 = 18; + pub const constant_buffer_11 = 19; + pub const constant_buffer_12 = 20; + pub const constant_buffer_13 = 21; + pub const constant_buffer_14 = 22; + pub const constant_buffer_15 = 23; + }; +}; diff --git a/test/stage2/llvm.zig b/test/stage2/llvm.zig index b5ec47c5de..e61e7181c6 100644 --- a/test/stage2/llvm.zig +++ b/test/stage2/llvm.zig @@ -302,4 +302,56 @@ pub fn addCases(ctx: *TestContext) !void { \\pub export fn main() void { _ = entry; } ); } + + { + var case = ctx.exeUsingLlvmBackend("address spaces pointer access chaining: array pointer", linux_x64); + case.compiles( + \\fn entry(a: *addrspace(.gs) [1]i32) *addrspace(.gs) i32 { + \\ return &a[0]; + \\} + \\pub export fn main() void { _ = entry; } + ); + } + + { + var case = ctx.exeUsingLlvmBackend("address spaces pointer access chaining: pointer to optional array", linux_x64); + case.compiles( + \\fn entry(a: *addrspace(.gs) ?[1]i32) *addrspace(.gs) i32 { + \\ return &a.*.?[0]; + \\} + \\pub export fn main() void { _ = entry; } + ); + } + + { + var case = ctx.exeUsingLlvmBackend("address spaces pointer access chaining: struct pointer", linux_x64); + case.compiles( + \\const A = struct{ a: i32 }; + \\fn entry(a: *addrspace(.gs) A) *addrspace(.gs) i32 { + \\ return &a.a; + \\} + \\pub export fn main() void { _ = entry; } + ); + } + + { + var case = ctx.exeUsingLlvmBackend("address spaces pointer access chaining: complex", linux_x64); + case.compiles( + \\const A = struct{ a: ?[1]i32 }; + \\fn entry(a: *addrspace(.gs) [1]A) *addrspace(.gs) i32 { + \\ return &a[0].a.?[0]; + \\} + \\pub export fn main() void { _ = entry; } + ); + } + + { + var case = ctx.exeUsingLlvmBackend("dereferencing through multiple pointers with address spaces", linux_x64); + case.compiles( + \\fn entry(a: *addrspace(.fs) *addrspace(.gs) *i32) *i32 { + \\ return a.*.*; + \\} + \\pub export fn main() void { _ = entry; } + ); + } } From ea393b2bca7587955df81d149caecc5522944d15 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 29 Aug 2021 06:08:19 +0200 Subject: [PATCH 19/30] Address Spaces: Implement in LLVM codegen --- src/Module.zig | 2 +- src/Sema.zig | 2 +- src/codegen.zig | 2 +- src/codegen/c.zig | 2 +- src/codegen/llvm.zig | 40 +++++++++++++++++++++++------ src/codegen/llvm/bindings.zig | 8 ++++++ src/type.zig | 48 ++++++++++++++++++++++++++++------- src/zig_llvm.cpp | 5 ++++ src/zig_llvm.h | 3 +++ 9 files changed, 91 insertions(+), 21 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index b2cef0792a..1f9b5abcb9 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4761,7 +4761,7 @@ pub fn populateTestFunctions(mod: *Module) !void { const builtin_file = (mod.importPkg(builtin_pkg) catch unreachable).file; const builtin_namespace = builtin_file.root_decl.?.namespace; const decl = builtin_namespace.decls.get("test_functions").?; - var buf: Type.Payload.ElemType = undefined; + var buf: Type.SlicePtrFieldTypeBuffer = undefined; const tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf).elemType(); const array_decl = d: { diff --git a/src/Sema.zig b/src/Sema.zig index 4b75cc4c43..d6e926e604 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8390,7 +8390,7 @@ fn fieldVal( .Pointer => switch (object_ty.ptrSize()) { .Slice => { if (mem.eql(u8, field_name, "ptr")) { - const buf = try arena.create(Type.Payload.ElemType); + const buf = try arena.create(Type.SlicePtrFieldTypeBuffer); const result_ty = object_ty.slicePtrFieldType(buf); if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| { if (val.isUndef()) return sema.addConstUndef(result_ty); diff --git a/src/codegen.zig b/src/codegen.zig index e0047de1f7..cbee79f139 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -4873,7 +4873,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { switch (typed_value.ty.zigTypeTag()) { .Pointer => switch (typed_value.ty.ptrSize()) { .Slice => { - var buf: Type.Payload.ElemType = undefined; + var buf: Type.SlicePtrFieldTypeBuffer = undefined; const ptr_type = typed_value.ty.slicePtrFieldType(&buf); const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val }); const slice_len = typed_value.val.sliceLen(); diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 5eb4388a9e..7a2dc343f7 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -251,7 +251,7 @@ pub const DeclGen = struct { try writer.writeByte('('); try dg.renderType(writer, t); try writer.writeAll("){"); - var buf: Type.Payload.ElemType = undefined; + var buf: Type.SlicePtrFieldTypeBuffer = undefined; try dg.renderValue(writer, t.slicePtrFieldType(&buf), val); try writer.writeAll(", "); try writer.print("{d}", .{val.sliceLen()}); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 53e57ee219..8b7282160e 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -554,7 +554,8 @@ pub const DeclGen = struct { @intCast(c_uint, fn_param_len), .False, ); - const llvm_fn = self.llvmModule().addFunction(decl.name, fn_type); + const llvm_addrspace = self.llvmAddressSpace(decl.@"addrspace"); + const llvm_fn = self.llvmModule().addFunctionInAddressSpace(decl.name, fn_type, llvm_addrspace); const is_extern = decl.val.tag() == .extern_fn; if (!is_extern) { @@ -576,7 +577,27 @@ pub const DeclGen = struct { if (llvm_module.getNamedGlobal(decl.name)) |val| return val; // TODO: remove this redundant `llvmType`, it is also called in `genTypedValue`. const llvm_type = try self.llvmType(decl.ty); - return llvm_module.addGlobal(llvm_type, decl.name); + const llvm_addrspace = self.llvmAddressSpace(decl.@"addrspace"); + return llvm_module.addGlobalInAddressSpace(llvm_type, decl.name, llvm_addrspace); + } + + fn llvmAddressSpace(self: DeclGen, address_space: std.builtin.AddressSpace) c_uint { + const target = self.module.getTarget(); + return switch (address_space) { + .generic => llvm.address_space.default, + .gs => switch (target.cpu.arch) { + .i386, .x86_64 => llvm.address_space.x86.gs, + else => unreachable, + }, + .fs => switch (target.cpu.arch) { + .i386, .x86_64 => llvm.address_space.x86.fs, + else => unreachable, + }, + .ss => switch (target.cpu.arch) { + .i386, .x86_64 => llvm.address_space.x86.ss, + else => unreachable, + }, + }; } fn llvmType(self: *DeclGen, t: Type) error{ OutOfMemory, CodegenFail }!*const llvm.Type { @@ -605,7 +626,7 @@ pub const DeclGen = struct { .Bool => return self.context.intType(1), .Pointer => { if (t.isSlice()) { - var buf: Type.Payload.ElemType = undefined; + var buf: Type.SlicePtrFieldTypeBuffer = undefined; const ptr_type = t.slicePtrFieldType(&buf); const fields: [2]*const llvm.Type = .{ @@ -615,7 +636,8 @@ pub const DeclGen = struct { return self.context.structType(&fields, fields.len, .False); } else { const elem_type = try self.llvmType(t.elemType()); - return elem_type.pointerType(0); + const llvm_addrspace = self.llvmAddressSpace(t.ptrAddressSpace()); + return elem_type.pointerType(llvm_addrspace); } }, .Array => { @@ -681,7 +703,8 @@ pub const DeclGen = struct { @intCast(c_uint, llvm_params.len), llvm.Bool.fromBool(is_var_args), ); - return llvm_fn_ty.pointerType(0); + const llvm_addrspace = self.llvmAddressSpace(t.fnAddressSpace()); + return llvm_fn_ty.pointerType(llvm_addrspace); }, .ComptimeInt => unreachable, .ComptimeFloat => unreachable, @@ -749,7 +772,7 @@ pub const DeclGen = struct { .Pointer => switch (tv.val.tag()) { .decl_ref => { if (tv.ty.isSlice()) { - var buf: Type.Payload.ElemType = undefined; + var buf: Type.SlicePtrFieldTypeBuffer = undefined; const ptr_ty = tv.ty.slicePtrFieldType(&buf); var slice_len: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, @@ -779,12 +802,13 @@ pub const DeclGen = struct { decl.alive = true; const val = try self.resolveGlobalDecl(decl); const llvm_var_type = try self.llvmType(tv.ty); - const llvm_type = llvm_var_type.pointerType(0); + const llvm_addrspace = self.llvmAddressSpace(decl.@"addrspace"); + const llvm_type = llvm_var_type.pointerType(llvm_addrspace); return val.constBitCast(llvm_type); }, .slice => { const slice = tv.val.castTag(.slice).?.data; - var buf: Type.Payload.ElemType = undefined; + var buf: Type.SlicePtrFieldTypeBuffer = undefined; const fields: [2]*const llvm.Value = .{ try self.genTypedValue(.{ .ty = tv.ty.slicePtrFieldType(&buf), diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 67b39784b1..e50589dee1 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -197,6 +197,9 @@ pub const Module = opaque { pub const addFunction = LLVMAddFunction; extern fn LLVMAddFunction(*const Module, Name: [*:0]const u8, FunctionTy: *const Type) *const Value; + pub const addFunctionInAddressSpace = ZigLLVMAddFunctionInAddressSpace; + extern fn ZigLLVMAddFunctionInAddressSpace(*const Module, Name: [*:0]const u8, FunctionTy: *const Type, AddressSpace: c_uint) *const Value; + pub const getNamedFunction = LLVMGetNamedFunction; extern fn LLVMGetNamedFunction(*const Module, Name: [*:0]const u8) ?*const Value; @@ -209,6 +212,9 @@ pub const Module = opaque { pub const addGlobal = LLVMAddGlobal; extern fn LLVMAddGlobal(M: *const Module, Ty: *const Type, Name: [*:0]const u8) *const Value; + pub const addGlobalInAddressSpace = LLVMAddGlobalInAddressSpace; + extern fn LLVMAddGlobalInAddressSpace(M: *const Module, Ty: *const Type, Name: [*:0]const u8, AddressSpace: c_uint) *const Value; + pub const getNamedGlobal = LLVMGetNamedGlobal; extern fn LLVMGetNamedGlobal(M: *const Module, Name: [*:0]const u8) ?*const Value; @@ -975,6 +981,8 @@ pub const TypeKind = enum(c_int) { }; pub const address_space = struct { + pub const default = 0; + // See llvm/lib/Target/X86/X86.h pub const x86_64 = x86; pub const x86 = struct { diff --git a/src/type.zig b/src/type.zig index b15026b595..9cda4aacf7 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2161,42 +2161,72 @@ pub const Type = extern union { }; } - pub fn slicePtrFieldType(self: Type, buffer: *Payload.ElemType) Type { + pub const SlicePtrFieldTypeBuffer = union { + elem_type: Payload.ElemType, + pointer: Payload.Pointer, + }; + + pub fn slicePtrFieldType(self: Type, buffer: *SlicePtrFieldTypeBuffer) Type { switch (self.tag()) { .const_slice_u8 => return Type.initTag(.manyptr_const_u8), .const_slice => { const elem_type = self.castTag(.const_slice).?.data; - buffer.* = .{ + buffer.elem_type = .{ .base = .{ .tag = .many_const_pointer }, .data = elem_type, }; - return Type.initPayload(&buffer.base); + return Type.initPayload(&buffer.elem_type.base); }, .mut_slice => { const elem_type = self.castTag(.mut_slice).?.data; - buffer.* = .{ + buffer.elem_type = .{ .base = .{ .tag = .many_mut_pointer }, .data = elem_type, }; - return Type.initPayload(&buffer.base); + return Type.initPayload(&buffer.elem_type.base); }, .pointer => { const payload = self.castTag(.pointer).?.data; assert(payload.size == .Slice); - if (payload.mutable) { - buffer.* = .{ + + if (payload.sentinel != null or + payload.@"align" != 0 or + payload.@"addrspace" != .generic or + payload.bit_offset != 0 or + payload.host_size != 0 or + payload.@"allowzero" or + payload.@"volatile" + ) { + buffer.pointer = .{ + .data = .{ + .pointee_type = payload.pointee_type, + .sentinel = payload.sentinel, + .@"align" = payload.@"align", + .@"addrspace" = payload.@"addrspace", + .bit_offset = payload.bit_offset, + .host_size = payload.host_size, + .@"allowzero" = payload.@"allowzero", + .mutable = payload.mutable, + .@"volatile" = payload.@"volatile", + .size = .Many + }, + }; + return Type.initPayload(&buffer.pointer.base); + } else if (payload.mutable) { + buffer.elem_type = .{ .base = .{ .tag = .many_mut_pointer }, .data = payload.pointee_type, }; + return Type.initPayload(&buffer.elem_type.base); } else { - buffer.* = .{ + buffer.elem_type = .{ .base = .{ .tag = .many_const_pointer }, .data = payload.pointee_type, }; + return Type.initPayload(&buffer.elem_type.base); } - return Type.initPayload(&buffer.base); }, else => unreachable, diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index e1ab74f423..6e136161a6 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -416,6 +416,11 @@ ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref) { return wrap(Type::getTokenTy(*unwrap(context_ref))); } +LLVMValueRef ZigLLVMAddFunctionInAddressSpace(LLVMModuleRef M, const char *Name, LLVMTypeRef FunctionTy, unsigned AddressSpace) { + Function* func = Function::Create(unwrap(FunctionTy), GlobalValue::ExternalLinkage, AddressSpace, Name, unwrap(M)); + return wrap(func); +} + LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, ZigLLVM_CallingConv CC, ZigLLVM_CallAttr attr, const char *Name) { diff --git a/src/zig_llvm.h b/src/zig_llvm.h index be279d86e1..49a4c0e8fd 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -65,6 +65,9 @@ ZIG_EXTERN_C LLVMTargetMachineRef ZigLLVMCreateTargetMachine(LLVMTargetRef T, co ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref); +ZIG_EXTERN_C LLVMValueRef ZigLLVMAddFunctionInAddressSpace(LLVMModuleRef M, const char *Name, + LLVMTypeRef FunctionTy, unsigned AddressSpace); + enum ZigLLVM_CallingConv { ZigLLVM_C = 0, ZigLLVM_Fast = 8, From 68fcbb5c0d5ece02876824a8be0e18b306954e26 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 29 Aug 2021 19:41:57 +0200 Subject: [PATCH 20/30] Address Spaces: fmt a bunch of stuff --- lib/std/zig/render.zig | 3 ++- src/AstGen.zig | 4 ++-- src/Zir.zig | 2 +- src/type.zig | 10 +++++----- test/cases.zig | 4 ++-- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 0703b5bbfa..3029d38cb9 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -958,7 +958,8 @@ fn renderVarDecl(gpa: *Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDe try renderToken(ais, tree, lparen, Space.none); // ( try renderExpression(gpa, ais, tree, var_decl.ast.align_node, Space.none); if (var_decl.ast.addrspace_node != 0 or var_decl.ast.section_node != 0 or - var_decl.ast.init_node != 0) { + var_decl.ast.init_node != 0) + { try renderToken(ais, tree, rparen, .space); // ) } else { try renderToken(ais, tree, rparen, .none); // ) diff --git a/src/AstGen.zig b/src/AstGen.zig index cffc626a1e..2e4671d92e 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -2393,11 +2393,11 @@ fn varDecl( } if (var_decl.ast.addrspace_node != 0) { - return astgen.failTok(main_tokens[var_decl.ast.addrspace_node], "cannot set address space of local variable '{s}'", .{ ident_name_raw }); + return astgen.failTok(main_tokens[var_decl.ast.addrspace_node], "cannot set address space of local variable '{s}'", .{ident_name_raw}); } if (var_decl.ast.section_node != 0) { - return astgen.failTok(main_tokens[var_decl.ast.section_node], "cannot set section of local variable '{s}'", .{ ident_name_raw }); + return astgen.failTok(main_tokens[var_decl.ast.section_node], "cannot set section of local variable '{s}'", .{ident_name_raw}); } const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node != 0) diff --git a/src/Zir.zig b/src/Zir.zig index 0e50f8c256..50c53e5485 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -4029,7 +4029,7 @@ const Writer = struct { }; const addrspace_inst: Inst.Ref = if (!has_section_or_addrspace) .none else inst: { const inst = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index +=1; + extra_index += 1; break :inst inst; }; const pub_str = if (is_pub) "pub " else ""; diff --git a/src/type.zig b/src/type.zig index 9cda4aacf7..fa2147f852 100644 --- a/src/type.zig +++ b/src/type.zig @@ -1002,7 +1002,7 @@ pub const Type = extern union { try writer.writeAll(@tagName(payload.cc)); try writer.writeAll(") "); if (payload.@"addrspace" != .generic) { - try writer.print("addrspace(.{s}) ", .{ @tagName(payload.@"addrspace") }); + try writer.print("addrspace(.{s}) ", .{@tagName(payload.@"addrspace")}); } ty = payload.return_type; continue; @@ -1136,7 +1136,7 @@ pub const Type = extern union { try writer.writeAll(") "); } if (payload.@"addrspace" != .generic) { - try writer.print("addrspace(.{s}) ", .{ @tagName(payload.@"addrspace") }); + try writer.print("addrspace(.{s}) ", .{@tagName(payload.@"addrspace")}); } if (!payload.mutable) try writer.writeAll("const "); if (payload.@"volatile") try writer.writeAll("volatile "); @@ -2197,8 +2197,8 @@ pub const Type = extern union { payload.bit_offset != 0 or payload.host_size != 0 or payload.@"allowzero" or - payload.@"volatile" - ) { + payload.@"volatile") + { buffer.pointer = .{ .data = .{ .pointee_type = payload.pointee_type, @@ -2210,7 +2210,7 @@ pub const Type = extern union { .@"allowzero" = payload.@"allowzero", .mutable = payload.mutable, .@"volatile" = payload.@"volatile", - .size = .Many + .size = .Many, }, }; return Type.initPayload(&buffer.pointer.base); diff --git a/test/cases.zig b/test/cases.zig index 62677b8424..33fa5b19e2 100644 --- a/test/cases.zig +++ b/test/cases.zig @@ -861,7 +861,7 @@ pub fn addCases(ctx: *TestContext) !void { "Hello, World!\n", ); try case.files.append(.{ - .src = + .src = \\pub fn print() void { \\ asm volatile ("syscall" \\ : @@ -924,7 +924,7 @@ pub fn addCases(ctx: *TestContext) !void { }, ); try case.files.append(.{ - .src = + .src = \\// dummy comment to make print be on line 2 \\fn print() void { \\ asm volatile ("syscall" From 0492b71319e5fa2367258b33206bc0d06f4a42be Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 30 Aug 2021 00:22:08 +0200 Subject: [PATCH 21/30] Address Spaces: Smol fixup --- src/type.zig | 58 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/src/type.zig b/src/type.zig index fa2147f852..e8a9d059d0 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2172,17 +2172,21 @@ pub const Type = extern union { .const_slice => { const elem_type = self.castTag(.const_slice).?.data; - buffer.elem_type = .{ - .base = .{ .tag = .many_const_pointer }, - .data = elem_type, + buffer.* = .{ + .elem_type = .{ + .base = .{ .tag = .many_const_pointer }, + .data = elem_type, + }, }; return Type.initPayload(&buffer.elem_type.base); }, .mut_slice => { const elem_type = self.castTag(.mut_slice).?.data; - buffer.elem_type = .{ - .base = .{ .tag = .many_mut_pointer }, - .data = elem_type, + buffer.* = .{ + .elem_type = .{ + .base = .{ .tag = .many_mut_pointer }, + .data = elem_type, + }, }; return Type.initPayload(&buffer.elem_type.base); }, @@ -2199,31 +2203,37 @@ pub const Type = extern union { payload.@"allowzero" or payload.@"volatile") { - buffer.pointer = .{ - .data = .{ - .pointee_type = payload.pointee_type, - .sentinel = payload.sentinel, - .@"align" = payload.@"align", - .@"addrspace" = payload.@"addrspace", - .bit_offset = payload.bit_offset, - .host_size = payload.host_size, - .@"allowzero" = payload.@"allowzero", - .mutable = payload.mutable, - .@"volatile" = payload.@"volatile", - .size = .Many, + buffer.* = .{ + .pointer = .{ + .data = .{ + .pointee_type = payload.pointee_type, + .sentinel = payload.sentinel, + .@"align" = payload.@"align", + .@"addrspace" = payload.@"addrspace", + .bit_offset = payload.bit_offset, + .host_size = payload.host_size, + .@"allowzero" = payload.@"allowzero", + .mutable = payload.mutable, + .@"volatile" = payload.@"volatile", + .size = .Many, + }, }, }; return Type.initPayload(&buffer.pointer.base); } else if (payload.mutable) { - buffer.elem_type = .{ - .base = .{ .tag = .many_mut_pointer }, - .data = payload.pointee_type, + buffer.* = .{ + .elem_type = .{ + .base = .{ .tag = .many_mut_pointer }, + .data = payload.pointee_type, + }, }; return Type.initPayload(&buffer.elem_type.base); } else { - buffer.elem_type = .{ - .base = .{ .tag = .many_const_pointer }, - .data = payload.pointee_type, + buffer.* = .{ + .elem_type = .{ + .base = .{ .tag = .many_const_pointer }, + .data = payload.pointee_type, + }, }; return Type.initPayload(&buffer.elem_type.base); } From 7a5d0cdf45f861f63d89666607dc86b3a2810826 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 30 Aug 2021 01:09:22 +0200 Subject: [PATCH 22/30] Address Spaces: Render addrspace token in docgen --- doc/docgen.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/docgen.zig b/doc/docgen.zig index 79fd1519cf..a062767ebf 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -901,6 +901,7 @@ fn tokenizeAndPrintRaw( switch (token.tag) { .eof => break, + .keyword_addrspace, .keyword_align, .keyword_and, .keyword_asm, From c5945467acfd580cb3413250ef52f13dc412a8cf Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 30 Aug 2021 02:54:03 +0200 Subject: [PATCH 23/30] Address Spaces: Pointer and function info in @Type --- lib/std/builtin.zig | 2 + lib/std/mem.zig | 2 + lib/std/meta.zig | 3 + lib/std/zig/c_translation.zig | 1 + src/Sema.zig | 15 +++-- src/stage1/all_types.hpp | 8 +++ src/stage1/analyze.cpp | 10 +++ src/stage1/analyze.hpp | 2 + src/stage1/ir.cpp | 123 ++++++++++++++++++++++------------ test/behavior/type.zig | 1 + test/compile_errors.zig | 4 ++ 11 files changed, 122 insertions(+), 49 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 09d93d5d21..11273eedeb 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -235,6 +235,7 @@ pub const TypeInfo = union(enum) { is_const: bool, is_volatile: bool, alignment: comptime_int, + address_space: AddressSpace, child: type, is_allowzero: bool, @@ -364,6 +365,7 @@ pub const TypeInfo = union(enum) { pub const Fn = struct { calling_convention: CallingConvention, alignment: comptime_int, + address_space: AddressSpace, is_generic: bool, is_var_args: bool, return_type: ?type, diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 9eaf185119..95d4c919db 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -2472,6 +2472,7 @@ fn CopyPtrAttrs(comptime source: type, comptime size: std.builtin.TypeInfo.Point .is_volatile = info.is_volatile, .is_allowzero = info.is_allowzero, .alignment = info.alignment, + .address_space = info.address_space, .child = child, .sentinel = null, }, @@ -2960,6 +2961,7 @@ fn AlignedSlice(comptime AttributeSource: type, comptime new_alignment: u29) typ .is_volatile = info.is_volatile, .is_allowzero = info.is_allowzero, .alignment = new_alignment, + .address_space = info.address_space, .child = info.child, .sentinel = null, }, diff --git a/lib/std/meta.zig b/lib/std/meta.zig index a1bfacf597..62866bb711 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -235,6 +235,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type { .is_const = info.is_const, .is_volatile = info.is_volatile, .alignment = info.alignment, + .address_space = info.address_space, .child = @Type(.{ .Array = .{ .len = array_info.len, @@ -254,6 +255,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type { .is_const = info.is_const, .is_volatile = info.is_volatile, .alignment = info.alignment, + .address_space = info.address_space, .child = info.child, .is_allowzero = info.is_allowzero, .sentinel = sentinel_val, @@ -271,6 +273,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type { .is_const = ptr_info.is_const, .is_volatile = ptr_info.is_volatile, .alignment = ptr_info.alignment, + .address_space = ptr_info.address_space, .child = ptr_info.child, .is_allowzero = ptr_info.is_allowzero, .sentinel = sentinel_val, diff --git a/lib/std/zig/c_translation.zig b/lib/std/zig/c_translation.zig index bb8a699f69..999572d212 100644 --- a/lib/std/zig/c_translation.zig +++ b/lib/std/zig/c_translation.zig @@ -325,6 +325,7 @@ pub fn FlexibleArrayType(comptime SelfType: type, ElementType: type) type { .is_const = ptr.is_const, .is_volatile = ptr.is_volatile, .alignment = @alignOf(ElementType), + .address_space = .generic, .child = ElementType, .is_allowzero = true, .sentinel = null, diff --git a/src/Sema.zig b/src/Sema.zig index d6e926e604..bf676866a1 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6413,7 +6413,7 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr switch (ty.zigTypeTag()) { .Fn => { - const field_values = try sema.arena.alloc(Value, 6); + const field_values = try sema.arena.alloc(Value, 7); // calling_convention: CallingConvention, field_values[0] = try Value.Tag.enum_field_index.create( sema.arena, @@ -6421,14 +6421,19 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr ); // alignment: comptime_int, field_values[1] = try Value.Tag.int_u64.create(sema.arena, ty.abiAlignment(target)); + // address_space: AddressSpace, + field_values[2] = try Value.Tag.enum_field_index.create( + sema.arena, + @enumToInt(ty.fnAddressSpace()), + ); // is_generic: bool, - field_values[2] = Value.initTag(.bool_false); // TODO - // is_var_args: bool, field_values[3] = Value.initTag(.bool_false); // TODO + // is_var_args: bool, + field_values[4] = Value.initTag(.bool_false); // TODO // return_type: ?type, - field_values[4] = try Value.Tag.ty.create(sema.arena, ty.fnReturnType()); + field_values[5] = try Value.Tag.ty.create(sema.arena, ty.fnReturnType()); // args: []const FnArg, - field_values[5] = Value.initTag(.null_value); // TODO + field_values[6] = Value.initTag(.null_value); // TODO return sema.addConstant( type_info_ty, diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp index 4004199eb6..13c37fc839 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -86,6 +86,14 @@ enum CallingConvention { CallingConventionSysV }; +// Stage 1 supports only the generic address space +enum AddressSpace { + AddressSpaceGeneric, + AddressSpaceGS, + AddressSpaceFS, + AddressSpaceSS, +}; + // This one corresponds to the builtin.zig enum. enum BuiltinPtrSize { BuiltinPtrSizeOne, diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index 2eb609ef1a..320d8ff9b2 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -1019,6 +1019,16 @@ bool calling_convention_allows_zig_types(CallingConvention cc) { zig_unreachable(); } +const char *address_space_name(AddressSpace as) { + switch (as) { + case AddressSpaceGeneric: return "generic"; + case AddressSpaceGS: return "gs"; + case AddressSpaceFS: return "fs"; + case AddressSpaceSS: return "ss"; + } + zig_unreachable(); +} + ZigType *get_stack_trace_type(CodeGen *g) { if (g->stack_trace_type == nullptr) { g->stack_trace_type = get_builtin_type(g, "StackTrace"); diff --git a/src/stage1/analyze.hpp b/src/stage1/analyze.hpp index 8290ef572c..6d584ff361 100644 --- a/src/stage1/analyze.hpp +++ b/src/stage1/analyze.hpp @@ -242,6 +242,8 @@ Error get_primitive_type(CodeGen *g, Buf *name, ZigType **result); bool calling_convention_allows_zig_types(CallingConvention cc); const char *calling_convention_name(CallingConvention cc); +const char *address_space_name(AddressSpace as); + Error ATTRIBUTE_MUST_USE file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents); void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk); diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 0604c05c46..a41384cee6 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -16124,7 +16124,7 @@ static Stage1AirInst *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira, static Stage1AirInst *ir_analyze_instruction_ctz(IrAnalyze *ira, Stage1ZirInstCtz *instruction) { Error err; - + ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); if (type_is_invalid(int_type)) return ira->codegen->invalid_inst_gen; @@ -16166,7 +16166,7 @@ static Stage1AirInst *ir_analyze_instruction_ctz(IrAnalyze *ira, Stage1ZirInstCt return ira->codegen->invalid_inst_gen; if (val->special == ConstValSpecialUndef) return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - + if (is_vector) { ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type); Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type); @@ -16200,7 +16200,7 @@ static Stage1AirInst *ir_analyze_instruction_ctz(IrAnalyze *ira, Stage1ZirInstCt static Stage1AirInst *ir_analyze_instruction_clz(IrAnalyze *ira, Stage1ZirInstClz *instruction) { Error err; - + ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); if (type_is_invalid(int_type)) return ira->codegen->invalid_inst_gen; @@ -16242,7 +16242,7 @@ static Stage1AirInst *ir_analyze_instruction_clz(IrAnalyze *ira, Stage1ZirInstCl return ira->codegen->invalid_inst_gen; if (val->special == ConstValSpecialUndef) return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - + if (is_vector) { ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type); Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type); @@ -16276,7 +16276,7 @@ static Stage1AirInst *ir_analyze_instruction_clz(IrAnalyze *ira, Stage1ZirInstCl static Stage1AirInst *ir_analyze_instruction_pop_count(IrAnalyze *ira, Stage1ZirInstPopCount *instruction) { Error err; - + ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); if (type_is_invalid(int_type)) return ira->codegen->invalid_inst_gen; @@ -16318,7 +16318,7 @@ static Stage1AirInst *ir_analyze_instruction_pop_count(IrAnalyze *ira, Stage1Zir return ira->codegen->invalid_inst_gen; if (val->special == ConstValSpecialUndef) return ir_const_undef(ira, instruction->base.scope, instruction->base.source_node, ira->codegen->builtin_types.entry_num_lit_int); - + if (is_vector) { ZigType *smallest_vec_type = get_vector_type(ira->codegen, vector_len, smallest_type); Stage1AirInst *result = ir_const(ira, instruction->base.scope, instruction->base.source_node, smallest_vec_type); @@ -17904,7 +17904,7 @@ static ZigValue *create_ptr_like_type_info(IrAnalyze *ira, Scope *scope, AstNode result->special = ConstValSpecialStatic; result->type = type_info_pointer_type; - ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 7); + ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 8); result->data.x_struct.fields = fields; // size: Size @@ -17939,24 +17939,29 @@ static ZigValue *create_ptr_like_type_info(IrAnalyze *ira, Scope *scope, AstNode lazy_align_of->base.id = LazyValueIdAlignOf; lazy_align_of->target_type = ir_const_type(ira, scope, source_node, attrs_type->data.pointer.child_type); } - // child: type - ensure_field_index(result->type, "child", 4); + // address_space: AddressSpace, + ensure_field_index(result->type, "address_space", 4); fields[4]->special = ConstValSpecialStatic; - fields[4]->type = ira->codegen->builtin_types.entry_type; - fields[4]->data.x_type = attrs_type->data.pointer.child_type; - // is_allowzero: bool - ensure_field_index(result->type, "is_allowzero", 5); + fields[4]->type = get_builtin_type(ira->codegen, "AddressSpace"); + bigint_init_unsigned(&fields[4]->data.x_enum_tag, AddressSpaceGeneric); + // child: type + ensure_field_index(result->type, "child", 5); fields[5]->special = ConstValSpecialStatic; - fields[5]->type = ira->codegen->builtin_types.entry_bool; - fields[5]->data.x_bool = attrs_type->data.pointer.allow_zero; - // sentinel: anytype - ensure_field_index(result->type, "sentinel", 6); + fields[5]->type = ira->codegen->builtin_types.entry_type; + fields[5]->data.x_type = attrs_type->data.pointer.child_type; + // is_allowzero: bool + ensure_field_index(result->type, "is_allowzero", 6); fields[6]->special = ConstValSpecialStatic; + fields[6]->type = ira->codegen->builtin_types.entry_bool; + fields[6]->data.x_bool = attrs_type->data.pointer.allow_zero; + // sentinel: anytype + ensure_field_index(result->type, "sentinel", 7); + fields[7]->special = ConstValSpecialStatic; if (attrs_type->data.pointer.sentinel != nullptr) { - fields[6]->type = get_optional_type(ira->codegen, attrs_type->data.pointer.child_type); - set_optional_payload(fields[6], attrs_type->data.pointer.sentinel); + fields[7]->type = get_optional_type(ira->codegen, attrs_type->data.pointer.child_type); + set_optional_payload(fields[7], attrs_type->data.pointer.sentinel); } else { - fields[6]->type = ira->codegen->builtin_types.entry_null; + fields[7]->type = ira->codegen->builtin_types.entry_null; } return result; @@ -18465,7 +18470,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour result->special = ConstValSpecialStatic; result->type = ir_type_info_get_type(ira, "Fn", nullptr); - ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 6); + ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 7); result->data.x_struct.fields = fields; // calling_convention: TypeInfo.CallingConvention @@ -18478,30 +18483,35 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour fields[1]->special = ConstValSpecialStatic; fields[1]->type = ira->codegen->builtin_types.entry_num_lit_int; bigint_init_unsigned(&fields[1]->data.x_bigint, get_ptr_align(ira->codegen, type_entry)); - // is_generic: bool - ensure_field_index(result->type, "is_generic", 2); - bool is_generic = type_entry->data.fn.is_generic; + // address_space: AddressSpace + ensure_field_index(result->type, "address_space", 2); fields[2]->special = ConstValSpecialStatic; - fields[2]->type = ira->codegen->builtin_types.entry_bool; - fields[2]->data.x_bool = is_generic; - // is_varargs: bool - ensure_field_index(result->type, "is_var_args", 3); - bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args; + fields[2]->type = get_builtin_type(ira->codegen, "AddressSpace"); + bigint_init_unsigned(&fields[2]->data.x_enum_tag, AddressSpaceGeneric); + // is_generic: bool + ensure_field_index(result->type, "is_generic", 3); + bool is_generic = type_entry->data.fn.is_generic; fields[3]->special = ConstValSpecialStatic; fields[3]->type = ira->codegen->builtin_types.entry_bool; - fields[3]->data.x_bool = is_varargs; - // return_type: ?type - ensure_field_index(result->type, "return_type", 4); + fields[3]->data.x_bool = is_generic; + // is_varargs: bool + ensure_field_index(result->type, "is_var_args", 4); + bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args; fields[4]->special = ConstValSpecialStatic; - fields[4]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type); + fields[4]->type = ira->codegen->builtin_types.entry_bool; + fields[4]->data.x_bool = is_varargs; + // return_type: ?type + ensure_field_index(result->type, "return_type", 5); + fields[5]->special = ConstValSpecialStatic; + fields[5]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type); if (type_entry->data.fn.fn_type_id.return_type == nullptr) - fields[4]->data.x_optional = nullptr; + fields[5]->data.x_optional = nullptr; else { ZigValue *return_type = ira->codegen->pass1_arena->create(); return_type->special = ConstValSpecialStatic; return_type->type = ira->codegen->builtin_types.entry_type; return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type; - fields[4]->data.x_optional = return_type; + fields[5]->data.x_optional = return_type; } // args: []TypeInfo.FnArg ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg", nullptr); @@ -18516,7 +18526,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour fn_arg_array->data.x_array.special = ConstArraySpecialNone; fn_arg_array->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(fn_arg_count); - init_const_slice(ira->codegen, fields[5], fn_arg_array, 0, fn_arg_count, false, nullptr); + init_const_slice(ira->codegen, fields[6], fn_arg_array, 0, fn_arg_count, false, nullptr); for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) { FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index]; @@ -18826,11 +18836,11 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ assert(size_value->type == ir_type_info_get_type(ira, "Size", type_info_pointer_type)); BuiltinPtrSize size_enum_index = (BuiltinPtrSize)bigint_as_u32(&size_value->data.x_enum_tag); PtrLen ptr_len = size_enum_index_to_ptr_len(size_enum_index); - ZigType *elem_type = get_const_field_meta_type(ira, source_node, payload, "child", 4); + ZigType *elem_type = get_const_field_meta_type(ira, source_node, payload, "child", 5); if (type_is_invalid(elem_type)) return ira->codegen->invalid_inst_gen->value->type; ZigValue *sentinel; - if ((err = get_const_field_sentinel(ira, scope, source_node, payload, "sentinel", 6, + if ((err = get_const_field_sentinel(ira, scope, source_node, payload, "sentinel", 7, elem_type, &sentinel))) { return ira->codegen->invalid_inst_gen->value->type; @@ -18845,6 +18855,19 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ if (alignment == nullptr) return ira->codegen->invalid_inst_gen->value->type; + ZigValue *as_value = get_const_field(ira, source_node, payload, "address_space", 4); + if (as_value == nullptr) + return ira->codegen->invalid_inst_gen->value->type; + assert(as_value->special == ConstValSpecialStatic); + assert(as_value->type == get_builtin_type(ira->codegen, "AddressSpace")); + AddressSpace as = (AddressSpace)bigint_as_u32(&as_value->data.x_enum_tag); + if (as != AddressSpaceGeneric) { + ir_add_error_node(ira, source_node, buf_sprintf( + "address space '%s' not available in stage 1 compiler, must be .generic", + address_space_name(as))); + return ira->codegen->invalid_inst_gen->value->type; + } + bool is_const; if ((err = get_const_field_bool(ira, source_node, payload, "is_const", 1, &is_const))) return ira->codegen->invalid_inst_gen->value->type; @@ -18857,13 +18880,12 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ } bool is_allowzero; - if ((err = get_const_field_bool(ira, source_node, payload, "is_allowzero", 5, + if ((err = get_const_field_bool(ira, source_node, payload, "is_allowzero", 6, &is_allowzero))) { return ira->codegen->invalid_inst_gen->value->type; } - ZigType *ptr_type = get_pointer_to_type_extra2(ira->codegen, elem_type, is_const, @@ -19308,9 +19330,22 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ if (alignment == nullptr) return ira->codegen->invalid_inst_gen->value->type; + ZigValue *as_value = get_const_field(ira, source_node, payload, "address_space", 2); + if (as_value == nullptr) + return ira->codegen->invalid_inst_gen->value->type; + assert(as_value->special == ConstValSpecialStatic); + assert(as_value->type == get_builtin_type(ira->codegen, "AddressSpace")); + AddressSpace as = (AddressSpace)bigint_as_u32(&as_value->data.x_enum_tag); + if (as != AddressSpaceGeneric) { + ir_add_error_node(ira, source_node, buf_sprintf( + "address space '%s' not available in stage 1 compiler, must be .generic", + address_space_name(as))); + return ira->codegen->invalid_inst_gen->value->type; + } + Error err; bool is_generic; - if ((err = get_const_field_bool(ira, source_node, payload, "is_generic", 2, &is_generic))) + if ((err = get_const_field_bool(ira, source_node, payload, "is_generic", 3, &is_generic))) return ira->codegen->invalid_inst_gen->value->type; if (is_generic) { ir_add_error_node(ira, source_node, buf_sprintf("TypeInfo.Fn.is_generic must be false for @Type")); @@ -19318,20 +19353,20 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ } bool is_var_args; - if ((err = get_const_field_bool(ira, source_node, payload, "is_var_args", 3, &is_var_args))) + if ((err = get_const_field_bool(ira, source_node, payload, "is_var_args", 4, &is_var_args))) return ira->codegen->invalid_inst_gen->value->type; if (is_var_args && cc != CallingConventionC) { ir_add_error_node(ira, source_node, buf_sprintf("varargs functions must have C calling convention")); return ira->codegen->invalid_inst_gen->value->type; } - ZigType *return_type = get_const_field_meta_type_optional(ira, source_node, payload, "return_type", 4); + ZigType *return_type = get_const_field_meta_type_optional(ira, source_node, payload, "return_type", 5); if (return_type == nullptr) { ir_add_error_node(ira, source_node, buf_sprintf("TypeInfo.Fn.return_type must be non-null for @Type")); return ira->codegen->invalid_inst_gen->value->type; } - ZigValue *args_value = get_const_field(ira, source_node, payload, "args", 5); + ZigValue *args_value = get_const_field(ira, source_node, payload, "args", 6); if (args_value == nullptr) return ira->codegen->invalid_inst_gen->value->type; assert(args_value->special == ConstValSpecialStatic); diff --git a/test/behavior/type.zig b/test/behavior/type.zig index 3a56f2171f..cd5d2c3e06 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -137,6 +137,7 @@ test "@Type create slice with null sentinel" { .is_volatile = false, .is_allowzero = false, .alignment = 8, + .address_space = .generic, .child = *i32, .sentinel = null, }, diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 9fd125a775..3e9508be37 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -410,6 +410,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ .Fn = .{ \\ .calling_convention = .Unspecified, \\ .alignment = 0, + \\ .address_space = 0, \\ .is_generic = true, \\ .is_var_args = false, \\ .return_type = u0, @@ -426,6 +427,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ .Fn = .{ \\ .calling_convention = .Unspecified, \\ .alignment = 0, + \\ .address_space = 0, \\ .is_generic = false, \\ .is_var_args = true, \\ .return_type = u0, @@ -442,6 +444,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ .Fn = .{ \\ .calling_convention = .Unspecified, \\ .alignment = 0, + \\ .address_space = 0, \\ .is_generic = false, \\ .is_var_args = false, \\ .return_type = null, @@ -711,6 +714,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ .is_const = false, \\ .is_volatile = false, \\ .alignment = 1, + \\ .address_space = .generic, \\ .child = u8, \\ .is_allowzero = false, \\ .sentinel = 0, From 7956eee1ab126cb6657f7b87e3fcf86794c141b0 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 30 Aug 2021 03:11:22 +0200 Subject: [PATCH 24/30] Address Spaces: Adapt compile error test cases to @Type with address spaces --- test/compile_errors.zig | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 3e9508be37..f2fa20d722 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -410,7 +410,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ .Fn = .{ \\ .calling_convention = .Unspecified, \\ .alignment = 0, - \\ .address_space = 0, + \\ .address_space = .generic, \\ .is_generic = true, \\ .is_var_args = false, \\ .return_type = u0, @@ -427,7 +427,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ .Fn = .{ \\ .calling_convention = .Unspecified, \\ .alignment = 0, - \\ .address_space = 0, + \\ .address_space = .generic, \\ .is_generic = false, \\ .is_var_args = true, \\ .return_type = u0, @@ -444,7 +444,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ .Fn = .{ \\ .calling_convention = .Unspecified, \\ .alignment = 0, - \\ .address_space = 0, + \\ .address_space = .generic, \\ .is_generic = false, \\ .is_var_args = false, \\ .return_type = null, @@ -456,6 +456,23 @@ pub fn addCases(ctx: *TestContext) !void { "tmp.zig:1:20: error: TypeInfo.Fn.return_type must be non-null for @Type", }); + ctx.objErrStage1("@Type(.Fn) with invalid address space ", + \\const Foo = @Type(.{ + \\ .Fn = .{ + \\ .calling_convention = .Unspecified, + \\ .alignment = 0, + \\ .address_space = .fs, + \\ .is_generic = false, + \\ .is_var_args = false, + \\ .return_type = u0, + \\ .args = &[_]@import("std").builtin.TypeInfo.FnArg{}, + \\ }, + \\}); + \\comptime { _ = Foo; } + , &[_][]const u8{ + "tmp.zig:1:20: error: address space 'fs' not available in stage 1 compiler, must be .generic", + }); + ctx.objErrStage1("@Type for union with opaque field", \\const TypeInfo = @import("std").builtin.TypeInfo; \\const Untagged = @Type(.{ @@ -724,6 +741,23 @@ pub fn addCases(ctx: *TestContext) !void { "tmp.zig:2:16: error: sentinels are only allowed on slices and unknown-length pointers", }); + ctx.objErrStage1("@Type(.Pointer) with invalid address space ", + \\export fn entry() void { + \\ _ = @Type(.{ .Pointer = .{ + \\ .size = .One, + \\ .is_const = false, + \\ .is_volatile = false, + \\ .alignment = 1, + \\ .address_space = .gs, + \\ .child = u8, + \\ .is_allowzero = false, + \\ .sentinel = null, + \\ }}); + \\} + , &[_][]const u8{ + "tmp.zig:2:16: error: address space 'gs' not available in stage 1 compiler, must be .generic", + }); + ctx.testErrStage1("helpful return type error message", \\export fn foo() u32 { \\ return error.Ohno; From 90a945b38c44c673e230feb8a6b124f5c8f977a1 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Wed, 1 Sep 2021 17:04:42 +0200 Subject: [PATCH 25/30] Address Spaces: Split out stage2 address llvm tests to individual cases This previously caused a test case to crash due to lingering llvm state. --- test/stage2/llvm.zig | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/test/stage2/llvm.zig b/test/stage2/llvm.zig index e61e7181c6..e1d32aa086 100644 --- a/test/stage2/llvm.zig +++ b/test/stage2/llvm.zig @@ -244,7 +244,7 @@ pub fn addCases(ctx: *TestContext) !void { } { - var case = ctx.exeUsingLlvmBackend("address space pointer coercions", linux_x64); + var case = ctx.exeUsingLlvmBackend("invalid address space coercion", linux_x64); case.addError( \\fn entry(a: *addrspace(.gs) i32) *i32 { \\ return a; @@ -253,21 +253,30 @@ pub fn addCases(ctx: *TestContext) !void { , &[_][]const u8{ ":2:12: error: expected *i32, found *addrspace(.gs) i32", }); + } + { + var case = ctx.exeUsingLlvmBackend("pointer keeps address space", linux_x64); case.compiles( \\fn entry(a: *addrspace(.gs) i32) *addrspace(.gs) i32 { \\ return a; \\} \\pub export fn main() void { _ = entry; } ); + } + { + var case = ctx.exeUsingLlvmBackend("pointer to explicit generic address space coerces to implicit pointer", linux_x64); case.compiles( \\fn entry(a: *addrspace(.generic) i32) *i32 { \\ return a; \\} \\pub export fn main() void { _ = entry; } ); + } + { + var case = ctx.exeUsingLlvmBackend("pointers with different address spaces", linux_x64); case.addError( \\fn entry(a: *addrspace(.gs) i32) *addrspace(.fs) i32 { \\ return a; @@ -276,7 +285,10 @@ pub fn addCases(ctx: *TestContext) !void { , &[_][]const u8{ ":2:12: error: expected *addrspace(.fs) i32, found *addrspace(.gs) i32", }); + } + { + var case = ctx.exeUsingLlvmBackend("pointers with different address spaces", linux_x64); case.addError( \\fn entry(a: ?*addrspace(.gs) i32) *i32 { \\ return a.?; @@ -285,7 +297,10 @@ pub fn addCases(ctx: *TestContext) !void { , &[_][]const u8{ ":2:13: error: expected *i32, found *addrspace(.gs) i32", }); + } + { + var case = ctx.exeUsingLlvmBackend("invalid pointer keeps address space when taking address of dereference", linux_x64); case.addError( \\fn entry(a: *addrspace(.gs) i32) *i32 { \\ return &a.*; @@ -294,7 +309,10 @@ pub fn addCases(ctx: *TestContext) !void { , &[_][]const u8{ ":2:12: error: expected *i32, found *addrspace(.gs) i32", }); + } + { + var case = ctx.exeUsingLlvmBackend("pointer keeps address space when taking address of dereference", linux_x64); case.compiles( \\fn entry(a: *addrspace(.gs) i32) *addrspace(.gs) i32 { \\ return &a.*; From 13b917148e97560760eb13cd0e4a0b7365739f64 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Wed, 1 Sep 2021 17:33:45 +0200 Subject: [PATCH 26/30] Address Spaces: basic system to check for validity. Validity checks are also based on context; whether the entity being validated is a mutable/constant value, a pointer (that is ascripted with an addrspace attribute) or a function with an addrspace attribute. Error messages are relatively simple for now. --- src/Module.zig | 15 +++++++++---- src/Sema.zig | 61 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 1f9b5abcb9..2313480aeb 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3213,11 +3213,18 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { break :blk (try sema.resolveInstConst(&block_scope, src, linksection_ref)).val; }; const address_space = blk: { - const addrspace_ref = decl.zirAddrspaceRef(); - if (addrspace_ref == .none) break :blk .generic; - const addrspace_tv = try sema.resolveInstConst(&block_scope, src, addrspace_ref); - break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace); + const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.tag()) { + .function, .extern_fn => .function, + .variable => .variable, + else => .constant, + }; + + break :blk switch (decl.zirAddrspaceRef()) { + .none => .generic, + else => |addrspace_ref| try sema.analyzeAddrspace(&block_scope, src, addrspace_ref, addrspace_ctx), + }; }; + // Note this resolves the type of the Decl, not the value; if this Decl // is a struct, for example, this resolves `type` (which needs no resolution), // not the struct itself. diff --git a/src/Sema.zig b/src/Sema.zig index bf676866a1..7f2b0e855e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6932,8 +6932,7 @@ fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr const address_space = if (inst_data.flags.has_addrspace) blk: { const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); extra_i += 1; - const addrspace_tv = try sema.resolveInstConst(block, .unneeded, ref); - break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace); + break :blk try sema.analyzeAddrspace(block, .unneeded, ref, .pointer); } else .generic; const bit_start = if (inst_data.flags.has_bit_range) blk: { @@ -8092,8 +8091,7 @@ fn zirFuncExtended( const address_space: std.builtin.AddressSpace = if (small.has_addrspace) blk: { const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); extra_index += 1; - const addrspace_tv = try sema.resolveInstConst(block, addrspace_src, addrspace_ref); - break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace); + break :blk try sema.analyzeAddrspace(block, addrspace_src, addrspace_ref, .function); } else .generic; const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len]; @@ -10973,3 +10971,58 @@ fn analyzeComptimeAlloc( .decl = decl, })); } + +/// The places where a user can specify an address space attribute +pub const AddressSpaceContext = enum { + /// A function is specificed to be placed in a certain address space. + function, + + /// A (global) variable is specified to be placed in a certain address space. + /// In contrast to .constant, these values (and thus the address space they will be + /// placed in) are required to be mutable. + variable, + + /// A (global) constant value is specified to be placed in a certain address space. + /// In contrast to .variable, values placed in this address space are not required to be mutable. + constant, + + /// A pointer is ascripted to point into a certian address space. + pointer, +}; + +pub fn analyzeAddrspace( + sema: *Sema, + block: *Scope.Block, + src: LazySrcLoc, + zir_ref: Zir.Inst.Ref, + ctx: AddressSpaceContext, +) !std.builtin.AddressSpace { + const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref); + const address_space = addrspace_tv.val.toEnum(std.builtin.AddressSpace); + const target = sema.mod.getTarget(); + const arch = target.cpu.arch; + + const supported = switch (address_space) { + .generic => true, + .gs, .fs, .ss => (arch == .i386 or arch == .x86_64) and ctx == .pointer, + }; + + if (!supported) { + // TODO error messages could be made more elaborate here + const entity = switch (ctx) { + .function => "functions", + .variable => "mutable values", + .constant => "constant values", + .pointer => "pointers", + }; + + return sema.mod.fail( + &block.base, + src, + "{s} with address space '{s}' are not supported on {s}", + .{ entity, @tagName(address_space), arch.genericName() }, + ); + } + + return address_space; +} From e4ac063297fc9210ae3a97fa370ea8c6c216ec43 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Fri, 3 Sep 2021 04:36:56 +0200 Subject: [PATCH 27/30] Address Spaces: Restructure llvmAddressSpace a bit --- src/codegen/llvm.zig | 19 ++++---- src/codegen/llvm/bindings.zig | 81 ++++++++++++++++++----------------- 2 files changed, 49 insertions(+), 51 deletions(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 8b7282160e..ce79d43fac 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -583,18 +583,15 @@ pub const DeclGen = struct { fn llvmAddressSpace(self: DeclGen, address_space: std.builtin.AddressSpace) c_uint { const target = self.module.getTarget(); - return switch (address_space) { - .generic => llvm.address_space.default, - .gs => switch (target.cpu.arch) { - .i386, .x86_64 => llvm.address_space.x86.gs, - else => unreachable, + return switch (target.cpu.arch) { + .i386, .x86_64 => switch (address_space) { + .generic => llvm.address_space.default, + .gs => llvm.address_space.x86.gs, + .fs => llvm.address_space.x86.fs, + .ss => llvm.address_space.x86.ss, }, - .fs => switch (target.cpu.arch) { - .i386, .x86_64 => llvm.address_space.x86.fs, - else => unreachable, - }, - .ss => switch (target.cpu.arch) { - .i386, .x86_64 => llvm.address_space.x86.ss, + else => switch (address_space) { + .generic => llvm.address_space.default, else => unreachable, }, }; diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index e50589dee1..ebb84cb05b 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -981,62 +981,63 @@ pub const TypeKind = enum(c_int) { }; pub const address_space = struct { - pub const default = 0; + pub const default: c_uint = 0; // See llvm/lib/Target/X86/X86.h pub const x86_64 = x86; pub const x86 = struct { - pub const gs = 256; - pub const fs = 257; - pub const ss = 258; + pub const gs: c_uint = 256; + pub const fs: c_uint = 257; + pub const ss: c_uint = 258; - pub const ptr32_sptr = 270; - pub const ptr32_uptr = 271; - pub const ptr64 = 272; + pub const ptr32_sptr: c_uint = 270; + pub const ptr32_uptr: c_uint = 271; + pub const ptr64: c_uint = 272; }; // See llvm/lib/Target/AVR/AVR.h pub const avr = struct { - pub const data_memory = 0; - pub const program_memory = 1; + pub const data_memory: c_uint = 0; + pub const program_memory: c_uint = 1; }; // See llvm/lib/Target/NVPTX/NVPTX.h pub const nvptx = struct { - pub const generic = 0; - pub const global = 1; - pub const constant = 2; - pub const shared = 3; - pub const param = 4; - pub const local = 5; + pub const generic: c_uint = 0; + pub const global: c_uint = 1; + pub const constant: c_uint = 2; + pub const shared: c_uint = 3; + pub const param: c_uint = 4; + pub const local: c_uint = 5; }; // See llvm/lib/Target/AMDGPU/AMDGPU.h pub const amdgpu = struct { - pub const flat = 0; - pub const global = 1; - pub const region = 2; - pub const local = 3; - pub const constant = 4; - pub const constant_32bit = 6; - pub const buffer_fat_pointer = 7; - pub const param_d = 6; - pub const param_i = 7; - pub const constant_buffer_0 = 8; - pub const constant_buffer_1 = 9; - pub const constant_buffer_2 = 10; - pub const constant_buffer_3 = 11; - pub const constant_buffer_4 = 12; - pub const constant_buffer_5 = 13; - pub const constant_buffer_6 = 14; - pub const constant_buffer_7 = 15; - pub const constant_buffer_8 = 16; - pub const constant_buffer_9 = 17; - pub const constant_buffer_10 = 18; - pub const constant_buffer_11 = 19; - pub const constant_buffer_12 = 20; - pub const constant_buffer_13 = 21; - pub const constant_buffer_14 = 22; - pub const constant_buffer_15 = 23; + pub const flat: c_uint = 0; + pub const global: c_uint = 1; + pub const region: c_uint = 2; + pub const local: c_uint = 3; + pub const constant: c_uint = 4; + pub const private: c_uint = 5; + pub const constant_32bit: c_uint = 6; + pub const buffer_fat_pointer: c_uint = 7; + pub const param_d: c_uint = 6; + pub const param_i: c_uint = 7; + pub const constant_buffer_0: c_uint = 8; + pub const constant_buffer_1: c_uint = 9; + pub const constant_buffer_2: c_uint = 10; + pub const constant_buffer_3: c_uint = 11; + pub const constant_buffer_4: c_uint = 12; + pub const constant_buffer_5: c_uint = 13; + pub const constant_buffer_6: c_uint = 14; + pub const constant_buffer_7: c_uint = 15; + pub const constant_buffer_8: c_uint = 16; + pub const constant_buffer_9: c_uint = 17; + pub const constant_buffer_10: c_uint = 18; + pub const constant_buffer_11: c_uint = 19; + pub const constant_buffer_12: c_uint = 20; + pub const constant_buffer_13: c_uint = 21; + pub const constant_buffer_14: c_uint = 22; + pub const constant_buffer_15: c_uint = 23; }; }; From 5a142dfa5651ec21792de211a6e9341c31ab4dbb Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Fri, 3 Sep 2021 04:37:07 +0200 Subject: [PATCH 28/30] Address Spaces: LLVM F segment address space test --- test/stage2/llvm.zig | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/stage2/llvm.zig b/test/stage2/llvm.zig index e1d32aa086..820768efe3 100644 --- a/test/stage2/llvm.zig +++ b/test/stage2/llvm.zig @@ -372,4 +372,54 @@ pub fn addCases(ctx: *TestContext) !void { \\pub export fn main() void { _ = entry; } ); } + + { + var case = ctx.exeUsingLlvmBackend("f segment address space reading and writing", linux_x64); + case.addCompareOutput( + \\fn assert(ok: bool) void { + \\ if (!ok) unreachable; + \\} + \\ + \\fn setFs(value: c_ulong) void { + \\ asm volatile ( + \\ \\syscall + \\ : + \\ : [number] "{rax}" (158), + \\ [code] "{rdi}" (0x1002), + \\ [val] "{rsi}" (value), + \\ : "rcx", "r11", "memory" + \\ ); + \\} + \\ + \\fn getFs() c_ulong { + \\ var result: c_ulong = undefined; + \\ asm volatile ( + \\ \\syscall + \\ : + \\ : [number] "{rax}" (158), + \\ [code] "{rdi}" (0x1003), + \\ [ptr] "{rsi}" (@ptrToInt(&result)), + \\ : "rcx", "r11", "memory" + \\ ); + \\ return result; + \\} + \\ + \\var test_value: u64 = 12345; + \\ + \\pub export fn main() c_int { + \\ const orig_fs = getFs(); + \\ + \\ setFs(@ptrToInt(&test_value)); + \\ assert(getFs() == @ptrToInt(&test_value)); + \\ + \\ var test_ptr = @intToPtr(*allowzero addrspace(.fs) u64, 0); + \\ assert(test_ptr.* == 12345); + \\ test_ptr.* = 98765; + \\ assert(test_value == 98765); + \\ + \\ setFs(orig_fs); + \\ return 0; + \\} + , ""); + } } From 95e83afa98c5af89c6e5f40d559eb54c6c31a54e Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 6 Sep 2021 00:29:04 +0200 Subject: [PATCH 29/30] Address Spaces: Yeet address space on function prototypes This is a property which solely belongs to pointers to functions, not to the functions themselves. This cannot be properly represented by stage 2 at the moment, as type with zigTypeTag() == .Fn is overloaded for for function pointers and function prototypes. --- lib/std/builtin.zig | 1 - src/AstGen.zig | 18 ++---- src/Module.zig | 116 +++++++++++++++++++------------------- src/Sema.zig | 121 +++++++++++++++++++++++++++------------- src/Zir.zig | 15 +---- src/codegen/llvm.zig | 3 +- src/stage1/ir.cpp | 54 ++++++------------ src/target.zig | 18 ++++++ src/type.zig | 23 -------- test/compile_errors.zig | 20 ------- 10 files changed, 180 insertions(+), 209 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 11273eedeb..f01e7605ab 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -365,7 +365,6 @@ pub const TypeInfo = union(enum) { pub const Fn = struct { calling_convention: CallingConvention, alignment: comptime_int, - address_space: AddressSpace, is_generic: bool, is_var_args: bool, return_type: ?type, diff --git a/src/AstGen.zig b/src/AstGen.zig index 2e4671d92e..f1eabe4c0c 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1117,9 +1117,9 @@ fn fnProtoExpr( break :inst try expr(gz, scope, align_rl, fn_proto.ast.align_expr); }; - const addrspace_inst: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: { - break :inst try expr(gz, scope, .{ .ty = .address_space_type }, fn_proto.ast.addrspace_expr); - }; + if (fn_proto.ast.addrspace_expr != 0) { + return astgen.failNode(fn_proto.ast.addrspace_expr, "addrspace not allowed on function prototypes", .{}); + } if (fn_proto.ast.section_expr != 0) { return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{}); @@ -1153,7 +1153,6 @@ fn fnProtoExpr( .body = &[0]Zir.Inst.Index{}, .cc = cc, .align_inst = align_inst, - .addrspace_inst = addrspace_inst, .lib_name = 0, .is_var_args = is_var_args, .is_inferred_error = false, @@ -3089,7 +3088,6 @@ fn fnDecl( .body = &[0]Zir.Inst.Index{}, .cc = cc, .align_inst = .none, // passed in the per-decl data - .addrspace_inst = .none, // passed in the per-decl data .lib_name = lib_name, .is_var_args = is_var_args, .is_inferred_error = false, @@ -3129,7 +3127,6 @@ fn fnDecl( .body = fn_gz.instructions.items, .cc = cc, .align_inst = .none, // passed in the per-decl data - .addrspace_inst = .none, // passed in the per-decl data .lib_name = lib_name, .is_var_args = is_var_args, .is_inferred_error = is_inferred_error, @@ -3481,7 +3478,6 @@ fn testDecl( .body = fn_block.instructions.items, .cc = .none, .align_inst = .none, - .addrspace_inst = .none, .lib_name = 0, .is_var_args = false, .is_inferred_error = true, @@ -9217,7 +9213,6 @@ const GenZir = struct { ret_br: Zir.Inst.Index, cc: Zir.Inst.Ref, align_inst: Zir.Inst.Ref, - addrspace_inst: Zir.Inst.Ref, lib_name: u32, is_var_args: bool, is_inferred_error: bool, @@ -9261,7 +9256,7 @@ const GenZir = struct { if (args.cc != .none or args.lib_name != 0 or args.is_var_args or args.is_test or args.align_inst != .none or - args.addrspace_inst != .none or args.is_extern) + args.is_extern) { try astgen.extra.ensureUnusedCapacity( gpa, @@ -9269,7 +9264,6 @@ const GenZir = struct { args.ret_ty.len + args.body.len + src_locs.len + @boolToInt(args.lib_name != 0) + @boolToInt(args.align_inst != .none) + - @boolToInt(args.addrspace_inst != .none) + @boolToInt(args.cc != .none), ); const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{ @@ -9287,9 +9281,6 @@ const GenZir = struct { if (args.align_inst != .none) { astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); } - if (args.addrspace_inst != .none) { - astgen.extra.appendAssumeCapacity(@enumToInt(args.addrspace_inst)); - } astgen.extra.appendSliceAssumeCapacity(args.ret_ty); astgen.extra.appendSliceAssumeCapacity(args.body); astgen.extra.appendSliceAssumeCapacity(src_locs); @@ -9308,7 +9299,6 @@ const GenZir = struct { .has_lib_name = args.lib_name != 0, .has_cc = args.cc != .none, .has_align = args.align_inst != .none, - .has_addrspace = args.addrspace_inst != .none, .is_test = args.is_test, .is_extern = args.is_extern, }), diff --git a/src/Module.zig b/src/Module.zig index 2313480aeb..500c34bcb0 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3220,7 +3220,12 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { }; break :blk switch (decl.zirAddrspaceRef()) { - .none => .generic, + .none => switch (addrspace_ctx) { + .function => target_util.defaultAddressSpace(sema.mod.getTarget(), .function), + .variable => target_util.defaultAddressSpace(sema.mod.getTarget(), .global_mutable), + .constant => target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant), + else => unreachable, + }, else => |addrspace_ref| try sema.analyzeAddrspace(&block_scope, src, addrspace_ref, addrspace_ctx), }; }; @@ -4359,26 +4364,21 @@ pub fn simplePtrType( elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size, + @"addrspace": std.builtin.AddressSpace, ) Allocator.Error!Type { - if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) { - return Type.initTag(.const_slice_u8); - } - // TODO stage1 type inference bug - const T = Type.Tag; - - const type_payload = try arena.create(Type.Payload.ElemType); - type_payload.* = .{ - .base = .{ - .tag = switch (size) { - .One => if (mutable) T.single_mut_pointer else T.single_const_pointer, - .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, - .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, - .Slice => if (mutable) T.mut_slice else T.const_slice, - }, - }, - .data = elem_ty, - }; - return Type.initPayload(&type_payload.base); + return ptrType( + arena, + elem_ty, + null, + 0, + @"addrspace", + 0, + 0, + mutable, + false, + false, + size, + ); } pub fn ptrType( @@ -4396,47 +4396,43 @@ pub fn ptrType( ) Allocator.Error!Type { assert(host_size == 0 or bit_offset < host_size * 8); - // TODO check if type can be represented by simplePtrType - return Type.Tag.pointer.create(arena, .{ - .pointee_type = elem_ty, - .sentinel = sentinel, - .@"align" = @"align", - .@"addrspace" = @"addrspace", - .bit_offset = bit_offset, - .host_size = host_size, - .@"allowzero" = @"allowzero", - .mutable = mutable, - .@"volatile" = @"volatile", - .size = size, - }); -} - -/// Create a pointer type with an explicit address space. This function might return results -/// of either simplePtrType or ptrType, depending on the address space. -/// TODO(Snektron) unify ptrType functions. -pub fn simplePtrTypeWithAddressSpace( - arena: *Allocator, - elem_ty: Type, - mutable: bool, - size: std.builtin.TypeInfo.Pointer.Size, - address_space: std.builtin.AddressSpace, -) Allocator.Error!Type { - switch (address_space) { - .generic => return simplePtrType(arena, elem_ty, mutable, size), - else => return ptrType( - arena, - elem_ty, - null, - 0, - address_space, - 0, - 0, - mutable, - false, - false, - size, - ), + if (sentinel != null or @"align" != 0 or @"addrspace" != .generic or + bit_offset != 0 or host_size != 0 or @"allowzero" or @"volatile") + { + return Type.Tag.pointer.create(arena, .{ + .pointee_type = elem_ty, + .sentinel = sentinel, + .@"align" = @"align", + .@"addrspace" = @"addrspace", + .bit_offset = bit_offset, + .host_size = host_size, + .@"allowzero" = @"allowzero", + .mutable = mutable, + .@"volatile" = @"volatile", + .size = size, + }); } + + if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) { + return Type.initTag(.const_slice_u8); + } + + // TODO stage1 type inference bug + const T = Type.Tag; + + const type_payload = try arena.create(Type.Payload.ElemType); + type_payload.* = .{ + .base = .{ + .tag = switch (size) { + .One => if (mutable) T.single_mut_pointer else T.single_const_pointer, + .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, + .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, + .Slice => if (mutable) T.mut_slice else T.const_slice, + }, + }, + .data = elem_ty, + }; + return Type.initPayload(&type_payload.base); } pub fn optionalType(arena: *Allocator, child_type: Type) Allocator.Error!Type { diff --git a/src/Sema.zig b/src/Sema.zig index 7f2b0e855e..f781138df5 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1373,7 +1373,13 @@ fn zirRetPtr( return sema.analyzeComptimeAlloc(block, sema.fn_ret_ty); } - const ptr_type = try Module.simplePtrType(sema.arena, sema.fn_ret_ty, true, .One); + const ptr_type = try Module.simplePtrType( + sema.arena, + sema.fn_ret_ty, + true, + .One, + target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + ); return block.addTy(.alloc, ptr_type); } @@ -1521,7 +1527,13 @@ fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; const var_decl_src = inst_data.src(); const var_type = try sema.resolveType(block, ty_src, inst_data.operand); - const ptr_type = try Module.simplePtrType(sema.arena, var_type, true, .One); + const ptr_type = try Module.simplePtrType( + sema.arena, + var_type, + true, + .One, + target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + ); try sema.requireRuntimeBlock(block, var_decl_src); return block.addTy(.alloc, ptr_type); } @@ -1538,7 +1550,13 @@ fn zirAllocMut(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr return sema.analyzeComptimeAlloc(block, var_type); } try sema.validateVarType(block, ty_src, var_type); - const ptr_type = try Module.simplePtrType(sema.arena, var_type, true, .One); + const ptr_type = try Module.simplePtrType( + sema.arena, + var_type, + true, + .One, + target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + ); try sema.requireRuntimeBlock(block, var_decl_src); return block.addTy(.alloc, ptr_type); } @@ -1598,7 +1616,13 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde try sema.mod.declareDeclDependency(sema.owner_decl, decl); const final_elem_ty = try decl.ty.copy(sema.arena); - const final_ptr_ty = try Module.simplePtrType(sema.arena, final_elem_ty, true, .One); + const final_ptr_ty = try Module.simplePtrType( + sema.arena, + final_elem_ty, + true, + .One, + target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + ); const final_ptr_ty_inst = try sema.addType(final_ptr_ty); sema.air_instructions.items(.data)[ptr_inst].ty_pl.ty = final_ptr_ty_inst; @@ -1620,7 +1644,13 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde try sema.validateVarType(block, ty_src, final_elem_ty); } // Change it to a normal alloc. - const final_ptr_ty = try Module.simplePtrType(sema.arena, final_elem_ty, true, .One); + const final_ptr_ty = try Module.simplePtrType( + sema.arena, + final_elem_ty, + true, + .One, + target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + ); sema.air_instructions.set(ptr_inst, .{ .tag = .alloc, .data = .{ .ty = final_ptr_ty }, @@ -1774,7 +1804,14 @@ fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co } const ptr = sema.resolveInst(bin_inst.lhs); const value = sema.resolveInst(bin_inst.rhs); - const ptr_ty = try Module.simplePtrType(sema.arena, sema.typeOf(value), true, .One); + const ptr_ty = try Module.simplePtrType( + sema.arena, + sema.typeOf(value), + true, + .One, + // TODO figure out which address space is appropriate here + target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + ); // TODO detect when this store should be done at compile-time. For example, // if expressions should force it when the condition is compile-time known. const src: LazySrcLoc = .unneeded; @@ -1821,7 +1858,14 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) // for the inferred allocation. try inferred_alloc.data.stored_inst_list.append(sema.arena, operand); // Create a runtime bitcast instruction with exactly the type the pointer wants. - const ptr_ty = try Module.simplePtrType(sema.arena, operand_ty, true, .One); + const ptr_ty = try Module.simplePtrType( + sema.arena, + operand_ty, + true, + .One, + // TODO figure out which address space is appropriate here + target_util.defaultAddressSpace(sema.mod.getTarget(), .local), + ); const bitcasted_ptr = try block.addTyOp(.bitcast, ptr_ty, ptr); return sema.storePtr(block, src, bitcasted_ptr, operand); } @@ -3658,7 +3702,7 @@ fn zirOptionalPayloadPtr( } const child_type = try opt_type.optionalChildAlloc(sema.arena); - const child_pointer = try Module.simplePtrTypeWithAddressSpace( + const child_pointer = try Module.simplePtrType( sema.arena, child_type, !optional_ptr_ty.isConstPtr(), @@ -3779,7 +3823,7 @@ fn zirErrUnionPayloadPtr( return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand_ty.elemType()}); const payload_ty = operand_ty.elemType().errorUnionPayload(); - const operand_pointer_ty = try Module.simplePtrTypeWithAddressSpace( + const operand_pointer_ty = try Module.simplePtrType( sema.arena, payload_ty, !operand_ty.isConstPtr(), @@ -3907,7 +3951,6 @@ fn zirFunc( ret_ty_body, cc, Value.initTag(.null_value), - .generic, false, inferred_error_set, false, @@ -3924,7 +3967,6 @@ fn funcCommon( ret_ty_body: []const Zir.Inst.Index, cc: std.builtin.CallingConvention, align_val: Value, - address_space: std.builtin.AddressSpace, var_args: bool, inferred_error_set: bool, is_extern: bool, @@ -3982,7 +4024,7 @@ fn funcCommon( // Hot path for some common function types. // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated. if (!is_generic and block.params.items.len == 0 and !var_args and - align_val.tag() == .null_value and !inferred_error_set and address_space == .generic) + align_val.tag() == .null_value and !inferred_error_set) { if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) { break :fn_ty Type.initTag(.fn_noreturn_no_args); @@ -4034,7 +4076,6 @@ fn funcCommon( .comptime_params = comptime_params.ptr, .return_type = return_type, .cc = cc, - .@"addrspace" = address_space, .is_var_args = var_args, .is_generic = is_generic, }); @@ -6413,7 +6454,7 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr switch (ty.zigTypeTag()) { .Fn => { - const field_values = try sema.arena.alloc(Value, 7); + const field_values = try sema.arena.alloc(Value, 6); // calling_convention: CallingConvention, field_values[0] = try Value.Tag.enum_field_index.create( sema.arena, @@ -6421,19 +6462,14 @@ fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr ); // alignment: comptime_int, field_values[1] = try Value.Tag.int_u64.create(sema.arena, ty.abiAlignment(target)); - // address_space: AddressSpace, - field_values[2] = try Value.Tag.enum_field_index.create( - sema.arena, - @enumToInt(ty.fnAddressSpace()), - ); // is_generic: bool, - field_values[3] = Value.initTag(.bool_false); // TODO + field_values[2] = Value.initTag(.bool_false); // TODO // is_var_args: bool, - field_values[4] = Value.initTag(.bool_false); // TODO + field_values[3] = Value.initTag(.bool_false); // TODO // return_type: ?type, - field_values[5] = try Value.Tag.ty.create(sema.arena, ty.fnReturnType()); + field_values[4] = try Value.Tag.ty.create(sema.arena, ty.fnReturnType()); // args: []const FnArg, - field_values[6] = Value.initTag(.null_value); // TODO + field_values[5] = Value.initTag(.null_value); // TODO return sema.addConstant( type_info_ty, @@ -8063,7 +8099,6 @@ fn zirFuncExtended( const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = extra.data.src_node }; const align_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at align - const addrspace_src: LazySrcLoc = src; // TODO(Snektron) add a LazySrcLoc that points at addrspace const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small); var extra_index: usize = extra.end; @@ -8088,12 +8123,6 @@ fn zirFuncExtended( break :blk align_tv.val; } else Value.initTag(.null_value); - const address_space: std.builtin.AddressSpace = if (small.has_addrspace) blk: { - const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); - extra_index += 1; - break :blk try sema.analyzeAddrspace(block, addrspace_src, addrspace_ref, .function); - } else .generic; - const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len]; extra_index += ret_ty_body.len; @@ -8116,7 +8145,6 @@ fn zirFuncExtended( ret_ty_body, cc, align_val, - address_space, is_var_args, is_inferred_error, is_extern, @@ -8309,7 +8337,13 @@ fn panicWithMsg( const panic_fn = try sema.getBuiltin(block, src, "panic"); const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); - const ptr_stack_trace_ty = try Module.simplePtrType(arena, stack_trace_ty, true, .One); + const ptr_stack_trace_ty = try Module.simplePtrType( + arena, + stack_trace_ty, + true, + .One, + target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant), // TODO might need a place that is more dynamic + ); const null_stack_trace = try sema.addConstant( try Module.optionalType(arena, ptr_stack_trace_ty), Value.initTag(.null_value), @@ -8788,7 +8822,7 @@ fn structFieldPtr( const field_index = struct_obj.fields.getIndex(field_name) orelse return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name); const field = struct_obj.fields.values()[field_index]; - const ptr_field_ty = try Module.simplePtrTypeWithAddressSpace( + const ptr_field_ty = try Module.simplePtrType( arena, field.ty, struct_ptr_ty.ptrIsMutable(), @@ -8893,7 +8927,7 @@ fn unionFieldPtr( return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name); const field = union_obj.fields.values()[field_index]; - const ptr_field_ty = try Module.simplePtrTypeWithAddressSpace( + const ptr_field_ty = try Module.simplePtrType( arena, field.ty, union_ptr_ty.ptrIsMutable(), @@ -9075,7 +9109,7 @@ fn elemPtrArray( ) CompileError!Air.Inst.Ref { const array_ptr_ty = sema.typeOf(array_ptr); const pointee_type = array_ptr_ty.elemType().elemType(); - const result_ty = try Module.simplePtrTypeWithAddressSpace( + const result_ty = try Module.simplePtrType( sema.arena, pointee_type, array_ptr_ty.ptrIsMutable(), @@ -9581,11 +9615,11 @@ fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref { const decl_tv = try decl.typedValue(); if (decl_tv.val.castTag(.variable)) |payload| { const variable = payload.data; - const ty = try Module.simplePtrTypeWithAddressSpace(sema.arena, decl_tv.ty, variable.is_mutable, .One, decl.@"addrspace"); + const ty = try Module.simplePtrType(sema.arena, decl_tv.ty, variable.is_mutable, .One, decl.@"addrspace"); return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl)); } return sema.addConstant( - try Module.simplePtrTypeWithAddressSpace(sema.arena, decl_tv.ty, false, .One, decl.@"addrspace"), + try Module.simplePtrType(sema.arena, decl_tv.ty, false, .One, decl.@"addrspace"), try Value.Tag.decl_ref.create(sema.arena, decl), ); } @@ -9608,8 +9642,9 @@ fn analyzeRef( } try sema.requireRuntimeBlock(block, src); - const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One); - const mut_ptr_type = try Module.simplePtrType(sema.arena, operand_ty, true, .One); + const address_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local); + const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One, address_space); + const mut_ptr_type = try Module.simplePtrType(sema.arena, operand_ty, true, .One, address_space); const alloc = try block.addTy(.alloc, mut_ptr_type); try sema.storePtr(block, src, alloc, operand); @@ -10955,7 +10990,13 @@ fn analyzeComptimeAlloc( block: *Scope.Block, var_type: Type, ) CompileError!Air.Inst.Ref { - const ptr_type = try Module.simplePtrType(sema.arena, var_type, true, .One); + const ptr_type = try Module.simplePtrType( + sema.arena, + var_type, + true, + .One, + target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant), + ); var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); diff --git a/src/Zir.zig b/src/Zir.zig index 50c53e5485..28fa92d4a0 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -2309,7 +2309,6 @@ pub const Inst = struct { /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set /// 1. cc: Ref, // if has_cc is set /// 2. align: Ref, // if has_align is set - /// 3. addrspace: Ref, // if has_addrspace is set /// 3. return_type: Index // for each ret_body_len /// 4. body: Index // for each body_len /// 5. src_locs: Func.SrcLocs // if body_len != 0 @@ -2327,10 +2326,9 @@ pub const Inst = struct { has_lib_name: bool, has_cc: bool, has_align: bool, - has_addrspace: bool, is_test: bool, is_extern: bool, - _: u8 = undefined, + _: u9 = undefined, }; }; @@ -4483,7 +4481,6 @@ const Writer = struct { false, .none, .none, - .none, body, src, src_locs, @@ -4512,11 +4509,6 @@ const Writer = struct { extra_index += 1; break :blk align_inst; }; - const addrspace_inst: Inst.Ref = if (!small.has_addrspace) .none else blk: { - const addrspace_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - break :blk addrspace_inst; - }; const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len]; extra_index += ret_ty_body.len; @@ -4536,7 +4528,6 @@ const Writer = struct { small.is_extern, cc, align_inst, - addrspace_inst, body, src, src_locs, @@ -4619,7 +4610,6 @@ const Writer = struct { is_extern: bool, cc: Inst.Ref, align_inst: Inst.Ref, - addrspace_inst: Inst.Ref, body: []const Inst.Index, src: LazySrcLoc, src_locs: Zir.Inst.Func.SrcLocs, @@ -4637,7 +4627,6 @@ const Writer = struct { try self.writeOptionalInstRef(stream, ", cc=", cc); try self.writeOptionalInstRef(stream, ", align=", align_inst); - try self.writeOptionalInstRef(stream, ", addrspace=", addrspace_inst); try self.writeFlag(stream, ", vargs", var_args); try self.writeFlag(stream, ", extern", is_extern); try self.writeFlag(stream, ", inferror", inferred_error_set); @@ -4915,7 +4904,6 @@ fn findDeclsInner( extra_index += @boolToInt(small.has_lib_name); extra_index += @boolToInt(small.has_cc); extra_index += @boolToInt(small.has_align); - extra_index += @boolToInt(small.has_addrspace); const body = zir.extra[extra_index..][0..extra.data.body_len]; return zir.findDeclsBody(list, body); }, @@ -5119,7 +5107,6 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { extra_index += @boolToInt(small.has_lib_name); extra_index += @boolToInt(small.has_cc); extra_index += @boolToInt(small.has_align); - extra_index += @boolToInt(small.has_addrspace); const ret_ty_body = zir.extra[extra_index..][0..extra.data.ret_body_len]; extra_index += ret_ty_body.len; const body = zir.extra[extra_index..][0..extra.data.body_len]; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index ce79d43fac..e2d6e964cf 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -700,7 +700,8 @@ pub const DeclGen = struct { @intCast(c_uint, llvm_params.len), llvm.Bool.fromBool(is_var_args), ); - const llvm_addrspace = self.llvmAddressSpace(t.fnAddressSpace()); + // TODO make .Fn not both a pointer type and a prototype + const llvm_addrspace = self.llvmAddressSpace(.generic); return llvm_fn_ty.pointerType(llvm_addrspace); }, .ComptimeInt => unreachable, diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index a41384cee6..87dfee1bf2 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -18483,35 +18483,30 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour fields[1]->special = ConstValSpecialStatic; fields[1]->type = ira->codegen->builtin_types.entry_num_lit_int; bigint_init_unsigned(&fields[1]->data.x_bigint, get_ptr_align(ira->codegen, type_entry)); - // address_space: AddressSpace - ensure_field_index(result->type, "address_space", 2); - fields[2]->special = ConstValSpecialStatic; - fields[2]->type = get_builtin_type(ira->codegen, "AddressSpace"); - bigint_init_unsigned(&fields[2]->data.x_enum_tag, AddressSpaceGeneric); // is_generic: bool - ensure_field_index(result->type, "is_generic", 3); + ensure_field_index(result->type, "is_generic", 2); bool is_generic = type_entry->data.fn.is_generic; + fields[2]->special = ConstValSpecialStatic; + fields[2]->type = ira->codegen->builtin_types.entry_bool; + fields[2]->data.x_bool = is_generic; + // is_varargs: bool + ensure_field_index(result->type, "is_var_args", 3); + bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args; fields[3]->special = ConstValSpecialStatic; fields[3]->type = ira->codegen->builtin_types.entry_bool; - fields[3]->data.x_bool = is_generic; - // is_varargs: bool - ensure_field_index(result->type, "is_var_args", 4); - bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args; - fields[4]->special = ConstValSpecialStatic; - fields[4]->type = ira->codegen->builtin_types.entry_bool; - fields[4]->data.x_bool = is_varargs; + fields[3]->data.x_bool = is_varargs; // return_type: ?type - ensure_field_index(result->type, "return_type", 5); - fields[5]->special = ConstValSpecialStatic; - fields[5]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type); + ensure_field_index(result->type, "return_type", 4); + fields[4]->special = ConstValSpecialStatic; + fields[4]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type); if (type_entry->data.fn.fn_type_id.return_type == nullptr) - fields[5]->data.x_optional = nullptr; + fields[4]->data.x_optional = nullptr; else { ZigValue *return_type = ira->codegen->pass1_arena->create(); return_type->special = ConstValSpecialStatic; return_type->type = ira->codegen->builtin_types.entry_type; return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type; - fields[5]->data.x_optional = return_type; + fields[4]->data.x_optional = return_type; } // args: []TypeInfo.FnArg ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg", nullptr); @@ -18526,7 +18521,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour fn_arg_array->data.x_array.special = ConstArraySpecialNone; fn_arg_array->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate(fn_arg_count); - init_const_slice(ira->codegen, fields[6], fn_arg_array, 0, fn_arg_count, false, nullptr); + init_const_slice(ira->codegen, fields[5], fn_arg_array, 0, fn_arg_count, false, nullptr); for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) { FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index]; @@ -19330,22 +19325,9 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ if (alignment == nullptr) return ira->codegen->invalid_inst_gen->value->type; - ZigValue *as_value = get_const_field(ira, source_node, payload, "address_space", 2); - if (as_value == nullptr) - return ira->codegen->invalid_inst_gen->value->type; - assert(as_value->special == ConstValSpecialStatic); - assert(as_value->type == get_builtin_type(ira->codegen, "AddressSpace")); - AddressSpace as = (AddressSpace)bigint_as_u32(&as_value->data.x_enum_tag); - if (as != AddressSpaceGeneric) { - ir_add_error_node(ira, source_node, buf_sprintf( - "address space '%s' not available in stage 1 compiler, must be .generic", - address_space_name(as))); - return ira->codegen->invalid_inst_gen->value->type; - } - Error err; bool is_generic; - if ((err = get_const_field_bool(ira, source_node, payload, "is_generic", 3, &is_generic))) + if ((err = get_const_field_bool(ira, source_node, payload, "is_generic", 2, &is_generic))) return ira->codegen->invalid_inst_gen->value->type; if (is_generic) { ir_add_error_node(ira, source_node, buf_sprintf("TypeInfo.Fn.is_generic must be false for @Type")); @@ -19353,20 +19335,20 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_ } bool is_var_args; - if ((err = get_const_field_bool(ira, source_node, payload, "is_var_args", 4, &is_var_args))) + if ((err = get_const_field_bool(ira, source_node, payload, "is_var_args", 3, &is_var_args))) return ira->codegen->invalid_inst_gen->value->type; if (is_var_args && cc != CallingConventionC) { ir_add_error_node(ira, source_node, buf_sprintf("varargs functions must have C calling convention")); return ira->codegen->invalid_inst_gen->value->type; } - ZigType *return_type = get_const_field_meta_type_optional(ira, source_node, payload, "return_type", 5); + ZigType *return_type = get_const_field_meta_type_optional(ira, source_node, payload, "return_type", 4); if (return_type == nullptr) { ir_add_error_node(ira, source_node, buf_sprintf("TypeInfo.Fn.return_type must be non-null for @Type")); return ira->codegen->invalid_inst_gen->value->type; } - ZigValue *args_value = get_const_field(ira, source_node, payload, "args", 6); + ZigValue *args_value = get_const_field(ira, source_node, payload, "args", 5); if (args_value == nullptr) return ira->codegen->invalid_inst_gen->value->type; assert(args_value->special == ConstValSpecialStatic); diff --git a/src/target.zig b/src/target.zig index c9d7e1742b..09e65ff909 100644 --- a/src/target.zig +++ b/src/target.zig @@ -544,3 +544,21 @@ pub fn largestAtomicBits(target: std.Target) u32 { .x86_64 => 128, }; } + +pub fn defaultAddressSpace( + target: std.Target, + context: enum { + /// Query the default address space for global constant values. + global_constant, + /// Query the default address space for global mutable values. + global_mutable, + /// Query the default address space for function-local values. + local, + /// Query the default address space for functions themselves. + function, + }, +) std.builtin.AddressSpace { + _ = target; + _ = context; + return .generic; +} diff --git a/src/type.zig b/src/type.zig index e8a9d059d0..f85ee12d4b 100644 --- a/src/type.zig +++ b/src/type.zig @@ -530,8 +530,6 @@ pub const Type = extern union { return false; if (a.fnCallingConvention() != b.fnCallingConvention()) return false; - if (a.fnAddressSpace() != b.fnAddressSpace()) - return false; const a_param_len = a.fnParamLen(); const b_param_len = b.fnParamLen(); if (a_param_len != b_param_len) @@ -838,7 +836,6 @@ pub const Type = extern union { .return_type = try payload.return_type.copy(allocator), .param_types = param_types, .cc = payload.cc, - .@"addrspace" = payload.@"addrspace", .is_var_args = payload.is_var_args, .is_generic = payload.is_generic, .comptime_params = comptime_params.ptr, @@ -1001,9 +998,6 @@ pub const Type = extern union { try writer.writeAll(") callconv(."); try writer.writeAll(@tagName(payload.cc)); try writer.writeAll(") "); - if (payload.@"addrspace" != .generic) { - try writer.print("addrspace(.{s}) ", .{@tagName(payload.@"addrspace")}); - } ty = payload.return_type; continue; }, @@ -2730,18 +2724,6 @@ pub const Type = extern union { }; } - pub fn fnAddressSpace(self: Type) std.builtin.AddressSpace { - return switch (self.tag()) { - .fn_noreturn_no_args => .generic, - .fn_void_no_args => .generic, - .fn_naked_noreturn_no_args => .generic, - .fn_ccc_void_no_args => .generic, - .function => self.castTag(.function).?.data.@"addrspace", - - else => unreachable, - }; - } - pub fn fnInfo(ty: Type) Payload.Function.Data { return switch (ty.tag()) { .fn_noreturn_no_args => .{ @@ -2749,7 +2731,6 @@ pub const Type = extern union { .comptime_params = undefined, .return_type = initTag(.noreturn), .cc = .Unspecified, - .@"addrspace" = .generic, .is_var_args = false, .is_generic = false, }, @@ -2758,7 +2739,6 @@ pub const Type = extern union { .comptime_params = undefined, .return_type = initTag(.void), .cc = .Unspecified, - .@"addrspace" = .generic, .is_var_args = false, .is_generic = false, }, @@ -2767,7 +2747,6 @@ pub const Type = extern union { .comptime_params = undefined, .return_type = initTag(.noreturn), .cc = .Naked, - .@"addrspace" = .generic, .is_var_args = false, .is_generic = false, }, @@ -2776,7 +2755,6 @@ pub const Type = extern union { .comptime_params = undefined, .return_type = initTag(.void), .cc = .C, - .@"addrspace" = .generic, .is_var_args = false, .is_generic = false, }, @@ -3648,7 +3626,6 @@ pub const Type = extern union { comptime_params: [*]bool, return_type: Type, cc: std.builtin.CallingConvention, - @"addrspace": std.builtin.AddressSpace, is_var_args: bool, is_generic: bool, diff --git a/test/compile_errors.zig b/test/compile_errors.zig index f2fa20d722..058fd1f2db 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -410,7 +410,6 @@ pub fn addCases(ctx: *TestContext) !void { \\ .Fn = .{ \\ .calling_convention = .Unspecified, \\ .alignment = 0, - \\ .address_space = .generic, \\ .is_generic = true, \\ .is_var_args = false, \\ .return_type = u0, @@ -427,7 +426,6 @@ pub fn addCases(ctx: *TestContext) !void { \\ .Fn = .{ \\ .calling_convention = .Unspecified, \\ .alignment = 0, - \\ .address_space = .generic, \\ .is_generic = false, \\ .is_var_args = true, \\ .return_type = u0, @@ -444,7 +442,6 @@ pub fn addCases(ctx: *TestContext) !void { \\ .Fn = .{ \\ .calling_convention = .Unspecified, \\ .alignment = 0, - \\ .address_space = .generic, \\ .is_generic = false, \\ .is_var_args = false, \\ .return_type = null, @@ -456,23 +453,6 @@ pub fn addCases(ctx: *TestContext) !void { "tmp.zig:1:20: error: TypeInfo.Fn.return_type must be non-null for @Type", }); - ctx.objErrStage1("@Type(.Fn) with invalid address space ", - \\const Foo = @Type(.{ - \\ .Fn = .{ - \\ .calling_convention = .Unspecified, - \\ .alignment = 0, - \\ .address_space = .fs, - \\ .is_generic = false, - \\ .is_var_args = false, - \\ .return_type = u0, - \\ .args = &[_]@import("std").builtin.TypeInfo.FnArg{}, - \\ }, - \\}); - \\comptime { _ = Foo; } - , &[_][]const u8{ - "tmp.zig:1:20: error: address space 'fs' not available in stage 1 compiler, must be .generic", - }); - ctx.objErrStage1("@Type for union with opaque field", \\const TypeInfo = @import("std").builtin.TypeInfo; \\const Untagged = @Type(.{ From 619260d94d68bdecdac649fa7b156dc8962a9889 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 20 Sep 2021 02:34:53 +0200 Subject: [PATCH 30/30] Address Spaces: Fix comments in Ast.zig --- lib/std/zig/Ast.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index a62e9c105d..5838dcd37a 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -2961,9 +2961,9 @@ pub const Node = struct { type_node: Index, /// Populated if align(A) is present. align_node: Index, - /// Populated if linksection(A) is present. - addrspace_node: Index, /// Populated if addrspace(A) is present. + addrspace_node: Index, + /// Populated if linksection(A) is present. section_node: Index, }; @@ -2995,9 +2995,9 @@ pub const Node = struct { param: Index, /// Populated if align(A) is present. align_expr: Index, - /// Populated if linksection(A) is present. - addrspace_expr: Index, /// Populated if addrspace(A) is present. + addrspace_expr: Index, + /// Populated if linksection(A) is present. section_expr: Index, /// Populated if callconv(A) is present. callconv_expr: Index,