aboutsummaryrefslogtreecommitdiff
path: root/src/Module.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/Module.zig')
-rw-r--r--src/Module.zig145
1 files changed, 100 insertions, 45 deletions
diff --git a/src/Module.zig b/src/Module.zig
index add0562d93..500c34bcb0 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -288,6 +288,8 @@ pub const Decl = struct {
align_val: Value,
/// Populated when `has_tv`.
linksection_val: Value,
+ /// Populated when `has_tv`.
+ @"addrspace": std.builtin.AddressSpace,
/// The memory for ty, val, align_val, linksection_val.
/// If this is `null` then there is no memory management needed.
value_arena: ?*std.heap.ArenaAllocator.State = null,
@@ -351,7 +353,7 @@ pub const Decl = struct {
/// to require re-analysis.
outdated,
},
- /// Whether `typed_value`, `align_val`, and `linksection_val` are populated.
+ /// Whether `typed_value`, `align_val`, `linksection_val` and `addrspace` are populated.
has_tv: bool,
/// If `true` it means the `Decl` is the resource owner of the type/value associated
/// with it. That means when `Decl` is destroyed, the cleanup code should additionally
@@ -366,8 +368,8 @@ pub const Decl = struct {
is_exported: bool,
/// Whether the ZIR code provides an align instruction.
has_align: bool,
- /// Whether the ZIR code provides a linksection instruction.
- has_linksection: bool,
+ /// Whether the ZIR code provides a linksection and address space instruction.
+ has_linksection_or_addrspace: bool,
/// Flag used by garbage collection to mark and sweep.
/// Decls which correspond to an AST node always have this field set to `true`.
/// Anonymous Decls are initialized with this field set to `false` and then it
@@ -489,14 +491,22 @@ pub const Decl = struct {
if (!decl.has_align) return .none;
assert(decl.zir_decl_index != 0);
const zir = decl.namespace.file_scope.zir;
- return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 6]);
+ return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 7]);
}
pub fn zirLinksectionRef(decl: Decl) Zir.Inst.Ref {
- if (!decl.has_linksection) return .none;
+ if (!decl.has_linksection_or_addrspace) return .none;
assert(decl.zir_decl_index != 0);
const zir = decl.namespace.file_scope.zir;
- const extra_index = decl.zir_decl_index + 6 + @boolToInt(decl.has_align);
+ const extra_index = decl.zir_decl_index + 7 + @boolToInt(decl.has_align);
+ return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
+ }
+
+ pub fn zirAddrspaceRef(decl: Decl) Zir.Inst.Ref {
+ if (!decl.has_linksection_or_addrspace) return .none;
+ assert(decl.zir_decl_index != 0);
+ const zir = decl.namespace.file_scope.zir;
+ const extra_index = decl.zir_decl_index + 7 + @boolToInt(decl.has_align) + 1;
return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
}
@@ -3072,7 +3082,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
new_decl.is_pub = true;
new_decl.is_exported = false;
new_decl.has_align = false;
- new_decl.has_linksection = false;
+ new_decl.has_linksection_or_addrspace = false;
new_decl.ty = struct_ty;
new_decl.val = struct_val;
new_decl.has_tv = true;
@@ -3202,6 +3212,24 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
if (linksection_ref == .none) break :blk Value.initTag(.null_value);
break :blk (try sema.resolveInstConst(&block_scope, src, linksection_ref)).val;
};
+ const address_space = blk: {
+ const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.tag()) {
+ .function, .extern_fn => .function,
+ .variable => .variable,
+ else => .constant,
+ };
+
+ break :blk switch (decl.zirAddrspaceRef()) {
+ .none => switch (addrspace_ctx) {
+ .function => target_util.defaultAddressSpace(sema.mod.getTarget(), .function),
+ .variable => target_util.defaultAddressSpace(sema.mod.getTarget(), .global_mutable),
+ .constant => target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant),
+ else => unreachable,
+ },
+ else => |addrspace_ref| try sema.analyzeAddrspace(&block_scope, src, addrspace_ref, addrspace_ctx),
+ };
+ };
+
// Note this resolves the type of the Decl, not the value; if this Decl
// is a struct, for example, this resolves `type` (which needs no resolution),
// not the struct itself.
@@ -3258,6 +3286,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
decl.val = try decl_tv.val.copy(&decl_arena.allocator);
decl.align_val = try align_val.copy(&decl_arena.allocator);
decl.linksection_val = try linksection_val.copy(&decl_arena.allocator);
+ decl.@"addrspace" = address_space;
decl.has_tv = true;
decl.owns_tv = owns_tv;
decl_arena_state.* = decl_arena.state;
@@ -3319,6 +3348,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
decl.val = try decl_tv.val.copy(&decl_arena.allocator);
decl.align_val = try align_val.copy(&decl_arena.allocator);
decl.linksection_val = try linksection_val.copy(&decl_arena.allocator);
+ decl.@"addrspace" = address_space;
decl.has_tv = true;
decl_arena_state.* = decl_arena.state;
decl.value_arena = decl_arena_state;
@@ -3526,8 +3556,8 @@ pub fn scanNamespace(
const decl_sub_index = extra_index;
extra_index += 7; // src_hash(4) + line(1) + name(1) + value(1)
- extra_index += @truncate(u1, flags >> 2);
- extra_index += @truncate(u1, flags >> 3);
+ extra_index += @truncate(u1, flags >> 2); // Align
+ extra_index += @as(u2, @truncate(u1, flags >> 3)) * 2; // Link section or address space, consists of 2 Refs
try scanDecl(&scan_decl_iter, decl_sub_index, flags);
}
@@ -3553,10 +3583,10 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
const zir = namespace.file_scope.zir;
// zig fmt: off
- const is_pub = (flags & 0b0001) != 0;
- const export_bit = (flags & 0b0010) != 0;
- const has_align = (flags & 0b0100) != 0;
- const has_linksection = (flags & 0b1000) != 0;
+ const is_pub = (flags & 0b0001) != 0;
+ const export_bit = (flags & 0b0010) != 0;
+ const has_align = (flags & 0b0100) != 0;
+ const has_linksection_or_addrspace = (flags & 0b1000) != 0;
// zig fmt: on
const line = iter.parent_decl.relativeToLine(zir.extra[decl_sub_index + 4]);
@@ -3639,7 +3669,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
new_decl.is_exported = is_exported;
new_decl.is_usingnamespace = is_usingnamespace;
new_decl.has_align = has_align;
- new_decl.has_linksection = has_linksection;
+ new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
new_decl.zir_decl_index = @intCast(u32, decl_sub_index);
new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive.
return;
@@ -3656,7 +3686,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
decl.is_exported = is_exported;
decl.is_usingnamespace = is_usingnamespace;
decl.has_align = has_align;
- decl.has_linksection = has_linksection;
+ decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
decl.zir_decl_index = @intCast(u32, decl_sub_index);
if (decl.getFunction()) |_| {
switch (mod.comp.bin_file.tag) {
@@ -4028,6 +4058,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.
.val = undefined,
.align_val = undefined,
.linksection_val = undefined,
+ .@"addrspace" = undefined,
.analysis = .unreferenced,
.deletion_flag = false,
.zir_decl_index = 0,
@@ -4052,7 +4083,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.
.generation = 0,
.is_pub = false,
.is_exported = false,
- .has_linksection = false,
+ .has_linksection_or_addrspace = false,
.has_align = false,
.alive = false,
.is_usingnamespace = false,
@@ -4185,6 +4216,9 @@ pub fn createAnonymousDeclFromDeclNamed(
new_decl.src_line = owner_decl.src_line;
new_decl.ty = typed_value.ty;
new_decl.val = typed_value.val;
+ new_decl.align_val = Value.initTag(.null_value);
+ new_decl.linksection_val = Value.initTag(.null_value);
+ new_decl.@"addrspace" = .generic; // default global addrspace
new_decl.has_tv = true;
new_decl.analysis = .complete;
new_decl.generation = mod.generation;
@@ -4330,10 +4364,59 @@ pub fn simplePtrType(
elem_ty: Type,
mutable: bool,
size: std.builtin.TypeInfo.Pointer.Size,
+ @"addrspace": std.builtin.AddressSpace,
) Allocator.Error!Type {
+ return ptrType(
+ arena,
+ elem_ty,
+ null,
+ 0,
+ @"addrspace",
+ 0,
+ 0,
+ mutable,
+ false,
+ false,
+ size,
+ );
+}
+
+pub fn ptrType(
+ arena: *Allocator,
+ elem_ty: Type,
+ sentinel: ?Value,
+ @"align": u32,
+ @"addrspace": std.builtin.AddressSpace,
+ bit_offset: u16,
+ host_size: u16,
+ mutable: bool,
+ @"allowzero": bool,
+ @"volatile": bool,
+ size: std.builtin.TypeInfo.Pointer.Size,
+) Allocator.Error!Type {
+ assert(host_size == 0 or bit_offset < host_size * 8);
+
+ if (sentinel != null or @"align" != 0 or @"addrspace" != .generic or
+ bit_offset != 0 or host_size != 0 or @"allowzero" or @"volatile")
+ {
+ return Type.Tag.pointer.create(arena, .{
+ .pointee_type = elem_ty,
+ .sentinel = sentinel,
+ .@"align" = @"align",
+ .@"addrspace" = @"addrspace",
+ .bit_offset = bit_offset,
+ .host_size = host_size,
+ .@"allowzero" = @"allowzero",
+ .mutable = mutable,
+ .@"volatile" = @"volatile",
+ .size = size,
+ });
+ }
+
if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) {
return Type.initTag(.const_slice_u8);
}
+
// TODO stage1 type inference bug
const T = Type.Tag;
@@ -4352,34 +4435,6 @@ pub fn simplePtrType(
return Type.initPayload(&type_payload.base);
}
-pub fn ptrType(
- arena: *Allocator,
- elem_ty: Type,
- sentinel: ?Value,
- @"align": u32,
- bit_offset: u16,
- host_size: u16,
- mutable: bool,
- @"allowzero": bool,
- @"volatile": bool,
- size: std.builtin.TypeInfo.Pointer.Size,
-) Allocator.Error!Type {
- assert(host_size == 0 or bit_offset < host_size * 8);
-
- // TODO check if type can be represented by simplePtrType
- return Type.Tag.pointer.create(arena, .{
- .pointee_type = elem_ty,
- .sentinel = sentinel,
- .@"align" = @"align",
- .bit_offset = bit_offset,
- .host_size = host_size,
- .@"allowzero" = @"allowzero",
- .mutable = mutable,
- .@"volatile" = @"volatile",
- .size = size,
- });
-}
-
pub fn optionalType(arena: *Allocator, child_type: Type) Allocator.Error!Type {
switch (child_type.tag()) {
.single_const_pointer => return Type.Tag.optional_single_const_pointer.create(
@@ -4709,7 +4764,7 @@ pub fn populateTestFunctions(mod: *Module) !void {
const builtin_file = (mod.importPkg(builtin_pkg) catch unreachable).file;
const builtin_namespace = builtin_file.root_decl.?.namespace;
const decl = builtin_namespace.decls.get("test_functions").?;
- var buf: Type.Payload.ElemType = undefined;
+ var buf: Type.SlicePtrFieldTypeBuffer = undefined;
const tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf).elemType();
const array_decl = d: {