mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 00:26:57 +00:00
commit
1ad905c71e
@ -901,6 +901,7 @@ fn tokenizeAndPrintRaw(
|
|||||||
switch (token.tag) {
|
switch (token.tag) {
|
||||||
.eof => break,
|
.eof => break,
|
||||||
|
|
||||||
|
.keyword_addrspace,
|
||||||
.keyword_align,
|
.keyword_align,
|
||||||
.keyword_and,
|
.keyword_and,
|
||||||
.keyword_asm,
|
.keyword_asm,
|
||||||
|
@ -166,6 +166,15 @@ pub const CallingConvention = enum {
|
|||||||
SysV,
|
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
|
/// This data structure is used by the Zig language code generation and
|
||||||
/// therefore must be kept in sync with the compiler implementation.
|
/// therefore must be kept in sync with the compiler implementation.
|
||||||
pub const SourceLocation = struct {
|
pub const SourceLocation = struct {
|
||||||
@ -226,6 +235,7 @@ pub const TypeInfo = union(enum) {
|
|||||||
is_const: bool,
|
is_const: bool,
|
||||||
is_volatile: bool,
|
is_volatile: bool,
|
||||||
alignment: comptime_int,
|
alignment: comptime_int,
|
||||||
|
address_space: AddressSpace,
|
||||||
child: type,
|
child: type,
|
||||||
is_allowzero: bool,
|
is_allowzero: bool,
|
||||||
|
|
||||||
|
@ -2472,6 +2472,7 @@ fn CopyPtrAttrs(comptime source: type, comptime size: std.builtin.TypeInfo.Point
|
|||||||
.is_volatile = info.is_volatile,
|
.is_volatile = info.is_volatile,
|
||||||
.is_allowzero = info.is_allowzero,
|
.is_allowzero = info.is_allowzero,
|
||||||
.alignment = info.alignment,
|
.alignment = info.alignment,
|
||||||
|
.address_space = info.address_space,
|
||||||
.child = child,
|
.child = child,
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
},
|
},
|
||||||
@ -2960,6 +2961,7 @@ fn AlignedSlice(comptime AttributeSource: type, comptime new_alignment: u29) typ
|
|||||||
.is_volatile = info.is_volatile,
|
.is_volatile = info.is_volatile,
|
||||||
.is_allowzero = info.is_allowzero,
|
.is_allowzero = info.is_allowzero,
|
||||||
.alignment = new_alignment,
|
.alignment = new_alignment,
|
||||||
|
.address_space = info.address_space,
|
||||||
.child = info.child,
|
.child = info.child,
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
},
|
},
|
||||||
|
@ -235,6 +235,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type {
|
|||||||
.is_const = info.is_const,
|
.is_const = info.is_const,
|
||||||
.is_volatile = info.is_volatile,
|
.is_volatile = info.is_volatile,
|
||||||
.alignment = info.alignment,
|
.alignment = info.alignment,
|
||||||
|
.address_space = info.address_space,
|
||||||
.child = @Type(.{
|
.child = @Type(.{
|
||||||
.Array = .{
|
.Array = .{
|
||||||
.len = array_info.len,
|
.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_const = info.is_const,
|
||||||
.is_volatile = info.is_volatile,
|
.is_volatile = info.is_volatile,
|
||||||
.alignment = info.alignment,
|
.alignment = info.alignment,
|
||||||
|
.address_space = info.address_space,
|
||||||
.child = info.child,
|
.child = info.child,
|
||||||
.is_allowzero = info.is_allowzero,
|
.is_allowzero = info.is_allowzero,
|
||||||
.sentinel = sentinel_val,
|
.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_const = ptr_info.is_const,
|
||||||
.is_volatile = ptr_info.is_volatile,
|
.is_volatile = ptr_info.is_volatile,
|
||||||
.alignment = ptr_info.alignment,
|
.alignment = ptr_info.alignment,
|
||||||
|
.address_space = ptr_info.address_space,
|
||||||
.child = ptr_info.child,
|
.child = ptr_info.child,
|
||||||
.is_allowzero = ptr_info.is_allowzero,
|
.is_allowzero = ptr_info.is_allowzero,
|
||||||
.sentinel = sentinel_val,
|
.sentinel = sentinel_val,
|
||||||
|
@ -262,6 +262,9 @@ pub fn renderError(tree: Tree, parse_error: Error, stream: anytype) !void {
|
|||||||
token_tags[parse_error.token].symbol(),
|
token_tags[parse_error.token].symbol(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
.extra_addrspace_qualifier => {
|
||||||
|
return stream.writeAll("extra addrspace qualifier");
|
||||||
|
},
|
||||||
.extra_align_qualifier => {
|
.extra_align_qualifier => {
|
||||||
return stream.writeAll("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 => {
|
.fn_proto_one => {
|
||||||
const extra = tree.extraData(datas[n].lhs, Node.FnProtoOne);
|
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.
|
// find the last one here.
|
||||||
var max_node: Node.Index = datas[n].rhs;
|
var max_node: Node.Index = datas[n].rhs;
|
||||||
var max_start = token_starts[main_tokens[max_node]];
|
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
|
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) {
|
if (extra.section_expr != 0) {
|
||||||
const start = token_starts[main_tokens[extra.section_expr]];
|
const start = token_starts[main_tokens[extra.section_expr]];
|
||||||
if (start > max_start) {
|
if (start > max_start) {
|
||||||
@ -1055,7 +1066,7 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
|
|||||||
},
|
},
|
||||||
.fn_proto => {
|
.fn_proto => {
|
||||||
const extra = tree.extraData(datas[n].lhs, Node.FnProto);
|
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.
|
// find the last one here.
|
||||||
var max_node: Node.Index = datas[n].rhs;
|
var max_node: Node.Index = datas[n].rhs;
|
||||||
var max_start = token_starts[main_tokens[max_node]];
|
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
|
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) {
|
if (extra.section_expr != 0) {
|
||||||
const start = token_starts[main_tokens[extra.section_expr]];
|
const start = token_starts[main_tokens[extra.section_expr]];
|
||||||
if (start > max_start) {
|
if (start > max_start) {
|
||||||
@ -1138,6 +1157,7 @@ pub fn globalVarDecl(tree: Tree, node: Node.Index) full.VarDecl {
|
|||||||
return tree.fullVarDecl(.{
|
return tree.fullVarDecl(.{
|
||||||
.type_node = extra.type_node,
|
.type_node = extra.type_node,
|
||||||
.align_node = extra.align_node,
|
.align_node = extra.align_node,
|
||||||
|
.addrspace_node = extra.addrspace_node,
|
||||||
.section_node = extra.section_node,
|
.section_node = extra.section_node,
|
||||||
.init_node = data.rhs,
|
.init_node = data.rhs,
|
||||||
.mut_token = tree.nodes.items(.main_token)[node],
|
.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(.{
|
return tree.fullVarDecl(.{
|
||||||
.type_node = extra.type_node,
|
.type_node = extra.type_node,
|
||||||
.align_node = extra.align_node,
|
.align_node = extra.align_node,
|
||||||
|
.addrspace_node = 0,
|
||||||
.section_node = 0,
|
.section_node = 0,
|
||||||
.init_node = data.rhs,
|
.init_node = data.rhs,
|
||||||
.mut_token = tree.nodes.items(.main_token)[node],
|
.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(.{
|
return tree.fullVarDecl(.{
|
||||||
.type_node = data.lhs,
|
.type_node = data.lhs,
|
||||||
.align_node = 0,
|
.align_node = 0,
|
||||||
|
.addrspace_node = 0,
|
||||||
.section_node = 0,
|
.section_node = 0,
|
||||||
.init_node = data.rhs,
|
.init_node = data.rhs,
|
||||||
.mut_token = tree.nodes.items(.main_token)[node],
|
.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(.{
|
return tree.fullVarDecl(.{
|
||||||
.type_node = 0,
|
.type_node = 0,
|
||||||
.align_node = data.lhs,
|
.align_node = data.lhs,
|
||||||
|
.addrspace_node = 0,
|
||||||
.section_node = 0,
|
.section_node = 0,
|
||||||
.init_node = data.rhs,
|
.init_node = data.rhs,
|
||||||
.mut_token = tree.nodes.items(.main_token)[node],
|
.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,
|
.return_type = data.rhs,
|
||||||
.params = params,
|
.params = params,
|
||||||
.align_expr = 0,
|
.align_expr = 0,
|
||||||
|
.addrspace_expr = 0,
|
||||||
.section_expr = 0,
|
.section_expr = 0,
|
||||||
.callconv_expr = 0,
|
.callconv_expr = 0,
|
||||||
});
|
});
|
||||||
@ -1265,6 +1289,7 @@ pub fn fnProtoMulti(tree: Tree, node: Node.Index) full.FnProto {
|
|||||||
.return_type = data.rhs,
|
.return_type = data.rhs,
|
||||||
.params = params,
|
.params = params,
|
||||||
.align_expr = 0,
|
.align_expr = 0,
|
||||||
|
.addrspace_expr = 0,
|
||||||
.section_expr = 0,
|
.section_expr = 0,
|
||||||
.callconv_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,
|
.return_type = data.rhs,
|
||||||
.params = params,
|
.params = params,
|
||||||
.align_expr = extra.align_expr,
|
.align_expr = extra.align_expr,
|
||||||
|
.addrspace_expr = extra.addrspace_expr,
|
||||||
.section_expr = extra.section_expr,
|
.section_expr = extra.section_expr,
|
||||||
.callconv_expr = extra.callconv_expr,
|
.callconv_expr = extra.callconv_expr,
|
||||||
});
|
});
|
||||||
@ -1298,6 +1324,7 @@ pub fn fnProto(tree: Tree, node: Node.Index) full.FnProto {
|
|||||||
.return_type = data.rhs,
|
.return_type = data.rhs,
|
||||||
.params = params,
|
.params = params,
|
||||||
.align_expr = extra.align_expr,
|
.align_expr = extra.align_expr,
|
||||||
|
.addrspace_expr = extra.addrspace_expr,
|
||||||
.section_expr = extra.section_expr,
|
.section_expr = extra.section_expr,
|
||||||
.callconv_expr = extra.callconv_expr,
|
.callconv_expr = extra.callconv_expr,
|
||||||
});
|
});
|
||||||
@ -1453,6 +1480,7 @@ pub fn ptrTypeAligned(tree: Tree, node: Node.Index) full.PtrType {
|
|||||||
return tree.fullPtrType(.{
|
return tree.fullPtrType(.{
|
||||||
.main_token = tree.nodes.items(.main_token)[node],
|
.main_token = tree.nodes.items(.main_token)[node],
|
||||||
.align_node = data.lhs,
|
.align_node = data.lhs,
|
||||||
|
.addrspace_node = 0,
|
||||||
.sentinel = 0,
|
.sentinel = 0,
|
||||||
.bit_range_start = 0,
|
.bit_range_start = 0,
|
||||||
.bit_range_end = 0,
|
.bit_range_end = 0,
|
||||||
@ -1466,6 +1494,7 @@ pub fn ptrTypeSentinel(tree: Tree, node: Node.Index) full.PtrType {
|
|||||||
return tree.fullPtrType(.{
|
return tree.fullPtrType(.{
|
||||||
.main_token = tree.nodes.items(.main_token)[node],
|
.main_token = tree.nodes.items(.main_token)[node],
|
||||||
.align_node = 0,
|
.align_node = 0,
|
||||||
|
.addrspace_node = 0,
|
||||||
.sentinel = data.lhs,
|
.sentinel = data.lhs,
|
||||||
.bit_range_start = 0,
|
.bit_range_start = 0,
|
||||||
.bit_range_end = 0,
|
.bit_range_end = 0,
|
||||||
@ -1480,6 +1509,7 @@ pub fn ptrType(tree: Tree, node: Node.Index) full.PtrType {
|
|||||||
return tree.fullPtrType(.{
|
return tree.fullPtrType(.{
|
||||||
.main_token = tree.nodes.items(.main_token)[node],
|
.main_token = tree.nodes.items(.main_token)[node],
|
||||||
.align_node = extra.align_node,
|
.align_node = extra.align_node,
|
||||||
|
.addrspace_node = extra.addrspace_node,
|
||||||
.sentinel = extra.sentinel,
|
.sentinel = extra.sentinel,
|
||||||
.bit_range_start = 0,
|
.bit_range_start = 0,
|
||||||
.bit_range_end = 0,
|
.bit_range_end = 0,
|
||||||
@ -1494,6 +1524,7 @@ pub fn ptrTypeBitRange(tree: Tree, node: Node.Index) full.PtrType {
|
|||||||
return tree.fullPtrType(.{
|
return tree.fullPtrType(.{
|
||||||
.main_token = tree.nodes.items(.main_token)[node],
|
.main_token = tree.nodes.items(.main_token)[node],
|
||||||
.align_node = extra.align_node,
|
.align_node = extra.align_node,
|
||||||
|
.addrspace_node = extra.addrspace_node,
|
||||||
.sentinel = extra.sentinel,
|
.sentinel = extra.sentinel,
|
||||||
.bit_range_start = extra.bit_range_start,
|
.bit_range_start = extra.bit_range_start,
|
||||||
.bit_range_end = extra.bit_range_end,
|
.bit_range_end = extra.bit_range_end,
|
||||||
@ -2063,6 +2094,7 @@ pub const full = struct {
|
|||||||
mut_token: TokenIndex,
|
mut_token: TokenIndex,
|
||||||
type_node: Node.Index,
|
type_node: Node.Index,
|
||||||
align_node: Node.Index,
|
align_node: Node.Index,
|
||||||
|
addrspace_node: Node.Index,
|
||||||
section_node: Node.Index,
|
section_node: Node.Index,
|
||||||
init_node: Node.Index,
|
init_node: Node.Index,
|
||||||
};
|
};
|
||||||
@ -2130,6 +2162,7 @@ pub const full = struct {
|
|||||||
return_type: Node.Index,
|
return_type: Node.Index,
|
||||||
params: []const Node.Index,
|
params: []const Node.Index,
|
||||||
align_expr: Node.Index,
|
align_expr: Node.Index,
|
||||||
|
addrspace_expr: Node.Index,
|
||||||
section_expr: Node.Index,
|
section_expr: Node.Index,
|
||||||
callconv_expr: Node.Index,
|
callconv_expr: Node.Index,
|
||||||
};
|
};
|
||||||
@ -2288,6 +2321,7 @@ pub const full = struct {
|
|||||||
pub const Components = struct {
|
pub const Components = struct {
|
||||||
main_token: TokenIndex,
|
main_token: TokenIndex,
|
||||||
align_node: Node.Index,
|
align_node: Node.Index,
|
||||||
|
addrspace_node: Node.Index,
|
||||||
sentinel: Node.Index,
|
sentinel: Node.Index,
|
||||||
bit_range_start: Node.Index,
|
bit_range_start: Node.Index,
|
||||||
bit_range_end: Node.Index,
|
bit_range_end: Node.Index,
|
||||||
@ -2397,6 +2431,7 @@ pub const Error = struct {
|
|||||||
expected_var_decl_or_fn,
|
expected_var_decl_or_fn,
|
||||||
expected_loop_payload,
|
expected_loop_payload,
|
||||||
expected_container,
|
expected_container,
|
||||||
|
extra_addrspace_qualifier,
|
||||||
extra_align_qualifier,
|
extra_align_qualifier,
|
||||||
extra_allowzero_qualifier,
|
extra_allowzero_qualifier,
|
||||||
extra_const_qualifier,
|
extra_const_qualifier,
|
||||||
@ -2723,13 +2758,13 @@ pub const Node = struct {
|
|||||||
/// main_token is the `fn` keyword.
|
/// main_token is the `fn` keyword.
|
||||||
/// extern function declarations use this tag.
|
/// extern function declarations use this tag.
|
||||||
fn_proto_multi,
|
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.
|
/// zero or one parameters.
|
||||||
/// anytype and ... parameters are omitted from the AST tree.
|
/// anytype and ... parameters are omitted from the AST tree.
|
||||||
/// main_token is the `fn` keyword.
|
/// main_token is the `fn` keyword.
|
||||||
/// extern function declarations use this tag.
|
/// extern function declarations use this tag.
|
||||||
fn_proto_one,
|
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.
|
/// anytype and ... parameters are omitted from the AST tree.
|
||||||
/// main_token is the `fn` keyword.
|
/// main_token is the `fn` keyword.
|
||||||
/// extern function declarations use this tag.
|
/// extern function declarations use this tag.
|
||||||
@ -2893,11 +2928,13 @@ pub const Node = struct {
|
|||||||
pub const PtrType = struct {
|
pub const PtrType = struct {
|
||||||
sentinel: Index,
|
sentinel: Index,
|
||||||
align_node: Index,
|
align_node: Index,
|
||||||
|
addrspace_node: Index,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const PtrTypeBitRange = struct {
|
pub const PtrTypeBitRange = struct {
|
||||||
sentinel: Index,
|
sentinel: Index,
|
||||||
align_node: Index,
|
align_node: Index,
|
||||||
|
addrspace_node: Index,
|
||||||
bit_range_start: Index,
|
bit_range_start: Index,
|
||||||
bit_range_end: Index,
|
bit_range_end: Index,
|
||||||
};
|
};
|
||||||
@ -2920,8 +2957,13 @@ pub const Node = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const GlobalVarDecl = struct {
|
pub const GlobalVarDecl = struct {
|
||||||
|
/// Populated if there is an explicit type ascription.
|
||||||
type_node: Index,
|
type_node: Index,
|
||||||
|
/// Populated if align(A) is present.
|
||||||
align_node: Index,
|
align_node: Index,
|
||||||
|
/// Populated if addrspace(A) is present.
|
||||||
|
addrspace_node: Index,
|
||||||
|
/// Populated if linksection(A) is present.
|
||||||
section_node: Index,
|
section_node: Index,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2953,6 +2995,8 @@ pub const Node = struct {
|
|||||||
param: Index,
|
param: Index,
|
||||||
/// Populated if align(A) is present.
|
/// Populated if align(A) is present.
|
||||||
align_expr: Index,
|
align_expr: Index,
|
||||||
|
/// Populated if addrspace(A) is present.
|
||||||
|
addrspace_expr: Index,
|
||||||
/// Populated if linksection(A) is present.
|
/// Populated if linksection(A) is present.
|
||||||
section_expr: Index,
|
section_expr: Index,
|
||||||
/// Populated if callconv(A) is present.
|
/// Populated if callconv(A) is present.
|
||||||
@ -2964,6 +3008,8 @@ pub const Node = struct {
|
|||||||
params_end: Index,
|
params_end: Index,
|
||||||
/// Populated if align(A) is present.
|
/// Populated if align(A) is present.
|
||||||
align_expr: Index,
|
align_expr: Index,
|
||||||
|
/// Populated if addrspace(A) is present.
|
||||||
|
addrspace_expr: Index,
|
||||||
/// Populated if linksection(A) is present.
|
/// Populated if linksection(A) is present.
|
||||||
section_expr: Index,
|
section_expr: Index,
|
||||||
/// Populated if callconv(A) is present.
|
/// 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_const = ptr.is_const,
|
||||||
.is_volatile = ptr.is_volatile,
|
.is_volatile = ptr.is_volatile,
|
||||||
.alignment = @alignOf(ElementType),
|
.alignment = @alignOf(ElementType),
|
||||||
|
.address_space = .generic,
|
||||||
.child = ElementType,
|
.child = ElementType,
|
||||||
.is_allowzero = true,
|
.is_allowzero = true,
|
||||||
.sentinel = null,
|
.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 {
|
fn parseFnProto(p: *Parser) !Node.Index {
|
||||||
const fn_token = p.eatToken(.keyword_fn) orelse return null_node;
|
const fn_token = p.eatToken(.keyword_fn) orelse return null_node;
|
||||||
|
|
||||||
@ -639,6 +639,7 @@ const Parser = struct {
|
|||||||
_ = p.eatToken(.identifier);
|
_ = p.eatToken(.identifier);
|
||||||
const params = try p.parseParamDeclList();
|
const params = try p.parseParamDeclList();
|
||||||
const align_expr = try p.parseByteAlign();
|
const align_expr = try p.parseByteAlign();
|
||||||
|
const addrspace_expr = try p.parseAddrSpace();
|
||||||
const section_expr = try p.parseLinkSection();
|
const section_expr = try p.parseLinkSection();
|
||||||
const callconv_expr = try p.parseCallconv();
|
const callconv_expr = try p.parseCallconv();
|
||||||
_ = p.eatToken(.bang);
|
_ = p.eatToken(.bang);
|
||||||
@ -650,7 +651,7 @@ const Parser = struct {
|
|||||||
try p.warn(.expected_return_type);
|
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) {
|
switch (params) {
|
||||||
.zero_or_one => |param| return p.setNode(fn_proto_index, .{
|
.zero_or_one => |param| return p.setNode(fn_proto_index, .{
|
||||||
.tag = .fn_proto_simple,
|
.tag = .fn_proto_simple,
|
||||||
@ -683,6 +684,7 @@ const Parser = struct {
|
|||||||
.lhs = try p.addExtra(Node.FnProtoOne{
|
.lhs = try p.addExtra(Node.FnProtoOne{
|
||||||
.param = param,
|
.param = param,
|
||||||
.align_expr = align_expr,
|
.align_expr = align_expr,
|
||||||
|
.addrspace_expr = addrspace_expr,
|
||||||
.section_expr = section_expr,
|
.section_expr = section_expr,
|
||||||
.callconv_expr = callconv_expr,
|
.callconv_expr = callconv_expr,
|
||||||
}),
|
}),
|
||||||
@ -698,6 +700,7 @@ const Parser = struct {
|
|||||||
.params_start = span.start,
|
.params_start = span.start,
|
||||||
.params_end = span.end,
|
.params_end = span.end,
|
||||||
.align_expr = align_expr,
|
.align_expr = align_expr,
|
||||||
|
.addrspace_expr = addrspace_expr,
|
||||||
.section_expr = section_expr,
|
.section_expr = section_expr,
|
||||||
.callconv_expr = callconv_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 {
|
fn parseVarDecl(p: *Parser) !Node.Index {
|
||||||
const mut_token = p.eatToken(.keyword_const) orelse
|
const mut_token = p.eatToken(.keyword_const) orelse
|
||||||
p.eatToken(.keyword_var) orelse
|
p.eatToken(.keyword_var) orelse
|
||||||
@ -717,9 +720,10 @@ const Parser = struct {
|
|||||||
_ = try p.expectToken(.identifier);
|
_ = try p.expectToken(.identifier);
|
||||||
const type_node: Node.Index = if (p.eatToken(.colon) == null) 0 else try p.expectTypeExpr();
|
const type_node: Node.Index = if (p.eatToken(.colon) == null) 0 else try p.expectTypeExpr();
|
||||||
const align_node = try p.parseByteAlign();
|
const align_node = try p.parseByteAlign();
|
||||||
|
const addrspace_node = try p.parseAddrSpace();
|
||||||
const section_node = try p.parseLinkSection();
|
const section_node = try p.parseLinkSection();
|
||||||
const init_node: Node.Index = if (p.eatToken(.equal) == null) 0 else try p.expectExpr();
|
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) {
|
if (align_node == 0) {
|
||||||
return p.addNode(.{
|
return p.addNode(.{
|
||||||
.tag = .simple_var_decl,
|
.tag = .simple_var_decl,
|
||||||
@ -759,6 +763,7 @@ const Parser = struct {
|
|||||||
.lhs = try p.addExtra(Node.GlobalVarDecl{
|
.lhs = try p.addExtra(Node.GlobalVarDecl{
|
||||||
.type_node = type_node,
|
.type_node = type_node,
|
||||||
.align_node = align_node,
|
.align_node = align_node,
|
||||||
|
.addrspace_node = addrspace_node,
|
||||||
.section_node = section_node,
|
.section_node = section_node,
|
||||||
}),
|
}),
|
||||||
.rhs = init_node,
|
.rhs = init_node,
|
||||||
@ -1440,8 +1445,8 @@ const Parser = struct {
|
|||||||
/// PrefixTypeOp
|
/// PrefixTypeOp
|
||||||
/// <- QUESTIONMARK
|
/// <- QUESTIONMARK
|
||||||
/// / KEYWORD_anyframe MINUSRARROW
|
/// / KEYWORD_anyframe MINUSRARROW
|
||||||
/// / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
/// / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
||||||
/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
/// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
||||||
/// / ArrayTypeStart
|
/// / ArrayTypeStart
|
||||||
/// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
|
/// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
|
||||||
/// PtrTypeStart
|
/// PtrTypeStart
|
||||||
@ -1474,16 +1479,7 @@ const Parser = struct {
|
|||||||
const asterisk = p.nextToken();
|
const asterisk = p.nextToken();
|
||||||
const mods = try p.parsePtrModifiers();
|
const mods = try p.parsePtrModifiers();
|
||||||
const elem_type = try p.expectTypeExpr();
|
const elem_type = try p.expectTypeExpr();
|
||||||
if (mods.bit_range_start == 0) {
|
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 {
|
|
||||||
return p.addNode(.{
|
return p.addNode(.{
|
||||||
.tag = .ptr_type_bit_range,
|
.tag = .ptr_type_bit_range,
|
||||||
.main_token = asterisk,
|
.main_token = asterisk,
|
||||||
@ -1491,12 +1487,35 @@ const Parser = struct {
|
|||||||
.lhs = try p.addExtra(Node.PtrTypeBitRange{
|
.lhs = try p.addExtra(Node.PtrTypeBitRange{
|
||||||
.sentinel = 0,
|
.sentinel = 0,
|
||||||
.align_node = mods.align_node,
|
.align_node = mods.align_node,
|
||||||
|
.addrspace_node = mods.addrspace_node,
|
||||||
.bit_range_start = mods.bit_range_start,
|
.bit_range_start = mods.bit_range_start,
|
||||||
.bit_range_end = mods.bit_range_end,
|
.bit_range_end = mods.bit_range_end,
|
||||||
}),
|
}),
|
||||||
.rhs = elem_type,
|
.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 => {
|
.asterisk_asterisk => {
|
||||||
@ -1504,16 +1523,7 @@ const Parser = struct {
|
|||||||
const mods = try p.parsePtrModifiers();
|
const mods = try p.parsePtrModifiers();
|
||||||
const elem_type = try p.expectTypeExpr();
|
const elem_type = try p.expectTypeExpr();
|
||||||
const inner: Node.Index = inner: {
|
const inner: Node.Index = inner: {
|
||||||
if (mods.bit_range_start == 0) {
|
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 {
|
|
||||||
break :inner try p.addNode(.{
|
break :inner try p.addNode(.{
|
||||||
.tag = .ptr_type_bit_range,
|
.tag = .ptr_type_bit_range,
|
||||||
.main_token = asterisk,
|
.main_token = asterisk,
|
||||||
@ -1521,12 +1531,35 @@ const Parser = struct {
|
|||||||
.lhs = try p.addExtra(Node.PtrTypeBitRange{
|
.lhs = try p.addExtra(Node.PtrTypeBitRange{
|
||||||
.sentinel = 0,
|
.sentinel = 0,
|
||||||
.align_node = mods.align_node,
|
.align_node = mods.align_node,
|
||||||
|
.addrspace_node = mods.addrspace_node,
|
||||||
.bit_range_start = mods.bit_range_start,
|
.bit_range_start = mods.bit_range_start,
|
||||||
.bit_range_end = mods.bit_range_end,
|
.bit_range_end = mods.bit_range_end,
|
||||||
}),
|
}),
|
||||||
.rhs = elem_type,
|
.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(.{
|
return p.addNode(.{
|
||||||
@ -1560,7 +1593,7 @@ const Parser = struct {
|
|||||||
const mods = try p.parsePtrModifiers();
|
const mods = try p.parsePtrModifiers();
|
||||||
const elem_type = try p.expectTypeExpr();
|
const elem_type = try p.expectTypeExpr();
|
||||||
if (mods.bit_range_start == 0) {
|
if (mods.bit_range_start == 0) {
|
||||||
if (sentinel == 0) {
|
if (sentinel == 0 and mods.addrspace_node == 0) {
|
||||||
return p.addNode(.{
|
return p.addNode(.{
|
||||||
.tag = .ptr_type_aligned,
|
.tag = .ptr_type_aligned,
|
||||||
.main_token = asterisk,
|
.main_token = asterisk,
|
||||||
@ -1569,7 +1602,7 @@ const Parser = struct {
|
|||||||
.rhs = elem_type,
|
.rhs = elem_type,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (mods.align_node == 0) {
|
} else if (mods.align_node == 0 and mods.addrspace_node == 0) {
|
||||||
return p.addNode(.{
|
return p.addNode(.{
|
||||||
.tag = .ptr_type_sentinel,
|
.tag = .ptr_type_sentinel,
|
||||||
.main_token = asterisk,
|
.main_token = asterisk,
|
||||||
@ -1586,6 +1619,7 @@ const Parser = struct {
|
|||||||
.lhs = try p.addExtra(Node.PtrType{
|
.lhs = try p.addExtra(Node.PtrType{
|
||||||
.sentinel = sentinel,
|
.sentinel = sentinel,
|
||||||
.align_node = mods.align_node,
|
.align_node = mods.align_node,
|
||||||
|
.addrspace_node = mods.addrspace_node,
|
||||||
}),
|
}),
|
||||||
.rhs = elem_type,
|
.rhs = elem_type,
|
||||||
},
|
},
|
||||||
@ -1599,6 +1633,7 @@ const Parser = struct {
|
|||||||
.lhs = try p.addExtra(Node.PtrTypeBitRange{
|
.lhs = try p.addExtra(Node.PtrTypeBitRange{
|
||||||
.sentinel = sentinel,
|
.sentinel = sentinel,
|
||||||
.align_node = mods.align_node,
|
.align_node = mods.align_node,
|
||||||
|
.addrspace_node = mods.addrspace_node,
|
||||||
.bit_range_start = mods.bit_range_start,
|
.bit_range_start = mods.bit_range_start,
|
||||||
.bit_range_end = mods.bit_range_end,
|
.bit_range_end = mods.bit_range_end,
|
||||||
}),
|
}),
|
||||||
@ -1624,7 +1659,7 @@ const Parser = struct {
|
|||||||
.token = p.nodes.items(.main_token)[mods.bit_range_start],
|
.token = p.nodes.items(.main_token)[mods.bit_range_start],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (sentinel == 0) {
|
if (sentinel == 0 and mods.addrspace_node == 0) {
|
||||||
return p.addNode(.{
|
return p.addNode(.{
|
||||||
.tag = .ptr_type_aligned,
|
.tag = .ptr_type_aligned,
|
||||||
.main_token = lbracket,
|
.main_token = lbracket,
|
||||||
@ -1633,7 +1668,7 @@ const Parser = struct {
|
|||||||
.rhs = elem_type,
|
.rhs = elem_type,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (mods.align_node == 0) {
|
} else if (mods.align_node == 0 and mods.addrspace_node == 0) {
|
||||||
return p.addNode(.{
|
return p.addNode(.{
|
||||||
.tag = .ptr_type_sentinel,
|
.tag = .ptr_type_sentinel,
|
||||||
.main_token = lbracket,
|
.main_token = lbracket,
|
||||||
@ -1650,6 +1685,7 @@ const Parser = struct {
|
|||||||
.lhs = try p.addExtra(Node.PtrType{
|
.lhs = try p.addExtra(Node.PtrType{
|
||||||
.sentinel = sentinel,
|
.sentinel = sentinel,
|
||||||
.align_node = mods.align_node,
|
.align_node = mods.align_node,
|
||||||
|
.addrspace_node = mods.addrspace_node,
|
||||||
}),
|
}),
|
||||||
.rhs = elem_type,
|
.rhs = elem_type,
|
||||||
},
|
},
|
||||||
@ -1661,6 +1697,7 @@ const Parser = struct {
|
|||||||
.keyword_const,
|
.keyword_const,
|
||||||
.keyword_volatile,
|
.keyword_volatile,
|
||||||
.keyword_allowzero,
|
.keyword_allowzero,
|
||||||
|
.keyword_addrspace,
|
||||||
=> return p.fail(.ptr_mod_on_array_child_type),
|
=> return p.fail(.ptr_mod_on_array_child_type),
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
@ -2879,6 +2916,15 @@ const Parser = struct {
|
|||||||
return expr_node;
|
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
|
/// ParamDecl
|
||||||
/// <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
|
/// <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
|
||||||
/// / DOT3
|
/// / DOT3
|
||||||
@ -3011,6 +3057,7 @@ const Parser = struct {
|
|||||||
|
|
||||||
const PtrModifiers = struct {
|
const PtrModifiers = struct {
|
||||||
align_node: Node.Index,
|
align_node: Node.Index,
|
||||||
|
addrspace_node: Node.Index,
|
||||||
bit_range_start: Node.Index,
|
bit_range_start: Node.Index,
|
||||||
bit_range_end: Node.Index,
|
bit_range_end: Node.Index,
|
||||||
};
|
};
|
||||||
@ -3018,12 +3065,14 @@ const Parser = struct {
|
|||||||
fn parsePtrModifiers(p: *Parser) !PtrModifiers {
|
fn parsePtrModifiers(p: *Parser) !PtrModifiers {
|
||||||
var result: PtrModifiers = .{
|
var result: PtrModifiers = .{
|
||||||
.align_node = 0,
|
.align_node = 0,
|
||||||
|
.addrspace_node = 0,
|
||||||
.bit_range_start = 0,
|
.bit_range_start = 0,
|
||||||
.bit_range_end = 0,
|
.bit_range_end = 0,
|
||||||
};
|
};
|
||||||
var saw_const = false;
|
var saw_const = false;
|
||||||
var saw_volatile = false;
|
var saw_volatile = false;
|
||||||
var saw_allowzero = false;
|
var saw_allowzero = false;
|
||||||
|
var saw_addrspace = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (p.token_tags[p.tok_i]) {
|
switch (p.token_tags[p.tok_i]) {
|
||||||
.keyword_align => {
|
.keyword_align => {
|
||||||
@ -3063,6 +3112,12 @@ const Parser = struct {
|
|||||||
p.tok_i += 1;
|
p.tok_i += 1;
|
||||||
saw_allowzero = true;
|
saw_allowzero = true;
|
||||||
},
|
},
|
||||||
|
.keyword_addrspace => {
|
||||||
|
if (saw_addrspace) {
|
||||||
|
try p.warn(.extra_addrspace_qualifier);
|
||||||
|
}
|
||||||
|
result.addrspace_node = try p.parseAddrSpace();
|
||||||
|
},
|
||||||
else => return result,
|
else => return result,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,6 +404,10 @@ test "zig fmt: trailing comma in fn parameter list" {
|
|||||||
\\pub fn f(
|
\\pub fn f(
|
||||||
\\ a: i32,
|
\\ a: i32,
|
||||||
\\ b: i32,
|
\\ b: i32,
|
||||||
|
\\) addrspace(.generic) i32 {}
|
||||||
|
\\pub fn f(
|
||||||
|
\\ a: i32,
|
||||||
|
\\ b: i32,
|
||||||
\\) linksection(".text") i32 {}
|
\\) linksection(".text") i32 {}
|
||||||
\\pub fn f(
|
\\pub fn f(
|
||||||
\\ a: i32,
|
\\ a: i32,
|
||||||
@ -553,8 +557,8 @@ test "zig fmt: sentinel-terminated slice type" {
|
|||||||
test "zig fmt: pointer-to-one with modifiers" {
|
test "zig fmt: pointer-to-one with modifiers" {
|
||||||
try testCanonical(
|
try testCanonical(
|
||||||
\\const x: *u32 = undefined;
|
\\const x: *u32 = undefined;
|
||||||
\\const y: *allowzero align(8) const volatile u32 = undefined;
|
\\const y: *allowzero align(8) addrspace(.generic) const volatile u32 = undefined;
|
||||||
\\const z: *allowzero align(8:4:2) 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" {
|
test "zig fmt: pointer-to-many with modifiers" {
|
||||||
try testCanonical(
|
try testCanonical(
|
||||||
\\const x: [*]u32 = undefined;
|
\\const x: [*]u32 = undefined;
|
||||||
\\const y: [*]allowzero align(8) const volatile u32 = undefined;
|
\\const y: [*]allowzero align(8) addrspace(.generic) const volatile u32 = undefined;
|
||||||
\\const z: [*]allowzero align(8:4:2) 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" {
|
test "zig fmt: sentinel pointer with modifiers" {
|
||||||
try testCanonical(
|
try testCanonical(
|
||||||
\\const x: [*:42]u32 = undefined;
|
\\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;
|
||||||
\\const y: [*:42]allowzero align(8:4:2) 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" {
|
test "zig fmt: c pointer with modifiers" {
|
||||||
try testCanonical(
|
try testCanonical(
|
||||||
\\const x: [*c]u32 = undefined;
|
\\const x: [*c]u32 = undefined;
|
||||||
\\const y: [*c]allowzero align(8) const volatile u32 = undefined;
|
\\const y: [*c]allowzero align(8) addrspace(.generic) const volatile u32 = undefined;
|
||||||
\\const z: [*c]allowzero align(8:4:2) 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" {
|
test "zig fmt: slice with modifiers" {
|
||||||
try testCanonical(
|
try testCanonical(
|
||||||
\\const x: []u32 = undefined;
|
\\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" {
|
test "zig fmt: sentinel slice with modifiers" {
|
||||||
try testCanonical(
|
try testCanonical(
|
||||||
\\const x: [:42]u32 = undefined;
|
\\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" {
|
test "zig fmt: correctly space struct fields with doc comments" {
|
||||||
try testTransform(
|
try testTransform(
|
||||||
\\pub const S = struct {
|
\\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| {
|
if (ptr_type.const_token) |const_token| {
|
||||||
try renderToken(ais, tree, const_token, .space);
|
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
|
const name_space = if (var_decl.ast.type_node == 0 and
|
||||||
(var_decl.ast.align_node != 0 or
|
(var_decl.ast.align_node != 0 or
|
||||||
|
var_decl.ast.addrspace_node != 0 or
|
||||||
var_decl.ast.section_node != 0 or
|
var_decl.ast.section_node != 0 or
|
||||||
var_decl.ast.init_node != 0))
|
var_decl.ast.init_node != 0))
|
||||||
Space.space
|
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) {
|
if (var_decl.ast.type_node != 0) {
|
||||||
try renderToken(ais, tree, var_decl.ast.mut_token + 2, Space.space); // :
|
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
|
if (var_decl.ast.align_node != 0 or var_decl.ast.addrspace_node != 0 or
|
||||||
var_decl.ast.init_node != 0)
|
var_decl.ast.section_node != 0 or var_decl.ast.init_node != 0)
|
||||||
{
|
{
|
||||||
try renderExpression(gpa, ais, tree, var_decl.ast.type_node, .space);
|
try renderExpression(gpa, ais, tree, var_decl.ast.type_node, .space);
|
||||||
} else {
|
} 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, align_kw, Space.none); // align
|
||||||
try renderToken(ais, tree, lparen, Space.none); // (
|
try renderToken(ais, tree, lparen, Space.none); // (
|
||||||
try renderExpression(gpa, ais, tree, var_decl.ast.align_node, 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) {
|
if (var_decl.ast.section_node != 0 or var_decl.ast.init_node != 0) {
|
||||||
try renderToken(ais, tree, rparen, .space); // )
|
try renderToken(ais, tree, rparen, .space); // )
|
||||||
} else {
|
} else {
|
||||||
@ -1267,6 +1293,14 @@ fn renderFnProto(gpa: *Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnPro
|
|||||||
smallest_start = start;
|
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) {
|
if (fn_proto.ast.section_expr != 0) {
|
||||||
const tok = tree.firstToken(fn_proto.ast.section_expr) - 3;
|
const tok = tree.firstToken(fn_proto.ast.section_expr) - 3;
|
||||||
const start = token_starts[tok];
|
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); // )
|
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) {
|
if (fn_proto.ast.section_expr != 0) {
|
||||||
const section_lparen = tree.firstToken(fn_proto.ast.section_expr) - 1;
|
const section_lparen = tree.firstToken(fn_proto.ast.section_expr) - 1;
|
||||||
const section_rparen = tree.lastToken(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, .{
|
pub const keywords = std.ComptimeStringMap(Tag, .{
|
||||||
|
.{ "addrspace", .keyword_addrspace },
|
||||||
.{ "align", .keyword_align },
|
.{ "align", .keyword_align },
|
||||||
.{ "allowzero", .keyword_allowzero },
|
.{ "allowzero", .keyword_allowzero },
|
||||||
.{ "and", .keyword_and },
|
.{ "and", .keyword_and },
|
||||||
@ -132,6 +133,7 @@ pub const Token = struct {
|
|||||||
float_literal,
|
float_literal,
|
||||||
doc_comment,
|
doc_comment,
|
||||||
container_doc_comment,
|
container_doc_comment,
|
||||||
|
keyword_addrspace,
|
||||||
keyword_align,
|
keyword_align,
|
||||||
keyword_allowzero,
|
keyword_allowzero,
|
||||||
keyword_and,
|
keyword_and,
|
||||||
@ -251,6 +253,7 @@ pub const Token = struct {
|
|||||||
.angle_bracket_angle_bracket_right => ">>",
|
.angle_bracket_angle_bracket_right => ">>",
|
||||||
.angle_bracket_angle_bracket_right_equal => ">>=",
|
.angle_bracket_angle_bracket_right_equal => ">>=",
|
||||||
.tilde => "~",
|
.tilde => "~",
|
||||||
|
.keyword_addrspace => "addrspace",
|
||||||
.keyword_align => "align",
|
.keyword_align => "align",
|
||||||
.keyword_allowzero => "allowzero",
|
.keyword_allowzero => "allowzero",
|
||||||
.keyword_and => "and",
|
.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: {
|
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);
|
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) {
|
if (fn_proto.ast.section_expr != 0) {
|
||||||
return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{});
|
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 gpa = astgen.gpa;
|
||||||
const tree = astgen.tree;
|
const tree = astgen.tree;
|
||||||
const token_tags = tree.tokens.items(.tag);
|
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 name_token = var_decl.ast.mut_token + 1;
|
||||||
const ident_name_raw = tree.tokenSlice(name_token);
|
const ident_name_raw = tree.tokenSlice(name_token);
|
||||||
@ -2385,6 +2391,14 @@ fn varDecl(
|
|||||||
return astgen.failNode(node, "variables must be initialized", .{});
|
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)
|
const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node != 0)
|
||||||
try expr(gz, scope, align_rl, var_decl.ast.align_node)
|
try expr(gz, scope, align_rl, var_decl.ast.align_node)
|
||||||
else
|
else
|
||||||
@ -2714,6 +2728,7 @@ fn ptrType(
|
|||||||
const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type);
|
const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type);
|
||||||
|
|
||||||
const simple = ptr_info.ast.align_node == 0 and
|
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.sentinel == 0 and
|
||||||
ptr_info.ast.bit_range_start == 0;
|
ptr_info.ast.bit_range_start == 0;
|
||||||
|
|
||||||
@ -2732,6 +2747,7 @@ fn ptrType(
|
|||||||
|
|
||||||
var sentinel_ref: Zir.Inst.Ref = .none;
|
var sentinel_ref: Zir.Inst.Ref = .none;
|
||||||
var align_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_start_ref: Zir.Inst.Ref = .none;
|
||||||
var bit_end_ref: Zir.Inst.Ref = .none;
|
var bit_end_ref: Zir.Inst.Ref = .none;
|
||||||
var trailing_count: u32 = 0;
|
var trailing_count: u32 = 0;
|
||||||
@ -2744,6 +2760,10 @@ fn ptrType(
|
|||||||
align_ref = try expr(gz, scope, align_rl, ptr_info.ast.align_node);
|
align_ref = try expr(gz, scope, align_rl, ptr_info.ast.align_node);
|
||||||
trailing_count += 1;
|
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) {
|
if (ptr_info.ast.bit_range_start != 0) {
|
||||||
assert(ptr_info.ast.bit_range_end != 0);
|
assert(ptr_info.ast.bit_range_end != 0);
|
||||||
bit_start_ref = try expr(gz, scope, .none, ptr_info.ast.bit_range_start);
|
bit_start_ref = try expr(gz, scope, .none, ptr_info.ast.bit_range_start);
|
||||||
@ -2764,6 +2784,9 @@ fn ptrType(
|
|||||||
if (align_ref != .none) {
|
if (align_ref != .none) {
|
||||||
gz.astgen.extra.appendAssumeCapacity(@enumToInt(align_ref));
|
gz.astgen.extra.appendAssumeCapacity(@enumToInt(align_ref));
|
||||||
}
|
}
|
||||||
|
if (addrspace_ref != .none) {
|
||||||
|
gz.astgen.extra.appendAssumeCapacity(@enumToInt(addrspace_ref));
|
||||||
|
}
|
||||||
if (bit_start_ref != .none) {
|
if (bit_start_ref != .none) {
|
||||||
gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_start_ref));
|
gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_start_ref));
|
||||||
gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_end_ref));
|
gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_end_ref));
|
||||||
@ -2779,6 +2802,7 @@ fn ptrType(
|
|||||||
.is_volatile = ptr_info.volatile_token != null,
|
.is_volatile = ptr_info.volatile_token != null,
|
||||||
.has_sentinel = sentinel_ref != .none,
|
.has_sentinel = sentinel_ref != .none,
|
||||||
.has_align = align_ref != .none,
|
.has_align = align_ref != .none,
|
||||||
|
.has_addrspace = addrspace_ref != .none,
|
||||||
.has_bit_range = bit_start_ref != .none,
|
.has_bit_range = bit_start_ref != .none,
|
||||||
},
|
},
|
||||||
.size = ptr_info.size,
|
.size = ptr_info.size,
|
||||||
@ -2847,7 +2871,7 @@ const WipDecls = struct {
|
|||||||
is_pub: bool,
|
is_pub: bool,
|
||||||
is_export: bool,
|
is_export: bool,
|
||||||
has_align: bool,
|
has_align: bool,
|
||||||
has_section: bool,
|
has_section_or_addrspace: bool,
|
||||||
) Allocator.Error!void {
|
) Allocator.Error!void {
|
||||||
if (wip_decls.decl_index % fields_per_u32 == 0 and wip_decls.decl_index != 0) {
|
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);
|
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_pub)) << 28) |
|
||||||
(@as(u32, @boolToInt(is_export)) << 29) |
|
(@as(u32, @boolToInt(is_export)) << 29) |
|
||||||
(@as(u32, @boolToInt(has_align)) << 30) |
|
(@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;
|
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;
|
const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false;
|
||||||
break :blk token_tags[maybe_inline_token] == .keyword_inline;
|
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;
|
var params_scope = &fn_gz.base;
|
||||||
const is_var_args = is_var_args: {
|
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: {
|
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);
|
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: {
|
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);
|
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.addBreak(.break_inline, block_inst, func_inst);
|
||||||
try decl_gz.setBlockBody(block_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 contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
|
||||||
const casted = @bitCast([4]u32, contents_hash);
|
const casted = @bitCast([4]u32, contents_hash);
|
||||||
@ -3127,8 +3155,10 @@ fn fnDecl(
|
|||||||
if (align_inst != .none) {
|
if (align_inst != .none) {
|
||||||
wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst));
|
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(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: {
|
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);
|
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: {
|
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);
|
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: {
|
const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: {
|
||||||
if (!is_mutable) {
|
if (!is_mutable) {
|
||||||
@ -3256,7 +3290,7 @@ fn globalVarDecl(
|
|||||||
_ = try block_scope.addBreak(.break_inline, block_inst, var_inst);
|
_ = try block_scope.addBreak(.break_inline, block_inst, var_inst);
|
||||||
try block_scope.setBlockBody(block_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 contents_hash = std.zig.hashSrc(tree.getNodeSource(node));
|
||||||
const casted = @bitCast([4]u32, contents_hash);
|
const casted = @bitCast([4]u32, contents_hash);
|
||||||
@ -3271,8 +3305,9 @@ fn globalVarDecl(
|
|||||||
if (align_inst != .none) {
|
if (align_inst != .none) {
|
||||||
wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst));
|
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(section_inst));
|
||||||
|
wip_decls.payload.appendAssumeCapacity(@enumToInt(addrspace_inst));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
139
src/Module.zig
139
src/Module.zig
@ -288,6 +288,8 @@ pub const Decl = struct {
|
|||||||
align_val: Value,
|
align_val: Value,
|
||||||
/// Populated when `has_tv`.
|
/// Populated when `has_tv`.
|
||||||
linksection_val: Value,
|
linksection_val: Value,
|
||||||
|
/// Populated when `has_tv`.
|
||||||
|
@"addrspace": std.builtin.AddressSpace,
|
||||||
/// The memory for ty, val, align_val, linksection_val.
|
/// The memory for ty, val, align_val, linksection_val.
|
||||||
/// If this is `null` then there is no memory management needed.
|
/// If this is `null` then there is no memory management needed.
|
||||||
value_arena: ?*std.heap.ArenaAllocator.State = null,
|
value_arena: ?*std.heap.ArenaAllocator.State = null,
|
||||||
@ -351,7 +353,7 @@ pub const Decl = struct {
|
|||||||
/// to require re-analysis.
|
/// to require re-analysis.
|
||||||
outdated,
|
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,
|
has_tv: bool,
|
||||||
/// If `true` it means the `Decl` is the resource owner of the type/value associated
|
/// 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
|
/// with it. That means when `Decl` is destroyed, the cleanup code should additionally
|
||||||
@ -366,8 +368,8 @@ pub const Decl = struct {
|
|||||||
is_exported: bool,
|
is_exported: bool,
|
||||||
/// Whether the ZIR code provides an align instruction.
|
/// Whether the ZIR code provides an align instruction.
|
||||||
has_align: bool,
|
has_align: bool,
|
||||||
/// Whether the ZIR code provides a linksection instruction.
|
/// Whether the ZIR code provides a linksection and address space instruction.
|
||||||
has_linksection: bool,
|
has_linksection_or_addrspace: bool,
|
||||||
/// Flag used by garbage collection to mark and sweep.
|
/// Flag used by garbage collection to mark and sweep.
|
||||||
/// Decls which correspond to an AST node always have this field set to `true`.
|
/// 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
|
/// 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;
|
if (!decl.has_align) return .none;
|
||||||
assert(decl.zir_decl_index != 0);
|
assert(decl.zir_decl_index != 0);
|
||||||
const zir = decl.namespace.file_scope.zir;
|
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 {
|
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);
|
assert(decl.zir_decl_index != 0);
|
||||||
const zir = decl.namespace.file_scope.zir;
|
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]);
|
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_pub = true;
|
||||||
new_decl.is_exported = false;
|
new_decl.is_exported = false;
|
||||||
new_decl.has_align = 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.ty = struct_ty;
|
||||||
new_decl.val = struct_val;
|
new_decl.val = struct_val;
|
||||||
new_decl.has_tv = true;
|
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);
|
if (linksection_ref == .none) break :blk Value.initTag(.null_value);
|
||||||
break :blk (try sema.resolveInstConst(&block_scope, src, linksection_ref)).val;
|
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
|
// 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),
|
// is a struct, for example, this resolves `type` (which needs no resolution),
|
||||||
// not the struct itself.
|
// 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.val = try decl_tv.val.copy(&decl_arena.allocator);
|
||||||
decl.align_val = try align_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.linksection_val = try linksection_val.copy(&decl_arena.allocator);
|
||||||
|
decl.@"addrspace" = address_space;
|
||||||
decl.has_tv = true;
|
decl.has_tv = true;
|
||||||
decl.owns_tv = owns_tv;
|
decl.owns_tv = owns_tv;
|
||||||
decl_arena_state.* = decl_arena.state;
|
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.val = try decl_tv.val.copy(&decl_arena.allocator);
|
||||||
decl.align_val = try align_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.linksection_val = try linksection_val.copy(&decl_arena.allocator);
|
||||||
|
decl.@"addrspace" = address_space;
|
||||||
decl.has_tv = true;
|
decl.has_tv = true;
|
||||||
decl_arena_state.* = decl_arena.state;
|
decl_arena_state.* = decl_arena.state;
|
||||||
decl.value_arena = decl_arena_state;
|
decl.value_arena = decl_arena_state;
|
||||||
@ -3526,8 +3556,8 @@ pub fn scanNamespace(
|
|||||||
|
|
||||||
const decl_sub_index = extra_index;
|
const decl_sub_index = extra_index;
|
||||||
extra_index += 7; // src_hash(4) + line(1) + name(1) + value(1)
|
extra_index += 7; // src_hash(4) + line(1) + name(1) + value(1)
|
||||||
extra_index += @truncate(u1, flags >> 2);
|
extra_index += @truncate(u1, flags >> 2); // Align
|
||||||
extra_index += @truncate(u1, flags >> 3);
|
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);
|
try scanDecl(&scan_decl_iter, decl_sub_index, flags);
|
||||||
}
|
}
|
||||||
@ -3556,7 +3586,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
|
|||||||
const is_pub = (flags & 0b0001) != 0;
|
const is_pub = (flags & 0b0001) != 0;
|
||||||
const export_bit = (flags & 0b0010) != 0;
|
const export_bit = (flags & 0b0010) != 0;
|
||||||
const has_align = (flags & 0b0100) != 0;
|
const has_align = (flags & 0b0100) != 0;
|
||||||
const has_linksection = (flags & 0b1000) != 0;
|
const has_linksection_or_addrspace = (flags & 0b1000) != 0;
|
||||||
// zig fmt: on
|
// zig fmt: on
|
||||||
|
|
||||||
const line = iter.parent_decl.relativeToLine(zir.extra[decl_sub_index + 4]);
|
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_exported = is_exported;
|
||||||
new_decl.is_usingnamespace = is_usingnamespace;
|
new_decl.is_usingnamespace = is_usingnamespace;
|
||||||
new_decl.has_align = has_align;
|
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.zir_decl_index = @intCast(u32, decl_sub_index);
|
||||||
new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive.
|
new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive.
|
||||||
return;
|
return;
|
||||||
@ -3656,7 +3686,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
|
|||||||
decl.is_exported = is_exported;
|
decl.is_exported = is_exported;
|
||||||
decl.is_usingnamespace = is_usingnamespace;
|
decl.is_usingnamespace = is_usingnamespace;
|
||||||
decl.has_align = has_align;
|
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);
|
decl.zir_decl_index = @intCast(u32, decl_sub_index);
|
||||||
if (decl.getFunction()) |_| {
|
if (decl.getFunction()) |_| {
|
||||||
switch (mod.comp.bin_file.tag) {
|
switch (mod.comp.bin_file.tag) {
|
||||||
@ -4028,6 +4058,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.
|
|||||||
.val = undefined,
|
.val = undefined,
|
||||||
.align_val = undefined,
|
.align_val = undefined,
|
||||||
.linksection_val = undefined,
|
.linksection_val = undefined,
|
||||||
|
.@"addrspace" = undefined,
|
||||||
.analysis = .unreferenced,
|
.analysis = .unreferenced,
|
||||||
.deletion_flag = false,
|
.deletion_flag = false,
|
||||||
.zir_decl_index = 0,
|
.zir_decl_index = 0,
|
||||||
@ -4052,7 +4083,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.
|
|||||||
.generation = 0,
|
.generation = 0,
|
||||||
.is_pub = false,
|
.is_pub = false,
|
||||||
.is_exported = false,
|
.is_exported = false,
|
||||||
.has_linksection = false,
|
.has_linksection_or_addrspace = false,
|
||||||
.has_align = false,
|
.has_align = false,
|
||||||
.alive = false,
|
.alive = false,
|
||||||
.is_usingnamespace = false,
|
.is_usingnamespace = false,
|
||||||
@ -4185,6 +4216,9 @@ pub fn createAnonymousDeclFromDeclNamed(
|
|||||||
new_decl.src_line = owner_decl.src_line;
|
new_decl.src_line = owner_decl.src_line;
|
||||||
new_decl.ty = typed_value.ty;
|
new_decl.ty = typed_value.ty;
|
||||||
new_decl.val = typed_value.val;
|
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.has_tv = true;
|
||||||
new_decl.analysis = .complete;
|
new_decl.analysis = .complete;
|
||||||
new_decl.generation = mod.generation;
|
new_decl.generation = mod.generation;
|
||||||
@ -4330,10 +4364,59 @@ pub fn simplePtrType(
|
|||||||
elem_ty: Type,
|
elem_ty: Type,
|
||||||
mutable: bool,
|
mutable: bool,
|
||||||
size: std.builtin.TypeInfo.Pointer.Size,
|
size: std.builtin.TypeInfo.Pointer.Size,
|
||||||
|
@"addrspace": std.builtin.AddressSpace,
|
||||||
) Allocator.Error!Type {
|
) 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))) {
|
if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) {
|
||||||
return Type.initTag(.const_slice_u8);
|
return Type.initTag(.const_slice_u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO stage1 type inference bug
|
// TODO stage1 type inference bug
|
||||||
const T = Type.Tag;
|
const T = Type.Tag;
|
||||||
|
|
||||||
@ -4352,34 +4435,6 @@ pub fn simplePtrType(
|
|||||||
return Type.initPayload(&type_payload.base);
|
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 {
|
pub fn optionalType(arena: *Allocator, child_type: Type) Allocator.Error!Type {
|
||||||
switch (child_type.tag()) {
|
switch (child_type.tag()) {
|
||||||
.single_const_pointer => return Type.Tag.optional_single_const_pointer.create(
|
.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_file = (mod.importPkg(builtin_pkg) catch unreachable).file;
|
||||||
const builtin_namespace = builtin_file.root_decl.?.namespace;
|
const builtin_namespace = builtin_file.root_decl.?.namespace;
|
||||||
const decl = builtin_namespace.decls.get("test_functions").?;
|
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 tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf).elemType();
|
||||||
|
|
||||||
const array_decl = d: {
|
const array_decl = d: {
|
||||||
|
241
src/Sema.zig
241
src/Sema.zig
@ -1373,7 +1373,13 @@ fn zirRetPtr(
|
|||||||
return sema.analyzeComptimeAlloc(block, sema.fn_ret_ty);
|
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);
|
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 ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
|
||||||
const var_decl_src = inst_data.src();
|
const var_decl_src = inst_data.src();
|
||||||
const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
|
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);
|
try sema.requireRuntimeBlock(block, var_decl_src);
|
||||||
return block.addTy(.alloc, ptr_type);
|
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);
|
return sema.analyzeComptimeAlloc(block, var_type);
|
||||||
}
|
}
|
||||||
try sema.validateVarType(block, ty_src, 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);
|
try sema.requireRuntimeBlock(block, var_decl_src);
|
||||||
return block.addTy(.alloc, ptr_type);
|
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);
|
try sema.mod.declareDeclDependency(sema.owner_decl, decl);
|
||||||
|
|
||||||
const final_elem_ty = try decl.ty.copy(sema.arena);
|
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);
|
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;
|
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);
|
try sema.validateVarType(block, ty_src, final_elem_ty);
|
||||||
}
|
}
|
||||||
// Change it to a normal alloc.
|
// 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, .{
|
sema.air_instructions.set(ptr_inst, .{
|
||||||
.tag = .alloc,
|
.tag = .alloc,
|
||||||
.data = .{ .ty = final_ptr_ty },
|
.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 ptr = sema.resolveInst(bin_inst.lhs);
|
||||||
const value = sema.resolveInst(bin_inst.rhs);
|
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,
|
// 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.
|
// if expressions should force it when the condition is compile-time known.
|
||||||
const src: LazySrcLoc = .unneeded;
|
const src: LazySrcLoc = .unneeded;
|
||||||
@ -1821,7 +1858,14 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index)
|
|||||||
// for the inferred allocation.
|
// for the inferred allocation.
|
||||||
try inferred_alloc.data.stored_inst_list.append(sema.arena, operand);
|
try inferred_alloc.data.stored_inst_list.append(sema.arena, operand);
|
||||||
// Create a runtime bitcast instruction with exactly the type the pointer wants.
|
// 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);
|
const bitcasted_ptr = try block.addTyOp(.bitcast, ptr_ty, ptr);
|
||||||
return sema.storePtr(block, src, bitcasted_ptr, operand);
|
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_pub = module_fn.owner_decl.is_pub;
|
||||||
new_decl.is_exported = module_fn.owner_decl.is_exported;
|
new_decl.is_exported = module_fn.owner_decl.is_exported;
|
||||||
new_decl.has_align = module_fn.owner_decl.has_align;
|
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.zir_decl_index = module_fn.owner_decl.zir_decl_index;
|
||||||
new_decl.alive = true; // This Decl is called at runtime.
|
new_decl.alive = true; // This Decl is called at runtime.
|
||||||
new_decl.has_tv = true;
|
new_decl.has_tv = true;
|
||||||
@ -3658,7 +3702,13 @@ fn zirOptionalPayloadPtr(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const child_type = try opt_type.optionalChildAlloc(sema.arena);
|
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 sema.resolveDefinedValue(block, src, optional_ptr)) |pointer_val| {
|
||||||
if (try pointer_val.pointerDeref(sema.arena)) |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()});
|
return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand_ty.elemType()});
|
||||||
|
|
||||||
const payload_ty = operand_ty.elemType().errorUnionPayload();
|
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 sema.resolveDefinedValue(block, src, operand)) |pointer_val| {
|
||||||
if (try pointer_val.pointerDeref(sema.arena)) |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,
|
elem_type,
|
||||||
null,
|
null,
|
||||||
0,
|
0,
|
||||||
|
.generic,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
inst_data.is_mutable,
|
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);
|
break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u32);
|
||||||
} else 0;
|
} 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 bit_start = if (inst_data.flags.has_bit_range) blk: {
|
||||||
const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
|
const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
|
||||||
extra_i += 1;
|
extra_i += 1;
|
||||||
@ -6933,6 +6996,7 @@ fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr
|
|||||||
elem_type,
|
elem_type,
|
||||||
sentinel,
|
sentinel,
|
||||||
abi_align,
|
abi_align,
|
||||||
|
address_space,
|
||||||
bit_start,
|
bit_start,
|
||||||
bit_end,
|
bit_end,
|
||||||
inst_data.flags.is_mutable,
|
inst_data.flags.is_mutable,
|
||||||
@ -8339,7 +8403,13 @@ fn panicWithMsg(
|
|||||||
const panic_fn = try sema.getBuiltin(block, src, "panic");
|
const panic_fn = try sema.getBuiltin(block, src, "panic");
|
||||||
const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
|
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 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(
|
const null_stack_trace = try sema.addConstant(
|
||||||
try Module.optionalType(arena, ptr_stack_trace_ty),
|
try Module.optionalType(arena, ptr_stack_trace_ty),
|
||||||
Value.initTag(.null_value),
|
Value.initTag(.null_value),
|
||||||
@ -8423,7 +8493,7 @@ fn fieldVal(
|
|||||||
.Pointer => switch (object_ty.ptrSize()) {
|
.Pointer => switch (object_ty.ptrSize()) {
|
||||||
.Slice => {
|
.Slice => {
|
||||||
if (mem.eql(u8, field_name, "ptr")) {
|
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);
|
const result_ty = object_ty.slicePtrFieldType(buf);
|
||||||
if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| {
|
if (try sema.resolveMaybeUndefVal(block, object_src, object)) |val| {
|
||||||
if (val.isUndef()) return sema.addConstUndef(result_ty);
|
if (val.isUndef()) return sema.addConstUndef(result_ty);
|
||||||
@ -8457,12 +8527,13 @@ fn fieldVal(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.One => {
|
.One => {
|
||||||
const elem_ty = object_ty.elemType();
|
const ptr_child = object_ty.elemType();
|
||||||
if (elem_ty.zigTypeTag() == .Array) {
|
switch (ptr_child.zigTypeTag()) {
|
||||||
|
.Array => {
|
||||||
if (mem.eql(u8, field_name, "len")) {
|
if (mem.eql(u8, field_name, "len")) {
|
||||||
return sema.addConstant(
|
return sema.addConstant(
|
||||||
Type.initTag(.comptime_int),
|
Type.initTag(.comptime_int),
|
||||||
try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()),
|
try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return mod.fail(
|
return mod.fail(
|
||||||
@ -8472,6 +8543,16 @@ fn fieldVal(
|
|||||||
.{ field_name, object_ty },
|
.{ 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 => {},
|
.Many, .C => {},
|
||||||
@ -8595,9 +8676,8 @@ fn fieldPtr(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Pointer => {
|
.Pointer => switch (object_ty.ptrSize()) {
|
||||||
const ptr_child = object_ty.elemType();
|
.Slice => {
|
||||||
if (ptr_child.isSlice()) {
|
|
||||||
// Here for the ptr and len fields what we need to do is the situation
|
// 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`.
|
// 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
|
// This value may be known at compile-time or runtime. In the former
|
||||||
@ -8627,7 +8707,10 @@ fn fieldPtr(
|
|||||||
.{ field_name, object_ty },
|
.{ field_name, object_ty },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else switch (ptr_child.zigTypeTag()) {
|
},
|
||||||
|
.One => {
|
||||||
|
const ptr_child = object_ty.elemType();
|
||||||
|
switch (ptr_child.zigTypeTag()) {
|
||||||
.Array => {
|
.Array => {
|
||||||
if (mem.eql(u8, field_name, "len")) {
|
if (mem.eql(u8, field_name, "len")) {
|
||||||
var anon_decl = try block.startAnonDecl();
|
var anon_decl = try block.startAnonDecl();
|
||||||
@ -8645,9 +8728,19 @@ fn fieldPtr(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.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 => {},
|
else => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.Many, .C => {},
|
||||||
|
},
|
||||||
.Type => {
|
.Type => {
|
||||||
_ = try sema.resolveConstValue(block, object_ptr_src, object_ptr);
|
_ = try sema.resolveConstValue(block, object_ptr_src, object_ptr);
|
||||||
const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src);
|
const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src);
|
||||||
@ -8788,13 +8881,20 @@ fn structFieldPtr(
|
|||||||
const arena = sema.arena;
|
const arena = sema.arena;
|
||||||
assert(unresolved_struct_ty.zigTypeTag() == .Struct);
|
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_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);
|
||||||
const struct_obj = struct_ty.castTag(.@"struct").?.data;
|
const struct_obj = struct_ty.castTag(.@"struct").?.data;
|
||||||
|
|
||||||
const field_index = struct_obj.fields.getIndex(field_name) orelse
|
const field_index = struct_obj.fields.getIndex(field_name) orelse
|
||||||
return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);
|
return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);
|
||||||
const field = struct_obj.fields.values()[field_index];
|
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| {
|
if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
|
||||||
return sema.addConstant(
|
return sema.addConstant(
|
||||||
@ -8885,6 +8985,7 @@ fn unionFieldPtr(
|
|||||||
const arena = sema.arena;
|
const arena = sema.arena;
|
||||||
assert(unresolved_union_ty.zigTypeTag() == .Union);
|
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_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);
|
||||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
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);
|
return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name);
|
||||||
|
|
||||||
const field = union_obj.fields.values()[field_index];
|
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| {
|
if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| {
|
||||||
// TODO detect inactive union field and emit compile error
|
// TODO detect inactive union field and emit compile error
|
||||||
@ -9068,10 +9175,13 @@ fn elemPtrArray(
|
|||||||
) CompileError!Air.Inst.Ref {
|
) CompileError!Air.Inst.Ref {
|
||||||
const array_ptr_ty = sema.typeOf(array_ptr);
|
const array_ptr_ty = sema.typeOf(array_ptr);
|
||||||
const pointee_type = array_ptr_ty.elemType().elemType();
|
const pointee_type = array_ptr_ty.elemType().elemType();
|
||||||
const result_ty = if (array_ptr_ty.ptrIsMutable())
|
const result_ty = try Module.simplePtrType(
|
||||||
try Type.Tag.single_mut_pointer.create(sema.arena, pointee_type)
|
sema.arena,
|
||||||
else
|
pointee_type,
|
||||||
try Type.Tag.single_const_pointer.create(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, src, array_ptr)) |array_ptr_val| {
|
||||||
if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_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();
|
const dest_is_mut = !dest_type.isConstPtr();
|
||||||
if (inst_ty.isConstPtr() and dest_is_mut) break :src_array_ptr;
|
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.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();
|
const dst_elem_type = dest_type.elemType();
|
||||||
switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type, dest_is_mut)) {
|
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;
|
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
|
const ok_sent = dest_info.sentinel == null or src_info.size == .C or
|
||||||
(src_info.sentinel != null and
|
(src_info.sentinel != null and
|
||||||
dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type));
|
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();
|
const decl_tv = try decl.typedValue();
|
||||||
if (decl_tv.val.castTag(.variable)) |payload| {
|
if (decl_tv.val.castTag(.variable)) |payload| {
|
||||||
const variable = payload.data;
|
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(ty, try Value.Tag.decl_ref.create(sema.arena, decl));
|
||||||
}
|
}
|
||||||
return sema.addConstant(
|
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),
|
try Value.Tag.decl_ref.create(sema.arena, decl),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -9617,8 +9732,9 @@ fn analyzeRef(
|
|||||||
}
|
}
|
||||||
|
|
||||||
try sema.requireRuntimeBlock(block, src);
|
try sema.requireRuntimeBlock(block, src);
|
||||||
const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One);
|
const address_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);
|
||||||
const mut_ptr_type = try Module.simplePtrType(sema.arena, operand_ty, true, .One);
|
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);
|
const alloc = try block.addTy(.alloc, mut_ptr_type);
|
||||||
try sema.storePtr(block, src, alloc, operand);
|
try sema.storePtr(block, src, alloc, operand);
|
||||||
|
|
||||||
@ -9779,6 +9895,7 @@ fn analyzeSlice(
|
|||||||
return_elem_type,
|
return_elem_type,
|
||||||
if (end_opt == .none) slice_sentinel else null,
|
if (end_opt == .none) slice_sentinel else null,
|
||||||
0, // TODO alignment
|
0, // TODO alignment
|
||||||
|
if (ptr_child.zigTypeTag() == .Pointer) ptr_child.ptrAddressSpace() else .generic,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
!ptr_child.isConstPtr(),
|
!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_order => return sema.resolveBuiltinTypeFields(block, src, "AtomicOrder"),
|
||||||
.atomic_rmw_op => return sema.resolveBuiltinTypeFields(block, src, "AtomicRmwOp"),
|
.atomic_rmw_op => return sema.resolveBuiltinTypeFields(block, src, "AtomicRmwOp"),
|
||||||
.calling_convention => return sema.resolveBuiltinTypeFields(block, src, "CallingConvention"),
|
.calling_convention => return sema.resolveBuiltinTypeFields(block, src, "CallingConvention"),
|
||||||
|
.address_space => return sema.resolveBuiltinTypeFields(block, src, "AddressSpace"),
|
||||||
.float_mode => return sema.resolveBuiltinTypeFields(block, src, "FloatMode"),
|
.float_mode => return sema.resolveBuiltinTypeFields(block, src, "FloatMode"),
|
||||||
.reduce_op => return sema.resolveBuiltinTypeFields(block, src, "ReduceOp"),
|
.reduce_op => return sema.resolveBuiltinTypeFields(block, src, "ReduceOp"),
|
||||||
.call_options => return sema.resolveBuiltinTypeFields(block, src, "CallOptions"),
|
.call_options => return sema.resolveBuiltinTypeFields(block, src, "CallOptions"),
|
||||||
@ -10680,6 +10798,7 @@ fn typeHasOnePossibleValue(
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -10865,6 +10984,7 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
|
|||||||
.atomic_order => return .atomic_order_type,
|
.atomic_order => return .atomic_order_type,
|
||||||
.atomic_rmw_op => return .atomic_rmw_op_type,
|
.atomic_rmw_op => return .atomic_rmw_op_type,
|
||||||
.calling_convention => return .calling_convention_type,
|
.calling_convention => return .calling_convention_type,
|
||||||
|
.address_space => return .address_space_type,
|
||||||
.float_mode => return .float_mode_type,
|
.float_mode => return .float_mode_type,
|
||||||
.reduce_op => return .reduce_op_type,
|
.reduce_op => return .reduce_op_type,
|
||||||
.call_options => return .call_options_type,
|
.call_options => return .call_options_type,
|
||||||
@ -10960,7 +11080,13 @@ fn analyzeComptimeAlloc(
|
|||||||
block: *Scope.Block,
|
block: *Scope.Block,
|
||||||
var_type: Type,
|
var_type: Type,
|
||||||
) CompileError!Air.Inst.Ref {
|
) 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();
|
var anon_decl = try block.startAnonDecl();
|
||||||
defer anon_decl.deinit();
|
defer anon_decl.deinit();
|
||||||
@ -10976,3 +11102,58 @@ fn analyzeComptimeAlloc(
|
|||||||
.decl = decl,
|
.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.
|
/// this instruction; a following 'ret' instruction will do the diversion.
|
||||||
/// Uses the `str_tok` union field.
|
/// Uses the `str_tok` union field.
|
||||||
ret_err_value_code,
|
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.
|
/// Uses the `ptr_type_simple` union field.
|
||||||
ptr_type_simple,
|
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.
|
/// Uses the `ptr_type` union field.
|
||||||
ptr_type,
|
ptr_type,
|
||||||
/// Slice operation `lhs[rhs..]`. No sentinel and no end offset.
|
/// Slice operation `lhs[rhs..]`. No sentinel and no end offset.
|
||||||
@ -1672,6 +1672,7 @@ pub const Inst = struct {
|
|||||||
atomic_order_type,
|
atomic_order_type,
|
||||||
atomic_rmw_op_type,
|
atomic_rmw_op_type,
|
||||||
calling_convention_type,
|
calling_convention_type,
|
||||||
|
address_space_type,
|
||||||
float_mode_type,
|
float_mode_type,
|
||||||
reduce_op_type,
|
reduce_op_type,
|
||||||
call_options_type,
|
call_options_type,
|
||||||
@ -1928,6 +1929,10 @@ pub const Inst = struct {
|
|||||||
.ty = Type.initTag(.type),
|
.ty = Type.initTag(.type),
|
||||||
.val = Value.initTag(.calling_convention_type),
|
.val = Value.initTag(.calling_convention_type),
|
||||||
},
|
},
|
||||||
|
.address_space_type = .{
|
||||||
|
.ty = Type.initTag(.type),
|
||||||
|
.val = Value.initTag(.address_space_type),
|
||||||
|
},
|
||||||
.float_mode_type = .{
|
.float_mode_type = .{
|
||||||
.ty = Type.initTag(.type),
|
.ty = Type.initTag(.type),
|
||||||
.val = Value.initTag(.float_mode_type),
|
.val = Value.initTag(.float_mode_type),
|
||||||
@ -2129,8 +2134,9 @@ pub const Inst = struct {
|
|||||||
is_volatile: bool,
|
is_volatile: bool,
|
||||||
has_sentinel: bool,
|
has_sentinel: bool,
|
||||||
has_align: bool,
|
has_align: bool,
|
||||||
|
has_addrspace: bool,
|
||||||
has_bit_range: bool,
|
has_bit_range: bool,
|
||||||
_: u2 = undefined,
|
_: u1 = undefined,
|
||||||
},
|
},
|
||||||
size: std.builtin.TypeInfo.Pointer.Size,
|
size: std.builtin.TypeInfo.Pointer.Size,
|
||||||
/// Index into extra. See `PtrType`.
|
/// Index into extra. See `PtrType`.
|
||||||
@ -2360,12 +2366,13 @@ pub const Inst = struct {
|
|||||||
else_body_len: u32,
|
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:
|
/// trailing Ref fields:
|
||||||
/// 0. sentinel: Ref // if `has_sentinel` flag is set
|
/// 0. sentinel: Ref // if `has_sentinel` flag is set
|
||||||
/// 1. align: Ref // if `has_align` flag is set
|
/// 1. align: Ref // if `has_align` flag is set
|
||||||
/// 2. bit_start: Ref // if `has_bit_range` flag is set
|
/// 2. address_space: Ref // if `has_addrspace` flag is set
|
||||||
/// 3. bit_end: Ref // if `has_bit_range` 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 {
|
pub const PtrType = struct {
|
||||||
elem_type: Ref,
|
elem_type: Ref,
|
||||||
};
|
};
|
||||||
@ -2483,7 +2490,7 @@ pub const Inst = struct {
|
|||||||
/// 0b000X: whether corresponding decl is pub
|
/// 0b000X: whether corresponding decl is pub
|
||||||
/// 0b00X0: whether corresponding decl is exported
|
/// 0b00X0: whether corresponding decl is exported
|
||||||
/// 0b0X00: whether corresponding decl has an align expression
|
/// 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
|
/// 5. decl: { // for every decls_len
|
||||||
/// src_hash: [4]u32, // hash of source bytes
|
/// src_hash: [4]u32, // hash of source bytes
|
||||||
/// line: u32, // line number of decl, relative to parent
|
/// 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`.
|
/// this is a test decl, and the name starts at `name+1`.
|
||||||
/// value: Index,
|
/// value: Index,
|
||||||
/// align: Ref, // if corresponding bit is set
|
/// 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
|
/// 6. inst: Index // for every body_len
|
||||||
/// 7. flags: u32 // for every 8 fields
|
/// 7. flags: u32 // for every 8 fields
|
||||||
@ -2547,7 +2557,7 @@ pub const Inst = struct {
|
|||||||
/// 0b000X: whether corresponding decl is pub
|
/// 0b000X: whether corresponding decl is pub
|
||||||
/// 0b00X0: whether corresponding decl is exported
|
/// 0b00X0: whether corresponding decl is exported
|
||||||
/// 0b0X00: whether corresponding decl has an align expression
|
/// 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
|
/// 6. decl: { // for every decls_len
|
||||||
/// src_hash: [4]u32, // hash of source bytes
|
/// src_hash: [4]u32, // hash of source bytes
|
||||||
/// line: u32, // line number of decl, relative to parent
|
/// 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`.
|
/// this is a test decl, and the name starts at `name+1`.
|
||||||
/// value: Index,
|
/// value: Index,
|
||||||
/// align: Ref, // if corresponding bit is set
|
/// 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
|
/// 7. inst: Index // for every body_len
|
||||||
/// 8. has_bits: u32 // for every 32 fields
|
/// 8. has_bits: u32 // for every 32 fields
|
||||||
@ -2592,7 +2605,7 @@ pub const Inst = struct {
|
|||||||
/// 0b000X: whether corresponding decl is pub
|
/// 0b000X: whether corresponding decl is pub
|
||||||
/// 0b00X0: whether corresponding decl is exported
|
/// 0b00X0: whether corresponding decl is exported
|
||||||
/// 0b0X00: whether corresponding decl has an align expression
|
/// 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
|
/// 6. decl: { // for every decls_len
|
||||||
/// src_hash: [4]u32, // hash of source bytes
|
/// src_hash: [4]u32, // hash of source bytes
|
||||||
/// line: u32, // line number of decl, relative to parent
|
/// 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`.
|
/// this is a test decl, and the name starts at `name+1`.
|
||||||
/// value: Index,
|
/// value: Index,
|
||||||
/// align: Ref, // if corresponding bit is set
|
/// 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
|
/// 7. inst: Index // for every body_len
|
||||||
/// 8. has_bits: u32 // for every 8 fields
|
/// 8. has_bits: u32 // for every 8 fields
|
||||||
@ -2641,7 +2657,7 @@ pub const Inst = struct {
|
|||||||
/// 0b000X: whether corresponding decl is pub
|
/// 0b000X: whether corresponding decl is pub
|
||||||
/// 0b00X0: whether corresponding decl is exported
|
/// 0b00X0: whether corresponding decl is exported
|
||||||
/// 0b0X00: whether corresponding decl has an align expression
|
/// 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
|
/// 1. decl: { // for every decls_len
|
||||||
/// src_hash: [4]u32, // hash of source bytes
|
/// src_hash: [4]u32, // hash of source bytes
|
||||||
/// line: u32, // line number of decl, relative to parent
|
/// 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`.
|
/// this is a test decl, and the name starts at `name+1`.
|
||||||
/// value: Index,
|
/// value: Index,
|
||||||
/// align: Ref, // if corresponding bit is set
|
/// 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 {
|
pub const OpaqueDecl = struct {
|
||||||
decls_len: u32,
|
decls_len: u32,
|
||||||
|
@ -4895,7 +4895,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
|||||||
switch (typed_value.ty.zigTypeTag()) {
|
switch (typed_value.ty.zigTypeTag()) {
|
||||||
.Pointer => switch (typed_value.ty.ptrSize()) {
|
.Pointer => switch (typed_value.ty.ptrSize()) {
|
||||||
.Slice => {
|
.Slice => {
|
||||||
var buf: Type.Payload.ElemType = undefined;
|
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||||
const ptr_type = typed_value.ty.slicePtrFieldType(&buf);
|
const ptr_type = typed_value.ty.slicePtrFieldType(&buf);
|
||||||
const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val });
|
const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val });
|
||||||
const slice_len = typed_value.val.sliceLen();
|
const slice_len = typed_value.val.sliceLen();
|
||||||
|
@ -251,7 +251,7 @@ pub const DeclGen = struct {
|
|||||||
try writer.writeByte('(');
|
try writer.writeByte('(');
|
||||||
try dg.renderType(writer, t);
|
try dg.renderType(writer, t);
|
||||||
try writer.writeAll("){");
|
try writer.writeAll("){");
|
||||||
var buf: Type.Payload.ElemType = undefined;
|
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||||
try dg.renderValue(writer, t.slicePtrFieldType(&buf), val);
|
try dg.renderValue(writer, t.slicePtrFieldType(&buf), val);
|
||||||
try writer.writeAll(", ");
|
try writer.writeAll(", ");
|
||||||
try writer.print("{d}", .{val.sliceLen()});
|
try writer.print("{d}", .{val.sliceLen()});
|
||||||
|
@ -558,7 +558,8 @@ pub const DeclGen = struct {
|
|||||||
llvm_params_len,
|
llvm_params_len,
|
||||||
.False,
|
.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;
|
const is_extern = decl.val.tag() == .extern_fn;
|
||||||
if (!is_extern) {
|
if (!is_extern) {
|
||||||
@ -580,7 +581,24 @@ pub const DeclGen = struct {
|
|||||||
if (llvm_module.getNamedGlobal(decl.name)) |val| return val;
|
if (llvm_module.getNamedGlobal(decl.name)) |val| return val;
|
||||||
// TODO: remove this redundant `llvmType`, it is also called in `genTypedValue`.
|
// TODO: remove this redundant `llvmType`, it is also called in `genTypedValue`.
|
||||||
const llvm_type = try self.llvmType(decl.ty);
|
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 {
|
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),
|
.Bool => return self.context.intType(1),
|
||||||
.Pointer => {
|
.Pointer => {
|
||||||
if (t.isSlice()) {
|
if (t.isSlice()) {
|
||||||
var buf: Type.Payload.ElemType = undefined;
|
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||||
const ptr_type = t.slicePtrFieldType(&buf);
|
const ptr_type = t.slicePtrFieldType(&buf);
|
||||||
|
|
||||||
const fields: [2]*const llvm.Type = .{
|
const fields: [2]*const llvm.Type = .{
|
||||||
@ -619,7 +637,8 @@ pub const DeclGen = struct {
|
|||||||
return self.context.structType(&fields, fields.len, .False);
|
return self.context.structType(&fields, fields.len, .False);
|
||||||
} else {
|
} else {
|
||||||
const elem_type = try self.llvmType(t.elemType());
|
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 => {
|
.Array => {
|
||||||
@ -685,7 +704,9 @@ pub const DeclGen = struct {
|
|||||||
@intCast(c_uint, llvm_params.len),
|
@intCast(c_uint, llvm_params.len),
|
||||||
llvm.Bool.fromBool(is_var_args),
|
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,
|
.ComptimeInt => unreachable,
|
||||||
.ComptimeFloat => unreachable,
|
.ComptimeFloat => unreachable,
|
||||||
@ -753,7 +774,7 @@ pub const DeclGen = struct {
|
|||||||
.Pointer => switch (tv.val.tag()) {
|
.Pointer => switch (tv.val.tag()) {
|
||||||
.decl_ref => {
|
.decl_ref => {
|
||||||
if (tv.ty.isSlice()) {
|
if (tv.ty.isSlice()) {
|
||||||
var buf: Type.Payload.ElemType = undefined;
|
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||||
const ptr_ty = tv.ty.slicePtrFieldType(&buf);
|
const ptr_ty = tv.ty.slicePtrFieldType(&buf);
|
||||||
var slice_len: Value.Payload.U64 = .{
|
var slice_len: Value.Payload.U64 = .{
|
||||||
.base = .{ .tag = .int_u64 },
|
.base = .{ .tag = .int_u64 },
|
||||||
@ -783,12 +804,13 @@ pub const DeclGen = struct {
|
|||||||
decl.alive = true;
|
decl.alive = true;
|
||||||
const val = try self.resolveGlobalDecl(decl);
|
const val = try self.resolveGlobalDecl(decl);
|
||||||
const llvm_var_type = try self.llvmType(tv.ty);
|
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);
|
return val.constBitCast(llvm_type);
|
||||||
},
|
},
|
||||||
.slice => {
|
.slice => {
|
||||||
const slice = tv.val.castTag(.slice).?.data;
|
const slice = tv.val.castTag(.slice).?.data;
|
||||||
var buf: Type.Payload.ElemType = undefined;
|
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||||
const fields: [2]*const llvm.Value = .{
|
const fields: [2]*const llvm.Value = .{
|
||||||
try self.genTypedValue(.{
|
try self.genTypedValue(.{
|
||||||
.ty = tv.ty.slicePtrFieldType(&buf),
|
.ty = tv.ty.slicePtrFieldType(&buf),
|
||||||
|
@ -197,6 +197,9 @@ pub const Module = opaque {
|
|||||||
pub const addFunction = LLVMAddFunction;
|
pub const addFunction = LLVMAddFunction;
|
||||||
extern fn LLVMAddFunction(*const Module, Name: [*:0]const u8, FunctionTy: *const Type) *const Value;
|
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;
|
pub const getNamedFunction = LLVMGetNamedFunction;
|
||||||
extern fn LLVMGetNamedFunction(*const Module, Name: [*:0]const u8) ?*const Value;
|
extern fn LLVMGetNamedFunction(*const Module, Name: [*:0]const u8) ?*const Value;
|
||||||
|
|
||||||
@ -209,6 +212,9 @@ pub const Module = opaque {
|
|||||||
pub const addGlobal = LLVMAddGlobal;
|
pub const addGlobal = LLVMAddGlobal;
|
||||||
extern fn LLVMAddGlobal(M: *const Module, Ty: *const Type, Name: [*:0]const u8) *const Value;
|
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;
|
pub const getNamedGlobal = LLVMGetNamedGlobal;
|
||||||
extern fn LLVMGetNamedGlobal(M: *const Module, Name: [*:0]const u8) ?*const Value;
|
extern fn LLVMGetNamedGlobal(M: *const Module, Name: [*:0]const u8) ?*const Value;
|
||||||
|
|
||||||
@ -1005,3 +1011,65 @@ pub const TypeKind = enum(c_int) {
|
|||||||
BFloat,
|
BFloat,
|
||||||
X86_AMX,
|
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;
|
cur_bit_bag >>= 1;
|
||||||
const has_align = @truncate(u1, cur_bit_bag) != 0;
|
const has_align = @truncate(u1, cur_bit_bag) != 0;
|
||||||
cur_bit_bag >>= 1;
|
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;
|
cur_bit_bag >>= 1;
|
||||||
|
|
||||||
const sub_index = extra_index;
|
const sub_index = extra_index;
|
||||||
@ -1165,7 +1165,12 @@ const Writer = struct {
|
|||||||
extra_index += 1;
|
extra_index += 1;
|
||||||
break :inst inst;
|
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]);
|
const inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
|
||||||
extra_index += 1;
|
extra_index += 1;
|
||||||
break :inst inst;
|
break :inst inst;
|
||||||
@ -1196,6 +1201,11 @@ const Writer = struct {
|
|||||||
try self.writeInstRef(stream, align_inst);
|
try self.writeInstRef(stream, align_inst);
|
||||||
try stream.writeAll(")");
|
try stream.writeAll(")");
|
||||||
}
|
}
|
||||||
|
if (addrspace_inst != .none) {
|
||||||
|
try stream.writeAll(" addrspace(");
|
||||||
|
try self.writeInstRef(stream, addrspace_inst);
|
||||||
|
try stream.writeAll(")");
|
||||||
|
}
|
||||||
if (section_inst != .none) {
|
if (section_inst != .none) {
|
||||||
try stream.writeAll(" linksection(");
|
try stream.writeAll(" linksection(");
|
||||||
try self.writeInstRef(stream, section_inst);
|
try self.writeInstRef(stream, section_inst);
|
||||||
|
@ -86,6 +86,14 @@ enum CallingConvention {
|
|||||||
CallingConventionSysV
|
CallingConventionSysV
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Stage 1 supports only the generic address space
|
||||||
|
enum AddressSpace {
|
||||||
|
AddressSpaceGeneric,
|
||||||
|
AddressSpaceGS,
|
||||||
|
AddressSpaceFS,
|
||||||
|
AddressSpaceSS,
|
||||||
|
};
|
||||||
|
|
||||||
// This one corresponds to the builtin.zig enum.
|
// This one corresponds to the builtin.zig enum.
|
||||||
enum BuiltinPtrSize {
|
enum BuiltinPtrSize {
|
||||||
BuiltinPtrSizeOne,
|
BuiltinPtrSizeOne,
|
||||||
|
@ -1019,6 +1019,16 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {
|
|||||||
zig_unreachable();
|
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) {
|
ZigType *get_stack_trace_type(CodeGen *g) {
|
||||||
if (g->stack_trace_type == nullptr) {
|
if (g->stack_trace_type == nullptr) {
|
||||||
g->stack_trace_type = get_builtin_type(g, "StackTrace");
|
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);
|
bool calling_convention_allows_zig_types(CallingConvention cc);
|
||||||
const char *calling_convention_name(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);
|
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);
|
void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk);
|
||||||
|
@ -17904,7 +17904,7 @@ static ZigValue *create_ptr_like_type_info(IrAnalyze *ira, Scope *scope, AstNode
|
|||||||
result->special = ConstValSpecialStatic;
|
result->special = ConstValSpecialStatic;
|
||||||
result->type = type_info_pointer_type;
|
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;
|
result->data.x_struct.fields = fields;
|
||||||
|
|
||||||
// size: Size
|
// 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->base.id = LazyValueIdAlignOf;
|
||||||
lazy_align_of->target_type = ir_const_type(ira, scope, source_node, attrs_type->data.pointer.child_type);
|
lazy_align_of->target_type = ir_const_type(ira, scope, source_node, attrs_type->data.pointer.child_type);
|
||||||
}
|
}
|
||||||
// child: type
|
// address_space: AddressSpace,
|
||||||
ensure_field_index(result->type, "child", 4);
|
ensure_field_index(result->type, "address_space", 4);
|
||||||
fields[4]->special = ConstValSpecialStatic;
|
fields[4]->special = ConstValSpecialStatic;
|
||||||
fields[4]->type = ira->codegen->builtin_types.entry_type;
|
fields[4]->type = get_builtin_type(ira->codegen, "AddressSpace");
|
||||||
fields[4]->data.x_type = attrs_type->data.pointer.child_type;
|
bigint_init_unsigned(&fields[4]->data.x_enum_tag, AddressSpaceGeneric);
|
||||||
// is_allowzero: bool
|
// child: type
|
||||||
ensure_field_index(result->type, "is_allowzero", 5);
|
ensure_field_index(result->type, "child", 5);
|
||||||
fields[5]->special = ConstValSpecialStatic;
|
fields[5]->special = ConstValSpecialStatic;
|
||||||
fields[5]->type = ira->codegen->builtin_types.entry_bool;
|
fields[5]->type = ira->codegen->builtin_types.entry_type;
|
||||||
fields[5]->data.x_bool = attrs_type->data.pointer.allow_zero;
|
fields[5]->data.x_type = attrs_type->data.pointer.child_type;
|
||||||
// sentinel: anytype
|
// is_allowzero: bool
|
||||||
ensure_field_index(result->type, "sentinel", 6);
|
ensure_field_index(result->type, "is_allowzero", 6);
|
||||||
fields[6]->special = ConstValSpecialStatic;
|
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) {
|
if (attrs_type->data.pointer.sentinel != nullptr) {
|
||||||
fields[6]->type = get_optional_type(ira->codegen, attrs_type->data.pointer.child_type);
|
fields[7]->type = get_optional_type(ira->codegen, attrs_type->data.pointer.child_type);
|
||||||
set_optional_payload(fields[6], attrs_type->data.pointer.sentinel);
|
set_optional_payload(fields[7], attrs_type->data.pointer.sentinel);
|
||||||
} else {
|
} else {
|
||||||
fields[6]->type = ira->codegen->builtin_types.entry_null;
|
fields[7]->type = ira->codegen->builtin_types.entry_null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -18465,7 +18470,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour
|
|||||||
result->special = ConstValSpecialStatic;
|
result->special = ConstValSpecialStatic;
|
||||||
result->type = ir_type_info_get_type(ira, "Fn", nullptr);
|
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;
|
result->data.x_struct.fields = fields;
|
||||||
|
|
||||||
// calling_convention: TypeInfo.CallingConvention
|
// 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));
|
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);
|
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);
|
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))
|
if (type_is_invalid(elem_type))
|
||||||
return ira->codegen->invalid_inst_gen->value->type;
|
return ira->codegen->invalid_inst_gen->value->type;
|
||||||
ZigValue *sentinel;
|
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)))
|
elem_type, &sentinel)))
|
||||||
{
|
{
|
||||||
return ira->codegen->invalid_inst_gen->value->type;
|
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)
|
if (alignment == nullptr)
|
||||||
return ira->codegen->invalid_inst_gen->value->type;
|
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;
|
bool is_const;
|
||||||
if ((err = get_const_field_bool(ira, source_node, payload, "is_const", 1, &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;
|
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;
|
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)))
|
&is_allowzero)))
|
||||||
{
|
{
|
||||||
return ira->codegen->invalid_inst_gen->value->type;
|
return ira->codegen->invalid_inst_gen->value->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ZigType *ptr_type = get_pointer_to_type_extra2(ira->codegen,
|
ZigType *ptr_type = get_pointer_to_type_extra2(ira->codegen,
|
||||||
elem_type,
|
elem_type,
|
||||||
is_const,
|
is_const,
|
||||||
|
@ -544,3 +544,21 @@ pub fn largestAtomicBits(target: std.Target) u32 {
|
|||||||
.x86_64 => 128,
|
.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,
|
.type_node = type_node,
|
||||||
.align_node = align_node,
|
.align_node = align_node,
|
||||||
.section_node = section_node,
|
.section_node = section_node,
|
||||||
|
.addrspace_node = 0,
|
||||||
}),
|
}),
|
||||||
.rhs = init_node,
|
.rhs = init_node,
|
||||||
},
|
},
|
||||||
@ -2705,6 +2706,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
|
|||||||
.lhs = try c.addExtra(std.zig.Ast.Node.FnProtoOne{
|
.lhs = try c.addExtra(std.zig.Ast.Node.FnProtoOne{
|
||||||
.param = params.items[0],
|
.param = params.items[0],
|
||||||
.align_expr = align_expr,
|
.align_expr = align_expr,
|
||||||
|
.addrspace_expr = 0, // TODO
|
||||||
.section_expr = section_expr,
|
.section_expr = section_expr,
|
||||||
.callconv_expr = callconv_expr,
|
.callconv_expr = callconv_expr,
|
||||||
}),
|
}),
|
||||||
@ -2720,6 +2722,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
|
|||||||
.params_start = span.start,
|
.params_start = span.start,
|
||||||
.params_end = span.end,
|
.params_end = span.end,
|
||||||
.align_expr = align_expr,
|
.align_expr = align_expr,
|
||||||
|
.addrspace_expr = 0, // TODO
|
||||||
.section_expr = section_expr,
|
.section_expr = section_expr,
|
||||||
.callconv_expr = callconv_expr,
|
.callconv_expr = callconv_expr,
|
||||||
}),
|
}),
|
||||||
|
112
src/type.zig
112
src/type.zig
@ -127,6 +127,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
=> return .Enum,
|
=> return .Enum,
|
||||||
@ -288,6 +289,7 @@ pub const Type = extern union {
|
|||||||
.pointee_type = Type.initTag(.comptime_int),
|
.pointee_type = Type.initTag(.comptime_int),
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
.@"align" = 0,
|
.@"align" = 0,
|
||||||
|
.@"addrspace" = .generic,
|
||||||
.bit_offset = 0,
|
.bit_offset = 0,
|
||||||
.host_size = 0,
|
.host_size = 0,
|
||||||
.@"allowzero" = false,
|
.@"allowzero" = false,
|
||||||
@ -299,6 +301,7 @@ pub const Type = extern union {
|
|||||||
.pointee_type = Type.initTag(.u8),
|
.pointee_type = Type.initTag(.u8),
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
.@"align" = 0,
|
.@"align" = 0,
|
||||||
|
.@"addrspace" = .generic,
|
||||||
.bit_offset = 0,
|
.bit_offset = 0,
|
||||||
.host_size = 0,
|
.host_size = 0,
|
||||||
.@"allowzero" = false,
|
.@"allowzero" = false,
|
||||||
@ -310,6 +313,7 @@ pub const Type = extern union {
|
|||||||
.pointee_type = self.castPointer().?.data,
|
.pointee_type = self.castPointer().?.data,
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
.@"align" = 0,
|
.@"align" = 0,
|
||||||
|
.@"addrspace" = .generic,
|
||||||
.bit_offset = 0,
|
.bit_offset = 0,
|
||||||
.host_size = 0,
|
.host_size = 0,
|
||||||
.@"allowzero" = false,
|
.@"allowzero" = false,
|
||||||
@ -321,6 +325,7 @@ pub const Type = extern union {
|
|||||||
.pointee_type = self.castPointer().?.data,
|
.pointee_type = self.castPointer().?.data,
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
.@"align" = 0,
|
.@"align" = 0,
|
||||||
|
.@"addrspace" = .generic,
|
||||||
.bit_offset = 0,
|
.bit_offset = 0,
|
||||||
.host_size = 0,
|
.host_size = 0,
|
||||||
.@"allowzero" = false,
|
.@"allowzero" = false,
|
||||||
@ -332,6 +337,7 @@ pub const Type = extern union {
|
|||||||
.pointee_type = self.castPointer().?.data,
|
.pointee_type = self.castPointer().?.data,
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
.@"align" = 0,
|
.@"align" = 0,
|
||||||
|
.@"addrspace" = .generic,
|
||||||
.bit_offset = 0,
|
.bit_offset = 0,
|
||||||
.host_size = 0,
|
.host_size = 0,
|
||||||
.@"allowzero" = false,
|
.@"allowzero" = false,
|
||||||
@ -343,6 +349,7 @@ pub const Type = extern union {
|
|||||||
.pointee_type = Type.initTag(.u8),
|
.pointee_type = Type.initTag(.u8),
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
.@"align" = 0,
|
.@"align" = 0,
|
||||||
|
.@"addrspace" = .generic,
|
||||||
.bit_offset = 0,
|
.bit_offset = 0,
|
||||||
.host_size = 0,
|
.host_size = 0,
|
||||||
.@"allowzero" = false,
|
.@"allowzero" = false,
|
||||||
@ -354,6 +361,7 @@ pub const Type = extern union {
|
|||||||
.pointee_type = self.castPointer().?.data,
|
.pointee_type = self.castPointer().?.data,
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
.@"align" = 0,
|
.@"align" = 0,
|
||||||
|
.@"addrspace" = .generic,
|
||||||
.bit_offset = 0,
|
.bit_offset = 0,
|
||||||
.host_size = 0,
|
.host_size = 0,
|
||||||
.@"allowzero" = false,
|
.@"allowzero" = false,
|
||||||
@ -365,6 +373,7 @@ pub const Type = extern union {
|
|||||||
.pointee_type = Type.initTag(.u8),
|
.pointee_type = Type.initTag(.u8),
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
.@"align" = 0,
|
.@"align" = 0,
|
||||||
|
.@"addrspace" = .generic,
|
||||||
.bit_offset = 0,
|
.bit_offset = 0,
|
||||||
.host_size = 0,
|
.host_size = 0,
|
||||||
.@"allowzero" = false,
|
.@"allowzero" = false,
|
||||||
@ -376,6 +385,7 @@ pub const Type = extern union {
|
|||||||
.pointee_type = self.castPointer().?.data,
|
.pointee_type = self.castPointer().?.data,
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
.@"align" = 0,
|
.@"align" = 0,
|
||||||
|
.@"addrspace" = .generic,
|
||||||
.bit_offset = 0,
|
.bit_offset = 0,
|
||||||
.host_size = 0,
|
.host_size = 0,
|
||||||
.@"allowzero" = false,
|
.@"allowzero" = false,
|
||||||
@ -387,6 +397,7 @@ pub const Type = extern union {
|
|||||||
.pointee_type = self.castPointer().?.data,
|
.pointee_type = self.castPointer().?.data,
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
.@"align" = 0,
|
.@"align" = 0,
|
||||||
|
.@"addrspace" = .generic,
|
||||||
.bit_offset = 0,
|
.bit_offset = 0,
|
||||||
.host_size = 0,
|
.host_size = 0,
|
||||||
.@"allowzero" = false,
|
.@"allowzero" = false,
|
||||||
@ -398,6 +409,7 @@ pub const Type = extern union {
|
|||||||
.pointee_type = self.castPointer().?.data,
|
.pointee_type = self.castPointer().?.data,
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
.@"align" = 0,
|
.@"align" = 0,
|
||||||
|
.@"addrspace" = .generic,
|
||||||
.bit_offset = 0,
|
.bit_offset = 0,
|
||||||
.host_size = 0,
|
.host_size = 0,
|
||||||
.@"allowzero" = false,
|
.@"allowzero" = false,
|
||||||
@ -409,6 +421,7 @@ pub const Type = extern union {
|
|||||||
.pointee_type = self.castPointer().?.data,
|
.pointee_type = self.castPointer().?.data,
|
||||||
.sentinel = null,
|
.sentinel = null,
|
||||||
.@"align" = 0,
|
.@"align" = 0,
|
||||||
|
.@"addrspace" = .generic,
|
||||||
.bit_offset = 0,
|
.bit_offset = 0,
|
||||||
.host_size = 0,
|
.host_size = 0,
|
||||||
.@"allowzero" = false,
|
.@"allowzero" = false,
|
||||||
@ -461,6 +474,8 @@ pub const Type = extern union {
|
|||||||
return false;
|
return false;
|
||||||
if (info_a.host_size != info_b.host_size)
|
if (info_a.host_size != info_b.host_size)
|
||||||
return false;
|
return false;
|
||||||
|
if (info_a.@"addrspace" != info_b.@"addrspace")
|
||||||
|
return false;
|
||||||
|
|
||||||
const sentinel_a = info_a.sentinel;
|
const sentinel_a = info_a.sentinel;
|
||||||
const sentinel_b = info_b.sentinel;
|
const sentinel_b = info_b.sentinel;
|
||||||
@ -746,6 +761,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -835,6 +851,7 @@ pub const Type = extern union {
|
|||||||
.pointee_type = try payload.pointee_type.copy(allocator),
|
.pointee_type = try payload.pointee_type.copy(allocator),
|
||||||
.sentinel = sent,
|
.sentinel = sent,
|
||||||
.@"align" = payload.@"align",
|
.@"align" = payload.@"align",
|
||||||
|
.@"addrspace" = payload.@"addrspace",
|
||||||
.bit_offset = payload.bit_offset,
|
.bit_offset = payload.bit_offset,
|
||||||
.host_size = payload.host_size,
|
.host_size = payload.host_size,
|
||||||
.@"allowzero" = payload.@"allowzero",
|
.@"allowzero" = payload.@"allowzero",
|
||||||
@ -958,6 +975,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order => return writer.writeAll("std.builtin.AtomicOrder"),
|
.atomic_order => return writer.writeAll("std.builtin.AtomicOrder"),
|
||||||
.atomic_rmw_op => return writer.writeAll("std.builtin.AtomicRmwOp"),
|
.atomic_rmw_op => return writer.writeAll("std.builtin.AtomicRmwOp"),
|
||||||
.calling_convention => return writer.writeAll("std.builtin.CallingConvention"),
|
.calling_convention => return writer.writeAll("std.builtin.CallingConvention"),
|
||||||
|
.address_space => return writer.writeAll("std.builtin.AddressSpace"),
|
||||||
.float_mode => return writer.writeAll("std.builtin.FloatMode"),
|
.float_mode => return writer.writeAll("std.builtin.FloatMode"),
|
||||||
.reduce_op => return writer.writeAll("std.builtin.ReduceOp"),
|
.reduce_op => return writer.writeAll("std.builtin.ReduceOp"),
|
||||||
.call_options => return writer.writeAll("std.builtin.CallOptions"),
|
.call_options => return writer.writeAll("std.builtin.CallOptions"),
|
||||||
@ -1111,6 +1129,9 @@ pub const Type = extern union {
|
|||||||
}
|
}
|
||||||
try writer.writeAll(") ");
|
try writer.writeAll(") ");
|
||||||
}
|
}
|
||||||
|
if (payload.@"addrspace" != .generic) {
|
||||||
|
try writer.print("addrspace(.{s}) ", .{@tagName(payload.@"addrspace")});
|
||||||
|
}
|
||||||
if (!payload.mutable) try writer.writeAll("const ");
|
if (!payload.mutable) try writer.writeAll("const ");
|
||||||
if (payload.@"volatile") try writer.writeAll("volatile ");
|
if (payload.@"volatile") try writer.writeAll("volatile ");
|
||||||
if (payload.@"allowzero") try writer.writeAll("allowzero ");
|
if (payload.@"allowzero") try writer.writeAll("allowzero ");
|
||||||
@ -1186,6 +1207,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -1301,6 +1323,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order => return Value.initTag(.atomic_order_type),
|
.atomic_order => return Value.initTag(.atomic_order_type),
|
||||||
.atomic_rmw_op => return Value.initTag(.atomic_rmw_op_type),
|
.atomic_rmw_op => return Value.initTag(.atomic_rmw_op_type),
|
||||||
.calling_convention => return Value.initTag(.calling_convention_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),
|
.float_mode => return Value.initTag(.float_mode_type),
|
||||||
.reduce_op => return Value.initTag(.reduce_op_type),
|
.reduce_op => return Value.initTag(.reduce_op_type),
|
||||||
.call_options => return Value.initTag(.call_options_type),
|
.call_options => return Value.initTag(.call_options_type),
|
||||||
@ -1362,6 +1385,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.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.
|
/// Asserts that hasCodeGenBits() is true.
|
||||||
pub fn abiAlignment(self: Type, target: Target) u32 {
|
pub fn abiAlignment(self: Type, target: Target) u32 {
|
||||||
return switch (self.tag()) {
|
return switch (self.tag()) {
|
||||||
@ -1508,6 +1556,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -1734,6 +1783,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -2019,6 +2069,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.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()) {
|
switch (self.tag()) {
|
||||||
.const_slice_u8 => return Type.initTag(.manyptr_const_u8),
|
.const_slice_u8 => return Type.initTag(.manyptr_const_u8),
|
||||||
|
|
||||||
.const_slice => {
|
.const_slice => {
|
||||||
const elem_type = self.castTag(.const_slice).?.data;
|
const elem_type = self.castTag(.const_slice).?.data;
|
||||||
buffer.* = .{
|
buffer.* = .{
|
||||||
|
.elem_type = .{
|
||||||
.base = .{ .tag = .many_const_pointer },
|
.base = .{ .tag = .many_const_pointer },
|
||||||
.data = elem_type,
|
.data = elem_type,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
return Type.initPayload(&buffer.base);
|
return Type.initPayload(&buffer.elem_type.base);
|
||||||
},
|
},
|
||||||
.mut_slice => {
|
.mut_slice => {
|
||||||
const elem_type = self.castTag(.mut_slice).?.data;
|
const elem_type = self.castTag(.mut_slice).?.data;
|
||||||
buffer.* = .{
|
buffer.* = .{
|
||||||
|
.elem_type = .{
|
||||||
.base = .{ .tag = .many_mut_pointer },
|
.base = .{ .tag = .many_mut_pointer },
|
||||||
.data = elem_type,
|
.data = elem_type,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
return Type.initPayload(&buffer.base);
|
return Type.initPayload(&buffer.elem_type.base);
|
||||||
},
|
},
|
||||||
|
|
||||||
.pointer => {
|
.pointer => {
|
||||||
const payload = self.castTag(.pointer).?.data;
|
const payload = self.castTag(.pointer).?.data;
|
||||||
assert(payload.size == .Slice);
|
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.* = .{
|
buffer.* = .{
|
||||||
|
.pointer = .{
|
||||||
|
.data = .{
|
||||||
|
.pointee_type = payload.pointee_type,
|
||||||
|
.sentinel = payload.sentinel,
|
||||||
|
.@"align" = payload.@"align",
|
||||||
|
.@"addrspace" = payload.@"addrspace",
|
||||||
|
.bit_offset = payload.bit_offset,
|
||||||
|
.host_size = payload.host_size,
|
||||||
|
.@"allowzero" = payload.@"allowzero",
|
||||||
|
.mutable = payload.mutable,
|
||||||
|
.@"volatile" = payload.@"volatile",
|
||||||
|
.size = .Many,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return Type.initPayload(&buffer.pointer.base);
|
||||||
|
} else if (payload.mutable) {
|
||||||
|
buffer.* = .{
|
||||||
|
.elem_type = .{
|
||||||
.base = .{ .tag = .many_mut_pointer },
|
.base = .{ .tag = .many_mut_pointer },
|
||||||
.data = payload.pointee_type,
|
.data = payload.pointee_type,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
return Type.initPayload(&buffer.elem_type.base);
|
||||||
} else {
|
} else {
|
||||||
buffer.* = .{
|
buffer.* = .{
|
||||||
|
.elem_type = .{
|
||||||
.base = .{ .tag = .many_const_pointer },
|
.base = .{ .tag = .many_const_pointer },
|
||||||
.data = payload.pointee_type,
|
.data = payload.pointee_type,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
return Type.initPayload(&buffer.elem_type.base);
|
||||||
}
|
}
|
||||||
return Type.initPayload(&buffer.base);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
@ -2793,6 +2884,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -3000,6 +3092,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -3024,6 +3117,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -3047,6 +3141,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -3100,6 +3195,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -3155,6 +3251,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -3192,6 +3289,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -3242,6 +3340,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -3302,6 +3401,7 @@ pub const Type = extern union {
|
|||||||
atomic_order,
|
atomic_order,
|
||||||
atomic_rmw_op,
|
atomic_rmw_op,
|
||||||
calling_convention,
|
calling_convention,
|
||||||
|
address_space,
|
||||||
float_mode,
|
float_mode,
|
||||||
reduce_op,
|
reduce_op,
|
||||||
call_options,
|
call_options,
|
||||||
@ -3425,6 +3525,7 @@ pub const Type = extern union {
|
|||||||
.atomic_order,
|
.atomic_order,
|
||||||
.atomic_rmw_op,
|
.atomic_rmw_op,
|
||||||
.calling_convention,
|
.calling_convention,
|
||||||
|
.address_space,
|
||||||
.float_mode,
|
.float_mode,
|
||||||
.reduce_op,
|
.reduce_op,
|
||||||
.call_options,
|
.call_options,
|
||||||
@ -3580,6 +3681,7 @@ pub const Type = extern union {
|
|||||||
sentinel: ?Value,
|
sentinel: ?Value,
|
||||||
/// If zero use pointee_type.AbiAlign()
|
/// If zero use pointee_type.AbiAlign()
|
||||||
@"align": u32,
|
@"align": u32,
|
||||||
|
@"addrspace": std.builtin.AddressSpace,
|
||||||
bit_offset: u16,
|
bit_offset: u16,
|
||||||
host_size: u16,
|
host_size: u16,
|
||||||
@"allowzero": bool,
|
@"allowzero": bool,
|
||||||
|
@ -63,6 +63,7 @@ pub const Value = extern union {
|
|||||||
atomic_order_type,
|
atomic_order_type,
|
||||||
atomic_rmw_op_type,
|
atomic_rmw_op_type,
|
||||||
calling_convention_type,
|
calling_convention_type,
|
||||||
|
address_space_type,
|
||||||
float_mode_type,
|
float_mode_type,
|
||||||
reduce_op_type,
|
reduce_op_type,
|
||||||
call_options_type,
|
call_options_type,
|
||||||
@ -226,6 +227,7 @@ pub const Value = extern union {
|
|||||||
.atomic_order_type,
|
.atomic_order_type,
|
||||||
.atomic_rmw_op_type,
|
.atomic_rmw_op_type,
|
||||||
.calling_convention_type,
|
.calling_convention_type,
|
||||||
|
.address_space_type,
|
||||||
.float_mode_type,
|
.float_mode_type,
|
||||||
.reduce_op_type,
|
.reduce_op_type,
|
||||||
.call_options_type,
|
.call_options_type,
|
||||||
@ -412,6 +414,7 @@ pub const Value = extern union {
|
|||||||
.atomic_order_type,
|
.atomic_order_type,
|
||||||
.atomic_rmw_op_type,
|
.atomic_rmw_op_type,
|
||||||
.calling_convention_type,
|
.calling_convention_type,
|
||||||
|
.address_space_type,
|
||||||
.float_mode_type,
|
.float_mode_type,
|
||||||
.reduce_op_type,
|
.reduce_op_type,
|
||||||
.call_options_type,
|
.call_options_type,
|
||||||
@ -625,6 +628,7 @@ pub const Value = extern union {
|
|||||||
.atomic_order_type => return out_stream.writeAll("std.builtin.AtomicOrder"),
|
.atomic_order_type => return out_stream.writeAll("std.builtin.AtomicOrder"),
|
||||||
.atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"),
|
.atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"),
|
||||||
.calling_convention_type => return out_stream.writeAll("std.builtin.CallingConvention"),
|
.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"),
|
.float_mode_type => return out_stream.writeAll("std.builtin.FloatMode"),
|
||||||
.reduce_op_type => return out_stream.writeAll("std.builtin.ReduceOp"),
|
.reduce_op_type => return out_stream.writeAll("std.builtin.ReduceOp"),
|
||||||
.call_options_type => return out_stream.writeAll("std.builtin.CallOptions"),
|
.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_order_type => Type.initTag(.atomic_order),
|
||||||
.atomic_rmw_op_type => Type.initTag(.atomic_rmw_op),
|
.atomic_rmw_op_type => Type.initTag(.atomic_rmw_op),
|
||||||
.calling_convention_type => Type.initTag(.calling_convention),
|
.calling_convention_type => Type.initTag(.calling_convention),
|
||||||
|
.address_space_type => Type.initTag(.address_space),
|
||||||
.float_mode_type => Type.initTag(.float_mode),
|
.float_mode_type => Type.initTag(.float_mode),
|
||||||
.reduce_op_type => Type.initTag(.reduce_op),
|
.reduce_op_type => Type.initTag(.reduce_op),
|
||||||
.call_options_type => Type.initTag(.call_options),
|
.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)));
|
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,
|
LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
|
||||||
unsigned NumArgs, ZigLLVM_CallingConv CC, ZigLLVM_CallAttr attr, const char *Name)
|
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 LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref);
|
||||||
|
|
||||||
|
ZIG_EXTERN_C LLVMValueRef ZigLLVMAddFunctionInAddressSpace(LLVMModuleRef M, const char *Name,
|
||||||
|
LLVMTypeRef FunctionTy, unsigned AddressSpace);
|
||||||
|
|
||||||
enum ZigLLVM_CallingConv {
|
enum ZigLLVM_CallingConv {
|
||||||
ZigLLVM_C = 0,
|
ZigLLVM_C = 0,
|
||||||
ZigLLVM_Fast = 8,
|
ZigLLVM_Fast = 8,
|
||||||
|
@ -137,6 +137,7 @@ test "@Type create slice with null sentinel" {
|
|||||||
.is_volatile = false,
|
.is_volatile = false,
|
||||||
.is_allowzero = false,
|
.is_allowzero = false,
|
||||||
.alignment = 8,
|
.alignment = 8,
|
||||||
|
.address_space = .generic,
|
||||||
.child = *i32,
|
.child = *i32,
|
||||||
.sentinel = null,
|
.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_const = false,
|
||||||
\\ .is_volatile = false,
|
\\ .is_volatile = false,
|
||||||
\\ .alignment = 1,
|
\\ .alignment = 1,
|
||||||
|
\\ .address_space = .generic,
|
||||||
\\ .child = u8,
|
\\ .child = u8,
|
||||||
\\ .is_allowzero = false,
|
\\ .is_allowzero = false,
|
||||||
\\ .sentinel = 0,
|
\\ .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",
|
"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",
|
ctx.testErrStage1("helpful return type error message",
|
||||||
\\export fn foo() u32 {
|
\\export fn foo() u32 {
|
||||||
\\ return error.Ohno;
|
\\ 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