Commit 7da9fa6fe2

Robin Voetter <robin@voetter.nl>
2021-08-17 01:38:22
Address spaces: AstGen
Adds AST generation for address spaces on pointers, function prototypes, function declarations and variable declarations. In the latter two cases, declaration properties were already stored more efficiently in a declaration structure. To accomodate these for address spaces, the bit indicating presence of a linksection attribute has been extended to include either linksection, address space, or both.
1 parent ccc7f99
Changed files (7)
lib/std/builtin.zig
@@ -166,6 +166,12 @@ pub const CallingConvention = enum {
     SysV,
 };
 
+/// This data structure is used by the Zig language code generation and
+/// therefore must be kept in sync with the compiler implementation.
+pub const AddressSpace = enum {
+    generic,
+};
+
 /// This data structure is used by the Zig language code generation and
 /// therefore must be kept in sync with the compiler implementation.
 pub const SourceLocation = struct {
src/translate_c/ast.zig
@@ -2706,6 +2706,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
                     .lhs = try c.addExtra(std.zig.Ast.Node.FnProtoOne{
                         .param = params.items[0],
                         .align_expr = align_expr,
+                        .addrspace_expr = 0, // TODO
                         .section_expr = section_expr,
                         .callconv_expr = callconv_expr,
                     }),
@@ -2721,6 +2722,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
                         .params_start = span.start,
                         .params_end = span.end,
                         .align_expr = align_expr,
+                        .addrspace_expr = 0, // TODO
                         .section_expr = section_expr,
                         .callconv_expr = callconv_expr,
                     }),
src/AstGen.zig
@@ -1116,6 +1116,11 @@ fn fnProtoExpr(
     const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
         break :inst try expr(gz, scope, align_rl, fn_proto.ast.align_expr);
     };
+
+    const addrspace_inst: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: {
+        break :inst try expr(gz, scope, .{ .ty = .address_space_type }, fn_proto.ast.addrspace_expr);
+    };
+
     if (fn_proto.ast.section_expr != 0) {
         return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{});
     }
@@ -1148,6 +1153,7 @@ fn fnProtoExpr(
         .body = &[0]Zir.Inst.Index{},
         .cc = cc,
         .align_inst = align_inst,
+        .addrspace_inst = addrspace_inst,
         .lib_name = 0,
         .is_var_args = is_var_args,
         .is_inferred_error = false,
@@ -2714,6 +2720,7 @@ fn ptrType(
     const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type);
 
     const simple = ptr_info.ast.align_node == 0 and
+        ptr_info.ast.addrspace_node == 0 and
         ptr_info.ast.sentinel == 0 and
         ptr_info.ast.bit_range_start == 0;
 
@@ -2732,6 +2739,7 @@ fn ptrType(
 
     var sentinel_ref: Zir.Inst.Ref = .none;
     var align_ref: Zir.Inst.Ref = .none;
+    var addrspace_ref: Zir.Inst.Ref = .none;
     var bit_start_ref: Zir.Inst.Ref = .none;
     var bit_end_ref: Zir.Inst.Ref = .none;
     var trailing_count: u32 = 0;
@@ -2744,6 +2752,10 @@ fn ptrType(
         align_ref = try expr(gz, scope, align_rl, ptr_info.ast.align_node);
         trailing_count += 1;
     }
+    if (ptr_info.ast.addrspace_node != 0) {
+        addrspace_ref = try expr(gz, scope, .{ .ty = .address_space_type }, ptr_info.ast.addrspace_node);
+        trailing_count += 1;
+    }
     if (ptr_info.ast.bit_range_start != 0) {
         assert(ptr_info.ast.bit_range_end != 0);
         bit_start_ref = try expr(gz, scope, .none, ptr_info.ast.bit_range_start);
@@ -2764,6 +2776,9 @@ fn ptrType(
     if (align_ref != .none) {
         gz.astgen.extra.appendAssumeCapacity(@enumToInt(align_ref));
     }
+    if (addrspace_ref != .none) {
+        gz.astgen.extra.appendAssumeCapacity(@enumToInt(addrspace_ref));
+    }
     if (bit_start_ref != .none) {
         gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_start_ref));
         gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_end_ref));
@@ -2779,6 +2794,7 @@ fn ptrType(
                 .is_volatile = ptr_info.volatile_token != null,
                 .has_sentinel = sentinel_ref != .none,
                 .has_align = align_ref != .none,
+                .has_addrspace = addrspace_ref != .none,
                 .has_bit_range = bit_start_ref != .none,
             },
             .size = ptr_info.size,
@@ -2847,7 +2863,7 @@ const WipDecls = struct {
         is_pub: bool,
         is_export: bool,
         has_align: bool,
-        has_section: bool,
+        has_section_or_addrspace: bool,
     ) Allocator.Error!void {
         if (wip_decls.decl_index % fields_per_u32 == 0 and wip_decls.decl_index != 0) {
             try wip_decls.bit_bag.append(gpa, wip_decls.cur_bit_bag);
@@ -2857,7 +2873,7 @@ const WipDecls = struct {
             (@as(u32, @boolToInt(is_pub)) << 28) |
             (@as(u32, @boolToInt(is_export)) << 29) |
             (@as(u32, @boolToInt(has_align)) << 30) |
-            (@as(u32, @boolToInt(has_section)) << 31);
+            (@as(u32, @boolToInt(has_section_or_addrspace)) << 31);
         wip_decls.decl_index += 1;
     }
 
@@ -2922,7 +2938,8 @@ fn fnDecl(
         const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false;
         break :blk token_tags[maybe_inline_token] == .keyword_inline;
     };
-    try wip_decls.next(gpa, is_pub, is_export, fn_proto.ast.align_expr != 0, fn_proto.ast.section_expr != 0);
+    const has_section_or_addrspace = fn_proto.ast.section_expr != 0 or fn_proto.ast.addrspace_expr != 0;
+    try wip_decls.next(gpa, is_pub, is_export, fn_proto.ast.align_expr != 0, has_section_or_addrspace);
 
     var params_scope = &fn_gz.base;
     const is_var_args = is_var_args: {
@@ -3011,6 +3028,9 @@ fn fnDecl(
     const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
         break :inst try expr(&decl_gz, params_scope, align_rl, fn_proto.ast.align_expr);
     };
+    const addrspace_inst: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: {
+        break :inst try expr(&decl_gz, params_scope, .{ .ty = .address_space_type }, fn_proto.ast.addrspace_expr);
+    };
     const section_inst: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: {
         break :inst try comptimeExpr(&decl_gz, params_scope, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr);
     };
@@ -3060,6 +3080,7 @@ fn fnDecl(
             .body = &[0]Zir.Inst.Index{},
             .cc = cc,
             .align_inst = .none, // passed in the per-decl data
+            .addrspace_inst = .none, // passed in the per-decl data
             .lib_name = lib_name,
             .is_var_args = is_var_args,
             .is_inferred_error = false,
@@ -3099,6 +3120,7 @@ fn fnDecl(
             .body = fn_gz.instructions.items,
             .cc = cc,
             .align_inst = .none, // passed in the per-decl data
+            .addrspace_inst = .none, // passed in the per-decl data
             .lib_name = lib_name,
             .is_var_args = is_var_args,
             .is_inferred_error = is_inferred_error,
@@ -3127,8 +3149,10 @@ fn fnDecl(
     if (align_inst != .none) {
         wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst));
     }
-    if (section_inst != .none) {
+
+    if (has_section_or_addrspace) {
         wip_decls.payload.appendAssumeCapacity(@enumToInt(section_inst));
+        wip_decls.payload.appendAssumeCapacity(@enumToInt(addrspace_inst));
     }
 }
 
@@ -3175,10 +3199,14 @@ fn globalVarDecl(
     const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node == 0) .none else inst: {
         break :inst try expr(&block_scope, &block_scope.base, align_rl, var_decl.ast.align_node);
     };
+    const addrspace_inst: Zir.Inst.Ref = if (var_decl.ast.addrspace_node == 0) .none else inst: {
+        break :inst try expr(&block_scope, &block_scope.base, .{ .ty = .address_space_type }, var_decl.ast.addrspace_node);
+    };
     const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: {
         break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .ty = .const_slice_u8_type }, var_decl.ast.section_node);
     };
-    try wip_decls.next(gpa, is_pub, is_export, align_inst != .none, section_inst != .none);
+    const has_section_or_addrspace = section_inst != .none or addrspace_inst != .none;
+    try wip_decls.next(gpa, is_pub, is_export, align_inst != .none, has_section_or_addrspace);
 
     const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: {
         if (!is_mutable) {
@@ -3271,8 +3299,9 @@ fn globalVarDecl(
     if (align_inst != .none) {
         wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst));
     }
-    if (section_inst != .none) {
+    if (has_section_or_addrspace) {
         wip_decls.payload.appendAssumeCapacity(@enumToInt(section_inst));
+        wip_decls.payload.appendAssumeCapacity(@enumToInt(addrspace_inst));
     }
 }
 
@@ -3443,6 +3472,7 @@ fn testDecl(
         .body = fn_block.instructions.items,
         .cc = .none,
         .align_inst = .none,
+        .addrspace_inst = .none,
         .lib_name = 0,
         .is_var_args = false,
         .is_inferred_error = true,
@@ -9178,6 +9208,7 @@ const GenZir = struct {
         ret_br: Zir.Inst.Index,
         cc: Zir.Inst.Ref,
         align_inst: Zir.Inst.Ref,
+        addrspace_inst: Zir.Inst.Ref,
         lib_name: u32,
         is_var_args: bool,
         is_inferred_error: bool,
@@ -9221,7 +9252,7 @@ const GenZir = struct {
 
         if (args.cc != .none or args.lib_name != 0 or
             args.is_var_args or args.is_test or args.align_inst != .none or
-            args.is_extern)
+            args.addrspace_inst != .none or args.is_extern)
         {
             try astgen.extra.ensureUnusedCapacity(
                 gpa,
@@ -9229,6 +9260,7 @@ const GenZir = struct {
                     args.ret_ty.len + args.body.len + src_locs.len +
                     @boolToInt(args.lib_name != 0) +
                     @boolToInt(args.align_inst != .none) +
+                    @boolToInt(args.addrspace_inst != .none) +
                     @boolToInt(args.cc != .none),
             );
             const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{
@@ -9246,6 +9278,9 @@ const GenZir = struct {
             if (args.align_inst != .none) {
                 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
             }
+            if (args.addrspace_inst != .none) {
+                astgen.extra.appendAssumeCapacity(@enumToInt(args.addrspace_inst));
+            }
             astgen.extra.appendSliceAssumeCapacity(args.ret_ty);
             astgen.extra.appendSliceAssumeCapacity(args.body);
             astgen.extra.appendSliceAssumeCapacity(src_locs);
@@ -9264,6 +9299,7 @@ const GenZir = struct {
                         .has_lib_name = args.lib_name != 0,
                         .has_cc = args.cc != .none,
                         .has_align = args.align_inst != .none,
+                        .has_addrspace = args.addrspace_inst != .none,
                         .is_test = args.is_test,
                         .is_extern = args.is_extern,
                     }),
src/Sema.zig
@@ -10200,6 +10200,7 @@ fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type
         .atomic_order => return sema.resolveBuiltinTypeFields(block, src, "AtomicOrder"),
         .atomic_rmw_op => return sema.resolveBuiltinTypeFields(block, src, "AtomicRmwOp"),
         .calling_convention => return sema.resolveBuiltinTypeFields(block, src, "CallingConvention"),
+        .address_space => return sema.resolveBuiltinTypeFields(block, src, "AddressSpace"),
         .float_mode => return sema.resolveBuiltinTypeFields(block, src, "FloatMode"),
         .reduce_op => return sema.resolveBuiltinTypeFields(block, src, "ReduceOp"),
         .call_options => return sema.resolveBuiltinTypeFields(block, src, "CallOptions"),
@@ -10594,6 +10595,7 @@ fn typeHasOnePossibleValue(
         .atomic_order,
         .atomic_rmw_op,
         .calling_convention,
+        .address_space,
         .float_mode,
         .reduce_op,
         .call_options,
@@ -10779,6 +10781,7 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
         .atomic_order => return .atomic_order_type,
         .atomic_rmw_op => return .atomic_rmw_op_type,
         .calling_convention => return .calling_convention_type,
+        .address_space => return .address_space_type,
         .float_mode => return .float_mode_type,
         .reduce_op => return .reduce_op_type,
         .call_options => return .call_options_type,
src/type.zig
@@ -127,6 +127,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             => return .Enum,
@@ -746,6 +747,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -958,6 +960,7 @@ pub const Type = extern union {
                 .atomic_order => return writer.writeAll("std.builtin.AtomicOrder"),
                 .atomic_rmw_op => return writer.writeAll("std.builtin.AtomicRmwOp"),
                 .calling_convention => return writer.writeAll("std.builtin.CallingConvention"),
+                .address_space => return writer.writeAll("std.builtin.AddressSpace"),
                 .float_mode => return writer.writeAll("std.builtin.FloatMode"),
                 .reduce_op => return writer.writeAll("std.builtin.ReduceOp"),
                 .call_options => return writer.writeAll("std.builtin.CallOptions"),
@@ -1186,6 +1189,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -1301,6 +1305,7 @@ pub const Type = extern union {
             .atomic_order => return Value.initTag(.atomic_order_type),
             .atomic_rmw_op => return Value.initTag(.atomic_rmw_op_type),
             .calling_convention => return Value.initTag(.calling_convention_type),
+            .address_space => return Value.initTag(.address_space_type),
             .float_mode => return Value.initTag(.float_mode_type),
             .reduce_op => return Value.initTag(.reduce_op_type),
             .call_options => return Value.initTag(.call_options_type),
@@ -1362,6 +1367,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -1508,6 +1514,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -1734,6 +1741,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -2018,6 +2026,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -2775,6 +2784,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -2982,6 +2992,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -3006,6 +3017,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -3029,6 +3041,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -3082,6 +3095,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -3137,6 +3151,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -3174,6 +3189,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -3224,6 +3240,7 @@ pub const Type = extern union {
             .atomic_order,
             .atomic_rmw_op,
             .calling_convention,
+            .address_space,
             .float_mode,
             .reduce_op,
             .call_options,
@@ -3284,6 +3301,7 @@ pub const Type = extern union {
         atomic_order,
         atomic_rmw_op,
         calling_convention,
+        address_space,
         float_mode,
         reduce_op,
         call_options,
@@ -3407,6 +3425,7 @@ pub const Type = extern union {
                 .atomic_order,
                 .atomic_rmw_op,
                 .calling_convention,
+                .address_space,
                 .float_mode,
                 .reduce_op,
                 .call_options,
src/value.zig
@@ -63,6 +63,7 @@ pub const Value = extern union {
         atomic_order_type,
         atomic_rmw_op_type,
         calling_convention_type,
+        address_space_type,
         float_mode_type,
         reduce_op_type,
         call_options_type,
@@ -226,6 +227,7 @@ pub const Value = extern union {
                 .atomic_order_type,
                 .atomic_rmw_op_type,
                 .calling_convention_type,
+                .address_space_type,
                 .float_mode_type,
                 .reduce_op_type,
                 .call_options_type,
@@ -412,6 +414,7 @@ pub const Value = extern union {
             .atomic_order_type,
             .atomic_rmw_op_type,
             .calling_convention_type,
+            .address_space_type,
             .float_mode_type,
             .reduce_op_type,
             .call_options_type,
@@ -625,6 +628,7 @@ pub const Value = extern union {
             .atomic_order_type => return out_stream.writeAll("std.builtin.AtomicOrder"),
             .atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"),
             .calling_convention_type => return out_stream.writeAll("std.builtin.CallingConvention"),
+            .address_space_type => return out_stream.writeAll("std.builtin.AddressSpace"),
             .float_mode_type => return out_stream.writeAll("std.builtin.FloatMode"),
             .reduce_op_type => return out_stream.writeAll("std.builtin.ReduceOp"),
             .call_options_type => return out_stream.writeAll("std.builtin.CallOptions"),
@@ -792,6 +796,7 @@ pub const Value = extern union {
             .atomic_order_type => Type.initTag(.atomic_order),
             .atomic_rmw_op_type => Type.initTag(.atomic_rmw_op),
             .calling_convention_type => Type.initTag(.calling_convention),
+            .address_space_type => Type.initTag(.address_space),
             .float_mode_type => Type.initTag(.float_mode),
             .reduce_op_type => Type.initTag(.reduce_op),
             .call_options_type => Type.initTag(.call_options),
src/Zir.zig
@@ -488,10 +488,10 @@ pub const Inst = struct {
         /// this instruction; a following 'ret' instruction will do the diversion.
         /// Uses the `str_tok` union field.
         ret_err_value_code,
-        /// Create a pointer type that does not have a sentinel, alignment, or bit range specified.
+        /// Create a pointer type that does not have a sentinel, alignment, address space, or bit range specified.
         /// Uses the `ptr_type_simple` union field.
         ptr_type_simple,
-        /// Create a pointer type which can have a sentinel, alignment, and/or bit range.
+        /// Create a pointer type which can have a sentinel, alignment, address space, and/or bit range.
         /// Uses the `ptr_type` union field.
         ptr_type,
         /// Slice operation `lhs[rhs..]`. No sentinel and no end offset.
@@ -1717,6 +1717,7 @@ pub const Inst = struct {
         atomic_order_type,
         atomic_rmw_op_type,
         calling_convention_type,
+        address_space_type,
         float_mode_type,
         reduce_op_type,
         call_options_type,
@@ -1973,6 +1974,10 @@ pub const Inst = struct {
                 .ty = Type.initTag(.type),
                 .val = Value.initTag(.calling_convention_type),
             },
+            .address_space_type = .{
+                .ty = Type.initTag(.type),
+                .val = Value.initTag(.address_space_type),
+            },
             .float_mode_type = .{
                 .ty = Type.initTag(.type),
                 .val = Value.initTag(.float_mode_type),
@@ -2174,8 +2179,9 @@ pub const Inst = struct {
                 is_volatile: bool,
                 has_sentinel: bool,
                 has_align: bool,
+                has_addrspace: bool,
                 has_bit_range: bool,
-                _: u2 = undefined,
+                _: u1 = undefined,
             },
             size: std.builtin.TypeInfo.Pointer.Size,
             /// Index into extra. See `PtrType`.
@@ -2303,6 +2309,7 @@ pub const Inst = struct {
     /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set
     /// 1. cc: Ref, // if has_cc is set
     /// 2. align: Ref, // if has_align is set
+    /// 3. addrspace: Ref, // if has_addrspace is set
     /// 3. return_type: Index // for each ret_body_len
     /// 4. body: Index // for each body_len
     /// 5. src_locs: Func.SrcLocs // if body_len != 0
@@ -2320,9 +2327,10 @@ pub const Inst = struct {
             has_lib_name: bool,
             has_cc: bool,
             has_align: bool,
+            has_addrspace: bool,
             is_test: bool,
             is_extern: bool,
-            _: u9 = undefined,
+            _: u8 = undefined,
         };
     };
 
@@ -2405,12 +2413,13 @@ pub const Inst = struct {
         else_body_len: u32,
     };
 
-    /// Stored in extra. Depending on the flags in Data, there will be up to 4
+    /// Stored in extra. Depending on the flags in Data, there will be up to 5
     /// trailing Ref fields:
     /// 0. sentinel: Ref // if `has_sentinel` flag is set
     /// 1. align: Ref // if `has_align` flag is set
-    /// 2. bit_start: Ref // if `has_bit_range` flag is set
-    /// 3. bit_end: Ref // if `has_bit_range` flag is set
+    /// 2. address_space: Ref // if `has_addrspace` flag is set
+    /// 3. bit_start: Ref // if `has_bit_range` flag is set
+    /// 4. bit_end: Ref // if `has_bit_range` flag is set
     pub const PtrType = struct {
         elem_type: Ref,
     };
@@ -2528,7 +2537,7 @@ pub const Inst = struct {
     ///      0b000X: whether corresponding decl is pub
     ///      0b00X0: whether corresponding decl is exported
     ///      0b0X00: whether corresponding decl has an align expression
-    ///      0bX000: whether corresponding decl has a linksection expression
+    ///      0bX000: whether corresponding decl has a linksection or an address space expression
     /// 5. decl: { // for every decls_len
     ///        src_hash: [4]u32, // hash of source bytes
     ///        line: u32, // line number of decl, relative to parent
@@ -2540,7 +2549,10 @@ pub const Inst = struct {
     ///          this is a test decl, and the name starts at `name+1`.
     ///        value: Index,
     ///        align: Ref, // if corresponding bit is set
-    ///        link_section: Ref, // if corresponding bit is set
+    ///        link_section_or_address_space: { // if corresponding bit is set.
+    ///            link_section: Ref,
+    ///            address_space: Ref,
+    ///        }
     ///    }
     /// 6. inst: Index // for every body_len
     /// 7. flags: u32 // for every 8 fields
@@ -2592,7 +2604,7 @@ pub const Inst = struct {
     ///      0b000X: whether corresponding decl is pub
     ///      0b00X0: whether corresponding decl is exported
     ///      0b0X00: whether corresponding decl has an align expression
-    ///      0bX000: whether corresponding decl has a linksection expression
+    ///      0bX000: whether corresponding decl has a linksection or an address space expression
     /// 6. decl: { // for every decls_len
     ///        src_hash: [4]u32, // hash of source bytes
     ///        line: u32, // line number of decl, relative to parent
@@ -2604,7 +2616,10 @@ pub const Inst = struct {
     ///          this is a test decl, and the name starts at `name+1`.
     ///        value: Index,
     ///        align: Ref, // if corresponding bit is set
-    ///        link_section: Ref, // if corresponding bit is set
+    ///        link_section_or_address_space: { // if corresponding bit is set.
+    ///            link_section: Ref,
+    ///            address_space: Ref,
+    ///        }
     ///    }
     /// 7. inst: Index // for every body_len
     /// 8. has_bits: u32 // for every 32 fields
@@ -2637,7 +2652,7 @@ pub const Inst = struct {
     ///      0b000X: whether corresponding decl is pub
     ///      0b00X0: whether corresponding decl is exported
     ///      0b0X00: whether corresponding decl has an align expression
-    ///      0bX000: whether corresponding decl has a linksection expression
+    ///      0bX000: whether corresponding decl has a linksection or an address space expression
     /// 6. decl: { // for every decls_len
     ///        src_hash: [4]u32, // hash of source bytes
     ///        line: u32, // line number of decl, relative to parent
@@ -2649,7 +2664,10 @@ pub const Inst = struct {
     ///          this is a test decl, and the name starts at `name+1`.
     ///        value: Index,
     ///        align: Ref, // if corresponding bit is set
-    ///        link_section: Ref, // if corresponding bit is set
+    ///        link_section_or_address_space: { // if corresponding bit is set.
+    ///            link_section: Ref,
+    ///            address_space: Ref,
+    ///        }
     ///    }
     /// 7. inst: Index // for every body_len
     /// 8. has_bits: u32 // for every 8 fields
@@ -2686,7 +2704,7 @@ pub const Inst = struct {
     ///      0b000X: whether corresponding decl is pub
     ///      0b00X0: whether corresponding decl is exported
     ///      0b0X00: whether corresponding decl has an align expression
-    ///      0bX000: whether corresponding decl has a linksection expression
+    ///      0bX000: whether corresponding decl has a linksection or an address space expression
     /// 1. decl: { // for every decls_len
     ///        src_hash: [4]u32, // hash of source bytes
     ///        line: u32, // line number of decl, relative to parent
@@ -2698,7 +2716,10 @@ pub const Inst = struct {
     ///          this is a test decl, and the name starts at `name+1`.
     ///        value: Index,
     ///        align: Ref, // if corresponding bit is set
-    ///        link_section: Ref, // if corresponding bit is set
+    ///        link_section_or_address_space: { // if corresponding bit is set.
+    ///            link_section: Ref,
+    ///            address_space: Ref,
+    ///        }
     ///    }
     pub const OpaqueDecl = struct {
         decls_len: u32,
@@ -3983,7 +4004,7 @@ const Writer = struct {
             cur_bit_bag >>= 1;
             const has_align = @truncate(u1, cur_bit_bag) != 0;
             cur_bit_bag >>= 1;
-            const has_section = @truncate(u1, cur_bit_bag) != 0;
+            const has_section_or_addrspace = @truncate(u1, cur_bit_bag) != 0;
             cur_bit_bag >>= 1;
 
             const sub_index = extra_index;
@@ -4001,12 +4022,16 @@ const Writer = struct {
                 extra_index += 1;
                 break :inst inst;
             };
-            const section_inst: Inst.Ref = if (!has_section) .none else inst: {
+            const section_inst: Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
                 const inst = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
                 extra_index += 1;
                 break :inst inst;
             };
-
+            const addrspace_inst: Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
+                const inst = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
+                extra_index +=1;
+                break :inst inst;
+            };
             const pub_str = if (is_pub) "pub " else "";
             const hash_bytes = @bitCast([16]u8, hash_u32s.*);
             try stream.writeByteNTimes(' ', self.indent);
@@ -4032,6 +4057,11 @@ const Writer = struct {
                     try self.writeInstRef(stream, align_inst);
                     try stream.writeAll(")");
                 }
+                if (addrspace_inst != .none) {
+                    try stream.writeAll(" addrspace(");
+                    try self.writeInstRef(stream, addrspace_inst);
+                    try stream.writeAll(")");
+                }
                 if (section_inst != .none) {
                     try stream.writeAll(" linksection(");
                     try self.writeInstRef(stream, section_inst);
@@ -4453,6 +4483,7 @@ const Writer = struct {
             false,
             .none,
             .none,
+            .none,
             body,
             src,
             src_locs,
@@ -4481,6 +4512,11 @@ const Writer = struct {
             extra_index += 1;
             break :blk align_inst;
         };
+        const addrspace_inst: Inst.Ref = if (!small.has_addrspace) .none else blk: {
+            const addrspace_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
+            extra_index += 1;
+            break :blk addrspace_inst;
+        };
 
         const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
         extra_index += ret_ty_body.len;
@@ -4500,6 +4536,7 @@ const Writer = struct {
             small.is_extern,
             cc,
             align_inst,
+            addrspace_inst,
             body,
             src,
             src_locs,
@@ -4582,6 +4619,7 @@ const Writer = struct {
         is_extern: bool,
         cc: Inst.Ref,
         align_inst: Inst.Ref,
+        addrspace_inst: Inst.Ref,
         body: []const Inst.Index,
         src: LazySrcLoc,
         src_locs: Zir.Inst.Func.SrcLocs,
@@ -4599,6 +4637,7 @@ const Writer = struct {
 
         try self.writeOptionalInstRef(stream, ", cc=", cc);
         try self.writeOptionalInstRef(stream, ", align=", align_inst);
+        try self.writeOptionalInstRef(stream, ", addrspace=", addrspace_inst);
         try self.writeFlag(stream, ", vargs", var_args);
         try self.writeFlag(stream, ", extern", is_extern);
         try self.writeFlag(stream, ", inferror", inferred_error_set);
@@ -4876,6 +4915,7 @@ fn findDeclsInner(
                     extra_index += @boolToInt(small.has_lib_name);
                     extra_index += @boolToInt(small.has_cc);
                     extra_index += @boolToInt(small.has_align);
+                    extra_index += @boolToInt(small.has_addrspace);
                     const body = zir.extra[extra_index..][0..extra.data.body_len];
                     return zir.findDeclsBody(list, body);
                 },
@@ -5079,6 +5119,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
             extra_index += @boolToInt(small.has_lib_name);
             extra_index += @boolToInt(small.has_cc);
             extra_index += @boolToInt(small.has_align);
+            extra_index += @boolToInt(small.has_addrspace);
             const ret_ty_body = zir.extra[extra_index..][0..extra.data.ret_body_len];
             extra_index += ret_ty_body.len;
             const body = zir.extra[extra_index..][0..extra.data.body_len];