diff options
| author | Robin Voetter <robin@voetter.nl> | 2021-09-02 14:46:31 +0200 |
|---|---|---|
| committer | Robin Voetter <robin@voetter.nl> | 2021-09-20 02:29:03 +0200 |
| commit | 805e1bffbdcab84717356fb1a7b375369407d9c2 (patch) | |
| tree | e6d3eb330017cea8e54eda7171ed75777e3088a0 /src | |
| parent | 7da9fa6fe2e982d10ebc9c3844d1249a4eb1d514 (diff) | |
| download | zig-805e1bffbdcab84717356fb1a7b375369407d9c2.tar.gz zig-805e1bffbdcab84717356fb1a7b375369407d9c2.zip | |
Address Spaces: Sema basics
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 4 | ||||
| -rw-r--r-- | src/Module.zig | 53 | ||||
| -rw-r--r-- | src/Sema.zig | 28 | ||||
| -rw-r--r-- | src/type.zig | 42 |
4 files changed, 107 insertions, 20 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index bfb7a0b10f..443834485f 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -3134,7 +3134,7 @@ fn fnDecl( _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst); try decl_gz.setBlockBody(block_inst); - try wip_decls.payload.ensureUnusedCapacity(gpa, 9); + try wip_decls.payload.ensureUnusedCapacity(gpa, 10); { const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); const casted = @bitCast([4]u32, contents_hash); @@ -3284,7 +3284,7 @@ fn globalVarDecl( _ = try block_scope.addBreak(.break_inline, block_inst, var_inst); try block_scope.setBlockBody(block_inst); - try wip_decls.payload.ensureUnusedCapacity(gpa, 9); + try wip_decls.payload.ensureUnusedCapacity(gpa, 10); { const contents_hash = std.zig.hashSrc(tree.getNodeSource(node)); const casted = @bitCast([4]u32, contents_hash); diff --git a/src/Module.zig b/src/Module.zig index add0562d93..957987b895 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -288,6 +288,8 @@ pub const Decl = struct { align_val: Value, /// Populated when `has_tv`. linksection_val: Value, + /// Populated when `has_tv`. + @"addrspace": std.builtin.AddressSpace, /// The memory for ty, val, align_val, linksection_val. /// If this is `null` then there is no memory management needed. value_arena: ?*std.heap.ArenaAllocator.State = null, @@ -351,7 +353,7 @@ pub const Decl = struct { /// to require re-analysis. outdated, }, - /// Whether `typed_value`, `align_val`, and `linksection_val` are populated. + /// Whether `typed_value`, `align_val`, `linksection_val` and `has_addrspace` are populated. has_tv: bool, /// If `true` it means the `Decl` is the resource owner of the type/value associated /// with it. That means when `Decl` is destroyed, the cleanup code should additionally @@ -366,8 +368,8 @@ pub const Decl = struct { is_exported: bool, /// Whether the ZIR code provides an align instruction. has_align: bool, - /// Whether the ZIR code provides a linksection instruction. - has_linksection: bool, + /// Whether the ZIR code provides a linksection and address space instruction. + has_linksection_or_addrspace: bool, /// Flag used by garbage collection to mark and sweep. /// Decls which correspond to an AST node always have this field set to `true`. /// Anonymous Decls are initialized with this field set to `false` and then it @@ -489,14 +491,22 @@ pub const Decl = struct { if (!decl.has_align) return .none; assert(decl.zir_decl_index != 0); const zir = decl.namespace.file_scope.zir; - return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 6]); + return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 7]); } pub fn zirLinksectionRef(decl: Decl) Zir.Inst.Ref { - if (!decl.has_linksection) return .none; + if (!decl.has_linksection_or_addrspace) return .none; assert(decl.zir_decl_index != 0); const zir = decl.namespace.file_scope.zir; - const extra_index = decl.zir_decl_index + 6 + @boolToInt(decl.has_align); + const extra_index = decl.zir_decl_index + 7 + @boolToInt(decl.has_align); + return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); + } + + pub fn zirAddrspaceRef(decl: Decl) Zir.Inst.Ref { + if (!decl.has_linksection_or_addrspace) return .none; + assert(decl.zir_decl_index != 0); + const zir = decl.namespace.file_scope.zir; + const extra_index = decl.zir_decl_index + 7 + @boolToInt(decl.has_align) + 1; return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); } @@ -3072,7 +3082,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void { new_decl.is_pub = true; new_decl.is_exported = false; new_decl.has_align = false; - new_decl.has_linksection = false; + new_decl.has_linksection_or_addrspace = false; new_decl.ty = struct_ty; new_decl.val = struct_val; new_decl.has_tv = true; @@ -3202,6 +3212,12 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { if (linksection_ref == .none) break :blk Value.initTag(.null_value); break :blk (try sema.resolveInstConst(&block_scope, src, linksection_ref)).val; }; + const address_space = blk: { + const addrspace_ref = decl.zirAddrspaceRef(); + if (addrspace_ref == .none) break :blk .generic; + const addrspace_tv = try sema.resolveInstConst(&block_scope, src, addrspace_ref); + break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace); + }; // Note this resolves the type of the Decl, not the value; if this Decl // is a struct, for example, this resolves `type` (which needs no resolution), // not the struct itself. @@ -3258,6 +3274,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { decl.val = try decl_tv.val.copy(&decl_arena.allocator); decl.align_val = try align_val.copy(&decl_arena.allocator); decl.linksection_val = try linksection_val.copy(&decl_arena.allocator); + decl.@"addrspace" = address_space; decl.has_tv = true; decl.owns_tv = owns_tv; decl_arena_state.* = decl_arena.state; @@ -3319,6 +3336,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { decl.val = try decl_tv.val.copy(&decl_arena.allocator); decl.align_val = try align_val.copy(&decl_arena.allocator); decl.linksection_val = try linksection_val.copy(&decl_arena.allocator); + decl.@"addrspace" = address_space; decl.has_tv = true; decl_arena_state.* = decl_arena.state; decl.value_arena = decl_arena_state; @@ -3526,8 +3544,8 @@ pub fn scanNamespace( const decl_sub_index = extra_index; extra_index += 7; // src_hash(4) + line(1) + name(1) + value(1) - extra_index += @truncate(u1, flags >> 2); - extra_index += @truncate(u1, flags >> 3); + extra_index += @truncate(u1, flags >> 2); // Align + extra_index += @as(u2, @truncate(u1, flags >> 3)) * 2; // Link section or address space, consists of 2 Refs try scanDecl(&scan_decl_iter, decl_sub_index, flags); } @@ -3553,10 +3571,10 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi const zir = namespace.file_scope.zir; // zig fmt: off - const is_pub = (flags & 0b0001) != 0; - const export_bit = (flags & 0b0010) != 0; - const has_align = (flags & 0b0100) != 0; - const has_linksection = (flags & 0b1000) != 0; + const is_pub = (flags & 0b0001) != 0; + const export_bit = (flags & 0b0010) != 0; + const has_align = (flags & 0b0100) != 0; + const has_linksection_or_addrspace = (flags & 0b1000) != 0; // zig fmt: on const line = iter.parent_decl.relativeToLine(zir.extra[decl_sub_index + 4]); @@ -3639,7 +3657,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi new_decl.is_exported = is_exported; new_decl.is_usingnamespace = is_usingnamespace; new_decl.has_align = has_align; - new_decl.has_linksection = has_linksection; + new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace; new_decl.zir_decl_index = @intCast(u32, decl_sub_index); new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive. return; @@ -3656,7 +3674,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi decl.is_exported = is_exported; decl.is_usingnamespace = is_usingnamespace; decl.has_align = has_align; - decl.has_linksection = has_linksection; + decl.has_linksection_or_addrspace = has_linksection_or_addrspace; decl.zir_decl_index = @intCast(u32, decl_sub_index); if (decl.getFunction()) |_| { switch (mod.comp.bin_file.tag) { @@ -4028,6 +4046,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast. .val = undefined, .align_val = undefined, .linksection_val = undefined, + .@"addrspace" = undefined, .analysis = .unreferenced, .deletion_flag = false, .zir_decl_index = 0, @@ -4052,7 +4071,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast. .generation = 0, .is_pub = false, .is_exported = false, - .has_linksection = false, + .has_linksection_or_addrspace = false, .has_align = false, .alive = false, .is_usingnamespace = false, @@ -4357,6 +4376,7 @@ pub fn ptrType( elem_ty: Type, sentinel: ?Value, @"align": u32, + @"addrspace": std.builtin.AddressSpace, bit_offset: u16, host_size: u16, mutable: bool, @@ -4371,6 +4391,7 @@ pub fn ptrType( .pointee_type = elem_ty, .sentinel = sentinel, .@"align" = @"align", + .@"addrspace" = @"addrspace", .bit_offset = bit_offset, .host_size = host_size, .@"allowzero" = @"allowzero", diff --git a/src/Sema.zig b/src/Sema.zig index 8200e95aa5..b1145bab99 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3004,7 +3004,7 @@ fn analyzeCall( new_decl.is_pub = module_fn.owner_decl.is_pub; new_decl.is_exported = module_fn.owner_decl.is_exported; new_decl.has_align = module_fn.owner_decl.has_align; - new_decl.has_linksection = module_fn.owner_decl.has_linksection; + new_decl.has_linksection_or_addrspace = module_fn.owner_decl.has_linksection_or_addrspace; new_decl.zir_decl_index = module_fn.owner_decl.zir_decl_index; new_decl.alive = true; // This Decl is called at runtime. new_decl.has_tv = true; @@ -3895,6 +3895,7 @@ fn zirFunc( ret_ty_body, cc, Value.initTag(.null_value), + .generic, false, inferred_error_set, false, @@ -3911,6 +3912,7 @@ fn funcCommon( ret_ty_body: []const Zir.Inst.Index, cc: std.builtin.CallingConvention, align_val: Value, + address_space: std.builtin.AddressSpace, var_args: bool, inferred_error_set: bool, is_extern: bool, @@ -3968,7 +3970,7 @@ fn funcCommon( // Hot path for some common function types. // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated. if (!is_generic and block.params.items.len == 0 and !var_args and - align_val.tag() == .null_value and !inferred_error_set) + align_val.tag() == .null_value and !inferred_error_set and address_space == .generic) { if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) { break :fn_ty Type.initTag(.fn_noreturn_no_args); @@ -4020,6 +4022,7 @@ fn funcCommon( .comptime_params = comptime_params.ptr, .return_type = return_type, .cc = cc, + .@"addrspace" = address_space, .is_var_args = var_args, .is_generic = is_generic, }); @@ -6876,6 +6879,7 @@ fn zirPtrTypeSimple(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp elem_type, null, 0, + .generic, 0, 0, inst_data.is_mutable, @@ -6908,6 +6912,13 @@ fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u32); } else 0; + const address_space = if (inst_data.flags.has_addrspace) blk: { + const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); + extra_i += 1; + const addrspace_tv = try sema.resolveInstConst(block, .unneeded, ref); + break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace); + } else .generic; + const bit_start = if (inst_data.flags.has_bit_range) blk: { const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); extra_i += 1; @@ -6930,6 +6941,7 @@ fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr elem_type, sentinel, abi_align, + address_space, bit_start, bit_end, inst_data.flags.is_mutable, @@ -8035,6 +8047,7 @@ fn zirFuncExtended( const src: LazySrcLoc = .{ .node_offset = extra.data.src_node }; const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = extra.data.src_node }; const align_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at align + const addrspace_src: LazySrcLoc = src; // TODO(Snektron) add a LazySrcLoc that points at addrspace const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small); var extra_index: usize = extra.end; @@ -8059,6 +8072,13 @@ fn zirFuncExtended( break :blk align_tv.val; } else Value.initTag(.null_value); + const address_space: std.builtin.AddressSpace = if (small.has_addrspace) blk: { + const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); + extra_index += 1; + const addrspace_tv = try sema.resolveInstConst(block, addrspace_src, addrspace_ref); + break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace); + } else .generic; + const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len]; extra_index += ret_ty_body.len; @@ -8081,6 +8101,7 @@ fn zirFuncExtended( ret_ty_body, cc, align_val, + address_space, is_var_args, is_inferred_error, is_extern, @@ -9693,6 +9714,9 @@ fn analyzeSlice( return_elem_type, if (end_opt == .none) slice_sentinel else null, 0, // TODO alignment + // TODO(Snektron) address space, should be inferred from the pointer type. + // TODO(Snektron) address space for slicing a local, should compute address space from context and architecture. + .generic, 0, 0, !ptr_child.isConstPtr(), diff --git a/src/type.zig b/src/type.zig index 8eca352eac..647d88c60f 100644 --- a/src/type.zig +++ b/src/type.zig @@ -289,6 +289,7 @@ pub const Type = extern union { .pointee_type = Type.initTag(.comptime_int), .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -300,6 +301,7 @@ pub const Type = extern union { .pointee_type = Type.initTag(.u8), .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -311,6 +313,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -322,6 +325,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -333,6 +337,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -344,6 +349,7 @@ pub const Type = extern union { .pointee_type = Type.initTag(.u8), .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -355,6 +361,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -366,6 +373,7 @@ pub const Type = extern union { .pointee_type = Type.initTag(.u8), .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -377,6 +385,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -388,6 +397,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -399,6 +409,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -410,6 +421,7 @@ pub const Type = extern union { .pointee_type = self.castPointer().?.data, .sentinel = null, .@"align" = 0, + .@"addrspace" = .generic, .bit_offset = 0, .host_size = 0, .@"allowzero" = false, @@ -462,6 +474,8 @@ pub const Type = extern union { return false; if (info_a.host_size != info_b.host_size) return false; + if (info_a.@"addrspace" != info_b.@"addrspace") + return false; const sentinel_a = info_a.sentinel; const sentinel_b = info_b.sentinel; @@ -516,6 +530,8 @@ pub const Type = extern union { return false; if (a.fnCallingConvention() != b.fnCallingConvention()) return false; + if (a.fnAddressSpace() != b.fnAddressSpace()) + return false; const a_param_len = a.fnParamLen(); const b_param_len = b.fnParamLen(); if (a_param_len != b_param_len) @@ -822,6 +838,7 @@ pub const Type = extern union { .return_type = try payload.return_type.copy(allocator), .param_types = param_types, .cc = payload.cc, + .@"addrspace" = payload.@"addrspace", .is_var_args = payload.is_var_args, .is_generic = payload.is_generic, .comptime_params = comptime_params.ptr, @@ -837,6 +854,7 @@ pub const Type = extern union { .pointee_type = try payload.pointee_type.copy(allocator), .sentinel = sent, .@"align" = payload.@"align", + .@"addrspace" = payload.@"addrspace", .bit_offset = payload.bit_offset, .host_size = payload.host_size, .@"allowzero" = payload.@"allowzero", @@ -983,6 +1001,9 @@ pub const Type = extern union { try writer.writeAll(") callconv(."); try writer.writeAll(@tagName(payload.cc)); try writer.writeAll(") "); + if (payload.@"addrspace" != .generic) { + try writer.print("addrspace(.{s}) ", .{ @tagName(payload.@"addrspace") }); + } ty = payload.return_type; continue; }, @@ -1114,6 +1135,9 @@ pub const Type = extern union { } try writer.writeAll(") "); } + if (payload.@"addrspace" != .generic) { + try writer.print("addrspace(.{s}) ", .{ @tagName(payload.@"addrspace") }); + } if (!payload.mutable) try writer.writeAll("const "); if (payload.@"volatile") try writer.writeAll("volatile "); if (payload.@"allowzero") try writer.writeAll("allowzero "); @@ -2642,6 +2666,18 @@ pub const Type = extern union { }; } + pub fn fnAddressSpace(self: Type) std.builtin.AddressSpace { + return switch (self.tag()) { + .fn_noreturn_no_args => .generic, + .fn_void_no_args => .generic, + .fn_naked_noreturn_no_args => .generic, + .fn_ccc_void_no_args => .generic, + .function => self.castTag(.function).?.data.@"addrspace", + + else => unreachable, + }; + } + pub fn fnInfo(ty: Type) Payload.Function.Data { return switch (ty.tag()) { .fn_noreturn_no_args => .{ @@ -2649,6 +2685,7 @@ pub const Type = extern union { .comptime_params = undefined, .return_type = initTag(.noreturn), .cc = .Unspecified, + .@"addrspace" = .generic, .is_var_args = false, .is_generic = false, }, @@ -2657,6 +2694,7 @@ pub const Type = extern union { .comptime_params = undefined, .return_type = initTag(.void), .cc = .Unspecified, + .@"addrspace" = .generic, .is_var_args = false, .is_generic = false, }, @@ -2665,6 +2703,7 @@ pub const Type = extern union { .comptime_params = undefined, .return_type = initTag(.noreturn), .cc = .Naked, + .@"addrspace" = .generic, .is_var_args = false, .is_generic = false, }, @@ -2673,6 +2712,7 @@ pub const Type = extern union { .comptime_params = undefined, .return_type = initTag(.void), .cc = .C, + .@"addrspace" = .generic, .is_var_args = false, .is_generic = false, }, @@ -3544,6 +3584,7 @@ pub const Type = extern union { comptime_params: [*]bool, return_type: Type, cc: std.builtin.CallingConvention, + @"addrspace": std.builtin.AddressSpace, is_var_args: bool, is_generic: bool, @@ -3581,6 +3622,7 @@ pub const Type = extern union { sentinel: ?Value, /// If zero use pointee_type.AbiAlign() @"align": u32, + @"addrspace": std.builtin.AddressSpace, bit_offset: u16, host_size: u16, @"allowzero": bool, |
