mirror of
https://github.com/ziglang/zig.git
synced 2024-11-14 16:13:24 +00:00
commit
1ad905c71e
@ -901,6 +901,7 @@ fn tokenizeAndPrintRaw(
|
||||
switch (token.tag) {
|
||||
.eof => break,
|
||||
|
||||
.keyword_addrspace,
|
||||
.keyword_align,
|
||||
.keyword_and,
|
||||
.keyword_asm,
|
||||
|
@ -166,6 +166,15 @@ 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,
|
||||
gs,
|
||||
fs,
|
||||
ss,
|
||||
};
|
||||
|
||||
/// 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 {
|
||||
@ -226,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,
|
||||
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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,
|
||||
|
@ -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 addrspace(A) is present.
|
||||
addrspace_node: Index,
|
||||
/// Populated if linksection(A) is present.
|
||||
section_node: Index,
|
||||
};
|
||||
|
||||
@ -2953,6 +2995,8 @@ pub const Node = struct {
|
||||
param: 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.
|
||||
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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,23 @@ 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 +1293,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 +1441,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;
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
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", .{});
|
||||
}
|
||||
@ -2371,6 +2376,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);
|
||||
@ -2385,6 +2391,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
|
||||
@ -2714,6 +2728,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 +2747,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 +2760,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 +2784,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 +2802,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 +2871,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 +2881,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 +2946,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 +3036,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);
|
||||
};
|
||||
@ -3112,7 +3140,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);
|
||||
@ -3127,8 +3155,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 +3205,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) {
|
||||
@ -3256,7 +3290,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);
|
||||
@ -3271,8 +3305,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));
|
||||
}
|
||||
}
|
||||
|
||||
|
145
src/Module.zig
145
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 `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,24 @@ 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_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.tag()) {
|
||||
.function, .extern_fn => .function,
|
||||
.variable => .variable,
|
||||
else => .constant,
|
||||
};
|
||||
|
||||
break :blk switch (decl.zirAddrspaceRef()) {
|
||||
.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),
|
||||
};
|
||||
};
|
||||
|
||||
// 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 +3286,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 +3348,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 +3556,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 +3583,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 +3669,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 +3686,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 +4058,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 +4083,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,
|
||||
@ -4185,6 +4216,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;
|
||||
@ -4330,10 +4364,59 @@ pub fn simplePtrType(
|
||||
elem_ty: Type,
|
||||
mutable: bool,
|
||||
size: std.builtin.TypeInfo.Pointer.Size,
|
||||
@"addrspace": std.builtin.AddressSpace,
|
||||
) Allocator.Error!Type {
|
||||
return ptrType(
|
||||
arena,
|
||||
elem_ty,
|
||||
null,
|
||||
0,
|
||||
@"addrspace",
|
||||
0,
|
||||
0,
|
||||
mutable,
|
||||
false,
|
||||
false,
|
||||
size,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn ptrType(
|
||||
arena: *Allocator,
|
||||
elem_ty: Type,
|
||||
sentinel: ?Value,
|
||||
@"align": u32,
|
||||
@"addrspace": std.builtin.AddressSpace,
|
||||
bit_offset: u16,
|
||||
host_size: u16,
|
||||
mutable: bool,
|
||||
@"allowzero": bool,
|
||||
@"volatile": bool,
|
||||
size: std.builtin.TypeInfo.Pointer.Size,
|
||||
) Allocator.Error!Type {
|
||||
assert(host_size == 0 or bit_offset < host_size * 8);
|
||||
|
||||
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;
|
||||
|
||||
@ -4352,34 +4435,6 @@ pub fn simplePtrType(
|
||||
return Type.initPayload(&type_payload.base);
|
||||
}
|
||||
|
||||
pub fn ptrType(
|
||||
arena: *Allocator,
|
||||
elem_ty: Type,
|
||||
sentinel: ?Value,
|
||||
@"align": u32,
|
||||
bit_offset: u16,
|
||||
host_size: u16,
|
||||
mutable: bool,
|
||||
@"allowzero": bool,
|
||||
@"volatile": bool,
|
||||
size: std.builtin.TypeInfo.Pointer.Size,
|
||||
) 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",
|
||||
.bit_offset = bit_offset,
|
||||
.host_size = host_size,
|
||||
.@"allowzero" = @"allowzero",
|
||||
.mutable = mutable,
|
||||
.@"volatile" = @"volatile",
|
||||
.size = 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(
|
||||
@ -4709,7 +4764,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: {
|
||||
|
303
src/Sema.zig
303
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);
|
||||
}
|
||||
@ -3004,7 +3048,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;
|
||||
@ -3658,7 +3702,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.simplePtrType(
|
||||
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 +3823,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.simplePtrType(
|
||||
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| {
|
||||
@ -6879,6 +6935,7 @@ fn zirPtrTypeSimple(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp
|
||||
elem_type,
|
||||
null,
|
||||
0,
|
||||
.generic,
|
||||
0,
|
||||
0,
|
||||
inst_data.is_mutable,
|
||||
@ -6911,6 +6968,12 @@ 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;
|
||||
break :blk try sema.analyzeAddrspace(block, .unneeded, ref, .pointer);
|
||||
} 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;
|
||||
@ -6933,6 +6996,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,
|
||||
@ -8339,7 +8403,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),
|
||||
@ -8423,7 +8493,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);
|
||||
@ -8457,21 +8527,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 => {},
|
||||
@ -8595,9 +8676,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
|
||||
@ -8627,26 +8707,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);
|
||||
@ -8788,13 +8881,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.simplePtrType(
|
||||
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(
|
||||
@ -8885,6 +8985,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;
|
||||
|
||||
@ -8892,7 +8993,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.simplePtrType(
|
||||
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
|
||||
@ -9068,10 +9175,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.simplePtrType(
|
||||
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| {
|
||||
@ -9162,6 +9272,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)) {
|
||||
@ -9297,6 +9408,10 @@ fn coerceInMemoryAllowed(dest_type: Type, src_type: Type, dest_is_mut: bool) InM
|
||||
return child;
|
||||
}
|
||||
|
||||
if (dest_info.@"addrspace" != src_info.@"addrspace") {
|
||||
return .no_match;
|
||||
}
|
||||
|
||||
const ok_sent = dest_info.sentinel == null or src_info.size == .C or
|
||||
(src_info.sentinel != null and
|
||||
dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type));
|
||||
@ -9590,11 +9705,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.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.simplePtrType(sema.arena, decl_tv.ty, false, .One),
|
||||
try Module.simplePtrType(sema.arena, decl_tv.ty, false, .One, decl.@"addrspace"),
|
||||
try Value.Tag.decl_ref.create(sema.arena, decl),
|
||||
);
|
||||
}
|
||||
@ -9617,8 +9732,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);
|
||||
|
||||
@ -9779,6 +9895,7 @@ fn analyzeSlice(
|
||||
return_elem_type,
|
||||
if (end_opt == .none) slice_sentinel else null,
|
||||
0, // TODO alignment
|
||||
if (ptr_child.zigTypeTag() == .Pointer) ptr_child.ptrAddressSpace() else .generic,
|
||||
0,
|
||||
0,
|
||||
!ptr_child.isConstPtr(),
|
||||
@ -10286,6 +10403,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"),
|
||||
@ -10680,6 +10798,7 @@ fn typeHasOnePossibleValue(
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -10865,6 +10984,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,
|
||||
@ -10960,7 +11080,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();
|
||||
@ -10976,3 +11102,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;
|
||||
}
|
||||
|
47
src/Zir.zig
47
src/Zir.zig
@ -443,10 +443,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.
|
||||
@ -1672,6 +1672,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,
|
||||
@ -1928,6 +1929,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),
|
||||
@ -2129,8 +2134,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`.
|
||||
@ -2360,12 +2366,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,
|
||||
};
|
||||
@ -2483,7 +2490,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
|
||||
@ -2495,7 +2502,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
|
||||
@ -2547,7 +2557,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
|
||||
@ -2559,7 +2569,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
|
||||
@ -2592,7 +2605,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 +2617,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
|
||||
@ -2641,7 +2657,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
|
||||
@ -2653,7 +2669,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,
|
||||
|
@ -4895,7 +4895,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();
|
||||
|
@ -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()});
|
||||
|
@ -558,7 +558,8 @@ pub const DeclGen = struct {
|
||||
llvm_params_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) {
|
||||
@ -580,7 +581,24 @@ 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 (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,
|
||||
},
|
||||
else => switch (address_space) {
|
||||
.generic => llvm.address_space.default,
|
||||
else => unreachable,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn llvmType(self: *DeclGen, t: Type) error{ OutOfMemory, CodegenFail }!*const llvm.Type {
|
||||
@ -609,7 +627,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 = .{
|
||||
@ -619,7 +637,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 => {
|
||||
@ -685,7 +704,9 @@ pub const DeclGen = struct {
|
||||
@intCast(c_uint, llvm_params.len),
|
||||
llvm.Bool.fromBool(is_var_args),
|
||||
);
|
||||
return llvm_fn_ty.pointerType(0);
|
||||
// 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,
|
||||
.ComptimeFloat => unreachable,
|
||||
@ -753,7 +774,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 },
|
||||
@ -783,12 +804,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),
|
||||
|
@ -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;
|
||||
|
||||
@ -1005,3 +1011,65 @@ pub const TypeKind = enum(c_int) {
|
||||
BFloat,
|
||||
X86_AMX,
|
||||
};
|
||||
|
||||
pub const address_space = struct {
|
||||
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: c_uint = 256;
|
||||
pub const fs: c_uint = 257;
|
||||
pub const ss: c_uint = 258;
|
||||
|
||||
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: c_uint = 0;
|
||||
pub const program_memory: c_uint = 1;
|
||||
};
|
||||
|
||||
// See llvm/lib/Target/NVPTX/NVPTX.h
|
||||
pub const nvptx = struct {
|
||||
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: 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;
|
||||
};
|
||||
};
|
||||
|
@ -1147,7 +1147,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;
|
||||
@ -1165,7 +1165,12 @@ const Writer = struct {
|
||||
extra_index += 1;
|
||||
break :inst inst;
|
||||
};
|
||||
const section_inst: Zir.Inst.Ref = if (!has_section) .none else inst: {
|
||||
const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
|
||||
const inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
break :inst inst;
|
||||
};
|
||||
const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
|
||||
const inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
break :inst inst;
|
||||
@ -1196,6 +1201,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);
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
@ -18826,11 +18831,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 +18850,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 +18875,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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
@ -2705,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,
|
||||
}),
|
||||
@ -2720,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,
|
||||
}),
|
||||
|
128
src/type.zig
128
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,
|
||||
@ -288,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,
|
||||
@ -299,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,
|
||||
@ -310,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,
|
||||
@ -321,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,
|
||||
@ -332,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,
|
||||
@ -343,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,
|
||||
@ -354,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,
|
||||
@ -365,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,
|
||||
@ -376,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,
|
||||
@ -387,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,
|
||||
@ -398,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,
|
||||
@ -409,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,
|
||||
@ -461,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;
|
||||
@ -746,6 +761,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -835,6 +851,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",
|
||||
@ -958,6 +975,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"),
|
||||
@ -1111,6 +1129,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 ");
|
||||
@ -1186,6 +1207,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -1301,6 +1323,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 +1385,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -1496,6 +1520,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()) {
|
||||
@ -1508,6 +1556,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -1734,6 +1783,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -2019,6 +2069,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -2105,42 +2156,82 @@ 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.* = .{
|
||||
.base = .{ .tag = .many_const_pointer },
|
||||
.data = elem_type,
|
||||
.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.* = .{
|
||||
.base = .{ .tag = .many_mut_pointer },
|
||||
.data = elem_type,
|
||||
.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) {
|
||||
|
||||
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.* = .{
|
||||
.base = .{ .tag = .many_mut_pointer },
|
||||
.data = payload.pointee_type,
|
||||
.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.* = .{
|
||||
.base = .{ .tag = .many_const_pointer },
|
||||
.data = payload.pointee_type,
|
||||
.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,
|
||||
@ -2793,6 +2884,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -3000,6 +3092,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -3024,6 +3117,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -3047,6 +3141,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -3100,6 +3195,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -3155,6 +3251,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -3192,6 +3289,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -3242,6 +3340,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -3302,6 +3401,7 @@ pub const Type = extern union {
|
||||
atomic_order,
|
||||
atomic_rmw_op,
|
||||
calling_convention,
|
||||
address_space,
|
||||
float_mode,
|
||||
reduce_op,
|
||||
call_options,
|
||||
@ -3425,6 +3525,7 @@ pub const Type = extern union {
|
||||
.atomic_order,
|
||||
.atomic_rmw_op,
|
||||
.calling_convention,
|
||||
.address_space,
|
||||
.float_mode,
|
||||
.reduce_op,
|
||||
.call_options,
|
||||
@ -3580,6 +3681,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,
|
||||
|
@ -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),
|
||||
|
@ -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<FunctionType>(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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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'",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -711,6 +711,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,
|
||||
@ -720,6 +721,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;
|
||||
|
@ -242,4 +242,184 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
|
||||
{
|
||||
var case = ctx.exeUsingLlvmBackend("invalid address space coercion", 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",
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
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;
|
||||
\\}
|
||||
\\pub export fn main() void { _ = entry; }
|
||||
, &[_][]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.?;
|
||||
\\}
|
||||
\\pub export fn main() void { _ = entry; }
|
||||
, &[_][]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.*;
|
||||
\\}
|
||||
\\pub export fn main() void { _ = entry; }
|
||||
, &[_][]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.*;
|
||||
\\}
|
||||
\\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; }
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
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;
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user