authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-15 10:04:52-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-15 10:36:10-07:00
log66d6183001e135e36df06194e29f082eb63503ec
treec7d4973f437fde43735ac8c08cb8e12f5e66257f
parent1087e677625b0846cf25dc43474a63f9a25f1e32
parent9ff60e356ec5be9c3e547d0db2b55bba88c0acbd

Merge branch 'amdgpu-improvements' of https://github.com/Snektron/zig into Snektron-amdgpu-improvements


34 files changed, 588 insertions(+), 156 deletions(-)

doc/langref.html.in+9
...@@ -7956,6 +7956,15 @@ fn readFile(allocator: Allocator, filename: []const u8) ![]u8 {...@@ -7956,6 +7956,15 @@ fn readFile(allocator: Allocator, filename: []const u8) ![]u8 {
7956 The {#syntax#}comptime{#endsyntax#} keyword on a parameter means that the parameter must be known7956 The {#syntax#}comptime{#endsyntax#} keyword on a parameter means that the parameter must be known
7957 at compile time.7957 at compile time.
7958 </p>7958 </p>
7959 {#header_open|@addrSpaceCast#}
7960 <pre>{#syntax#}@addrSpaceCast(comptime addrspace: std.builtin.AddressSpace, ptr: anytype) anytype{#endsyntax#}</pre>
7961 <p>
7962 Converts a pointer from one address space to another. Depending on the current target and
7963 address spaces, this cast may be a no-op, a complex operation, or illegal. If the cast is
7964 legal, then the resulting pointer points to the same memory location as the pointer operand.
7965 It is always valid to cast a pointer between the same address spaces.
7966 </p>
7967 {#header_close#}
7959 {#header_open|@addWithOverflow#}7968 {#header_open|@addWithOverflow#}
7960 <pre>{#syntax#}@addWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}</pre>7969 <pre>{#syntax#}@addWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}</pre>
7961 <p>7970 <p>
lib/c.zig+3-3
...@@ -64,10 +64,10 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, _: ?...@@ -64,10 +64,10 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, _: ?
64 if (builtin.is_test) {64 if (builtin.is_test) {
65 std.debug.panic("{s}", .{msg});65 std.debug.panic("{s}", .{msg});
66 }66 }
67 if (native_os != .freestanding and native_os != .other) {67 switch (native_os) {
68 std.os.abort();68 .freestanding, .other, .amdhsa, .amdpal => while (true) {},
69 else => std.os.abort(),
69 }70 }
70 while (true) {}
71}71}
7272
73extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;73extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
lib/compiler_rt/atomics.zig+63-10
...@@ -35,6 +35,17 @@ const largest_atomic_size = switch (arch) {...@@ -35,6 +35,17 @@ const largest_atomic_size = switch (arch) {
35 else => @sizeOf(usize),35 else => @sizeOf(usize),
36};36};
3737
38// The size (in bytes) of the smallest atomic object that the architecture can
39// perform fetch/exchange atomically. Note, this does not encompass load and store.
40// Objects smaller than this threshold are implemented in terms of compare-exchange
41// of a larger value.
42const smallest_atomic_fetch_exch_size = switch (arch) {
43 // On AMDGPU, there are no instructions for atomic operations other than load and store
44 // (as of LLVM 15), and so these need to be implemented in terms of atomic CAS.
45 .amdgcn => @sizeOf(u32),
46 else => @sizeOf(u8),
47};
48
38const cache_line_size = 64;49const cache_line_size = 64;
3950
40const SpinlockTable = struct {51const SpinlockTable = struct {
...@@ -206,6 +217,31 @@ fn __atomic_store_8(dst: *u64, value: u64, model: i32) callconv(.C) void {...@@ -206,6 +217,31 @@ fn __atomic_store_8(dst: *u64, value: u64, model: i32) callconv(.C) void {
206 return atomic_store_N(u64, dst, value, model);217 return atomic_store_N(u64, dst, value, model);
207}218}
208219
220fn wideUpdate(comptime T: type, ptr: *T, val: T, update: anytype) T {
221 const WideAtomic = std.meta.Int(.unsigned, smallest_atomic_fetch_exch_size * 8);
222
223 const addr = @ptrToInt(ptr);
224 const wide_addr = addr & ~(@as(T, smallest_atomic_fetch_exch_size) - 1);
225 const wide_ptr = @alignCast(smallest_atomic_fetch_exch_size, @intToPtr(*WideAtomic, wide_addr));
226
227 const inner_offset = addr & (@as(T, smallest_atomic_fetch_exch_size) - 1);
228 const inner_shift = @intCast(std.math.Log2Int(T), inner_offset * 8);
229
230 const mask = @as(WideAtomic, std.math.maxInt(T)) << inner_shift;
231
232 var wide_old = @atomicLoad(WideAtomic, wide_ptr, .SeqCst);
233 while (true) {
234 const old = @truncate(T, (wide_old & mask) >> inner_shift);
235 const new = update(val, old);
236 const wide_new = wide_old & ~mask | (@as(WideAtomic, new) << inner_shift);
237 if (@cmpxchgWeak(WideAtomic, wide_ptr, wide_old, wide_new, .SeqCst, .SeqCst)) |new_wide_old| {
238 wide_old = new_wide_old;
239 } else {
240 return old;
241 }
242 }
243}
244
209inline fn atomic_exchange_N(comptime T: type, ptr: *T, val: T, model: i32) T {245inline fn atomic_exchange_N(comptime T: type, ptr: *T, val: T, model: i32) T {
210 _ = model;246 _ = model;
211 if (@sizeOf(T) > largest_atomic_size) {247 if (@sizeOf(T) > largest_atomic_size) {
...@@ -214,6 +250,15 @@ inline fn atomic_exchange_N(comptime T: type, ptr: *T, val: T, model: i32) T {...@@ -214,6 +250,15 @@ inline fn atomic_exchange_N(comptime T: type, ptr: *T, val: T, model: i32) T {
214 const value = ptr.*;250 const value = ptr.*;
215 ptr.* = val;251 ptr.* = val;
216 return value;252 return value;
253 } else if (@sizeOf(T) < smallest_atomic_fetch_exch_size) {
254 // Machine does not support this type, but it does support a larger type.
255 const Updater = struct {
256 fn update(new: T, old: T) T {
257 _ = old;
258 return new;
259 }
260 };
261 return wideUpdate(T, ptr, val, Updater.update);
217 } else {262 } else {
218 return @atomicRmw(T, ptr, .Xchg, val, .SeqCst);263 return @atomicRmw(T, ptr, .Xchg, val, .SeqCst);
219 }264 }
...@@ -282,22 +327,30 @@ fn __atomic_compare_exchange_8(ptr: *u64, expected: *u64, desired: u64, success:...@@ -282,22 +327,30 @@ fn __atomic_compare_exchange_8(ptr: *u64, expected: *u64, desired: u64, success:
282327
283inline fn fetch_op_N(comptime T: type, comptime op: std.builtin.AtomicRmwOp, ptr: *T, val: T, model: i32) T {328inline fn fetch_op_N(comptime T: type, comptime op: std.builtin.AtomicRmwOp, ptr: *T, val: T, model: i32) T {
284 _ = model;329 _ = model;
330 const Updater = struct {
331 fn update(new: T, old: T) T {
332 return switch (op) {
333 .Add => old +% new,
334 .Sub => old -% new,
335 .And => old & new,
336 .Nand => ~(old & new),
337 .Or => old | new,
338 .Xor => old ^ new,
339 else => @compileError("unsupported atomic op"),
340 };
341 }
342 };
343
285 if (@sizeOf(T) > largest_atomic_size) {344 if (@sizeOf(T) > largest_atomic_size) {
286 var sl = spinlocks.get(@ptrToInt(ptr));345 var sl = spinlocks.get(@ptrToInt(ptr));
287 defer sl.release();346 defer sl.release();
288347
289 const value = ptr.*;348 const value = ptr.*;
290 ptr.* = switch (op) {349 ptr.* = Updater.update(val, value);
291 .Add => value +% val,
292 .Sub => value -% val,
293 .And => value & val,
294 .Nand => ~(value & val),
295 .Or => value | val,
296 .Xor => value ^ val,
297 else => @compileError("unsupported atomic op"),
298 };
299
300 return value;350 return value;
351 } else if (@sizeOf(T) < smallest_atomic_fetch_exch_size) {
352 // Machine does not support this type, but it does support a larger type.
353 return wideUpdate(T, ptr, val, Updater.update);
301 }354 }
302355
303 return @atomicRmw(T, ptr, op, val, .SeqCst);356 return @atomicRmw(T, ptr, op, val, .SeqCst);
lib/std/builtin.zig+1
...@@ -157,6 +157,7 @@ pub const CallingConvention = enum {...@@ -157,6 +157,7 @@ pub const CallingConvention = enum {
157 SysV,157 SysV,
158 Win64,158 Win64,
159 PtxKernel,159 PtxKernel,
160 AmdgpuKernel,
160};161};
161162
162/// This data structure is used by the Zig language code generation and163/// This data structure is used by the Zig language code generation and
lib/std/math/big/int.zig+1-1
...@@ -1859,7 +1859,7 @@ pub const Mutable = struct {...@@ -1859,7 +1859,7 @@ pub const Mutable = struct {
1859 /// [1, 2, 3, 4, 0] -> [1, 2, 3, 4]1859 /// [1, 2, 3, 4, 0] -> [1, 2, 3, 4]
1860 /// [1, 2, 0, 0, 0] -> [1, 2]1860 /// [1, 2, 0, 0, 0] -> [1, 2]
1861 /// [0, 0, 0, 0, 0] -> [0]1861 /// [0, 0, 0, 0, 0] -> [0]
1862 fn normalize(r: *Mutable, length: usize) void {1862 pub fn normalize(r: *Mutable, length: usize) void {
1863 r.len = llnormalize(r.limbs[0..length]);1863 r.len = llnormalize(r.limbs[0..length]);
1864 }1864 }
1865};1865};
lib/std/target.zig+11
...@@ -1157,6 +1157,17 @@ pub const Target = struct {...@@ -1157,6 +1157,17 @@ pub const Target = struct {
1157 };1157 };
1158 }1158 }
11591159
1160 /// Returns whether this architecture supports the address space
1161 pub fn supportsAddressSpace(arch: Arch, address_space: std.builtin.AddressSpace) bool {
1162 const is_nvptx = arch == .nvptx or arch == .nvptx64;
1163 return switch (address_space) {
1164 .generic => true,
1165 .fs, .gs, .ss => arch == .x86_64 or arch == .i386,
1166 .global, .constant, .local, .shared => arch == .amdgcn or is_nvptx,
1167 .param => is_nvptx,
1168 };
1169 }
1170
1160 pub fn ptrBitWidth(arch: Arch) u16 {1171 pub fn ptrBitWidth(arch: Arch) u16 {
1161 switch (arch) {1172 switch (arch) {
1162 .avr,1173 .avr,
src/Air.zig+5
...@@ -729,6 +729,10 @@ pub const Inst = struct {...@@ -729,6 +729,10 @@ pub const Inst = struct {
729 /// Sets the operand as the current error return trace,729 /// Sets the operand as the current error return trace,
730 set_err_return_trace,730 set_err_return_trace,
731731
732 /// Convert the address space of a pointer.
733 /// Uses the `ty_op` field.
734 addrspace_cast,
735
732 pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag {736 pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag {
733 switch (op) {737 switch (op) {
734 .lt => return if (optimized) .cmp_lt_optimized else .cmp_lt,738 .lt => return if (optimized) .cmp_lt_optimized else .cmp_lt,
...@@ -1138,6 +1142,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -1138,6 +1142,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
1138 .popcount,1142 .popcount,
1139 .byte_swap,1143 .byte_swap,
1140 .bit_reverse,1144 .bit_reverse,
1145 .addrspace_cast,
1141 => return air.getRefType(datas[inst].ty_op.ty),1146 => return air.getRefType(datas[inst].ty_op.ty),
11421147
1143 .loop,1148 .loop,
src/AstGen.zig+8
...@@ -7789,6 +7789,14 @@ fn builtinCall(...@@ -7789,6 +7789,14 @@ fn builtinCall(
7789 });7789 });
7790 return rvalue(gz, rl, result, node);7790 return rvalue(gz, rl, result, node);
7791 },7791 },
7792 .addrspace_cast => {
7793 const result = try gz.addExtendedPayload(.addrspace_cast, Zir.Inst.BinNode{
7794 .lhs = try comptimeExpr(gz, scope, .{ .ty = .address_space_type }, params[0]),
7795 .rhs = try expr(gz, scope, .none, params[1]),
7796 .node = gz.nodeIndexToRelative(node),
7797 });
7798 return rvalue(gz, rl, result, node);
7799 },
77927800
7793 // zig fmt: off7801 // zig fmt: off
7794 .has_decl => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_decl),7802 .has_decl => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_decl),
src/BuiltinFn.zig+8
...@@ -2,6 +2,7 @@ const std = @import("std");...@@ -2,6 +2,7 @@ const std = @import("std");
22
3pub const Tag = enum {3pub const Tag = enum {
4 add_with_overflow,4 add_with_overflow,
5 addrspace_cast,
5 align_cast,6 align_cast,
6 align_of,7 align_of,
7 as,8 as,
...@@ -152,6 +153,13 @@ pub const list = list: {...@@ -152,6 +153,13 @@ pub const list = list: {
152 .param_count = 4,153 .param_count = 4,
153 },154 },
154 },155 },
156 .{
157 "@addrSpaceCast",
158 .{
159 .tag = .addrspace_cast,
160 .param_count = 2,
161 },
162 },
155 .{163 .{
156 "@alignCast",164 "@alignCast",
157 .{165 .{
src/Liveness.zig+2
...@@ -268,6 +268,7 @@ pub fn categorizeOperand(...@@ -268,6 +268,7 @@ pub fn categorizeOperand(
268 .bit_reverse,268 .bit_reverse,
269 .splat,269 .splat,
270 .error_set_has_value,270 .error_set_has_value,
271 .addrspace_cast,
271 => {272 => {
272 const o = air_datas[inst].ty_op;273 const o = air_datas[inst].ty_op;
273 if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);274 if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
...@@ -844,6 +845,7 @@ fn analyzeInst(...@@ -844,6 +845,7 @@ fn analyzeInst(
844 .bit_reverse,845 .bit_reverse,
845 .splat,846 .splat,
846 .error_set_has_value,847 .error_set_has_value,
848 .addrspace_cast,
847 => {849 => {
848 const o = inst_datas[inst].ty_op;850 const o = inst_datas[inst].ty_op;
849 return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });851 return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });
src/Module.zig+1-1
...@@ -4617,7 +4617,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -4617,7 +4617,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
4617 .constant => target_util.defaultAddressSpace(target, .global_constant),4617 .constant => target_util.defaultAddressSpace(target, .global_constant),
4618 else => unreachable,4618 else => unreachable,
4619 },4619 },
4620 else => |addrspace_ref| try sema.analyzeAddrspace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx),4620 else => |addrspace_ref| try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx),
4621 };4621 };
4622 };4622 };
46234623
src/Sema.zig+65-6
...@@ -975,8 +975,9 @@ fn analyzeBodyInner(...@@ -975,8 +975,9 @@ fn analyzeBodyInner(
975 .reify => try sema.zirReify( block, extended, inst),975 .reify => try sema.zirReify( block, extended, inst),
976 .builtin_async_call => try sema.zirBuiltinAsyncCall( block, extended),976 .builtin_async_call => try sema.zirBuiltinAsyncCall( block, extended),
977 .cmpxchg => try sema.zirCmpxchg( block, extended),977 .cmpxchg => try sema.zirCmpxchg( block, extended),
978978 .addrspace_cast => try sema.zirAddrSpaceCast( block, extended),
979 // zig fmt: on979 // zig fmt: on
980
980 .fence => {981 .fence => {
981 try sema.zirFence(block, extended);982 try sema.zirFence(block, extended);
982 i += 1;983 i += 1;
...@@ -5897,7 +5898,7 @@ fn analyzeCall(...@@ -5897,7 +5898,7 @@ fn analyzeCall(
5897 },5898 },
5898 else => {},5899 else => {},
5899 }5900 }
5900 return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});5901 return sema.fail(block, func_src, "type '{}' is not a function", .{callee_ty.fmt(sema.mod)});
5901 };5902 };
59025903
5903 const func_ty_info = func_ty.fnInfo();5904 const func_ty_info = func_ty.fnInfo();
...@@ -8141,6 +8142,10 @@ fn funcCommon(...@@ -8141,6 +8142,10 @@ fn funcCommon(
8141 .nvptx, .nvptx64 => null,8142 .nvptx, .nvptx64 => null,
8142 else => @as([]const u8, "nvptx and nvptx64"),8143 else => @as([]const u8, "nvptx and nvptx64"),
8143 },8144 },
8145 .AmdgpuKernel => switch (arch) {
8146 .amdgcn => null,
8147 else => @as([]const u8, "amdgcn"),
8148 },
8144 }) |allowed_platform| {8149 }) |allowed_platform| {
8145 return sema.fail(block, cc_src, "callconv '{s}' is only available on {s}, not {s}", .{8150 return sema.fail(block, cc_src, "callconv '{s}' is only available on {s}, not {s}", .{
8146 @tagName(cc_workaround),8151 @tagName(cc_workaround),
...@@ -16246,7 +16251,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -16246,7 +16251,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
16246 const address_space = if (inst_data.flags.has_addrspace) blk: {16251 const address_space = if (inst_data.flags.has_addrspace) blk: {
16247 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);16252 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
16248 extra_i += 1;16253 extra_i += 1;
16249 break :blk try sema.analyzeAddrspace(block, addrspace_src, ref, .pointer);16254 break :blk try sema.analyzeAddressSpace(block, addrspace_src, ref, .pointer);
16250 } else .generic;16255 } else .generic;
1625116256
16252 const bit_offset = if (inst_data.flags.has_bit_range) blk: {16257 const bit_offset = if (inst_data.flags.has_bit_range) blk: {
...@@ -18166,6 +18171,55 @@ fn reifyStruct(...@@ -18166,6 +18171,55 @@ fn reifyStruct(
18166 return sema.analyzeDeclVal(block, src, new_decl_index);18171 return sema.analyzeDeclVal(block, src, new_decl_index);
18167}18172}
1816818173
18174fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
18175 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
18176 const src = LazySrcLoc.nodeOffset(extra.node);
18177 const addrspace_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
18178 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
18179
18180 const dest_addrspace = try sema.analyzeAddressSpace(block, addrspace_src, extra.lhs, .pointer);
18181 const ptr = try sema.resolveInst(extra.rhs);
18182 const ptr_ty = sema.typeOf(ptr);
18183
18184 try sema.checkPtrOperand(block, ptr_src, ptr_ty);
18185
18186 var ptr_info = ptr_ty.ptrInfo().data;
18187 const src_addrspace = ptr_info.@"addrspace";
18188 if (!target_util.addrSpaceCastIsValid(sema.mod.getTarget(), src_addrspace, dest_addrspace)) {
18189 const msg = msg: {
18190 const msg = try sema.errMsg(block, src, "invalid address space cast", .{});
18191 errdefer msg.destroy(sema.gpa);
18192 try sema.errNote(block, src, msg, "address space '{s}' is not compatible with address space '{s}'", .{ @tagName(src_addrspace), @tagName(dest_addrspace) });
18193 break :msg msg;
18194 };
18195 return sema.failWithOwnedErrorMsg(msg);
18196 }
18197
18198 ptr_info.@"addrspace" = dest_addrspace;
18199 const dest_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
18200 const dest_ty = if (ptr_ty.zigTypeTag() == .Optional)
18201 try Type.optional(sema.arena, dest_ptr_ty)
18202 else
18203 dest_ptr_ty;
18204
18205 if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |val| {
18206 // Pointer value should compatible with both address spaces.
18207 // TODO: Figure out why this generates an invalid bitcast.
18208 return sema.addConstant(dest_ty, val);
18209 }
18210
18211 try sema.requireRuntimeBlock(block, src, ptr_src);
18212 // TODO: Address space cast safety?
18213
18214 return block.addInst(.{
18215 .tag = .addrspace_cast,
18216 .data = .{ .ty_op = .{
18217 .ty = try sema.addType(dest_ty),
18218 .operand = ptr,
18219 } },
18220 });
18221}
18222
18169fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {18223fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
18170 const inst_data = sema.code.instructions.items(.data)[inst].un_node;18224 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
18171 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };18225 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
...@@ -18413,6 +18467,9 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -18413,6 +18467,9 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18413 if (operand_info.@"volatile" and !dest_info.@"volatile") {18467 if (operand_info.@"volatile" and !dest_info.@"volatile") {
18414 return sema.fail(block, src, "cast discards volatile qualifier", .{});18468 return sema.fail(block, src, "cast discards volatile qualifier", .{});
18415 }18469 }
18470 if (operand_info.@"addrspace" != dest_info.@"addrspace") {
18471 return sema.fail(block, src, "cast changes pointer address space", .{});
18472 }
1841618473
18417 const dest_is_slice = dest_ty.isSlice();18474 const dest_is_slice = dest_ty.isSlice();
18418 const operand_is_slice = operand_ty.isSlice();18475 const operand_is_slice = operand_ty.isSlice();
...@@ -30302,7 +30359,7 @@ pub const AddressSpaceContext = enum {...@@ -30302,7 +30359,7 @@ pub const AddressSpaceContext = enum {
30302 pointer,30359 pointer,
30303};30360};
3030430361
30305pub fn analyzeAddrspace(30362pub fn analyzeAddressSpace(
30306 sema: *Sema,30363 sema: *Sema,
30307 block: *Block,30364 block: *Block,
30308 src: LazySrcLoc,30365 src: LazySrcLoc,
...@@ -30313,13 +30370,15 @@ pub fn analyzeAddrspace(...@@ -30313,13 +30370,15 @@ pub fn analyzeAddrspace(
30313 const address_space = addrspace_tv.val.toEnum(std.builtin.AddressSpace);30370 const address_space = addrspace_tv.val.toEnum(std.builtin.AddressSpace);
30314 const target = sema.mod.getTarget();30371 const target = sema.mod.getTarget();
30315 const arch = target.cpu.arch;30372 const arch = target.cpu.arch;
30316 const is_gpu = arch == .nvptx or arch == .nvptx64;30373 const is_nv = arch == .nvptx or arch == .nvptx64;
30374 const is_gpu = is_nv or arch == .amdgcn;
3031730375
30318 const supported = switch (address_space) {30376 const supported = switch (address_space) {
30319 .generic => true,30377 .generic => true,
30320 .gs, .fs, .ss => (arch == .i386 or arch == .x86_64) and ctx == .pointer,30378 .gs, .fs, .ss => (arch == .i386 or arch == .x86_64) and ctx == .pointer,
30321 // TODO: check that .shared and .local are left uninitialized30379 // TODO: check that .shared and .local are left uninitialized
30322 .global, .param, .shared, .local => is_gpu,30380 .param => is_nv,
30381 .global, .shared, .local => is_gpu,
30323 .constant => is_gpu and (ctx == .constant),30382 .constant => is_gpu and (ctx == .constant),
30324 };30383 };
3032530384
src/Zir.zig+3
...@@ -1969,6 +1969,9 @@ pub const Inst = struct {...@@ -1969,6 +1969,9 @@ pub const Inst = struct {
1969 /// `small` 0=>weak 1=>strong1969 /// `small` 0=>weak 1=>strong
1970 /// `operand` is payload index to `Cmpxchg`.1970 /// `operand` is payload index to `Cmpxchg`.
1971 cmpxchg,1971 cmpxchg,
1972 /// Implement the builtin `@addrSpaceCast`
1973 /// `Operand` is payload index to `BinNode`. `lhs` is dest type, `rhs` is operand.
1974 addrspace_cast,
19721975
1973 pub const InstData = struct {1976 pub const InstData = struct {
1974 opcode: Extended,1977 opcode: Extended,
src/arch/aarch64/CodeGen.zig+1
...@@ -677,6 +677,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -677,6 +677,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
677 .union_init => try self.airUnionInit(inst),677 .union_init => try self.airUnionInit(inst),
678 .prefetch => try self.airPrefetch(inst),678 .prefetch => try self.airPrefetch(inst),
679 .mul_add => try self.airMulAdd(inst),679 .mul_add => try self.airMulAdd(inst),
680 .addrspace_cast => return self.fail("TODO implement addrspace_cast", .{}),
680681
681 .@"try" => try self.airTry(inst),682 .@"try" => try self.airTry(inst),
682 .try_ptr => try self.airTryPtr(inst),683 .try_ptr => try self.airTryPtr(inst),
src/arch/arm/CodeGen.zig+1
...@@ -690,6 +690,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -690,6 +690,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
690 .union_init => try self.airUnionInit(inst),690 .union_init => try self.airUnionInit(inst),
691 .prefetch => try self.airPrefetch(inst),691 .prefetch => try self.airPrefetch(inst),
692 .mul_add => try self.airMulAdd(inst),692 .mul_add => try self.airMulAdd(inst),
693 .addrspace_cast => return self.fail("TODO implement addrspace_cast", .{}),
693694
694 .@"try" => try self.airTry(inst),695 .@"try" => try self.airTry(inst),
695 .try_ptr => try self.airTryPtr(inst),696 .try_ptr => try self.airTryPtr(inst),
src/arch/riscv64/CodeGen.zig+1
...@@ -604,6 +604,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -604,6 +604,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
604 .union_init => try self.airUnionInit(inst),604 .union_init => try self.airUnionInit(inst),
605 .prefetch => try self.airPrefetch(inst),605 .prefetch => try self.airPrefetch(inst),
606 .mul_add => try self.airMulAdd(inst),606 .mul_add => try self.airMulAdd(inst),
607 .addrspace_cast => @panic("TODO"),
607608
608 .@"try" => @panic("TODO"),609 .@"try" => @panic("TODO"),
609 .try_ptr => @panic("TODO"),610 .try_ptr => @panic("TODO"),
src/arch/sparc64/CodeGen.zig+1
...@@ -618,6 +618,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -618,6 +618,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
618 .union_init => @panic("TODO try self.airUnionInit(inst)"),618 .union_init => @panic("TODO try self.airUnionInit(inst)"),
619 .prefetch => try self.airPrefetch(inst),619 .prefetch => try self.airPrefetch(inst),
620 .mul_add => @panic("TODO try self.airMulAdd(inst)"),620 .mul_add => @panic("TODO try self.airMulAdd(inst)"),
621 .addrspace_cast => @panic("TODO try self.airAddrSpaceCast(int)"),
621622
622 .@"try" => try self.airTry(inst),623 .@"try" => try self.airTry(inst),
623 .try_ptr => @panic("TODO try self.airTryPtr(inst)"),624 .try_ptr => @panic("TODO try self.airTryPtr(inst)"),
src/arch/wasm/CodeGen.zig+1
...@@ -1699,6 +1699,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1699,6 +1699,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1699 .set_err_return_trace,1699 .set_err_return_trace,
1700 .is_named_enum_value,1700 .is_named_enum_value,
1701 .error_set_has_value,1701 .error_set_has_value,
1702 .addrspace_cast,
1702 => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),1703 => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
17031704
1704 .add_optimized,1705 .add_optimized,
src/arch/x86_64/CodeGen.zig+1
...@@ -695,6 +695,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -695,6 +695,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
695 .union_init => try self.airUnionInit(inst),695 .union_init => try self.airUnionInit(inst),
696 .prefetch => try self.airPrefetch(inst),696 .prefetch => try self.airPrefetch(inst),
697 .mul_add => try self.airMulAdd(inst),697 .mul_add => try self.airMulAdd(inst),
698 .addrspace_cast => return self.fail("TODO implement addrspace_cast", .{}),
698699
699 .@"try" => try self.airTry(inst),700 .@"try" => try self.airTry(inst),
700 .try_ptr => try self.airTryPtr(inst),701 .try_ptr => try self.airTryPtr(inst),
src/codegen/c.zig+1
...@@ -1871,6 +1871,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1871,6 +1871,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1871 .aggregate_init => try airAggregateInit(f, inst),1871 .aggregate_init => try airAggregateInit(f, inst),
1872 .union_init => try airUnionInit(f, inst),1872 .union_init => try airUnionInit(f, inst),
1873 .prefetch => try airPrefetch(f, inst),1873 .prefetch => try airPrefetch(f, inst),
1874 .addrspace_cast => return f.fail("TODO: C backend: implement addrspace_cast", .{}),
18741875
1875 .@"try" => try airTry(f, inst),1876 .@"try" => try airTry(f, inst),
1876 .try_ptr => try airTryPtr(f, inst),1877 .try_ptr => try airTryPtr(f, inst),
src/codegen/llvm.zig+212-120
...@@ -956,8 +956,7 @@ pub const Object = struct {...@@ -956,8 +956,7 @@ pub const Object = struct {
956 if (isByRef(param_ty)) {956 if (isByRef(param_ty)) {
957 const alignment = param_ty.abiAlignment(target);957 const alignment = param_ty.abiAlignment(target);
958 const param_llvm_ty = param.typeOf();958 const param_llvm_ty = param.typeOf();
959 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);959 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
960 arg_ptr.setAlignment(alignment);
961 const store_inst = builder.buildStore(param, arg_ptr);960 const store_inst = builder.buildStore(param, arg_ptr);
962 store_inst.setAlignment(alignment);961 store_inst.setAlignment(alignment);
963 args.appendAssumeCapacity(arg_ptr);962 args.appendAssumeCapacity(arg_ptr);
...@@ -1001,8 +1000,7 @@ pub const Object = struct {...@@ -1001,8 +1000,7 @@ pub const Object = struct {
1001 param_ty.abiAlignment(target),1000 param_ty.abiAlignment(target),
1002 dg.object.target_data.abiAlignmentOfType(int_llvm_ty),1001 dg.object.target_data.abiAlignmentOfType(int_llvm_ty),
1003 );1002 );
1004 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);1003 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
1005 arg_ptr.setAlignment(alignment);
1006 const casted_ptr = builder.buildBitCast(arg_ptr, int_ptr_llvm_ty, "");1004 const casted_ptr = builder.buildBitCast(arg_ptr, int_ptr_llvm_ty, "");
1007 const store_inst = builder.buildStore(param, casted_ptr);1005 const store_inst = builder.buildStore(param, casted_ptr);
1008 store_inst.setAlignment(alignment);1006 store_inst.setAlignment(alignment);
...@@ -1053,8 +1051,7 @@ pub const Object = struct {...@@ -1053,8 +1051,7 @@ pub const Object = struct {
1053 const param_ty = fn_info.param_types[it.zig_index - 1];1051 const param_ty = fn_info.param_types[it.zig_index - 1];
1054 const param_llvm_ty = try dg.lowerType(param_ty);1052 const param_llvm_ty = try dg.lowerType(param_ty);
1055 const param_alignment = param_ty.abiAlignment(target);1053 const param_alignment = param_ty.abiAlignment(target);
1056 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);1054 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, param_alignment, target);
1057 arg_ptr.setAlignment(param_alignment);
1058 var field_types_buf: [8]*llvm.Type = undefined;1055 var field_types_buf: [8]*llvm.Type = undefined;
1059 const field_types = field_types_buf[0..llvm_ints.len];1056 const field_types = field_types_buf[0..llvm_ints.len];
1060 for (llvm_ints) |int_bits, i| {1057 for (llvm_ints) |int_bits, i| {
...@@ -1085,8 +1082,7 @@ pub const Object = struct {...@@ -1085,8 +1082,7 @@ pub const Object = struct {
1085 const param_ty = fn_info.param_types[it.zig_index - 1];1082 const param_ty = fn_info.param_types[it.zig_index - 1];
1086 const param_llvm_ty = try dg.lowerType(param_ty);1083 const param_llvm_ty = try dg.lowerType(param_ty);
1087 const param_alignment = param_ty.abiAlignment(target);1084 const param_alignment = param_ty.abiAlignment(target);
1088 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);1085 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, param_alignment, target);
1089 arg_ptr.setAlignment(param_alignment);
1090 var field_types_buf: [8]*llvm.Type = undefined;1086 var field_types_buf: [8]*llvm.Type = undefined;
1091 const field_types = field_types_buf[0..llvm_floats.len];1087 const field_types = field_types_buf[0..llvm_floats.len];
1092 for (llvm_floats) |float_bits, i| {1088 for (llvm_floats) |float_bits, i| {
...@@ -1130,8 +1126,7 @@ pub const Object = struct {...@@ -1130,8 +1126,7 @@ pub const Object = struct {
1130 llvm_arg_i += 1;1126 llvm_arg_i += 1;
11311127
1132 const alignment = param_ty.abiAlignment(target);1128 const alignment = param_ty.abiAlignment(target);
1133 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);1129 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
1134 arg_ptr.setAlignment(alignment);
1135 const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), "");1130 const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), "");
1136 _ = builder.buildStore(param, casted_ptr);1131 _ = builder.buildStore(param, casted_ptr);
11371132
...@@ -2431,19 +2426,21 @@ pub const DeclGen = struct {...@@ -2431,19 +2426,21 @@ pub const DeclGen = struct {
2431 // mismatch, because we don't have the LLVM type until the *value* is created,2426 // mismatch, because we don't have the LLVM type until the *value* is created,
2432 // whereas the global needs to be created based on the type alone, because2427 // whereas the global needs to be created based on the type alone, because
2433 // lowering the value may reference the global as a pointer.2428 // lowering the value may reference the global as a pointer.
2429 const llvm_global_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
2434 const new_global = dg.object.llvm_module.addGlobalInAddressSpace(2430 const new_global = dg.object.llvm_module.addGlobalInAddressSpace(
2435 llvm_init.typeOf(),2431 llvm_init.typeOf(),
2436 "",2432 "",
2437 dg.llvmAddressSpace(decl.@"addrspace"),2433 llvm_global_addrspace,
2438 );2434 );
2439 new_global.setLinkage(global.getLinkage());2435 new_global.setLinkage(global.getLinkage());
2440 new_global.setUnnamedAddr(global.getUnnamedAddress());2436 new_global.setUnnamedAddr(global.getUnnamedAddress());
2441 new_global.setAlignment(global.getAlignment());2437 new_global.setAlignment(global.getAlignment());
2442 if (decl.@"linksection") |section| new_global.setSection(section);2438 if (decl.@"linksection") |section| new_global.setSection(section);
2443 new_global.setInitializer(llvm_init);2439 new_global.setInitializer(llvm_init);
2444 // replaceAllUsesWith requires the type to be unchanged. So we bitcast2440 // replaceAllUsesWith requires the type to be unchanged. So we convert
2445 // the new global to the old type and use that as the thing to replace2441 // the new global to the old type and use that as the thing to replace
2446 // old uses.2442 // old uses.
2443 // TODO: How should this work then the address space of a global changed?
2447 const new_global_ptr = new_global.constBitCast(global.typeOf());2444 const new_global_ptr = new_global.constBitCast(global.typeOf());
2448 global.replaceAllUsesWith(new_global_ptr);2445 global.replaceAllUsesWith(new_global_ptr);
2449 dg.object.decl_map.putAssumeCapacity(decl_index, new_global);2446 dg.object.decl_map.putAssumeCapacity(decl_index, new_global);
...@@ -2492,7 +2489,7 @@ pub const DeclGen = struct {...@@ -2492,7 +2489,7 @@ pub const DeclGen = struct {
2492 const fqn = try decl.getFullyQualifiedName(dg.module);2489 const fqn = try decl.getFullyQualifiedName(dg.module);
2493 defer dg.gpa.free(fqn);2490 defer dg.gpa.free(fqn);
24942491
2495 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");2492 const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
2496 const llvm_fn = dg.llvmModule().addFunctionInAddressSpace(fqn, fn_type, llvm_addrspace);2493 const llvm_fn = dg.llvmModule().addFunctionInAddressSpace(fqn, fn_type, llvm_addrspace);
2497 gop.value_ptr.* = llvm_fn;2494 gop.value_ptr.* = llvm_fn;
24982495
...@@ -2640,9 +2637,16 @@ pub const DeclGen = struct {...@@ -2640,9 +2637,16 @@ pub const DeclGen = struct {
2640 const fqn = try decl.getFullyQualifiedName(dg.module);2637 const fqn = try decl.getFullyQualifiedName(dg.module);
2641 defer dg.gpa.free(fqn);2638 defer dg.gpa.free(fqn);
26422639
2640 const target = dg.module.getTarget();
2641
2643 const llvm_type = try dg.lowerType(decl.ty);2642 const llvm_type = try dg.lowerType(decl.ty);
2644 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");2643 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
2645 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace);2644
2645 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(
2646 llvm_type,
2647 fqn,
2648 llvm_actual_addrspace,
2649 );
2646 gop.value_ptr.* = llvm_global;2650 gop.value_ptr.* = llvm_global;
26472651
2648 // This is needed for declarations created by `@extern`.2652 // This is needed for declarations created by `@extern`.
...@@ -2667,32 +2671,6 @@ pub const DeclGen = struct {...@@ -2667,32 +2671,6 @@ pub const DeclGen = struct {
2667 return llvm_global;2671 return llvm_global;
2668 }2672 }
26692673
2670 fn llvmAddressSpace(self: DeclGen, address_space: std.builtin.AddressSpace) c_uint {
2671 const target = self.module.getTarget();
2672 return switch (target.cpu.arch) {
2673 .i386, .x86_64 => switch (address_space) {
2674 .generic => llvm.address_space.default,
2675 .gs => llvm.address_space.x86.gs,
2676 .fs => llvm.address_space.x86.fs,
2677 .ss => llvm.address_space.x86.ss,
2678 else => unreachable,
2679 },
2680 .nvptx, .nvptx64 => switch (address_space) {
2681 .generic => llvm.address_space.default,
2682 .global => llvm.address_space.nvptx.global,
2683 .constant => llvm.address_space.nvptx.constant,
2684 .param => llvm.address_space.nvptx.param,
2685 .shared => llvm.address_space.nvptx.shared,
2686 .local => llvm.address_space.nvptx.local,
2687 else => unreachable,
2688 },
2689 else => switch (address_space) {
2690 .generic => llvm.address_space.default,
2691 else => unreachable,
2692 },
2693 };
2694 }
2695
2696 fn isUnnamedType(dg: *DeclGen, ty: Type, val: *llvm.Value) bool {2674 fn isUnnamedType(dg: *DeclGen, ty: Type, val: *llvm.Value) bool {
2697 // Once `lowerType` succeeds, successive calls to it with the same Zig type2675 // Once `lowerType` succeeds, successive calls to it with the same Zig type
2698 // are guaranteed to succeed. So if a call to `lowerType` fails here it means2676 // are guaranteed to succeed. So if a call to `lowerType` fails here it means
...@@ -2758,7 +2736,7 @@ pub const DeclGen = struct {...@@ -2758,7 +2736,7 @@ pub const DeclGen = struct {
2758 return dg.context.structType(&fields, fields.len, .False);2736 return dg.context.structType(&fields, fields.len, .False);
2759 }2737 }
2760 const ptr_info = t.ptrInfo().data;2738 const ptr_info = t.ptrInfo().data;
2761 const llvm_addrspace = dg.llvmAddressSpace(ptr_info.@"addrspace");2739 const llvm_addrspace = toLlvmAddressSpace(ptr_info.@"addrspace", target);
2762 if (ptr_info.host_size != 0) {2740 if (ptr_info.host_size != 0) {
2763 return dg.context.intType(ptr_info.host_size * 8).pointerType(llvm_addrspace);2741 return dg.context.intType(ptr_info.host_size * 8).pointerType(llvm_addrspace);
2764 }2742 }
...@@ -3295,11 +3273,20 @@ pub const DeclGen = struct {...@@ -3295,11 +3273,20 @@ pub const DeclGen = struct {
3295 const decl_index = tv.val.castTag(.variable).?.data.owner_decl;3273 const decl_index = tv.val.castTag(.variable).?.data.owner_decl;
3296 const decl = dg.module.declPtr(decl_index);3274 const decl = dg.module.declPtr(decl_index);
3297 dg.module.markDeclAlive(decl);3275 dg.module.markDeclAlive(decl);
3298 const val = try dg.resolveGlobalDecl(decl_index);3276
3277 const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
3278 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
3279
3299 const llvm_var_type = try dg.lowerType(tv.ty);3280 const llvm_var_type = try dg.lowerType(tv.ty);
3300 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");3281 const llvm_actual_ptr_type = llvm_var_type.pointerType(llvm_actual_addrspace);
3301 const llvm_type = llvm_var_type.pointerType(llvm_addrspace);3282
3302 return val.constBitCast(llvm_type);3283 const val = try dg.resolveGlobalDecl(decl_index);
3284 const val_ptr = val.constBitCast(llvm_actual_ptr_type);
3285 if (llvm_actual_addrspace != llvm_wanted_addrspace) {
3286 const llvm_wanted_ptr_type = llvm_var_type.pointerType(llvm_wanted_addrspace);
3287 return val_ptr.constAddrSpaceCast(llvm_wanted_ptr_type);
3288 }
3289 return val_ptr;
3303 },3290 },
3304 .slice => {3291 .slice => {
3305 const slice = tv.val.castTag(.slice).?.data;3292 const slice = tv.val.castTag(.slice).?.data;
...@@ -4096,11 +4083,20 @@ pub const DeclGen = struct {...@@ -4096,11 +4083,20 @@ pub const DeclGen = struct {
40964083
4097 self.module.markDeclAlive(decl);4084 self.module.markDeclAlive(decl);
40984085
4099 const llvm_val = if (is_fn_body)4086 const llvm_decl_val = if (is_fn_body)
4100 try self.resolveLlvmFunction(decl_index)4087 try self.resolveLlvmFunction(decl_index)
4101 else4088 else
4102 try self.resolveGlobalDecl(decl_index);4089 try self.resolveGlobalDecl(decl_index);
41034090
4091 const target = self.module.getTarget();
4092 const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
4093 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
4094 const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) blk: {
4095 const llvm_decl_ty = try self.lowerType(decl.ty);
4096 const llvm_decl_wanted_ptr_ty = llvm_decl_ty.pointerType(llvm_wanted_addrspace);
4097 break :blk llvm_decl_val.constAddrSpaceCast(llvm_decl_wanted_ptr_ty);
4098 } else llvm_decl_val;
4099
4104 const llvm_type = try self.lowerType(tv.ty);4100 const llvm_type = try self.lowerType(tv.ty);
4105 if (tv.ty.zigTypeTag() == .Int) {4101 if (tv.ty.zigTypeTag() == .Int) {
4106 return llvm_val.constPtrToInt(llvm_type);4102 return llvm_val.constPtrToInt(llvm_type);
...@@ -4370,7 +4366,9 @@ pub const FuncGen = struct {...@@ -4370,7 +4366,9 @@ pub const FuncGen = struct {
4370 // We have an LLVM value but we need to create a global constant and4366 // We have an LLVM value but we need to create a global constant and
4371 // set the value as its initializer, and then return a pointer to the global.4367 // set the value as its initializer, and then return a pointer to the global.
4372 const target = self.dg.module.getTarget();4368 const target = self.dg.module.getTarget();
4373 const global = self.dg.object.llvm_module.addGlobal(llvm_val.typeOf(), "");4369 const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target);
4370 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target);
4371 const global = self.dg.object.llvm_module.addGlobalInAddressSpace(llvm_val.typeOf(), "", llvm_actual_addrspace);
4374 global.setInitializer(llvm_val);4372 global.setInitializer(llvm_val);
4375 global.setLinkage(.Private);4373 global.setLinkage(.Private);
4376 global.setGlobalConstant(.True);4374 global.setGlobalConstant(.True);
...@@ -4380,8 +4378,14 @@ pub const FuncGen = struct {...@@ -4380,8 +4378,14 @@ pub const FuncGen = struct {
4380 // the type of global constants might not match the type it is supposed to4378 // the type of global constants might not match the type it is supposed to
4381 // be, and so we must bitcast the pointer at the usage sites.4379 // be, and so we must bitcast the pointer at the usage sites.
4382 const wanted_llvm_ty = try self.dg.lowerType(tv.ty);4380 const wanted_llvm_ty = try self.dg.lowerType(tv.ty);
4383 const wanted_llvm_ptr_ty = wanted_llvm_ty.pointerType(0);4381 const wanted_bitcasted_llvm_ptr_ty = wanted_llvm_ty.pointerType(llvm_actual_addrspace);
4384 return global.constBitCast(wanted_llvm_ptr_ty);4382 const bitcasted_ptr = global.constBitCast(wanted_bitcasted_llvm_ptr_ty);
4383 const wanted_llvm_ptr_ty = wanted_llvm_ty.pointerType(llvm_wanted_addrspace);
4384 const casted_ptr = if (llvm_wanted_addrspace != llvm_actual_addrspace)
4385 bitcasted_ptr.constAddrSpaceCast(wanted_llvm_ptr_ty)
4386 else
4387 bitcasted_ptr;
4388 return casted_ptr;
4385 }4389 }
43864390
4387 fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void {4391 fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void {
...@@ -4462,7 +4466,7 @@ pub const FuncGen = struct {...@@ -4462,7 +4466,7 @@ pub const FuncGen = struct {
4462 .cmp_lt => try self.airCmp(inst, .lt, false),4466 .cmp_lt => try self.airCmp(inst, .lt, false),
4463 .cmp_lte => try self.airCmp(inst, .lte, false),4467 .cmp_lte => try self.airCmp(inst, .lte, false),
4464 .cmp_neq => try self.airCmp(inst, .neq, false),4468 .cmp_neq => try self.airCmp(inst, .neq, false),
4465 4469
4466 .cmp_eq_optimized => try self.airCmp(inst, .eq, true),4470 .cmp_eq_optimized => try self.airCmp(inst, .eq, true),
4467 .cmp_gt_optimized => try self.airCmp(inst, .gt, true),4471 .cmp_gt_optimized => try self.airCmp(inst, .gt, true),
4468 .cmp_gte_optimized => try self.airCmp(inst, .gte, true),4472 .cmp_gte_optimized => try self.airCmp(inst, .gte, true),
...@@ -4548,6 +4552,7 @@ pub const FuncGen = struct {...@@ -4548,6 +4552,7 @@ pub const FuncGen = struct {
4548 .aggregate_init => try self.airAggregateInit(inst),4552 .aggregate_init => try self.airAggregateInit(inst),
4549 .union_init => try self.airUnionInit(inst),4553 .union_init => try self.airUnionInit(inst),
4550 .prefetch => try self.airPrefetch(inst),4554 .prefetch => try self.airPrefetch(inst),
4555 .addrspace_cast => try self.airAddrSpaceCast(inst),
45514556
4552 .is_named_enum_value => try self.airIsNamedEnumValue(inst),4557 .is_named_enum_value => try self.airIsNamedEnumValue(inst),
4553 .error_set_has_value => try self.airErrorSetHasValue(inst),4558 .error_set_has_value => try self.airErrorSetHasValue(inst),
...@@ -4635,8 +4640,7 @@ pub const FuncGen = struct {...@@ -4635,8 +4640,7 @@ pub const FuncGen = struct {
46354640
4636 const ret_ptr = if (!sret) null else blk: {4641 const ret_ptr = if (!sret) null else blk: {
4637 const llvm_ret_ty = try self.dg.lowerType(return_type);4642 const llvm_ret_ty = try self.dg.lowerType(return_type);
4638 const ret_ptr = self.buildAlloca(llvm_ret_ty);4643 const ret_ptr = self.buildAlloca(llvm_ret_ty, return_type.abiAlignment(target));
4639 ret_ptr.setAlignment(return_type.abiAlignment(target));
4640 try llvm_args.append(ret_ptr);4644 try llvm_args.append(ret_ptr);
4641 break :blk ret_ptr;4645 break :blk ret_ptr;
4642 };4646 };
...@@ -4683,8 +4687,7 @@ pub const FuncGen = struct {...@@ -4683,8 +4687,7 @@ pub const FuncGen = struct {
4683 } else {4687 } else {
4684 const alignment = param_ty.abiAlignment(target);4688 const alignment = param_ty.abiAlignment(target);
4685 const param_llvm_ty = llvm_arg.typeOf();4689 const param_llvm_ty = llvm_arg.typeOf();
4686 const arg_ptr = self.buildAlloca(param_llvm_ty);4690 const arg_ptr = self.buildAlloca(param_llvm_ty, alignment);
4687 arg_ptr.setAlignment(alignment);
4688 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);4691 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
4689 store_inst.setAlignment(alignment);4692 store_inst.setAlignment(alignment);
4690 try llvm_args.append(arg_ptr);4693 try llvm_args.append(arg_ptr);
...@@ -4711,8 +4714,7 @@ pub const FuncGen = struct {...@@ -4711,8 +4714,7 @@ pub const FuncGen = struct {
4711 param_ty.abiAlignment(target),4714 param_ty.abiAlignment(target),
4712 self.dg.object.target_data.abiAlignmentOfType(int_llvm_ty),4715 self.dg.object.target_data.abiAlignmentOfType(int_llvm_ty),
4713 );4716 );
4714 const int_ptr = self.buildAlloca(int_llvm_ty);4717 const int_ptr = self.buildAlloca(int_llvm_ty, alignment);
4715 int_ptr.setAlignment(alignment);
4716 const param_llvm_ty = try self.dg.lowerType(param_ty);4718 const param_llvm_ty = try self.dg.lowerType(param_ty);
4717 const casted_ptr = self.builder.buildBitCast(int_ptr, param_llvm_ty.pointerType(0), "");4719 const casted_ptr = self.builder.buildBitCast(int_ptr, param_llvm_ty.pointerType(0), "");
4718 const store_inst = self.builder.buildStore(llvm_arg, casted_ptr);4720 const store_inst = self.builder.buildStore(llvm_arg, casted_ptr);
...@@ -4738,7 +4740,7 @@ pub const FuncGen = struct {...@@ -4738,7 +4740,7 @@ pub const FuncGen = struct {
4738 const llvm_arg = try self.resolveInst(arg);4740 const llvm_arg = try self.resolveInst(arg);
4739 const is_by_ref = isByRef(param_ty);4741 const is_by_ref = isByRef(param_ty);
4740 const arg_ptr = if (is_by_ref) llvm_arg else p: {4742 const arg_ptr = if (is_by_ref) llvm_arg else p: {
4741 const p = self.buildAlloca(llvm_arg.typeOf());4743 const p = self.buildAlloca(llvm_arg.typeOf(), null);
4742 const store_inst = self.builder.buildStore(llvm_arg, p);4744 const store_inst = self.builder.buildStore(llvm_arg, p);
4743 store_inst.setAlignment(param_ty.abiAlignment(target));4745 store_inst.setAlignment(param_ty.abiAlignment(target));
4744 break :p p;4746 break :p p;
...@@ -4767,7 +4769,7 @@ pub const FuncGen = struct {...@@ -4767,7 +4769,7 @@ pub const FuncGen = struct {
4767 const llvm_arg = try self.resolveInst(arg);4769 const llvm_arg = try self.resolveInst(arg);
4768 const is_by_ref = isByRef(param_ty);4770 const is_by_ref = isByRef(param_ty);
4769 const arg_ptr = if (is_by_ref) llvm_arg else p: {4771 const arg_ptr = if (is_by_ref) llvm_arg else p: {
4770 const p = self.buildAlloca(llvm_arg.typeOf());4772 const p = self.buildAlloca(llvm_arg.typeOf(), null);
4771 const store_inst = self.builder.buildStore(llvm_arg, p);4773 const store_inst = self.builder.buildStore(llvm_arg, p);
4772 store_inst.setAlignment(param_ty.abiAlignment(target));4774 store_inst.setAlignment(param_ty.abiAlignment(target));
4773 break :p p;4775 break :p p;
...@@ -4804,7 +4806,7 @@ pub const FuncGen = struct {...@@ -4804,7 +4806,7 @@ pub const FuncGen = struct {
4804 const arg_ty = self.air.typeOf(arg);4806 const arg_ty = self.air.typeOf(arg);
4805 var llvm_arg = try self.resolveInst(arg);4807 var llvm_arg = try self.resolveInst(arg);
4806 if (!isByRef(arg_ty)) {4808 if (!isByRef(arg_ty)) {
4807 const p = self.buildAlloca(llvm_arg.typeOf());4809 const p = self.buildAlloca(llvm_arg.typeOf(), null);
4808 const store_inst = self.builder.buildStore(llvm_arg, p);4810 const store_inst = self.builder.buildStore(llvm_arg, p);
4809 store_inst.setAlignment(arg_ty.abiAlignment(target));4811 store_inst.setAlignment(arg_ty.abiAlignment(target));
4810 llvm_arg = store_inst;4812 llvm_arg = store_inst;
...@@ -4861,9 +4863,8 @@ pub const FuncGen = struct {...@@ -4861,9 +4863,8 @@ pub const FuncGen = struct {
4861 // In this case the function return type is honoring the calling convention by having4863 // In this case the function return type is honoring the calling convention by having
4862 // a different LLVM type than the usual one. We solve this here at the callsite4864 // a different LLVM type than the usual one. We solve this here at the callsite
4863 // by bitcasting a pointer to our canonical type, then loading it if necessary.4865 // by bitcasting a pointer to our canonical type, then loading it if necessary.
4864 const rp = self.buildAlloca(llvm_ret_ty);
4865 const alignment = return_type.abiAlignment(target);4866 const alignment = return_type.abiAlignment(target);
4866 rp.setAlignment(alignment);4867 const rp = self.buildAlloca(llvm_ret_ty, alignment);
4867 const ptr_abi_ty = abi_ret_ty.pointerType(0);4868 const ptr_abi_ty = abi_ret_ty.pointerType(0);
4868 const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");4869 const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");
4869 const store_inst = self.builder.buildStore(call, casted_ptr);4870 const store_inst = self.builder.buildStore(call, casted_ptr);
...@@ -4880,9 +4881,8 @@ pub const FuncGen = struct {...@@ -4880,9 +4881,8 @@ pub const FuncGen = struct {
4880 if (isByRef(return_type)) {4881 if (isByRef(return_type)) {
4881 // our by-ref status disagrees with sret so we must allocate, store,4882 // our by-ref status disagrees with sret so we must allocate, store,
4882 // and return the allocation pointer.4883 // and return the allocation pointer.
4883 const rp = self.buildAlloca(llvm_ret_ty);
4884 const alignment = return_type.abiAlignment(target);4884 const alignment = return_type.abiAlignment(target);
4885 rp.setAlignment(alignment);4885 const rp = self.buildAlloca(llvm_ret_ty, alignment);
4886 const store_inst = self.builder.buildStore(call, rp);4886 const store_inst = self.builder.buildStore(call, rp);
4887 store_inst.setAlignment(alignment);4887 store_inst.setAlignment(alignment);
4888 return rp;4888 return rp;
...@@ -4941,8 +4941,7 @@ pub const FuncGen = struct {...@@ -4941,8 +4941,7 @@ pub const FuncGen = struct {
4941 return null;4941 return null;
4942 }4942 }
49434943
4944 const rp = self.buildAlloca(llvm_ret_ty);4944 const rp = self.buildAlloca(llvm_ret_ty, alignment);
4945 rp.setAlignment(alignment);
4946 const store_inst = self.builder.buildStore(operand, rp);4945 const store_inst = self.builder.buildStore(operand, rp);
4947 store_inst.setAlignment(alignment);4946 store_inst.setAlignment(alignment);
4948 const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");4947 const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");
...@@ -6060,8 +6059,7 @@ pub const FuncGen = struct {...@@ -6060,8 +6059,7 @@ pub const FuncGen = struct {
6060 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();6059 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();
6061 } else {6060 } else {
6062 const alignment = arg_ty.abiAlignment(target);6061 const alignment = arg_ty.abiAlignment(target);
6063 const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf());6062 const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf(), alignment);
6064 arg_ptr.setAlignment(alignment);
6065 const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr);6063 const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr);
6066 store_inst.setAlignment(alignment);6064 store_inst.setAlignment(alignment);
6067 llvm_param_values[llvm_param_i] = arg_ptr;6065 llvm_param_values[llvm_param_i] = arg_ptr;
...@@ -6562,8 +6560,7 @@ pub const FuncGen = struct {...@@ -6562,8 +6560,7 @@ pub const FuncGen = struct {
6562 const llvm_optional_ty = try self.dg.lowerType(optional_ty);6560 const llvm_optional_ty = try self.dg.lowerType(optional_ty);
6563 if (isByRef(optional_ty)) {6561 if (isByRef(optional_ty)) {
6564 const target = self.dg.module.getTarget();6562 const target = self.dg.module.getTarget();
6565 const optional_ptr = self.buildAlloca(llvm_optional_ty);6563 const optional_ptr = self.buildAlloca(llvm_optional_ty, optional_ty.abiAlignment(target));
6566 optional_ptr.setAlignment(optional_ty.abiAlignment(target));
6567 const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, "");6564 const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, "");
6568 var ptr_ty_payload: Type.Payload.ElemType = .{6565 var ptr_ty_payload: Type.Payload.ElemType = .{
6569 .base = .{ .tag = .single_mut_pointer },6566 .base = .{ .tag = .single_mut_pointer },
...@@ -6596,8 +6593,7 @@ pub const FuncGen = struct {...@@ -6596,8 +6593,7 @@ pub const FuncGen = struct {
6596 const payload_offset = errUnionPayloadOffset(payload_ty, target);6593 const payload_offset = errUnionPayloadOffset(payload_ty, target);
6597 const error_offset = errUnionErrorOffset(payload_ty, target);6594 const error_offset = errUnionErrorOffset(payload_ty, target);
6598 if (isByRef(err_un_ty)) {6595 if (isByRef(err_un_ty)) {
6599 const result_ptr = self.buildAlloca(err_un_llvm_ty);6596 const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target));
6600 result_ptr.setAlignment(err_un_ty.abiAlignment(target));
6601 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");6597 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
6602 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);6598 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);
6603 store_inst.setAlignment(Type.anyerror.abiAlignment(target));6599 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
...@@ -6631,8 +6627,7 @@ pub const FuncGen = struct {...@@ -6631,8 +6627,7 @@ pub const FuncGen = struct {
6631 const payload_offset = errUnionPayloadOffset(payload_ty, target);6627 const payload_offset = errUnionPayloadOffset(payload_ty, target);
6632 const error_offset = errUnionErrorOffset(payload_ty, target);6628 const error_offset = errUnionErrorOffset(payload_ty, target);
6633 if (isByRef(err_un_ty)) {6629 if (isByRef(err_un_ty)) {
6634 const result_ptr = self.buildAlloca(err_un_llvm_ty);6630 const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target));
6635 result_ptr.setAlignment(err_un_ty.abiAlignment(target));
6636 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");6631 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
6637 const store_inst = self.builder.buildStore(operand, err_ptr);6632 const store_inst = self.builder.buildStore(operand, err_ptr);
6638 store_inst.setAlignment(Type.anyerror.abiAlignment(target));6633 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
...@@ -7050,9 +7045,8 @@ pub const FuncGen = struct {...@@ -7050,9 +7045,8 @@ pub const FuncGen = struct {
70507045
7051 if (isByRef(dest_ty)) {7046 if (isByRef(dest_ty)) {
7052 const target = self.dg.module.getTarget();7047 const target = self.dg.module.getTarget();
7053 const alloca_inst = self.buildAlloca(llvm_dest_ty);
7054 const result_alignment = dest_ty.abiAlignment(target);7048 const result_alignment = dest_ty.abiAlignment(target);
7055 alloca_inst.setAlignment(result_alignment);7049 const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment);
7056 {7050 {
7057 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");7051 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");
7058 const store_inst = self.builder.buildStore(result, field_ptr);7052 const store_inst = self.builder.buildStore(result, field_ptr);
...@@ -7402,9 +7396,8 @@ pub const FuncGen = struct {...@@ -7402,9 +7396,8 @@ pub const FuncGen = struct {
74027396
7403 if (isByRef(dest_ty)) {7397 if (isByRef(dest_ty)) {
7404 const target = self.dg.module.getTarget();7398 const target = self.dg.module.getTarget();
7405 const alloca_inst = self.buildAlloca(llvm_dest_ty);
7406 const result_alignment = dest_ty.abiAlignment(target);7399 const result_alignment = dest_ty.abiAlignment(target);
7407 alloca_inst.setAlignment(result_alignment);7400 const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment);
7408 {7401 {
7409 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");7402 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");
7410 const store_inst = self.builder.buildStore(result, field_ptr);7403 const store_inst = self.builder.buildStore(result, field_ptr);
...@@ -7710,7 +7703,7 @@ pub const FuncGen = struct {...@@ -7710,7 +7703,7 @@ pub const FuncGen = struct {
7710 if (!result_is_ref) {7703 if (!result_is_ref) {
7711 return self.dg.todo("implement bitcast vector to non-ref array", .{});7704 return self.dg.todo("implement bitcast vector to non-ref array", .{});
7712 }7705 }
7713 const array_ptr = self.buildAlloca(llvm_dest_ty);7706 const array_ptr = self.buildAlloca(llvm_dest_ty, null);
7714 const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8;7707 const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8;
7715 if (bitcast_ok) {7708 if (bitcast_ok) {
7716 const llvm_vector_ty = try self.dg.lowerType(operand_ty);7709 const llvm_vector_ty = try self.dg.lowerType(operand_ty);
...@@ -7786,8 +7779,7 @@ pub const FuncGen = struct {...@@ -7786,8 +7779,7 @@ pub const FuncGen = struct {
7786 if (result_is_ref) {7779 if (result_is_ref) {
7787 // Bitcast the result pointer, then store.7780 // Bitcast the result pointer, then store.
7788 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));7781 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
7789 const result_ptr = self.buildAlloca(llvm_dest_ty);7782 const result_ptr = self.buildAlloca(llvm_dest_ty, alignment);
7790 result_ptr.setAlignment(alignment);
7791 const operand_llvm_ty = try self.dg.lowerType(operand_ty);7783 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
7792 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");7784 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
7793 const store_inst = self.builder.buildStore(operand, casted_ptr);7785 const store_inst = self.builder.buildStore(operand, casted_ptr);
...@@ -7800,8 +7792,7 @@ pub const FuncGen = struct {...@@ -7800,8 +7792,7 @@ pub const FuncGen = struct {
7800 // but LLVM won't let us bitcast struct values.7792 // but LLVM won't let us bitcast struct values.
7801 // Therefore, we store operand to bitcasted alloca, then load for result.7793 // Therefore, we store operand to bitcasted alloca, then load for result.
7802 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));7794 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
7803 const result_ptr = self.buildAlloca(llvm_dest_ty);7795 const result_ptr = self.buildAlloca(llvm_dest_ty, alignment);
7804 result_ptr.setAlignment(alignment);
7805 const operand_llvm_ty = try self.dg.lowerType(operand_ty);7796 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
7806 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");7797 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
7807 const store_inst = self.builder.buildStore(operand, casted_ptr);7798 const store_inst = self.builder.buildStore(operand, casted_ptr);
...@@ -7877,11 +7868,9 @@ pub const FuncGen = struct {...@@ -7877,11 +7868,9 @@ pub const FuncGen = struct {
7877 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);7868 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
78787869
7879 const pointee_llvm_ty = try self.dg.lowerType(pointee_type);7870 const pointee_llvm_ty = try self.dg.lowerType(pointee_type);
7880 const alloca_inst = self.buildAlloca(pointee_llvm_ty);
7881 const target = self.dg.module.getTarget();7871 const target = self.dg.module.getTarget();
7882 const alignment = ptr_ty.ptrAlignment(target);7872 const alignment = ptr_ty.ptrAlignment(target);
7883 alloca_inst.setAlignment(alignment);7873 return self.buildAlloca(pointee_llvm_ty, alignment);
7884 return alloca_inst;
7885 }7874 }
78867875
7887 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7876 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
...@@ -7892,15 +7881,13 @@ pub const FuncGen = struct {...@@ -7892,15 +7881,13 @@ pub const FuncGen = struct {
7892 if (self.ret_ptr) |ret_ptr| return ret_ptr;7881 if (self.ret_ptr) |ret_ptr| return ret_ptr;
7893 const ret_llvm_ty = try self.dg.lowerType(ret_ty);7882 const ret_llvm_ty = try self.dg.lowerType(ret_ty);
7894 const target = self.dg.module.getTarget();7883 const target = self.dg.module.getTarget();
7895 const alloca_inst = self.buildAlloca(ret_llvm_ty);7884 return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(target));
7896 alloca_inst.setAlignment(ptr_ty.ptrAlignment(target));
7897 return alloca_inst;
7898 }7885 }
78997886
7900 /// Use this instead of builder.buildAlloca, because this function makes sure to7887 /// Use this instead of builder.buildAlloca, because this function makes sure to
7901 /// put the alloca instruction at the top of the function!7888 /// put the alloca instruction at the top of the function!
7902 fn buildAlloca(self: *FuncGen, llvm_ty: *llvm.Type) *llvm.Value {7889 fn buildAlloca(self: *FuncGen, llvm_ty: *llvm.Type, alignment: ?c_uint) *llvm.Value {
7903 return buildAllocaInner(self.builder, self.llvm_func, self.di_scope != null, llvm_ty);7890 return buildAllocaInner(self.builder, self.llvm_func, self.di_scope != null, llvm_ty, alignment, self.dg.module.getTarget());
7904 }7891 }
79057892
7906 fn airStore(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7893 fn airStore(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
...@@ -8779,9 +8766,9 @@ pub const FuncGen = struct {...@@ -8779,9 +8766,9 @@ pub const FuncGen = struct {
8779 const llvm_result_ty = accum_init.typeOf();8766 const llvm_result_ty = accum_init.typeOf();
87808767
8781 // Allocate and initialize our mutable variables8768 // Allocate and initialize our mutable variables
8782 const i_ptr = self.buildAlloca(llvm_usize_ty);8769 const i_ptr = self.buildAlloca(llvm_usize_ty, null);
8783 _ = self.builder.buildStore(llvm_usize_ty.constInt(0, .False), i_ptr);8770 _ = self.builder.buildStore(llvm_usize_ty.constInt(0, .False), i_ptr);
8784 const accum_ptr = self.buildAlloca(llvm_result_ty);8771 const accum_ptr = self.buildAlloca(llvm_result_ty, null);
8785 _ = self.builder.buildStore(accum_init, accum_ptr);8772 _ = self.builder.buildStore(accum_init, accum_ptr);
87868773
8787 // Setup the loop8774 // Setup the loop
...@@ -8966,10 +8953,9 @@ pub const FuncGen = struct {...@@ -8966,10 +8953,9 @@ pub const FuncGen = struct {
89668953
8967 if (isByRef(result_ty)) {8954 if (isByRef(result_ty)) {
8968 const llvm_u32 = self.context.intType(32);8955 const llvm_u32 = self.context.intType(32);
8969 const alloca_inst = self.buildAlloca(llvm_result_ty);
8970 // TODO in debug builds init to undef so that the padding will be 0xaa8956 // TODO in debug builds init to undef so that the padding will be 0xaa
8971 // even if we fully populate the fields.8957 // even if we fully populate the fields.
8972 alloca_inst.setAlignment(result_ty.abiAlignment(target));8958 const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(target));
89738959
8974 var indices: [2]*llvm.Value = .{ llvm_u32.constNull(), undefined };8960 var indices: [2]*llvm.Value = .{ llvm_u32.constNull(), undefined };
8975 for (elements) |elem, i| {8961 for (elements) |elem, i| {
...@@ -9007,8 +8993,7 @@ pub const FuncGen = struct {...@@ -9007,8 +8993,7 @@ pub const FuncGen = struct {
9007 assert(isByRef(result_ty));8993 assert(isByRef(result_ty));
90088994
9009 const llvm_usize = try self.dg.lowerType(Type.usize);8995 const llvm_usize = try self.dg.lowerType(Type.usize);
9010 const alloca_inst = self.buildAlloca(llvm_result_ty);8996 const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(target));
9011 alloca_inst.setAlignment(result_ty.abiAlignment(target));
90128997
9013 const array_info = result_ty.arrayInfo();8998 const array_info = result_ty.arrayInfo();
9014 var elem_ptr_payload: Type.Payload.Pointer = .{8999 var elem_ptr_payload: Type.Payload.Pointer = .{
...@@ -9083,7 +9068,7 @@ pub const FuncGen = struct {...@@ -9083,7 +9068,7 @@ pub const FuncGen = struct {
9083 // necessarily match the format that we need, depending on which tag is active. We9068 // necessarily match the format that we need, depending on which tag is active. We
9084 // must construct the correct unnamed struct type here and bitcast, in order to9069 // must construct the correct unnamed struct type here and bitcast, in order to
9085 // then set the fields appropriately.9070 // then set the fields appropriately.
9086 const result_ptr = self.buildAlloca(union_llvm_ty);9071 const result_ptr = self.buildAlloca(union_llvm_ty, null);
9087 const llvm_payload = try self.resolveInst(extra.init);9072 const llvm_payload = try self.resolveInst(extra.init);
9088 assert(union_obj.haveFieldTypes());9073 assert(union_obj.haveFieldTypes());
9089 const field = union_obj.fields.values()[extra.field_index];9074 const field = union_obj.fields.values()[extra.field_index];
...@@ -9243,6 +9228,17 @@ pub const FuncGen = struct {...@@ -9243,6 +9228,17 @@ pub const FuncGen = struct {
9243 return null;9228 return null;
9244 }9229 }
92459230
9231 fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9232 if (self.liveness.isUnused(inst)) return null;
9233
9234 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
9235 const inst_ty = self.air.typeOfIndex(inst);
9236 const operand = try self.resolveInst(ty_op.operand);
9237
9238 const llvm_dest_ty = try self.dg.lowerType(inst_ty);
9239 return self.builder.buildAddrSpaceCast(operand, llvm_dest_ty, "");
9240 }
9241
9246 fn getErrorNameTable(self: *FuncGen) !*llvm.Value {9242 fn getErrorNameTable(self: *FuncGen) !*llvm.Value {
9247 if (self.dg.object.error_name_table) |table| {9243 if (self.dg.object.error_name_table) |table| {
9248 return table;9244 return table;
...@@ -9324,9 +9320,8 @@ pub const FuncGen = struct {...@@ -9324,9 +9320,8 @@ pub const FuncGen = struct {
93249320
9325 if (isByRef(optional_ty)) {9321 if (isByRef(optional_ty)) {
9326 const target = self.dg.module.getTarget();9322 const target = self.dg.module.getTarget();
9327 const alloca_inst = self.buildAlloca(optional_llvm_ty);
9328 const payload_alignment = optional_ty.abiAlignment(target);9323 const payload_alignment = optional_ty.abiAlignment(target);
9329 alloca_inst.setAlignment(payload_alignment);9324 const alloca_inst = self.buildAlloca(optional_llvm_ty, payload_alignment);
93309325
9331 {9326 {
9332 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 0, "");9327 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 0, "");
...@@ -9450,8 +9445,7 @@ pub const FuncGen = struct {...@@ -9450,8 +9445,7 @@ pub const FuncGen = struct {
9450 if (isByRef(info.pointee_type)) {9445 if (isByRef(info.pointee_type)) {
9451 const result_align = info.pointee_type.abiAlignment(target);9446 const result_align = info.pointee_type.abiAlignment(target);
9452 const max_align = @maximum(result_align, ptr_alignment);9447 const max_align = @maximum(result_align, ptr_alignment);
9453 const result_ptr = self.buildAlloca(elem_llvm_ty);9448 const result_ptr = self.buildAlloca(elem_llvm_ty, max_align);
9454 result_ptr.setAlignment(max_align);
9455 const llvm_ptr_u8 = self.context.intType(8).pointerType(0);9449 const llvm_ptr_u8 = self.context.intType(8).pointerType(0);
9456 const llvm_usize = self.context.intType(Type.usize.intInfo(target).bits);9450 const llvm_usize = self.context.intType(Type.usize.intInfo(target).bits);
9457 const size_bytes = info.pointee_type.abiSize(target);9451 const size_bytes = info.pointee_type.abiSize(target);
...@@ -9484,8 +9478,7 @@ pub const FuncGen = struct {...@@ -9484,8 +9478,7 @@ pub const FuncGen = struct {
94849478
9485 if (isByRef(info.pointee_type)) {9479 if (isByRef(info.pointee_type)) {
9486 const result_align = info.pointee_type.abiAlignment(target);9480 const result_align = info.pointee_type.abiAlignment(target);
9487 const result_ptr = self.buildAlloca(elem_llvm_ty);9481 const result_ptr = self.buildAlloca(elem_llvm_ty, result_align);
9488 result_ptr.setAlignment(result_align);
94899482
9490 const same_size_int = self.context.intType(elem_bits);9483 const same_size_int = self.context.intType(elem_bits);
9491 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");9484 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
...@@ -9609,8 +9602,7 @@ pub const FuncGen = struct {...@@ -9609,8 +9602,7 @@ pub const FuncGen = struct {
9609 .x86_64 => {9602 .x86_64 => {
9610 const array_llvm_ty = usize_llvm_ty.arrayType(6);9603 const array_llvm_ty = usize_llvm_ty.arrayType(6);
9611 const array_ptr = fg.valgrind_client_request_array orelse a: {9604 const array_ptr = fg.valgrind_client_request_array orelse a: {
9612 const array_ptr = fg.buildAlloca(array_llvm_ty);9605 const array_ptr = fg.buildAlloca(array_llvm_ty, usize_alignment);
9613 array_ptr.setAlignment(usize_alignment);
9614 fg.valgrind_client_request_array = array_ptr;9606 fg.valgrind_client_request_array = array_ptr;
9615 break :a array_ptr;9607 break :a array_ptr;
9616 };9608 };
...@@ -9905,6 +9897,78 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca...@@ -9905,6 +9897,78 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca
9905 .nvptx, .nvptx64 => .PTX_Kernel,9897 .nvptx, .nvptx64 => .PTX_Kernel,
9906 else => unreachable,9898 else => unreachable,
9907 },9899 },
9900 .AmdgpuKernel => return switch (target.cpu.arch) {
9901 .amdgcn => .AMDGPU_KERNEL,
9902 else => unreachable,
9903 },
9904 };
9905}
9906
9907/// Convert a zig-address space to an llvm address space.
9908fn toLlvmAddressSpace(address_space: std.builtin.AddressSpace, target: std.Target) c_uint {
9909 return switch (target.cpu.arch) {
9910 .i386, .x86_64 => switch (address_space) {
9911 .generic => llvm.address_space.default,
9912 .gs => llvm.address_space.x86.gs,
9913 .fs => llvm.address_space.x86.fs,
9914 .ss => llvm.address_space.x86.ss,
9915 else => unreachable,
9916 },
9917 .nvptx, .nvptx64 => switch (address_space) {
9918 .generic => llvm.address_space.default,
9919 .global => llvm.address_space.nvptx.global,
9920 .constant => llvm.address_space.nvptx.constant,
9921 .param => llvm.address_space.nvptx.param,
9922 .shared => llvm.address_space.nvptx.shared,
9923 .local => llvm.address_space.nvptx.local,
9924 else => unreachable,
9925 },
9926 .amdgcn => switch (address_space) {
9927 .generic => llvm.address_space.amdgpu.flat,
9928 .global => llvm.address_space.amdgpu.global,
9929 .constant => llvm.address_space.amdgpu.constant,
9930 .shared => llvm.address_space.amdgpu.local,
9931 .local => llvm.address_space.amdgpu.private,
9932 else => unreachable,
9933 },
9934 else => switch (address_space) {
9935 .generic => llvm.address_space.default,
9936 else => unreachable,
9937 },
9938 };
9939}
9940
9941/// On some targets, local values that are in the generic address space must be generated into a
9942/// different address, space and then cast back to the generic address space.
9943/// For example, on GPUs local variable declarations must be generated into the local address space.
9944/// This function returns the address space local values should be generated into.
9945fn llvmAllocaAddressSpace(target: std.Target) c_uint {
9946 return switch (target.cpu.arch) {
9947 // On amdgcn, locals should be generated into the private address space.
9948 // To make Zig not impossible to use, these are then converted to addresses in the
9949 // generic address space and treates as regular pointers. This is the way that HIP also does it.
9950 .amdgcn => llvm.address_space.amdgpu.private,
9951 else => llvm.address_space.default,
9952 };
9953}
9954
9955/// On some targets, global values that are in the generic address space must be generated into a
9956/// different address space, and then cast back to the generic address space.
9957fn llvmDefaultGlobalAddressSpace(target: std.Target) c_uint {
9958 return switch (target.cpu.arch) {
9959 // On amdgcn, globals must be explicitly allocated and uploaded so that the program can access
9960 // them.
9961 .amdgcn => llvm.address_space.amdgpu.global,
9962 else => llvm.address_space.default,
9963 };
9964}
9965
9966/// Return the actual address space that a value should be stored in if its a global address space.
9967/// When a value is placed in the resulting address space, it needs to be cast back into wanted_address_space.
9968fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, target: std.Target) c_uint {
9969 return switch (wanted_address_space) {
9970 .generic => llvmDefaultGlobalAddressSpace(target),
9971 else => |as| toLlvmAddressSpace(as, target),
9908 };9972 };
9909}9973}
99109974
...@@ -10537,13 +10601,23 @@ fn backendSupportsF16(target: std.Target) bool {...@@ -10537,13 +10601,23 @@ fn backendSupportsF16(target: std.Target) bool {
10537 };10601 };
10538}10602}
1053910603
10604/// This function returns true if we expect LLVM to lower f128 correctly,
10605/// and false if we expect LLVm to crash if it encounters and f128 type
10606/// or if it produces miscompilations.
10607fn backendSupportsF128(target: std.Target) bool {
10608 return switch (target.cpu.arch) {
10609 .amdgcn => false,
10610 else => true,
10611 };
10612}
10613
10540/// LLVM does not support all relevant intrinsics for all targets, so we10614/// LLVM does not support all relevant intrinsics for all targets, so we
10541/// may need to manually generate a libc call10615/// may need to manually generate a libc call
10542fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool {10616fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool {
10543 return switch (scalar_ty.tag()) {10617 return switch (scalar_ty.tag()) {
10544 .f16 => backendSupportsF16(target),10618 .f16 => backendSupportsF16(target),
10545 .f80 => target.longDoubleIs(f80) and backendSupportsF80(target),10619 .f80 => target.longDoubleIs(f80) and backendSupportsF80(target),
10546 .f128 => target.longDoubleIs(f128),10620 .f128 => target.longDoubleIs(f128) and backendSupportsF128(target),
10547 else => true,10621 else => true,
10548 };10622 };
10549}10623}
...@@ -10620,25 +10694,43 @@ fn buildAllocaInner(...@@ -10620,25 +10694,43 @@ fn buildAllocaInner(
10620 llvm_func: *llvm.Value,10694 llvm_func: *llvm.Value,
10621 di_scope_non_null: bool,10695 di_scope_non_null: bool,
10622 llvm_ty: *llvm.Type,10696 llvm_ty: *llvm.Type,
10697 maybe_alignment: ?c_uint,
10698 target: std.Target,
10623) *llvm.Value {10699) *llvm.Value {
10624 const prev_block = builder.getInsertBlock();10700 const address_space = llvmAllocaAddressSpace(target);
10625 const prev_debug_location = builder.getCurrentDebugLocation2();10701
10626 defer {10702 const alloca = blk: {
10627 builder.positionBuilderAtEnd(prev_block);10703 const prev_block = builder.getInsertBlock();
10628 if (di_scope_non_null) {10704 const prev_debug_location = builder.getCurrentDebugLocation2();
10629 builder.setCurrentDebugLocation2(prev_debug_location);10705 defer {
10706 builder.positionBuilderAtEnd(prev_block);
10707 if (di_scope_non_null) {
10708 builder.setCurrentDebugLocation2(prev_debug_location);
10709 }
10630 }10710 }
10711
10712 const entry_block = llvm_func.getFirstBasicBlock().?;
10713 if (entry_block.getFirstInstruction()) |first_inst| {
10714 builder.positionBuilder(entry_block, first_inst);
10715 } else {
10716 builder.positionBuilderAtEnd(entry_block);
10717 }
10718 builder.clearCurrentDebugLocation();
10719
10720 break :blk builder.buildAllocaInAddressSpace(llvm_ty, address_space, "");
10721 };
10722
10723 if (maybe_alignment) |alignment| {
10724 alloca.setAlignment(alignment);
10631 }10725 }
1063210726
10633 const entry_block = llvm_func.getFirstBasicBlock().?;10727 // The pointer returned from this function should have the generic address space,
10634 if (entry_block.getFirstInstruction()) |first_inst| {10728 // if this isn't the case then cast it to the generic address space.
10635 builder.positionBuilder(entry_block, first_inst);10729 if (address_space != llvm.address_space.default) {
10636 } else {10730 return builder.buildAddrSpaceCast(alloca, llvm_ty.pointerType(llvm.address_space.default), "");
10637 builder.positionBuilderAtEnd(entry_block);
10638 }10731 }
10639 builder.clearCurrentDebugLocation();
1064010732
10641 return builder.buildAlloca(llvm_ty, "");10733 return alloca;
10642}10734}
1064310735
10644fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u1 {10736fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u1 {
src/codegen/llvm/bindings.zig+9
...@@ -171,6 +171,9 @@ pub const Value = opaque {...@@ -171,6 +171,9 @@ pub const Value = opaque {
171 pub const constAdd = LLVMConstAdd;171 pub const constAdd = LLVMConstAdd;
172 extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;172 extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
173173
174 pub const constAddrSpaceCast = LLVMConstAddrSpaceCast;
175 extern fn LLVMConstAddrSpaceCast(ConstantVal: *Value, ToType: *Type) *Value;
176
174 pub const setWeak = LLVMSetWeak;177 pub const setWeak = LLVMSetWeak;
175 extern fn LLVMSetWeak(CmpXchgInst: *Value, IsWeak: Bool) void;178 extern fn LLVMSetWeak(CmpXchgInst: *Value, IsWeak: Bool) void;
176179
...@@ -956,6 +959,12 @@ pub const Builder = opaque {...@@ -956,6 +959,12 @@ pub const Builder = opaque {
956959
957 pub const setFastMath = ZigLLVMSetFastMath;960 pub const setFastMath = ZigLLVMSetFastMath;
958 extern fn ZigLLVMSetFastMath(B: *Builder, on_state: bool) void;961 extern fn ZigLLVMSetFastMath(B: *Builder, on_state: bool) void;
962
963 pub const buildAddrSpaceCast = LLVMBuildAddrSpaceCast;
964 extern fn LLVMBuildAddrSpaceCast(B: *Builder, Val: *Value, DestTy: *Type, Name: [*:0]const u8) *Value;
965
966 pub const buildAllocaInAddressSpace = ZigLLVMBuildAllocaInAddressSpace;
967 extern fn ZigLLVMBuildAllocaInAddressSpace(B: *Builder, Ty: *Type, AddressSpace: c_uint, Name: [*:0]const u8) *Value;
959};968};
960969
961pub const MDString = opaque {970pub const MDString = opaque {
src/print_air.zig+1
...@@ -244,6 +244,7 @@ const Writer = struct {...@@ -244,6 +244,7 @@ const Writer = struct {
244 .byte_swap,244 .byte_swap,
245 .bit_reverse,245 .bit_reverse,
246 .error_set_has_value,246 .error_set_has_value,
247 .addrspace_cast,
247 => try w.writeTyOp(s, inst),248 => try w.writeTyOp(s, inst),
248249
249 .block,250 .block,
src/print_zir.zig+1
...@@ -512,6 +512,7 @@ const Writer = struct {...@@ -512,6 +512,7 @@ const Writer = struct {
512 .err_set_cast,512 .err_set_cast,
513 .wasm_memory_grow,513 .wasm_memory_grow,
514 .prefetch,514 .prefetch,
515 .addrspace_cast,
515 => {516 => {
516 const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;517 const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
517 const src = LazySrcLoc.nodeOffset(inst_data.node);518 const src = LazySrcLoc.nodeOffset(inst_data.node);
src/stage1/all_types.hpp+16-1
...@@ -85,7 +85,8 @@ enum CallingConvention {...@@ -85,7 +85,8 @@ enum CallingConvention {
85 CallingConventionAAPCSVFP,85 CallingConventionAAPCSVFP,
86 CallingConventionSysV,86 CallingConventionSysV,
87 CallingConventionWin64,87 CallingConventionWin64,
88 CallingConventionPtxKernel88 CallingConventionPtxKernel,
89 CallingConventionAmdgpuKernel
89};90};
9091
91// Stage 1 supports only the generic address space92// Stage 1 supports only the generic address space
...@@ -94,6 +95,11 @@ enum AddressSpace {...@@ -94,6 +95,11 @@ enum AddressSpace {
94 AddressSpaceGS,95 AddressSpaceGS,
95 AddressSpaceFS,96 AddressSpaceFS,
96 AddressSpaceSS,97 AddressSpaceSS,
98 AddressSpaceGlobal,
99 AddressSpaceConstant,
100 AddressSpaceParam,
101 AddressSpaceShared,
102 AddressSpaceLocal
97};103};
98104
99// This one corresponds to the builtin.zig enum.105// This one corresponds to the builtin.zig enum.
...@@ -1841,6 +1847,7 @@ enum BuiltinFnId {...@@ -1841,6 +1847,7 @@ enum BuiltinFnId {
1841 BuiltinFnIdMaximum,1847 BuiltinFnIdMaximum,
1842 BuiltinFnIdMinimum,1848 BuiltinFnIdMinimum,
1843 BuiltinFnIdPrefetch,1849 BuiltinFnIdPrefetch,
1850 BuiltinFnIdAddrSpaceCast,
1844};1851};
18451852
1846struct BuiltinFnEntry {1853struct BuiltinFnEntry {
...@@ -2672,6 +2679,7 @@ enum Stage1ZirInstId : uint8_t {...@@ -2672,6 +2679,7 @@ enum Stage1ZirInstId : uint8_t {
2672 Stage1ZirInstIdWasmMemoryGrow,2679 Stage1ZirInstIdWasmMemoryGrow,
2673 Stage1ZirInstIdSrc,2680 Stage1ZirInstIdSrc,
2674 Stage1ZirInstIdPrefetch,2681 Stage1ZirInstIdPrefetch,
2682 Stage1ZirInstIdAddrSpaceCast,
2675};2683};
26762684
2677// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.2685// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.
...@@ -4168,6 +4176,13 @@ struct Stage1AirInstAlignCast {...@@ -4168,6 +4176,13 @@ struct Stage1AirInstAlignCast {
4168 Stage1AirInst *target;4176 Stage1AirInst *target;
4169};4177};
41704178
4179struct Stage1ZirInstAddrSpaceCast {
4180 Stage1ZirInst base;
4181
4182 Stage1ZirInst *addrspace;
4183 Stage1ZirInst *ptr;
4184};
4185
4171struct Stage1ZirInstSetAlignStack {4186struct Stage1ZirInstSetAlignStack {
4172 Stage1ZirInst base;4187 Stage1ZirInst base;
41734188
src/stage1/analyze.cpp+14-3
...@@ -993,6 +993,7 @@ const char *calling_convention_name(CallingConvention cc) {...@@ -993,6 +993,7 @@ const char *calling_convention_name(CallingConvention cc) {
993 case CallingConventionSysV: return "SysV";993 case CallingConventionSysV: return "SysV";
994 case CallingConventionWin64: return "Win64";994 case CallingConventionWin64: return "Win64";
995 case CallingConventionPtxKernel: return "PtxKernel";995 case CallingConventionPtxKernel: return "PtxKernel";
996 case CallingConventionAmdgpuKernel: return "AmdgpuKernel";
996 }997 }
997 zig_unreachable();998 zig_unreachable();
998}999}
...@@ -1017,6 +1018,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {...@@ -1017,6 +1018,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {
1017 case CallingConventionAAPCSVFP:1018 case CallingConventionAAPCSVFP:
1018 case CallingConventionSysV:1019 case CallingConventionSysV:
1019 case CallingConventionWin64:1020 case CallingConventionWin64:
1021 case CallingConventionAmdgpuKernel:
1020 return false;1022 return false;
1021 }1023 }
1022 zig_unreachable();1024 zig_unreachable();
...@@ -1028,6 +1030,11 @@ const char *address_space_name(AddressSpace as) {...@@ -1028,6 +1030,11 @@ const char *address_space_name(AddressSpace as) {
1028 case AddressSpaceGS: return "gs";1030 case AddressSpaceGS: return "gs";
1029 case AddressSpaceFS: return "fs";1031 case AddressSpaceFS: return "fs";
1030 case AddressSpaceSS: return "ss";1032 case AddressSpaceSS: return "ss";
1033 case AddressSpaceGlobal: return "global";
1034 case AddressSpaceConstant: return "constant";
1035 case AddressSpaceParam: return "param";
1036 case AddressSpaceShared: return "shared";
1037 case AddressSpaceLocal: return "local";
1031 }1038 }
1032 zig_unreachable();1039 zig_unreachable();
1033}1040}
...@@ -2019,6 +2026,9 @@ Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_...@@ -2019,6 +2026,9 @@ Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_
2019 allowed_platforms = "nvptx and nvptx64";2026 allowed_platforms = "nvptx and nvptx64";
2020 }2027 }
2021 break;2028 break;
2029 case CallingConventionAmdgpuKernel:
2030 if (g->zig_target->arch != ZigLLVM_amdgcn)
2031 allowed_platforms = "amdgcn and amdpal";
20222032
2023 }2033 }
2024 if (allowed_platforms != nullptr) {2034 if (allowed_platforms != nullptr) {
...@@ -3857,6 +3867,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -3857,6 +3867,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
3857 case CallingConventionSysV:3867 case CallingConventionSysV:
3858 case CallingConventionWin64:3868 case CallingConventionWin64:
3859 case CallingConventionPtxKernel:3869 case CallingConventionPtxKernel:
3870 case CallingConventionAmdgpuKernel:
3860 add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name),3871 add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name),
3861 GlobalLinkageIdStrong, fn_cc);3872 GlobalLinkageIdStrong, fn_cc);
3862 break;3873 break;
...@@ -6012,7 +6023,7 @@ Error type_has_bits2(CodeGen *g, ZigType *type_entry, bool *result) {...@@ -6012,7 +6023,7 @@ Error type_has_bits2(CodeGen *g, ZigType *type_entry, bool *result) {
60126023
6013bool fn_returns_c_abi_small_struct(FnTypeId *fn_type_id) {6024bool fn_returns_c_abi_small_struct(FnTypeId *fn_type_id) {
6014 ZigType *type = fn_type_id->return_type;6025 ZigType *type = fn_type_id->return_type;
6015 return !calling_convention_allows_zig_types(fn_type_id->cc) && 6026 return !calling_convention_allows_zig_types(fn_type_id->cc) &&
6016 type->id == ZigTypeIdStruct && type->abi_size <= 16;6027 type->id == ZigTypeIdStruct && type->abi_size <= 16;
6017}6028}
60186029
...@@ -8700,7 +8711,7 @@ static LLVMTypeRef llvm_int_for_size(size_t size) {...@@ -8700,7 +8711,7 @@ static LLVMTypeRef llvm_int_for_size(size_t size) {
8700static LLVMTypeRef llvm_sse_for_size(size_t size) {8711static LLVMTypeRef llvm_sse_for_size(size_t size) {
8701 if (size > 4)8712 if (size > 4)
8702 return LLVMDoubleType();8713 return LLVMDoubleType();
8703 else 8714 else
8704 return LLVMFloatType();8715 return LLVMFloatType();
8705}8716}
87068717
...@@ -8758,7 +8769,7 @@ static Error resolve_llvm_c_abi_type(CodeGen *g, ZigType *ty) {...@@ -8758,7 +8769,7 @@ static Error resolve_llvm_c_abi_type(CodeGen *g, ZigType *ty) {
87588769
8759 LLVMTypeRef return_elem_types[] = {8770 LLVMTypeRef return_elem_types[] = {
8760 LLVMVoidType(),8771 LLVMVoidType(),
8761 LLVMVoidType(), 8772 LLVMVoidType(),
8762 };8773 };
8763 for (uint32_t i = 0; i <= eightbyte_index; i += 1) {8774 for (uint32_t i = 0; i <= eightbyte_index; i += 1) {
8764 if (type_classes[i] == X64CABIClass_INTEGER) {8775 if (type_classes[i] == X64CABIClass_INTEGER) {
src/stage1/astgen.cpp+34
...@@ -351,6 +351,8 @@ void destroy_instruction_src(Stage1ZirInst *inst) {...@@ -351,6 +351,8 @@ void destroy_instruction_src(Stage1ZirInst *inst) {
351 return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstSrc *>(inst));351 return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstSrc *>(inst));
352 case Stage1ZirInstIdPrefetch:352 case Stage1ZirInstIdPrefetch:
353 return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstPrefetch *>(inst));353 return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstPrefetch *>(inst));
354 case Stage1ZirInstIdAddrSpaceCast:
355 return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstAddrSpaceCast *>(inst));
354 }356 }
355 zig_unreachable();357 zig_unreachable();
356}358}
...@@ -947,6 +949,10 @@ static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPrefetch *) {...@@ -947,6 +949,10 @@ static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPrefetch *) {
947 return Stage1ZirInstIdPrefetch;949 return Stage1ZirInstIdPrefetch;
948}950}
949951
952static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAddrSpaceCast *) {
953 return Stage1ZirInstIdAddrSpaceCast;
954}
955
950template<typename T>956template<typename T>
951static T *ir_create_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node) {957static T *ir_create_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node) {
952 T *special_instruction = heap::c_allocator.create<T>();958 T *special_instruction = heap::c_allocator.create<T>();
...@@ -2572,6 +2578,19 @@ static Stage1ZirInst *ir_build_align_cast_src(Stage1AstGen *ag, Scope *scope, As...@@ -2572,6 +2578,19 @@ static Stage1ZirInst *ir_build_align_cast_src(Stage1AstGen *ag, Scope *scope, As
2572 return &instruction->base;2578 return &instruction->base;
2573}2579}
25742580
2581static Stage1ZirInst *ir_build_addrspace_cast(Stage1AstGen *ag, Scope *scope, AstNode *source_node,
2582 Stage1ZirInst *addrspace, Stage1ZirInst *ptr)
2583{
2584 Stage1ZirInstAddrSpaceCast *instruction = ir_build_instruction<Stage1ZirInstAddrSpaceCast>(ag, scope, source_node);
2585 instruction->addrspace = addrspace;
2586 instruction->ptr = ptr;
2587
2588 ir_ref_instruction(addrspace, ag->current_basic_block);
2589 ir_ref_instruction(ptr, ag->current_basic_block);
2590
2591 return &instruction->base;
2592}
2593
2575static Stage1ZirInst *ir_build_resolve_result(Stage1AstGen *ag, Scope *scope, AstNode *source_node,2594static Stage1ZirInst *ir_build_resolve_result(Stage1AstGen *ag, Scope *scope, AstNode *source_node,
2576 ResultLoc *result_loc, Stage1ZirInst *ty)2595 ResultLoc *result_loc, Stage1ZirInst *ty)
2577{2596{
...@@ -5459,6 +5478,21 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast...@@ -5459,6 +5478,21 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
5459 Stage1ZirInst *ir_extern = ir_build_prefetch(ag, scope, node, ptr_value, casted_options_value);5478 Stage1ZirInst *ir_extern = ir_build_prefetch(ag, scope, node, ptr_value, casted_options_value);
5460 return ir_lval_wrap(ag, scope, ir_extern, lval, result_loc);5479 return ir_lval_wrap(ag, scope, ir_extern, lval, result_loc);
5461 }5480 }
5481 case BuiltinFnIdAddrSpaceCast:
5482 {
5483 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
5484 Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope);
5485 if (arg0_value == ag->codegen->invalid_inst_src)
5486 return arg0_value;
5487
5488 AstNode* arg1_node = node->data.fn_call_expr.params.at(1);
5489 Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope);
5490 if (arg1_value == ag->codegen->invalid_inst_src)
5491 return arg1_value;
5492
5493 Stage1ZirInst *addrspace_cast = ir_build_addrspace_cast(ag, scope, node, arg0_value, arg1_value);
5494 return ir_lval_wrap(ag, scope, addrspace_cast, lval, result_loc);
5495 }
5462 }5496 }
5463 zig_unreachable();5497 zig_unreachable();
5464}5498}
src/stage1/codegen.cpp+7-2
...@@ -217,6 +217,9 @@ static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) {...@@ -217,6 +217,9 @@ static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
217 assert(g->zig_target->arch == ZigLLVM_nvptx ||217 assert(g->zig_target->arch == ZigLLVM_nvptx ||
218 g->zig_target->arch == ZigLLVM_nvptx64);218 g->zig_target->arch == ZigLLVM_nvptx64);
219 return ZigLLVM_PTX_Kernel;219 return ZigLLVM_PTX_Kernel;
220 case CallingConventionAmdgpuKernel:
221 assert(g->zig_target->arch == ZigLLVM_amdgcn);
222 return ZigLLVM_AMDGPU_KERNEL;
220223
221 }224 }
222 zig_unreachable();225 zig_unreachable();
...@@ -365,6 +368,7 @@ static bool cc_want_sret_attr(CallingConvention cc) {...@@ -365,6 +368,7 @@ static bool cc_want_sret_attr(CallingConvention cc) {
365 case CallingConventionSysV:368 case CallingConventionSysV:
366 case CallingConventionWin64:369 case CallingConventionWin64:
367 case CallingConventionPtxKernel:370 case CallingConventionPtxKernel:
371 case CallingConventionAmdgpuKernel:
368 return true;372 return true;
369 case CallingConventionAsync:373 case CallingConventionAsync:
370 case CallingConventionUnspecified:374 case CallingConventionUnspecified:
...@@ -3515,7 +3519,7 @@ static LLVMValueRef gen_soft_float_to_int_op(CodeGen *g, LLVMValueRef value_ref,...@@ -3515,7 +3519,7 @@ static LLVMValueRef gen_soft_float_to_int_op(CodeGen *g, LLVMValueRef value_ref,
35153519
3516 // Handle integers of non-pot bitsize by shortening them on the output3520 // Handle integers of non-pot bitsize by shortening them on the output
3517 if (result_type != wider_type) {3521 if (result_type != wider_type) {
3518 result = gen_widen_or_shorten(g, false, wider_type, result_type, result); 3522 result = gen_widen_or_shorten(g, false, wider_type, result_type, result);
3519 }3523 }
35203524
3521 return result;3525 return result;
...@@ -4370,7 +4374,7 @@ static LLVMValueRef ir_render_binary_not(CodeGen *g, Stage1Air *executable,...@@ -4370,7 +4374,7 @@ static LLVMValueRef ir_render_binary_not(CodeGen *g, Stage1Air *executable,
43704374
4371static LLVMValueRef gen_soft_float_neg(CodeGen *g, ZigType *operand_type, LLVMValueRef operand) {4375static LLVMValueRef gen_soft_float_neg(CodeGen *g, ZigType *operand_type, LLVMValueRef operand) {
4372 uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0;4376 uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0;
4373 uint16_t num_bits = operand_type->id == ZigTypeIdVector ? 4377 uint16_t num_bits = operand_type->id == ZigTypeIdVector ?
4374 operand_type->data.vector.elem_type->data.floating.bit_count :4378 operand_type->data.vector.elem_type->data.floating.bit_count :
4375 operand_type->data.floating.bit_count;4379 operand_type->data.floating.bit_count;
43764380
...@@ -10181,6 +10185,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -10181,6 +10185,7 @@ static void define_builtin_fns(CodeGen *g) {
10181 create_builtin_fn(g, BuiltinFnIdMaximum, "maximum", 2);10185 create_builtin_fn(g, BuiltinFnIdMaximum, "maximum", 2);
10182 create_builtin_fn(g, BuiltinFnIdMinimum, "minimum", 2);10186 create_builtin_fn(g, BuiltinFnIdMinimum, "minimum", 2);
10183 create_builtin_fn(g, BuiltinFnIdPrefetch, "prefetch", 2);10187 create_builtin_fn(g, BuiltinFnIdPrefetch, "prefetch", 2);
10188 create_builtin_fn(g, BuiltinFnIdAddrSpaceCast, "addrSpaceCast", 2);
10184}10189}
1018510190
10186static const char *bool_to_str(bool b) {10191static const char *bool_to_str(bool b) {
src/stage1/ir.cpp+48
...@@ -11753,6 +11753,7 @@ static Stage1AirInst *ir_analyze_instruction_export(IrAnalyze *ira, Stage1ZirIns...@@ -11753,6 +11753,7 @@ static Stage1AirInst *ir_analyze_instruction_export(IrAnalyze *ira, Stage1ZirIns
11753 case CallingConventionSysV:11753 case CallingConventionSysV:
11754 case CallingConventionWin64:11754 case CallingConventionWin64:
11755 case CallingConventionPtxKernel:11755 case CallingConventionPtxKernel:
11756 case CallingConventionAmdgpuKernel:
11756 add_fn_export(ira->codegen, fn_entry, buf_ptr(symbol_name), global_linkage_id, cc);11757 add_fn_export(ira->codegen, fn_entry, buf_ptr(symbol_name), global_linkage_id, cc);
11757 fn_entry->section_name = section_name;11758 fn_entry->section_name = section_name;
11758 break;11759 break;
...@@ -23745,6 +23746,50 @@ static Stage1AirInst *ir_analyze_instruction_align_cast(IrAnalyze *ira, Stage1Zi...@@ -23745,6 +23746,50 @@ static Stage1AirInst *ir_analyze_instruction_align_cast(IrAnalyze *ira, Stage1Zi
23745 return result;23746 return result;
23746}23747}
2374723748
23749static bool ir_resolve_addrspace(IrAnalyze *ira, Stage1AirInst *value, AddressSpace *out) {
23750 if (type_is_invalid(value->value->type))
23751 return false;
23752
23753 ZigType *addrspace_type = get_builtin_type(ira->codegen, "AddressSpace");
23754
23755 Stage1AirInst *casted_value = ir_implicit_cast(ira, value, addrspace_type);
23756 if (type_is_invalid(casted_value->value->type))
23757 return false;
23758
23759 ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
23760 if (!const_val)
23761 return false;
23762
23763 *out = (AddressSpace)bigint_as_u32(&const_val->data.x_enum_tag);
23764 return true;
23765}
23766
23767static Stage1AirInst *ir_analyze_instruction_addrspace_cast(IrAnalyze *ira, Stage1ZirInstAddrSpaceCast *instruction) {
23768 Stage1AirInst *ptr_inst = instruction->ptr->child;
23769 ZigType *ptr_type = ptr_inst->value->type;
23770 if (type_is_invalid(ptr_type))
23771 return ira->codegen->invalid_inst_gen;
23772
23773 AddressSpace addrspace;
23774 if (!ir_resolve_addrspace(ira, instruction->addrspace->child, &addrspace))
23775 return ira->codegen->invalid_inst_gen;
23776
23777 if (addrspace != AddressSpaceGeneric) {
23778 ir_add_error_node(ira, instruction->addrspace->source_node, buf_sprintf(
23779 "address space '%s' not available in stage 1 compiler, must be .generic",
23780 address_space_name(addrspace)));
23781 return ira->codegen->invalid_inst_gen;
23782 }
23783
23784 if (is_slice(ptr_type) || get_src_ptr_type(ptr_type) != nullptr) {
23785 ir_add_error_node(ira, instruction->ptr->source_node,
23786 buf_sprintf("expected pointer or slice, found '%s'", buf_ptr(&ptr_type->name)));
23787 return ira->codegen->invalid_inst_gen;
23788 }
23789
23790 return ptr_inst;
23791}
23792
23748static Stage1AirInst *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, Stage1ZirInstSetAlignStack *instruction) {23793static Stage1AirInst *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, Stage1ZirInstSetAlignStack *instruction) {
23749 uint32_t align_bytes;23794 uint32_t align_bytes;
23750 Stage1AirInst *align_bytes_inst = instruction->align_bytes->child;23795 Stage1AirInst *align_bytes_inst = instruction->align_bytes->child;
...@@ -25450,6 +25495,8 @@ static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst...@@ -25450,6 +25495,8 @@ static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst
25450 return ir_analyze_instruction_src(ira, (Stage1ZirInstSrc *)instruction);25495 return ir_analyze_instruction_src(ira, (Stage1ZirInstSrc *)instruction);
25451 case Stage1ZirInstIdPrefetch:25496 case Stage1ZirInstIdPrefetch:
25452 return ir_analyze_instruction_prefetch(ira, (Stage1ZirInstPrefetch *)instruction);25497 return ir_analyze_instruction_prefetch(ira, (Stage1ZirInstPrefetch *)instruction);
25498 case Stage1ZirInstIdAddrSpaceCast:
25499 return ir_analyze_instruction_addrspace_cast(ira, (Stage1ZirInstAddrSpaceCast *)instruction);
25453 }25500 }
25454 zig_unreachable();25501 zig_unreachable();
25455}25502}
...@@ -25831,6 +25878,7 @@ bool ir_inst_src_has_side_effects(Stage1ZirInst *instruction) {...@@ -25831,6 +25878,7 @@ bool ir_inst_src_has_side_effects(Stage1ZirInst *instruction) {
25831 case Stage1ZirInstIdWasmMemorySize:25878 case Stage1ZirInstIdWasmMemorySize:
25832 case Stage1ZirInstIdSrc:25879 case Stage1ZirInstIdSrc:
25833 case Stage1ZirInstIdReduce:25880 case Stage1ZirInstIdReduce:
25881 case Stage1ZirInstIdAddrSpaceCast:
25834 return false;25882 return false;
2583525883
25836 case Stage1ZirInstIdAsm:25884 case Stage1ZirInstIdAsm:
src/stage1/ir_print.cpp+13
...@@ -373,6 +373,8 @@ const char* ir_inst_src_type_str(Stage1ZirInstId id) {...@@ -373,6 +373,8 @@ const char* ir_inst_src_type_str(Stage1ZirInstId id) {
373 return "SrcSrc";373 return "SrcSrc";
374 case Stage1ZirInstIdPrefetch:374 case Stage1ZirInstIdPrefetch:
375 return "SrcPrefetch";375 return "SrcPrefetch";
376 case Stage1ZirInstIdAddrSpaceCast:
377 return "SrcAddrSpaceCast";
376 }378 }
377 zig_unreachable();379 zig_unreachable();
378}380}
...@@ -2382,6 +2384,14 @@ static void ir_print_align_cast(IrPrintSrc *irp, Stage1ZirInstAlignCast *instruc...@@ -2382,6 +2384,14 @@ static void ir_print_align_cast(IrPrintSrc *irp, Stage1ZirInstAlignCast *instruc
2382 fprintf(irp->f, ")");2384 fprintf(irp->f, ")");
2383}2385}
23842386
2387static void ir_print_addrspace_cast(IrPrintSrc *irp, Stage1ZirInstAddrSpaceCast *instruction) {
2388 fprintf(irp->f, "@addrSpaceCast(");
2389 ir_print_other_inst_src(irp, instruction->addrspace);
2390 fprintf(irp->f, ",");
2391 ir_print_other_inst_src(irp, instruction->ptr);
2392 fprintf(irp->f, ")");
2393}
2394
2385static void ir_print_align_cast(IrPrintGen *irp, Stage1AirInstAlignCast *instruction) {2395static void ir_print_align_cast(IrPrintGen *irp, Stage1AirInstAlignCast *instruction) {
2386 fprintf(irp->f, "@alignCast(");2396 fprintf(irp->f, "@alignCast(");
2387 ir_print_other_inst_gen(irp, instruction->target);2397 ir_print_other_inst_gen(irp, instruction->target);
...@@ -3127,6 +3137,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, Stage1ZirInst *instruction, bool...@@ -3127,6 +3137,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, Stage1ZirInst *instruction, bool
3127 case Stage1ZirInstIdPrefetch:3137 case Stage1ZirInstIdPrefetch:
3128 ir_print_prefetch(irp, (Stage1ZirInstPrefetch *)instruction);3138 ir_print_prefetch(irp, (Stage1ZirInstPrefetch *)instruction);
3129 break;3139 break;
3140 case Stage1ZirInstIdAddrSpaceCast:
3141 ir_print_addrspace_cast(irp, (Stage1ZirInstAddrSpaceCast *)instruction);
3142 break;
3130 }3143 }
3131 fprintf(irp->f, "\n");3144 fprintf(irp->f, "\n");
3132}3145}
src/target.zig+20-1
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const Type = @import("type.zig").Type;2const Type = @import("type.zig").Type;
3const AddressSpace = std.builtin.AddressSpace;
34
4pub const ArchOsAbi = struct {5pub const ArchOsAbi = struct {
5 arch: std.Target.Cpu.Arch,6 arch: std.Target.Cpu.Arch,
...@@ -635,12 +636,30 @@ pub fn defaultAddressSpace(...@@ -635,12 +636,30 @@ pub fn defaultAddressSpace(
635 /// Query the default address space for functions themselves.636 /// Query the default address space for functions themselves.
636 function,637 function,
637 },638 },
638) std.builtin.AddressSpace {639) AddressSpace {
639 _ = target;640 _ = target;
640 _ = context;641 _ = context;
641 return .generic;642 return .generic;
642}643}
643644
645/// Returns true if pointers in `from` can be converted to a pointer in `to`.
646pub fn addrSpaceCastIsValid(
647 target: std.Target,
648 from: AddressSpace,
649 to: AddressSpace,
650) bool {
651 const arch = target.cpu.arch;
652 switch (arch) {
653 .x86_64, .i386 => return arch.supportsAddressSpace(from) and arch.supportsAddressSpace(to),
654 .amdgcn => {
655 const to_generic = arch.supportsAddressSpace(from) and to == .generic;
656 const from_generic = arch.supportsAddressSpace(to) and from == .generic;
657 return to_generic or from_generic;
658 },
659 else => return from == .generic and to == .generic,
660 }
661}
662
644pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {663pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {
645 const have_float = switch (target.abi) {664 const have_float = switch (target.abi) {
646 .gnuilp32 => return "ilp32",665 .gnuilp32 => return "ilp32",
src/type.zig+13-2
...@@ -2786,6 +2786,12 @@ pub const Type = extern union {...@@ -2786,6 +2786,12 @@ pub const Type = extern union {
27862786
2787 .pointer => self.castTag(.pointer).?.data.@"addrspace",2787 .pointer => self.castTag(.pointer).?.data.@"addrspace",
27882788
2789 .optional => {
2790 var buf: Payload.ElemType = undefined;
2791 const child_type = self.optionalChild(&buf);
2792 return child_type.ptrAddressSpace();
2793 },
2794
2789 else => unreachable,2795 else => unreachable,
2790 };2796 };
2791 }2797 }
...@@ -6768,6 +6774,13 @@ pub const CType = enum {...@@ -6768,6 +6774,13 @@ pub const CType = enum {
6768 },6774 },
6769 },6775 },
67706776
6777 .amdhsa, .amdpal => switch (self) {
6778 .short, .ushort => return 16,
6779 .int, .uint => return 32,
6780 .long, .ulong, .longlong, .ulonglong => return 64,
6781 .longdouble => return 128,
6782 },
6783
6771 .cloudabi,6784 .cloudabi,
6772 .kfreebsd,6785 .kfreebsd,
6773 .lv2,6786 .lv2,
...@@ -6777,13 +6790,11 @@ pub const CType = enum {...@@ -6777,13 +6790,11 @@ pub const CType = enum {
6777 .aix,6790 .aix,
6778 .cuda,6791 .cuda,
6779 .nvcl,6792 .nvcl,
6780 .amdhsa,
6781 .ps4,6793 .ps4,
6782 .ps5,6794 .ps5,
6783 .elfiamcu,6795 .elfiamcu,
6784 .mesa3d,6796 .mesa3d,
6785 .contiki,6797 .contiki,
6786 .amdpal,
6787 .hermit,6798 .hermit,
6788 .hurd,6799 .hurd,
6789 .opencl,6800 .opencl,
src/zig_llvm.cpp+11-6
...@@ -512,22 +512,22 @@ LLVMValueRef ZigLLVMBuildUSubSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRe...@@ -512,22 +512,22 @@ LLVMValueRef ZigLLVMBuildUSubSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRe
512512
513LLVMValueRef ZigLLVMBuildSMulFixSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {513LLVMValueRef ZigLLVMBuildSMulFixSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
514 llvm::Type* types[1] = {514 llvm::Type* types[1] = {
515 unwrap(LHS)->getType(), 515 unwrap(LHS)->getType(),
516 };516 };
517 // pass scale = 0 as third argument517 // pass scale = 0 as third argument
518 llvm::Value* values[3] = {unwrap(LHS), unwrap(RHS), unwrap(B)->getInt32(0)};518 llvm::Value* values[3] = {unwrap(LHS), unwrap(RHS), unwrap(B)->getInt32(0)};
519 519
520 CallInst *call_inst = unwrap(B)->CreateIntrinsic(Intrinsic::smul_fix_sat, types, values, nullptr, name);520 CallInst *call_inst = unwrap(B)->CreateIntrinsic(Intrinsic::smul_fix_sat, types, values, nullptr, name);
521 return wrap(call_inst);521 return wrap(call_inst);
522}522}
523523
524LLVMValueRef ZigLLVMBuildUMulFixSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {524LLVMValueRef ZigLLVMBuildUMulFixSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
525 llvm::Type* types[1] = {525 llvm::Type* types[1] = {
526 unwrap(LHS)->getType(), 526 unwrap(LHS)->getType(),
527 };527 };
528 // pass scale = 0 as third argument528 // pass scale = 0 as third argument
529 llvm::Value* values[3] = {unwrap(LHS), unwrap(RHS), unwrap(B)->getInt32(0)};529 llvm::Value* values[3] = {unwrap(LHS), unwrap(RHS), unwrap(B)->getInt32(0)};
530 530
531 CallInst *call_inst = unwrap(B)->CreateIntrinsic(Intrinsic::umul_fix_sat, types, values, nullptr, name);531 CallInst *call_inst = unwrap(B)->CreateIntrinsic(Intrinsic::umul_fix_sat, types, values, nullptr, name);
532 return wrap(call_inst);532 return wrap(call_inst);
533}533}
...@@ -808,7 +808,7 @@ void ZigLLVMSetCurrentDebugLocation2(LLVMBuilderRef builder, unsigned int line,...@@ -808,7 +808,7 @@ void ZigLLVMSetCurrentDebugLocation2(LLVMBuilderRef builder, unsigned int line,
808 unsigned int column, ZigLLVMDIScope *scope, ZigLLVMDILocation *inlined_at)808 unsigned int column, ZigLLVMDIScope *scope, ZigLLVMDILocation *inlined_at)
809{809{
810 DIScope* di_scope = reinterpret_cast<DIScope*>(scope);810 DIScope* di_scope = reinterpret_cast<DIScope*>(scope);
811 DebugLoc debug_loc = DILocation::get(di_scope->getContext(), line, column, di_scope, 811 DebugLoc debug_loc = DILocation::get(di_scope->getContext(), line, column, di_scope,
812 reinterpret_cast<DILocation *>(inlined_at), false);812 reinterpret_cast<DILocation *>(inlined_at), false);
813 unwrap(builder)->SetCurrentDebugLocation(debug_loc);813 unwrap(builder)->SetCurrentDebugLocation(debug_loc);
814}814}
...@@ -1177,9 +1177,14 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV...@@ -1177,9 +1177,14 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV
1177 return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));1177 return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));
1178}1178}
11791179
1180LLVMValueRef ZigLLVMBuildAllocaInAddressSpace(LLVMBuilderRef builder, LLVMTypeRef Ty,
1181 unsigned AddressSpace, const char *Name) {
1182 return wrap(unwrap(builder)->CreateAlloca(unwrap(Ty), AddressSpace, nullptr, Name));
1183}
1184
1180void ZigLLVMSetTailCall(LLVMValueRef Call) {1185void ZigLLVMSetTailCall(LLVMValueRef Call) {
1181 unwrap<CallInst>(Call)->setTailCallKind(CallInst::TCK_MustTail);1186 unwrap<CallInst>(Call)->setTailCallKind(CallInst::TCK_MustTail);
1182} 1187}
11831188
1184void ZigLLVMSetCallSret(LLVMValueRef Call, LLVMTypeRef return_type) {1189void ZigLLVMSetCallSret(LLVMValueRef Call, LLVMTypeRef return_type) {
1185 CallInst *call_inst = unwrap<CallInst>(Call);1190 CallInst *call_inst = unwrap<CallInst>(Call);
src/zig_llvm.h+2
...@@ -162,6 +162,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValu...@@ -162,6 +162,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValu
162ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,162ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
163 const char *name);163 const char *name);
164164
165ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildAllocaInAddressSpace(LLVMBuilderRef builder, LLVMTypeRef Ty, unsigned AddressSpace,
166 const char *Name);
165167
166ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugPointerType(struct ZigLLVMDIBuilder *dibuilder,168ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugPointerType(struct ZigLLVMDIBuilder *dibuilder,
167 struct ZigLLVMDIType *pointee_type, uint64_t size_in_bits, uint64_t align_in_bits, const char *name);169 struct ZigLLVMDIType *pointee_type, uint64_t size_in_bits, uint64_t align_in_bits, const char *name);