Commit 0048166867

Alex Rønne Petersen <alex@alexrp.com>
2025-01-24 01:58:31
std.Target: Make Cpu.Arch.supportsAddressSpace() take an optional context.
Allows deduplicating the code in Sema.
1 parent aa4ac2f
Changed files (4)
lib/std/builtin.zig
@@ -491,6 +491,21 @@ pub const CallingConvention = union(enum(u8)) {
 /// 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(u5) {
+    /// The places where a user can specify an address space attribute
+    pub const Context = enum {
+        /// A function is specified 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 certain address space.
+        pointer,
+    };
+
     // CPU address spaces.
     generic,
     gs,
lib/std/Target.zig
@@ -1576,15 +1576,23 @@ pub const Cpu = struct {
             };
         }
 
-        /// Returns whether this architecture supports the address space
-        pub fn supportsAddressSpace(arch: Arch, address_space: std.builtin.AddressSpace) bool {
+        /// Returns whether this architecture supports `address_space`. If `context` is `null`, this
+        /// function simply answers the general question of whether the architecture has any concept
+        /// of `address_space`; if non-`null`, the function additionally checks whether
+        /// `address_space` is valid in that context.
+        pub fn supportsAddressSpace(
+            arch: Arch,
+            address_space: std.builtin.AddressSpace,
+            context: ?std.builtin.AddressSpace.Context,
+        ) bool {
             const is_nvptx = arch.isNvptx();
             const is_spirv = arch.isSpirV();
             const is_gpu = is_nvptx or is_spirv or arch == .amdgcn;
             return switch (address_space) {
                 .generic => true,
-                .fs, .gs, .ss => arch == .x86_64 or arch == .x86,
-                .global, .constant, .local, .shared => is_gpu,
+                .fs, .gs, .ss => (arch == .x86_64 or arch == .x86) and (context == null or context == .pointer),
+                .global, .local, .shared => is_gpu,
+                .constant => is_gpu and (context == null or context == .constant),
                 .param => is_nvptx,
                 .input, .output, .uniform, .push_constant, .storage_buffer => is_spirv,
                 // TODO this should also check how many flash banks the cpu has
src/Sema.zig
@@ -37220,30 +37220,12 @@ fn analyzeComptimeAlloc(
     } })));
 }
 
-/// The places where a user can specify an address space attribute
-pub const AddressSpaceContext = enum {
-    /// A function is specified 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 certain address space.
-    pointer,
-};
-
 fn resolveAddressSpace(
     sema: *Sema,
     block: *Block,
     src: LazySrcLoc,
     zir_ref: Zir.Inst.Ref,
-    ctx: AddressSpaceContext,
+    ctx: std.builtin.AddressSpace.Context,
 ) !std.builtin.AddressSpace {
     const air_ref = try sema.resolveInst(zir_ref);
     return sema.analyzeAsAddressSpace(block, src, air_ref, ctx);
@@ -37254,7 +37236,7 @@ pub fn analyzeAsAddressSpace(
     block: *Block,
     src: LazySrcLoc,
     air_ref: Air.Inst.Ref,
-    ctx: AddressSpaceContext,
+    ctx: std.builtin.AddressSpace.Context,
 ) !std.builtin.AddressSpace {
     const pt = sema.pt;
     const addrspace_ty = try sema.getBuiltinType(src, .AddressSpace);
@@ -37264,29 +37246,7 @@ pub fn analyzeAsAddressSpace(
     const target = pt.zcu.getTarget();
     const arch = target.cpu.arch;
 
-    const is_nv = arch.isNvptx();
-    const is_amd = arch == .amdgcn;
-    const is_spirv = arch.isSpirV();
-    const is_gpu = is_nv or is_amd or is_spirv;
-
-    // TODO: Deduplicate with `std.Target.Cpu.Arch.supportsAddressSpace`.
-    const supported = switch (address_space) {
-        // TODO: on spir-v only when os is opencl.
-        .generic => true,
-        .gs, .fs, .ss => (arch == .x86 or arch == .x86_64) and ctx == .pointer,
-        // TODO: check that .shared and .local are left uninitialized
-        .param => is_nv,
-        .input, .output, .uniform, .push_constant, .storage_buffer => is_spirv,
-        .global, .shared, .local => is_gpu,
-        .constant => is_gpu and (ctx == .constant),
-        // TODO this should also check how many flash banks the cpu has
-        .flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr,
-
-        .cog, .hub => arch == .propeller,
-        .lut => arch == .propeller and std.Target.propeller.featureSetHas(target.cpu.features, .p2),
-    };
-
-    if (!supported) {
+    if (!arch.supportsAddressSpace(address_space, ctx)) {
         // TODO error messages could be made more elaborate here
         const entity = switch (ctx) {
             .function => "functions",
@@ -38728,7 +38688,7 @@ pub fn resolveNavPtrModifiers(
     };
 
     const @"addrspace": std.builtin.AddressSpace = as: {
-        const addrspace_ctx: Sema.AddressSpaceContext = switch (zir_decl.kind) {
+        const addrspace_ctx: std.builtin.AddressSpace.Context = switch (zir_decl.kind) {
             .@"var" => .variable,
             else => switch (nav_ty.zigTypeTag(zcu)) {
                 .@"fn" => .function,
src/target.zig
@@ -444,10 +444,10 @@ pub fn addrSpaceCastIsValid(
 ) bool {
     const arch = target.cpu.arch;
     switch (arch) {
-        .x86_64, .x86 => return arch.supportsAddressSpace(from) and arch.supportsAddressSpace(to),
+        .x86_64, .x86 => return arch.supportsAddressSpace(from, null) and arch.supportsAddressSpace(to, null),
         .nvptx64, .nvptx, .amdgcn => {
-            const to_generic = arch.supportsAddressSpace(from) and to == .generic;
-            const from_generic = arch.supportsAddressSpace(to) and from == .generic;
+            const to_generic = arch.supportsAddressSpace(from, null) and to == .generic;
+            const from_generic = arch.supportsAddressSpace(to, null) and from == .generic;
             return to_generic or from_generic;
         },
         else => return from == .generic and to == .generic,