authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-15 13:36:43-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-15 13:36:43-04:00
log65f860bef7995a6120e49606d549bdf154bca150
treec7d4973f437fde43735ac8c08cb8e12f5e66257f
parent1087e677625b0846cf25dc43474a63f9a25f1e32
parent66d6183001e135e36df06194e29f082eb63503ec
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12879 from Snektron/amdgpu-improvements

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 {
79567956 The {#syntax#}comptime{#endsyntax#} keyword on a parameter means that the parameter must be known
79577957 at compile time.
79587958 </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#}
79597968 {#header_open|@addWithOverflow#}
79607969 <pre>{#syntax#}@addWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}</pre>
79617970 <p>
lib/c.zig+3-3
......@@ -64,10 +64,10 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, _: ?
6464 if (builtin.is_test) {
6565 std.debug.panic("{s}", .{msg});
6666 }
67 if (native_os != .freestanding and native_os != .other) {
68 std.os.abort();
67 switch (native_os) {
68 .freestanding, .other, .amdhsa, .amdpal => while (true) {},
69 else => std.os.abort(),
6970 }
70 while (true) {}
7171}
7272
7373extern 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) {
3535 else => @sizeOf(usize),
3636};
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
3849const cache_line_size = 64;
3950
4051const SpinlockTable = struct {
......@@ -206,6 +217,31 @@ fn __atomic_store_8(dst: *u64, value: u64, model: i32) callconv(.C) void {
206217 return atomic_store_N(u64, dst, value, model);
207218}
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
209245inline fn atomic_exchange_N(comptime T: type, ptr: *T, val: T, model: i32) T {
210246 _ = model;
211247 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 {
214250 const value = ptr.*;
215251 ptr.* = val;
216252 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);
217262 } else {
218263 return @atomicRmw(T, ptr, .Xchg, val, .SeqCst);
219264 }
......@@ -282,22 +327,30 @@ fn __atomic_compare_exchange_8(ptr: *u64, expected: *u64, desired: u64, success:
282327
283328inline fn fetch_op_N(comptime T: type, comptime op: std.builtin.AtomicRmwOp, ptr: *T, val: T, model: i32) T {
284329 _ = 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
285344 if (@sizeOf(T) > largest_atomic_size) {
286345 var sl = spinlocks.get(@ptrToInt(ptr));
287346 defer sl.release();
288347
289348 const value = ptr.*;
290 ptr.* = switch (op) {
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
349 ptr.* = Updater.update(val, value);
300350 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);
301354 }
302355
303356 return @atomicRmw(T, ptr, op, val, .SeqCst);
lib/std/builtin.zig+1
......@@ -157,6 +157,7 @@ pub const CallingConvention = enum {
157157 SysV,
158158 Win64,
159159 PtxKernel,
160 AmdgpuKernel,
160161};
161162
162163/// 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 {
18591859 /// [1, 2, 3, 4, 0] -> [1, 2, 3, 4]
18601860 /// [1, 2, 0, 0, 0] -> [1, 2]
18611861 /// [0, 0, 0, 0, 0] -> [0]
1862 fn normalize(r: *Mutable, length: usize) void {
1862 pub fn normalize(r: *Mutable, length: usize) void {
18631863 r.len = llnormalize(r.limbs[0..length]);
18641864 }
18651865};
lib/std/target.zig+11
......@@ -1157,6 +1157,17 @@ pub const Target = struct {
11571157 };
11581158 }
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
11601171 pub fn ptrBitWidth(arch: Arch) u16 {
11611172 switch (arch) {
11621173 .avr,
src/Air.zig+5
......@@ -729,6 +729,10 @@ pub const Inst = struct {
729729 /// Sets the operand as the current error return trace,
730730 set_err_return_trace,
731731
732 /// Convert the address space of a pointer.
733 /// Uses the `ty_op` field.
734 addrspace_cast,
735
732736 pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag {
733737 switch (op) {
734738 .lt => return if (optimized) .cmp_lt_optimized else .cmp_lt,
......@@ -1138,6 +1142,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
11381142 .popcount,
11391143 .byte_swap,
11401144 .bit_reverse,
1145 .addrspace_cast,
11411146 => return air.getRefType(datas[inst].ty_op.ty),
11421147
11431148 .loop,
src/AstGen.zig+8
......@@ -7789,6 +7789,14 @@ fn builtinCall(
77897789 });
77907790 return rvalue(gz, rl, result, node);
77917791 },
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
77937801 // zig fmt: off
77947802 .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");
22
33pub const Tag = enum {
44 add_with_overflow,
5 addrspace_cast,
56 align_cast,
67 align_of,
78 as,
......@@ -152,6 +153,13 @@ pub const list = list: {
152153 .param_count = 4,
153154 },
154155 },
156 .{
157 "@addrSpaceCast",
158 .{
159 .tag = .addrspace_cast,
160 .param_count = 2,
161 },
162 },
155163 .{
156164 "@alignCast",
157165 .{
src/Liveness.zig+2
......@@ -268,6 +268,7 @@ pub fn categorizeOperand(
268268 .bit_reverse,
269269 .splat,
270270 .error_set_has_value,
271 .addrspace_cast,
271272 => {
272273 const o = air_datas[inst].ty_op;
273274 if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
......@@ -844,6 +845,7 @@ fn analyzeInst(
844845 .bit_reverse,
845846 .splat,
846847 .error_set_has_value,
848 .addrspace_cast,
847849 => {
848850 const o = inst_datas[inst].ty_op;
849851 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 {
46174617 .constant => target_util.defaultAddressSpace(target, .global_constant),
46184618 else => unreachable,
46194619 },
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),
46214621 };
46224622 };
46234623
src/Sema.zig+65-6
......@@ -975,8 +975,9 @@ fn analyzeBodyInner(
975975 .reify => try sema.zirReify( block, extended, inst),
976976 .builtin_async_call => try sema.zirBuiltinAsyncCall( block, extended),
977977 .cmpxchg => try sema.zirCmpxchg( block, extended),
978
978 .addrspace_cast => try sema.zirAddrSpaceCast( block, extended),
979979 // zig fmt: on
980
980981 .fence => {
981982 try sema.zirFence(block, extended);
982983 i += 1;
......@@ -5897,7 +5898,7 @@ fn analyzeCall(
58975898 },
58985899 else => {},
58995900 }
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)});
59015902 };
59025903
59035904 const func_ty_info = func_ty.fnInfo();
......@@ -8141,6 +8142,10 @@ fn funcCommon(
81418142 .nvptx, .nvptx64 => null,
81428143 else => @as([]const u8, "nvptx and nvptx64"),
81438144 },
8145 .AmdgpuKernel => switch (arch) {
8146 .amdgcn => null,
8147 else => @as([]const u8, "amdgcn"),
8148 },
81448149 }) |allowed_platform| {
81458150 return sema.fail(block, cc_src, "callconv '{s}' is only available on {s}, not {s}", .{
81468151 @tagName(cc_workaround),
......@@ -16246,7 +16251,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1624616251 const address_space = if (inst_data.flags.has_addrspace) blk: {
1624716252 const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
1624816253 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);
1625016255 } else .generic;
1625116256
1625216257 const bit_offset = if (inst_data.flags.has_bit_range) blk: {
......@@ -18166,6 +18171,55 @@ fn reifyStruct(
1816618171 return sema.analyzeDeclVal(block, src, new_decl_index);
1816718172}
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
1816918223fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1817018224 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1817118225 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
1841318467 if (operand_info.@"volatile" and !dest_info.@"volatile") {
1841418468 return sema.fail(block, src, "cast discards volatile qualifier", .{});
1841518469 }
18470 if (operand_info.@"addrspace" != dest_info.@"addrspace") {
18471 return sema.fail(block, src, "cast changes pointer address space", .{});
18472 }
1841618473
1841718474 const dest_is_slice = dest_ty.isSlice();
1841818475 const operand_is_slice = operand_ty.isSlice();
......@@ -30302,7 +30359,7 @@ pub const AddressSpaceContext = enum {
3030230359 pointer,
3030330360};
3030430361
30305pub fn analyzeAddrspace(
30362pub fn analyzeAddressSpace(
3030630363 sema: *Sema,
3030730364 block: *Block,
3030830365 src: LazySrcLoc,
......@@ -30313,13 +30370,15 @@ pub fn analyzeAddrspace(
3031330370 const address_space = addrspace_tv.val.toEnum(std.builtin.AddressSpace);
3031430371 const target = sema.mod.getTarget();
3031530372 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
3031830376 const supported = switch (address_space) {
3031930377 .generic => true,
3032030378 .gs, .fs, .ss => (arch == .i386 or arch == .x86_64) and ctx == .pointer,
3032130379 // 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,
3032330382 .constant => is_gpu and (ctx == .constant),
3032430383 };
3032530384
src/Zir.zig+3
......@@ -1969,6 +1969,9 @@ pub const Inst = struct {
19691969 /// `small` 0=>weak 1=>strong
19701970 /// `operand` is payload index to `Cmpxchg`.
19711971 cmpxchg,
1972 /// Implement the builtin `@addrSpaceCast`
1973 /// `Operand` is payload index to `BinNode`. `lhs` is dest type, `rhs` is operand.
1974 addrspace_cast,
19721975
19731976 pub const InstData = struct {
19741977 opcode: Extended,
src/arch/aarch64/CodeGen.zig+1
......@@ -677,6 +677,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
677677 .union_init => try self.airUnionInit(inst),
678678 .prefetch => try self.airPrefetch(inst),
679679 .mul_add => try self.airMulAdd(inst),
680 .addrspace_cast => return self.fail("TODO implement addrspace_cast", .{}),
680681
681682 .@"try" => try self.airTry(inst),
682683 .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 {
690690 .union_init => try self.airUnionInit(inst),
691691 .prefetch => try self.airPrefetch(inst),
692692 .mul_add => try self.airMulAdd(inst),
693 .addrspace_cast => return self.fail("TODO implement addrspace_cast", .{}),
693694
694695 .@"try" => try self.airTry(inst),
695696 .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 {
604604 .union_init => try self.airUnionInit(inst),
605605 .prefetch => try self.airPrefetch(inst),
606606 .mul_add => try self.airMulAdd(inst),
607 .addrspace_cast => @panic("TODO"),
607608
608609 .@"try" => @panic("TODO"),
609610 .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 {
618618 .union_init => @panic("TODO try self.airUnionInit(inst)"),
619619 .prefetch => try self.airPrefetch(inst),
620620 .mul_add => @panic("TODO try self.airMulAdd(inst)"),
621 .addrspace_cast => @panic("TODO try self.airAddrSpaceCast(int)"),
621622
622623 .@"try" => try self.airTry(inst),
623624 .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 {
16991699 .set_err_return_trace,
17001700 .is_named_enum_value,
17011701 .error_set_has_value,
1702 .addrspace_cast,
17021703 => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
17031704
17041705 .add_optimized,
src/arch/x86_64/CodeGen.zig+1
......@@ -695,6 +695,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
695695 .union_init => try self.airUnionInit(inst),
696696 .prefetch => try self.airPrefetch(inst),
697697 .mul_add => try self.airMulAdd(inst),
698 .addrspace_cast => return self.fail("TODO implement addrspace_cast", .{}),
698699
699700 .@"try" => try self.airTry(inst),
700701 .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
18711871 .aggregate_init => try airAggregateInit(f, inst),
18721872 .union_init => try airUnionInit(f, inst),
18731873 .prefetch => try airPrefetch(f, inst),
1874 .addrspace_cast => return f.fail("TODO: C backend: implement addrspace_cast", .{}),
18741875
18751876 .@"try" => try airTry(f, inst),
18761877 .try_ptr => try airTryPtr(f, inst),
src/codegen/llvm.zig+212-120
......@@ -956,8 +956,7 @@ pub const Object = struct {
956956 if (isByRef(param_ty)) {
957957 const alignment = param_ty.abiAlignment(target);
958958 const param_llvm_ty = param.typeOf();
959 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);
960 arg_ptr.setAlignment(alignment);
959 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
961960 const store_inst = builder.buildStore(param, arg_ptr);
962961 store_inst.setAlignment(alignment);
963962 args.appendAssumeCapacity(arg_ptr);
......@@ -1001,8 +1000,7 @@ pub const Object = struct {
10011000 param_ty.abiAlignment(target),
10021001 dg.object.target_data.abiAlignmentOfType(int_llvm_ty),
10031002 );
1004 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);
1005 arg_ptr.setAlignment(alignment);
1003 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
10061004 const casted_ptr = builder.buildBitCast(arg_ptr, int_ptr_llvm_ty, "");
10071005 const store_inst = builder.buildStore(param, casted_ptr);
10081006 store_inst.setAlignment(alignment);
......@@ -1053,8 +1051,7 @@ pub const Object = struct {
10531051 const param_ty = fn_info.param_types[it.zig_index - 1];
10541052 const param_llvm_ty = try dg.lowerType(param_ty);
10551053 const param_alignment = param_ty.abiAlignment(target);
1056 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);
1057 arg_ptr.setAlignment(param_alignment);
1054 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, param_alignment, target);
10581055 var field_types_buf: [8]*llvm.Type = undefined;
10591056 const field_types = field_types_buf[0..llvm_ints.len];
10601057 for (llvm_ints) |int_bits, i| {
......@@ -1085,8 +1082,7 @@ pub const Object = struct {
10851082 const param_ty = fn_info.param_types[it.zig_index - 1];
10861083 const param_llvm_ty = try dg.lowerType(param_ty);
10871084 const param_alignment = param_ty.abiAlignment(target);
1088 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);
1089 arg_ptr.setAlignment(param_alignment);
1085 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, param_alignment, target);
10901086 var field_types_buf: [8]*llvm.Type = undefined;
10911087 const field_types = field_types_buf[0..llvm_floats.len];
10921088 for (llvm_floats) |float_bits, i| {
......@@ -1130,8 +1126,7 @@ pub const Object = struct {
11301126 llvm_arg_i += 1;
11311127
11321128 const alignment = param_ty.abiAlignment(target);
1133 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);
1134 arg_ptr.setAlignment(alignment);
1129 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
11351130 const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), "");
11361131 _ = builder.buildStore(param, casted_ptr);
11371132
......@@ -2431,19 +2426,21 @@ pub const DeclGen = struct {
24312426 // mismatch, because we don't have the LLVM type until the *value* is created,
24322427 // whereas the global needs to be created based on the type alone, because
24332428 // lowering the value may reference the global as a pointer.
2429 const llvm_global_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
24342430 const new_global = dg.object.llvm_module.addGlobalInAddressSpace(
24352431 llvm_init.typeOf(),
24362432 "",
2437 dg.llvmAddressSpace(decl.@"addrspace"),
2433 llvm_global_addrspace,
24382434 );
24392435 new_global.setLinkage(global.getLinkage());
24402436 new_global.setUnnamedAddr(global.getUnnamedAddress());
24412437 new_global.setAlignment(global.getAlignment());
24422438 if (decl.@"linksection") |section| new_global.setSection(section);
24432439 new_global.setInitializer(llvm_init);
2444 // replaceAllUsesWith requires the type to be unchanged. So we bitcast
2440 // replaceAllUsesWith requires the type to be unchanged. So we convert
24452441 // the new global to the old type and use that as the thing to replace
24462442 // old uses.
2443 // TODO: How should this work then the address space of a global changed?
24472444 const new_global_ptr = new_global.constBitCast(global.typeOf());
24482445 global.replaceAllUsesWith(new_global_ptr);
24492446 dg.object.decl_map.putAssumeCapacity(decl_index, new_global);
......@@ -2492,7 +2489,7 @@ pub const DeclGen = struct {
24922489 const fqn = try decl.getFullyQualifiedName(dg.module);
24932490 defer dg.gpa.free(fqn);
24942491
2495 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");
2492 const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
24962493 const llvm_fn = dg.llvmModule().addFunctionInAddressSpace(fqn, fn_type, llvm_addrspace);
24972494 gop.value_ptr.* = llvm_fn;
24982495
......@@ -2640,9 +2637,16 @@ pub const DeclGen = struct {
26402637 const fqn = try decl.getFullyQualifiedName(dg.module);
26412638 defer dg.gpa.free(fqn);
26422639
2640 const target = dg.module.getTarget();
2641
26432642 const llvm_type = try dg.lowerType(decl.ty);
2644 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");
2645 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace);
2643 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
2644
2645 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(
2646 llvm_type,
2647 fqn,
2648 llvm_actual_addrspace,
2649 );
26462650 gop.value_ptr.* = llvm_global;
26472651
26482652 // This is needed for declarations created by `@extern`.
......@@ -2667,32 +2671,6 @@ pub const DeclGen = struct {
26672671 return llvm_global;
26682672 }
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
26962674 fn isUnnamedType(dg: *DeclGen, ty: Type, val: *llvm.Value) bool {
26972675 // Once `lowerType` succeeds, successive calls to it with the same Zig type
26982676 // are guaranteed to succeed. So if a call to `lowerType` fails here it means
......@@ -2758,7 +2736,7 @@ pub const DeclGen = struct {
27582736 return dg.context.structType(&fields, fields.len, .False);
27592737 }
27602738 const ptr_info = t.ptrInfo().data;
2761 const llvm_addrspace = dg.llvmAddressSpace(ptr_info.@"addrspace");
2739 const llvm_addrspace = toLlvmAddressSpace(ptr_info.@"addrspace", target);
27622740 if (ptr_info.host_size != 0) {
27632741 return dg.context.intType(ptr_info.host_size * 8).pointerType(llvm_addrspace);
27642742 }
......@@ -3295,11 +3273,20 @@ pub const DeclGen = struct {
32953273 const decl_index = tv.val.castTag(.variable).?.data.owner_decl;
32963274 const decl = dg.module.declPtr(decl_index);
32973275 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
32993280 const llvm_var_type = try dg.lowerType(tv.ty);
3300 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");
3301 const llvm_type = llvm_var_type.pointerType(llvm_addrspace);
3302 return val.constBitCast(llvm_type);
3281 const llvm_actual_ptr_type = llvm_var_type.pointerType(llvm_actual_addrspace);
3282
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;
33033290 },
33043291 .slice => {
33053292 const slice = tv.val.castTag(.slice).?.data;
......@@ -4096,11 +4083,20 @@ pub const DeclGen = struct {
40964083
40974084 self.module.markDeclAlive(decl);
40984085
4099 const llvm_val = if (is_fn_body)
4086 const llvm_decl_val = if (is_fn_body)
41004087 try self.resolveLlvmFunction(decl_index)
41014088 else
41024089 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
41044100 const llvm_type = try self.lowerType(tv.ty);
41054101 if (tv.ty.zigTypeTag() == .Int) {
41064102 return llvm_val.constPtrToInt(llvm_type);
......@@ -4370,7 +4366,9 @@ pub const FuncGen = struct {
43704366 // We have an LLVM value but we need to create a global constant and
43714367 // set the value as its initializer, and then return a pointer to the global.
43724368 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);
43744372 global.setInitializer(llvm_val);
43754373 global.setLinkage(.Private);
43764374 global.setGlobalConstant(.True);
......@@ -4380,8 +4378,14 @@ pub const FuncGen = struct {
43804378 // the type of global constants might not match the type it is supposed to
43814379 // be, and so we must bitcast the pointer at the usage sites.
43824380 const wanted_llvm_ty = try self.dg.lowerType(tv.ty);
4383 const wanted_llvm_ptr_ty = wanted_llvm_ty.pointerType(0);
4384 return global.constBitCast(wanted_llvm_ptr_ty);
4381 const wanted_bitcasted_llvm_ptr_ty = wanted_llvm_ty.pointerType(llvm_actual_addrspace);
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;
43854389 }
43864390
43874391 fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void {
......@@ -4462,7 +4466,7 @@ pub const FuncGen = struct {
44624466 .cmp_lt => try self.airCmp(inst, .lt, false),
44634467 .cmp_lte => try self.airCmp(inst, .lte, false),
44644468 .cmp_neq => try self.airCmp(inst, .neq, false),
4465
4469
44664470 .cmp_eq_optimized => try self.airCmp(inst, .eq, true),
44674471 .cmp_gt_optimized => try self.airCmp(inst, .gt, true),
44684472 .cmp_gte_optimized => try self.airCmp(inst, .gte, true),
......@@ -4548,6 +4552,7 @@ pub const FuncGen = struct {
45484552 .aggregate_init => try self.airAggregateInit(inst),
45494553 .union_init => try self.airUnionInit(inst),
45504554 .prefetch => try self.airPrefetch(inst),
4555 .addrspace_cast => try self.airAddrSpaceCast(inst),
45514556
45524557 .is_named_enum_value => try self.airIsNamedEnumValue(inst),
45534558 .error_set_has_value => try self.airErrorSetHasValue(inst),
......@@ -4635,8 +4640,7 @@ pub const FuncGen = struct {
46354640
46364641 const ret_ptr = if (!sret) null else blk: {
46374642 const llvm_ret_ty = try self.dg.lowerType(return_type);
4638 const ret_ptr = self.buildAlloca(llvm_ret_ty);
4639 ret_ptr.setAlignment(return_type.abiAlignment(target));
4643 const ret_ptr = self.buildAlloca(llvm_ret_ty, return_type.abiAlignment(target));
46404644 try llvm_args.append(ret_ptr);
46414645 break :blk ret_ptr;
46424646 };
......@@ -4683,8 +4687,7 @@ pub const FuncGen = struct {
46834687 } else {
46844688 const alignment = param_ty.abiAlignment(target);
46854689 const param_llvm_ty = llvm_arg.typeOf();
4686 const arg_ptr = self.buildAlloca(param_llvm_ty);
4687 arg_ptr.setAlignment(alignment);
4690 const arg_ptr = self.buildAlloca(param_llvm_ty, alignment);
46884691 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
46894692 store_inst.setAlignment(alignment);
46904693 try llvm_args.append(arg_ptr);
......@@ -4711,8 +4714,7 @@ pub const FuncGen = struct {
47114714 param_ty.abiAlignment(target),
47124715 self.dg.object.target_data.abiAlignmentOfType(int_llvm_ty),
47134716 );
4714 const int_ptr = self.buildAlloca(int_llvm_ty);
4715 int_ptr.setAlignment(alignment);
4717 const int_ptr = self.buildAlloca(int_llvm_ty, alignment);
47164718 const param_llvm_ty = try self.dg.lowerType(param_ty);
47174719 const casted_ptr = self.builder.buildBitCast(int_ptr, param_llvm_ty.pointerType(0), "");
47184720 const store_inst = self.builder.buildStore(llvm_arg, casted_ptr);
......@@ -4738,7 +4740,7 @@ pub const FuncGen = struct {
47384740 const llvm_arg = try self.resolveInst(arg);
47394741 const is_by_ref = isByRef(param_ty);
47404742 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);
47424744 const store_inst = self.builder.buildStore(llvm_arg, p);
47434745 store_inst.setAlignment(param_ty.abiAlignment(target));
47444746 break :p p;
......@@ -4767,7 +4769,7 @@ pub const FuncGen = struct {
47674769 const llvm_arg = try self.resolveInst(arg);
47684770 const is_by_ref = isByRef(param_ty);
47694771 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);
47714773 const store_inst = self.builder.buildStore(llvm_arg, p);
47724774 store_inst.setAlignment(param_ty.abiAlignment(target));
47734775 break :p p;
......@@ -4804,7 +4806,7 @@ pub const FuncGen = struct {
48044806 const arg_ty = self.air.typeOf(arg);
48054807 var llvm_arg = try self.resolveInst(arg);
48064808 if (!isByRef(arg_ty)) {
4807 const p = self.buildAlloca(llvm_arg.typeOf());
4809 const p = self.buildAlloca(llvm_arg.typeOf(), null);
48084810 const store_inst = self.builder.buildStore(llvm_arg, p);
48094811 store_inst.setAlignment(arg_ty.abiAlignment(target));
48104812 llvm_arg = store_inst;
......@@ -4861,9 +4863,8 @@ pub const FuncGen = struct {
48614863 // In this case the function return type is honoring the calling convention by having
48624864 // a different LLVM type than the usual one. We solve this here at the callsite
48634865 // by bitcasting a pointer to our canonical type, then loading it if necessary.
4864 const rp = self.buildAlloca(llvm_ret_ty);
48654866 const alignment = return_type.abiAlignment(target);
4866 rp.setAlignment(alignment);
4867 const rp = self.buildAlloca(llvm_ret_ty, alignment);
48674868 const ptr_abi_ty = abi_ret_ty.pointerType(0);
48684869 const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");
48694870 const store_inst = self.builder.buildStore(call, casted_ptr);
......@@ -4880,9 +4881,8 @@ pub const FuncGen = struct {
48804881 if (isByRef(return_type)) {
48814882 // our by-ref status disagrees with sret so we must allocate, store,
48824883 // and return the allocation pointer.
4883 const rp = self.buildAlloca(llvm_ret_ty);
48844884 const alignment = return_type.abiAlignment(target);
4885 rp.setAlignment(alignment);
4885 const rp = self.buildAlloca(llvm_ret_ty, alignment);
48864886 const store_inst = self.builder.buildStore(call, rp);
48874887 store_inst.setAlignment(alignment);
48884888 return rp;
......@@ -4941,8 +4941,7 @@ pub const FuncGen = struct {
49414941 return null;
49424942 }
49434943
4944 const rp = self.buildAlloca(llvm_ret_ty);
4945 rp.setAlignment(alignment);
4944 const rp = self.buildAlloca(llvm_ret_ty, alignment);
49464945 const store_inst = self.builder.buildStore(operand, rp);
49474946 store_inst.setAlignment(alignment);
49484947 const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");
......@@ -6060,8 +6059,7 @@ pub const FuncGen = struct {
60606059 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();
60616060 } else {
60626061 const alignment = arg_ty.abiAlignment(target);
6063 const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf());
6064 arg_ptr.setAlignment(alignment);
6062 const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf(), alignment);
60656063 const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr);
60666064 store_inst.setAlignment(alignment);
60676065 llvm_param_values[llvm_param_i] = arg_ptr;
......@@ -6562,8 +6560,7 @@ pub const FuncGen = struct {
65626560 const llvm_optional_ty = try self.dg.lowerType(optional_ty);
65636561 if (isByRef(optional_ty)) {
65646562 const target = self.dg.module.getTarget();
6565 const optional_ptr = self.buildAlloca(llvm_optional_ty);
6566 optional_ptr.setAlignment(optional_ty.abiAlignment(target));
6563 const optional_ptr = self.buildAlloca(llvm_optional_ty, optional_ty.abiAlignment(target));
65676564 const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, "");
65686565 var ptr_ty_payload: Type.Payload.ElemType = .{
65696566 .base = .{ .tag = .single_mut_pointer },
......@@ -6596,8 +6593,7 @@ pub const FuncGen = struct {
65966593 const payload_offset = errUnionPayloadOffset(payload_ty, target);
65976594 const error_offset = errUnionErrorOffset(payload_ty, target);
65986595 if (isByRef(err_un_ty)) {
6599 const result_ptr = self.buildAlloca(err_un_llvm_ty);
6600 result_ptr.setAlignment(err_un_ty.abiAlignment(target));
6596 const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target));
66016597 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
66026598 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);
66036599 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
......@@ -6631,8 +6627,7 @@ pub const FuncGen = struct {
66316627 const payload_offset = errUnionPayloadOffset(payload_ty, target);
66326628 const error_offset = errUnionErrorOffset(payload_ty, target);
66336629 if (isByRef(err_un_ty)) {
6634 const result_ptr = self.buildAlloca(err_un_llvm_ty);
6635 result_ptr.setAlignment(err_un_ty.abiAlignment(target));
6630 const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target));
66366631 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
66376632 const store_inst = self.builder.buildStore(operand, err_ptr);
66386633 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
......@@ -7050,9 +7045,8 @@ pub const FuncGen = struct {
70507045
70517046 if (isByRef(dest_ty)) {
70527047 const target = self.dg.module.getTarget();
7053 const alloca_inst = self.buildAlloca(llvm_dest_ty);
70547048 const result_alignment = dest_ty.abiAlignment(target);
7055 alloca_inst.setAlignment(result_alignment);
7049 const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment);
70567050 {
70577051 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");
70587052 const store_inst = self.builder.buildStore(result, field_ptr);
......@@ -7402,9 +7396,8 @@ pub const FuncGen = struct {
74027396
74037397 if (isByRef(dest_ty)) {
74047398 const target = self.dg.module.getTarget();
7405 const alloca_inst = self.buildAlloca(llvm_dest_ty);
74067399 const result_alignment = dest_ty.abiAlignment(target);
7407 alloca_inst.setAlignment(result_alignment);
7400 const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment);
74087401 {
74097402 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");
74107403 const store_inst = self.builder.buildStore(result, field_ptr);
......@@ -7710,7 +7703,7 @@ pub const FuncGen = struct {
77107703 if (!result_is_ref) {
77117704 return self.dg.todo("implement bitcast vector to non-ref array", .{});
77127705 }
7713 const array_ptr = self.buildAlloca(llvm_dest_ty);
7706 const array_ptr = self.buildAlloca(llvm_dest_ty, null);
77147707 const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8;
77157708 if (bitcast_ok) {
77167709 const llvm_vector_ty = try self.dg.lowerType(operand_ty);
......@@ -7786,8 +7779,7 @@ pub const FuncGen = struct {
77867779 if (result_is_ref) {
77877780 // Bitcast the result pointer, then store.
77887781 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
7789 const result_ptr = self.buildAlloca(llvm_dest_ty);
7790 result_ptr.setAlignment(alignment);
7782 const result_ptr = self.buildAlloca(llvm_dest_ty, alignment);
77917783 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
77927784 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
77937785 const store_inst = self.builder.buildStore(operand, casted_ptr);
......@@ -7800,8 +7792,7 @@ pub const FuncGen = struct {
78007792 // but LLVM won't let us bitcast struct values.
78017793 // Therefore, we store operand to bitcasted alloca, then load for result.
78027794 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
7803 const result_ptr = self.buildAlloca(llvm_dest_ty);
7804 result_ptr.setAlignment(alignment);
7795 const result_ptr = self.buildAlloca(llvm_dest_ty, alignment);
78057796 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
78067797 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
78077798 const store_inst = self.builder.buildStore(operand, casted_ptr);
......@@ -7877,11 +7868,9 @@ pub const FuncGen = struct {
78777868 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
78787869
78797870 const pointee_llvm_ty = try self.dg.lowerType(pointee_type);
7880 const alloca_inst = self.buildAlloca(pointee_llvm_ty);
78817871 const target = self.dg.module.getTarget();
78827872 const alignment = ptr_ty.ptrAlignment(target);
7883 alloca_inst.setAlignment(alignment);
7884 return alloca_inst;
7873 return self.buildAlloca(pointee_llvm_ty, alignment);
78857874 }
78867875
78877876 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
......@@ -7892,15 +7881,13 @@ pub const FuncGen = struct {
78927881 if (self.ret_ptr) |ret_ptr| return ret_ptr;
78937882 const ret_llvm_ty = try self.dg.lowerType(ret_ty);
78947883 const target = self.dg.module.getTarget();
7895 const alloca_inst = self.buildAlloca(ret_llvm_ty);
7896 alloca_inst.setAlignment(ptr_ty.ptrAlignment(target));
7897 return alloca_inst;
7884 return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(target));
78987885 }
78997886
79007887 /// Use this instead of builder.buildAlloca, because this function makes sure to
79017888 /// put the alloca instruction at the top of the function!
7902 fn buildAlloca(self: *FuncGen, llvm_ty: *llvm.Type) *llvm.Value {
7903 return buildAllocaInner(self.builder, self.llvm_func, self.di_scope != null, llvm_ty);
7889 fn buildAlloca(self: *FuncGen, llvm_ty: *llvm.Type, alignment: ?c_uint) *llvm.Value {
7890 return buildAllocaInner(self.builder, self.llvm_func, self.di_scope != null, llvm_ty, alignment, self.dg.module.getTarget());
79047891 }
79057892
79067893 fn airStore(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
......@@ -8779,9 +8766,9 @@ pub const FuncGen = struct {
87798766 const llvm_result_ty = accum_init.typeOf();
87808767
87818768 // 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);
87838770 _ = 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);
87858772 _ = self.builder.buildStore(accum_init, accum_ptr);
87868773
87878774 // Setup the loop
......@@ -8966,10 +8953,9 @@ pub const FuncGen = struct {
89668953
89678954 if (isByRef(result_ty)) {
89688955 const llvm_u32 = self.context.intType(32);
8969 const alloca_inst = self.buildAlloca(llvm_result_ty);
89708956 // TODO in debug builds init to undef so that the padding will be 0xaa
89718957 // 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
89748960 var indices: [2]*llvm.Value = .{ llvm_u32.constNull(), undefined };
89758961 for (elements) |elem, i| {
......@@ -9007,8 +8993,7 @@ pub const FuncGen = struct {
90078993 assert(isByRef(result_ty));
90088994
90098995 const llvm_usize = try self.dg.lowerType(Type.usize);
9010 const alloca_inst = self.buildAlloca(llvm_result_ty);
9011 alloca_inst.setAlignment(result_ty.abiAlignment(target));
8996 const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(target));
90128997
90138998 const array_info = result_ty.arrayInfo();
90148999 var elem_ptr_payload: Type.Payload.Pointer = .{
......@@ -9083,7 +9068,7 @@ pub const FuncGen = struct {
90839068 // necessarily match the format that we need, depending on which tag is active. We
90849069 // must construct the correct unnamed struct type here and bitcast, in order to
90859070 // then set the fields appropriately.
9086 const result_ptr = self.buildAlloca(union_llvm_ty);
9071 const result_ptr = self.buildAlloca(union_llvm_ty, null);
90879072 const llvm_payload = try self.resolveInst(extra.init);
90889073 assert(union_obj.haveFieldTypes());
90899074 const field = union_obj.fields.values()[extra.field_index];
......@@ -9243,6 +9228,17 @@ pub const FuncGen = struct {
92439228 return null;
92449229 }
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
92469242 fn getErrorNameTable(self: *FuncGen) !*llvm.Value {
92479243 if (self.dg.object.error_name_table) |table| {
92489244 return table;
......@@ -9324,9 +9320,8 @@ pub const FuncGen = struct {
93249320
93259321 if (isByRef(optional_ty)) {
93269322 const target = self.dg.module.getTarget();
9327 const alloca_inst = self.buildAlloca(optional_llvm_ty);
93289323 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
93319326 {
93329327 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 0, "");
......@@ -9450,8 +9445,7 @@ pub const FuncGen = struct {
94509445 if (isByRef(info.pointee_type)) {
94519446 const result_align = info.pointee_type.abiAlignment(target);
94529447 const max_align = @maximum(result_align, ptr_alignment);
9453 const result_ptr = self.buildAlloca(elem_llvm_ty);
9454 result_ptr.setAlignment(max_align);
9448 const result_ptr = self.buildAlloca(elem_llvm_ty, max_align);
94559449 const llvm_ptr_u8 = self.context.intType(8).pointerType(0);
94569450 const llvm_usize = self.context.intType(Type.usize.intInfo(target).bits);
94579451 const size_bytes = info.pointee_type.abiSize(target);
......@@ -9484,8 +9478,7 @@ pub const FuncGen = struct {
94849478
94859479 if (isByRef(info.pointee_type)) {
94869480 const result_align = info.pointee_type.abiAlignment(target);
9487 const result_ptr = self.buildAlloca(elem_llvm_ty);
9488 result_ptr.setAlignment(result_align);
9481 const result_ptr = self.buildAlloca(elem_llvm_ty, result_align);
94899482
94909483 const same_size_int = self.context.intType(elem_bits);
94919484 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
......@@ -9609,8 +9602,7 @@ pub const FuncGen = struct {
96099602 .x86_64 => {
96109603 const array_llvm_ty = usize_llvm_ty.arrayType(6);
96119604 const array_ptr = fg.valgrind_client_request_array orelse a: {
9612 const array_ptr = fg.buildAlloca(array_llvm_ty);
9613 array_ptr.setAlignment(usize_alignment);
9605 const array_ptr = fg.buildAlloca(array_llvm_ty, usize_alignment);
96149606 fg.valgrind_client_request_array = array_ptr;
96159607 break :a array_ptr;
96169608 };
......@@ -9905,6 +9897,78 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca
99059897 .nvptx, .nvptx64 => .PTX_Kernel,
99069898 else => unreachable,
99079899 },
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),
99089972 };
99099973}
99109974
......@@ -10537,13 +10601,23 @@ fn backendSupportsF16(target: std.Target) bool {
1053710601 };
1053810602}
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
1054010614/// LLVM does not support all relevant intrinsics for all targets, so we
1054110615/// may need to manually generate a libc call
1054210616fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool {
1054310617 return switch (scalar_ty.tag()) {
1054410618 .f16 => backendSupportsF16(target),
1054510619 .f80 => target.longDoubleIs(f80) and backendSupportsF80(target),
10546 .f128 => target.longDoubleIs(f128),
10620 .f128 => target.longDoubleIs(f128) and backendSupportsF128(target),
1054710621 else => true,
1054810622 };
1054910623}
......@@ -10620,25 +10694,43 @@ fn buildAllocaInner(
1062010694 llvm_func: *llvm.Value,
1062110695 di_scope_non_null: bool,
1062210696 llvm_ty: *llvm.Type,
10697 maybe_alignment: ?c_uint,
10698 target: std.Target,
1062310699) *llvm.Value {
10624 const prev_block = builder.getInsertBlock();
10625 const prev_debug_location = builder.getCurrentDebugLocation2();
10626 defer {
10627 builder.positionBuilderAtEnd(prev_block);
10628 if (di_scope_non_null) {
10629 builder.setCurrentDebugLocation2(prev_debug_location);
10700 const address_space = llvmAllocaAddressSpace(target);
10701
10702 const alloca = blk: {
10703 const prev_block = builder.getInsertBlock();
10704 const prev_debug_location = builder.getCurrentDebugLocation2();
10705 defer {
10706 builder.positionBuilderAtEnd(prev_block);
10707 if (di_scope_non_null) {
10708 builder.setCurrentDebugLocation2(prev_debug_location);
10709 }
1063010710 }
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);
1063110725 }
1063210726
10633 const entry_block = llvm_func.getFirstBasicBlock().?;
10634 if (entry_block.getFirstInstruction()) |first_inst| {
10635 builder.positionBuilder(entry_block, first_inst);
10636 } else {
10637 builder.positionBuilderAtEnd(entry_block);
10727 // The pointer returned from this function should have the generic address space,
10728 // if this isn't the case then cast it to the generic address space.
10729 if (address_space != llvm.address_space.default) {
10730 return builder.buildAddrSpaceCast(alloca, llvm_ty.pointerType(llvm.address_space.default), "");
1063810731 }
10639 builder.clearCurrentDebugLocation();
1064010732
10641 return builder.buildAlloca(llvm_ty, "");
10733 return alloca;
1064210734}
1064310735
1064410736fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u1 {
src/codegen/llvm/bindings.zig+9
......@@ -171,6 +171,9 @@ pub const Value = opaque {
171171 pub const constAdd = LLVMConstAdd;
172172 extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
173173
174 pub const constAddrSpaceCast = LLVMConstAddrSpaceCast;
175 extern fn LLVMConstAddrSpaceCast(ConstantVal: *Value, ToType: *Type) *Value;
176
174177 pub const setWeak = LLVMSetWeak;
175178 extern fn LLVMSetWeak(CmpXchgInst: *Value, IsWeak: Bool) void;
176179
......@@ -956,6 +959,12 @@ pub const Builder = opaque {
956959
957960 pub const setFastMath = ZigLLVMSetFastMath;
958961 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;
959968};
960969
961970pub const MDString = opaque {
src/print_air.zig+1
......@@ -244,6 +244,7 @@ const Writer = struct {
244244 .byte_swap,
245245 .bit_reverse,
246246 .error_set_has_value,
247 .addrspace_cast,
247248 => try w.writeTyOp(s, inst),
248249
249250 .block,
src/print_zir.zig+1
......@@ -512,6 +512,7 @@ const Writer = struct {
512512 .err_set_cast,
513513 .wasm_memory_grow,
514514 .prefetch,
515 .addrspace_cast,
515516 => {
516517 const inst_data = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
517518 const src = LazySrcLoc.nodeOffset(inst_data.node);
src/stage1/all_types.hpp+16-1
......@@ -85,7 +85,8 @@ enum CallingConvention {
8585 CallingConventionAAPCSVFP,
8686 CallingConventionSysV,
8787 CallingConventionWin64,
88 CallingConventionPtxKernel
88 CallingConventionPtxKernel,
89 CallingConventionAmdgpuKernel
8990};
9091
9192// Stage 1 supports only the generic address space
......@@ -94,6 +95,11 @@ enum AddressSpace {
9495 AddressSpaceGS,
9596 AddressSpaceFS,
9697 AddressSpaceSS,
98 AddressSpaceGlobal,
99 AddressSpaceConstant,
100 AddressSpaceParam,
101 AddressSpaceShared,
102 AddressSpaceLocal
97103};
98104
99105// This one corresponds to the builtin.zig enum.
......@@ -1841,6 +1847,7 @@ enum BuiltinFnId {
18411847 BuiltinFnIdMaximum,
18421848 BuiltinFnIdMinimum,
18431849 BuiltinFnIdPrefetch,
1850 BuiltinFnIdAddrSpaceCast,
18441851};
18451852
18461853struct BuiltinFnEntry {
......@@ -2672,6 +2679,7 @@ enum Stage1ZirInstId : uint8_t {
26722679 Stage1ZirInstIdWasmMemoryGrow,
26732680 Stage1ZirInstIdSrc,
26742681 Stage1ZirInstIdPrefetch,
2682 Stage1ZirInstIdAddrSpaceCast,
26752683};
26762684
26772685// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.
......@@ -4168,6 +4176,13 @@ struct Stage1AirInstAlignCast {
41684176 Stage1AirInst *target;
41694177};
41704178
4179struct Stage1ZirInstAddrSpaceCast {
4180 Stage1ZirInst base;
4181
4182 Stage1ZirInst *addrspace;
4183 Stage1ZirInst *ptr;
4184};
4185
41714186struct Stage1ZirInstSetAlignStack {
41724187 Stage1ZirInst base;
41734188
src/stage1/analyze.cpp+14-3
......@@ -993,6 +993,7 @@ const char *calling_convention_name(CallingConvention cc) {
993993 case CallingConventionSysV: return "SysV";
994994 case CallingConventionWin64: return "Win64";
995995 case CallingConventionPtxKernel: return "PtxKernel";
996 case CallingConventionAmdgpuKernel: return "AmdgpuKernel";
996997 }
997998 zig_unreachable();
998999}
......@@ -1017,6 +1018,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {
10171018 case CallingConventionAAPCSVFP:
10181019 case CallingConventionSysV:
10191020 case CallingConventionWin64:
1021 case CallingConventionAmdgpuKernel:
10201022 return false;
10211023 }
10221024 zig_unreachable();
......@@ -1028,6 +1030,11 @@ const char *address_space_name(AddressSpace as) {
10281030 case AddressSpaceGS: return "gs";
10291031 case AddressSpaceFS: return "fs";
10301032 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";
10311038 }
10321039 zig_unreachable();
10331040}
......@@ -2019,6 +2026,9 @@ Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_
20192026 allowed_platforms = "nvptx and nvptx64";
20202027 }
20212028 break;
2029 case CallingConventionAmdgpuKernel:
2030 if (g->zig_target->arch != ZigLLVM_amdgcn)
2031 allowed_platforms = "amdgcn and amdpal";
20222032
20232033 }
20242034 if (allowed_platforms != nullptr) {
......@@ -3857,6 +3867,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
38573867 case CallingConventionSysV:
38583868 case CallingConventionWin64:
38593869 case CallingConventionPtxKernel:
3870 case CallingConventionAmdgpuKernel:
38603871 add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name),
38613872 GlobalLinkageIdStrong, fn_cc);
38623873 break;
......@@ -6012,7 +6023,7 @@ Error type_has_bits2(CodeGen *g, ZigType *type_entry, bool *result) {
60126023
60136024bool fn_returns_c_abi_small_struct(FnTypeId *fn_type_id) {
60146025 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) &&
60166027 type->id == ZigTypeIdStruct && type->abi_size <= 16;
60176028}
60186029
......@@ -8700,7 +8711,7 @@ static LLVMTypeRef llvm_int_for_size(size_t size) {
87008711static LLVMTypeRef llvm_sse_for_size(size_t size) {
87018712 if (size > 4)
87028713 return LLVMDoubleType();
8703 else
8714 else
87048715 return LLVMFloatType();
87058716}
87068717
......@@ -8758,7 +8769,7 @@ static Error resolve_llvm_c_abi_type(CodeGen *g, ZigType *ty) {
87588769
87598770 LLVMTypeRef return_elem_types[] = {
87608771 LLVMVoidType(),
8761 LLVMVoidType(),
8772 LLVMVoidType(),
87628773 };
87638774 for (uint32_t i = 0; i <= eightbyte_index; i += 1) {
87648775 if (type_classes[i] == X64CABIClass_INTEGER) {
src/stage1/astgen.cpp+34
......@@ -351,6 +351,8 @@ void destroy_instruction_src(Stage1ZirInst *inst) {
351351 return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstSrc *>(inst));
352352 case Stage1ZirInstIdPrefetch:
353353 return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstPrefetch *>(inst));
354 case Stage1ZirInstIdAddrSpaceCast:
355 return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstAddrSpaceCast *>(inst));
354356 }
355357 zig_unreachable();
356358}
......@@ -947,6 +949,10 @@ static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPrefetch *) {
947949 return Stage1ZirInstIdPrefetch;
948950}
949951
952static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAddrSpaceCast *) {
953 return Stage1ZirInstIdAddrSpaceCast;
954}
955
950956template<typename T>
951957static T *ir_create_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node) {
952958 T *special_instruction = heap::c_allocator.create<T>();
......@@ -2572,6 +2578,19 @@ static Stage1ZirInst *ir_build_align_cast_src(Stage1AstGen *ag, Scope *scope, As
25722578 return &instruction->base;
25732579}
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
25752594static Stage1ZirInst *ir_build_resolve_result(Stage1AstGen *ag, Scope *scope, AstNode *source_node,
25762595 ResultLoc *result_loc, Stage1ZirInst *ty)
25772596{
......@@ -5459,6 +5478,21 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
54595478 Stage1ZirInst *ir_extern = ir_build_prefetch(ag, scope, node, ptr_value, casted_options_value);
54605479 return ir_lval_wrap(ag, scope, ir_extern, lval, result_loc);
54615480 }
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 }
54625496 }
54635497 zig_unreachable();
54645498}
src/stage1/codegen.cpp+7-2
......@@ -217,6 +217,9 @@ static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
217217 assert(g->zig_target->arch == ZigLLVM_nvptx ||
218218 g->zig_target->arch == ZigLLVM_nvptx64);
219219 return ZigLLVM_PTX_Kernel;
220 case CallingConventionAmdgpuKernel:
221 assert(g->zig_target->arch == ZigLLVM_amdgcn);
222 return ZigLLVM_AMDGPU_KERNEL;
220223
221224 }
222225 zig_unreachable();
......@@ -365,6 +368,7 @@ static bool cc_want_sret_attr(CallingConvention cc) {
365368 case CallingConventionSysV:
366369 case CallingConventionWin64:
367370 case CallingConventionPtxKernel:
371 case CallingConventionAmdgpuKernel:
368372 return true;
369373 case CallingConventionAsync:
370374 case CallingConventionUnspecified:
......@@ -3515,7 +3519,7 @@ static LLVMValueRef gen_soft_float_to_int_op(CodeGen *g, LLVMValueRef value_ref,
35153519
35163520 // Handle integers of non-pot bitsize by shortening them on the output
35173521 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);
35193523 }
35203524
35213525 return result;
......@@ -4370,7 +4374,7 @@ static LLVMValueRef ir_render_binary_not(CodeGen *g, Stage1Air *executable,
43704374
43714375static LLVMValueRef gen_soft_float_neg(CodeGen *g, ZigType *operand_type, LLVMValueRef operand) {
43724376 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 ?
43744378 operand_type->data.vector.elem_type->data.floating.bit_count :
43754379 operand_type->data.floating.bit_count;
43764380
......@@ -10181,6 +10185,7 @@ static void define_builtin_fns(CodeGen *g) {
1018110185 create_builtin_fn(g, BuiltinFnIdMaximum, "maximum", 2);
1018210186 create_builtin_fn(g, BuiltinFnIdMinimum, "minimum", 2);
1018310187 create_builtin_fn(g, BuiltinFnIdPrefetch, "prefetch", 2);
10188 create_builtin_fn(g, BuiltinFnIdAddrSpaceCast, "addrSpaceCast", 2);
1018410189}
1018510190
1018610191static 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
1175311753 case CallingConventionSysV:
1175411754 case CallingConventionWin64:
1175511755 case CallingConventionPtxKernel:
11756 case CallingConventionAmdgpuKernel:
1175611757 add_fn_export(ira->codegen, fn_entry, buf_ptr(symbol_name), global_linkage_id, cc);
1175711758 fn_entry->section_name = section_name;
1175811759 break;
......@@ -23745,6 +23746,50 @@ static Stage1AirInst *ir_analyze_instruction_align_cast(IrAnalyze *ira, Stage1Zi
2374523746 return result;
2374623747}
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
2374823793static Stage1AirInst *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, Stage1ZirInstSetAlignStack *instruction) {
2374923794 uint32_t align_bytes;
2375023795 Stage1AirInst *align_bytes_inst = instruction->align_bytes->child;
......@@ -25450,6 +25495,8 @@ static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst
2545025495 return ir_analyze_instruction_src(ira, (Stage1ZirInstSrc *)instruction);
2545125496 case Stage1ZirInstIdPrefetch:
2545225497 return ir_analyze_instruction_prefetch(ira, (Stage1ZirInstPrefetch *)instruction);
25498 case Stage1ZirInstIdAddrSpaceCast:
25499 return ir_analyze_instruction_addrspace_cast(ira, (Stage1ZirInstAddrSpaceCast *)instruction);
2545325500 }
2545425501 zig_unreachable();
2545525502}
......@@ -25831,6 +25878,7 @@ bool ir_inst_src_has_side_effects(Stage1ZirInst *instruction) {
2583125878 case Stage1ZirInstIdWasmMemorySize:
2583225879 case Stage1ZirInstIdSrc:
2583325880 case Stage1ZirInstIdReduce:
25881 case Stage1ZirInstIdAddrSpaceCast:
2583425882 return false;
2583525883
2583625884 case Stage1ZirInstIdAsm:
src/stage1/ir_print.cpp+13
......@@ -373,6 +373,8 @@ const char* ir_inst_src_type_str(Stage1ZirInstId id) {
373373 return "SrcSrc";
374374 case Stage1ZirInstIdPrefetch:
375375 return "SrcPrefetch";
376 case Stage1ZirInstIdAddrSpaceCast:
377 return "SrcAddrSpaceCast";
376378 }
377379 zig_unreachable();
378380}
......@@ -2382,6 +2384,14 @@ static void ir_print_align_cast(IrPrintSrc *irp, Stage1ZirInstAlignCast *instruc
23822384 fprintf(irp->f, ")");
23832385}
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
23852395static void ir_print_align_cast(IrPrintGen *irp, Stage1AirInstAlignCast *instruction) {
23862396 fprintf(irp->f, "@alignCast(");
23872397 ir_print_other_inst_gen(irp, instruction->target);
......@@ -3127,6 +3137,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, Stage1ZirInst *instruction, bool
31273137 case Stage1ZirInstIdPrefetch:
31283138 ir_print_prefetch(irp, (Stage1ZirInstPrefetch *)instruction);
31293139 break;
3140 case Stage1ZirInstIdAddrSpaceCast:
3141 ir_print_addrspace_cast(irp, (Stage1ZirInstAddrSpaceCast *)instruction);
3142 break;
31303143 }
31313144 fprintf(irp->f, "\n");
31323145}
src/target.zig+20-1
......@@ -1,5 +1,6 @@
11const std = @import("std");
22const Type = @import("type.zig").Type;
3const AddressSpace = std.builtin.AddressSpace;
34
45pub const ArchOsAbi = struct {
56 arch: std.Target.Cpu.Arch,
......@@ -635,12 +636,30 @@ pub fn defaultAddressSpace(
635636 /// Query the default address space for functions themselves.
636637 function,
637638 },
638) std.builtin.AddressSpace {
639) AddressSpace {
639640 _ = target;
640641 _ = context;
641642 return .generic;
642643}
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
644663pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {
645664 const have_float = switch (target.abi) {
646665 .gnuilp32 => return "ilp32",
src/type.zig+13-2
......@@ -2786,6 +2786,12 @@ pub const Type = extern union {
27862786
27872787 .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
27892795 else => unreachable,
27902796 };
27912797 }
......@@ -6768,6 +6774,13 @@ pub const CType = enum {
67686774 },
67696775 },
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
67716784 .cloudabi,
67726785 .kfreebsd,
67736786 .lv2,
......@@ -6777,13 +6790,11 @@ pub const CType = enum {
67776790 .aix,
67786791 .cuda,
67796792 .nvcl,
6780 .amdhsa,
67816793 .ps4,
67826794 .ps5,
67836795 .elfiamcu,
67846796 .mesa3d,
67856797 .contiki,
6786 .amdpal,
67876798 .hermit,
67886799 .hurd,
67896800 .opencl,
src/zig_llvm.cpp+11-6
......@@ -512,22 +512,22 @@ LLVMValueRef ZigLLVMBuildUSubSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRe
512512
513513LLVMValueRef ZigLLVMBuildSMulFixSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
514514 llvm::Type* types[1] = {
515 unwrap(LHS)->getType(),
515 unwrap(LHS)->getType(),
516516 };
517517 // pass scale = 0 as third argument
518518 llvm::Value* values[3] = {unwrap(LHS), unwrap(RHS), unwrap(B)->getInt32(0)};
519
519
520520 CallInst *call_inst = unwrap(B)->CreateIntrinsic(Intrinsic::smul_fix_sat, types, values, nullptr, name);
521521 return wrap(call_inst);
522522}
523523
524524LLVMValueRef ZigLLVMBuildUMulFixSat(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
525525 llvm::Type* types[1] = {
526 unwrap(LHS)->getType(),
526 unwrap(LHS)->getType(),
527527 };
528528 // pass scale = 0 as third argument
529529 llvm::Value* values[3] = {unwrap(LHS), unwrap(RHS), unwrap(B)->getInt32(0)};
530
530
531531 CallInst *call_inst = unwrap(B)->CreateIntrinsic(Intrinsic::umul_fix_sat, types, values, nullptr, name);
532532 return wrap(call_inst);
533533}
......@@ -808,7 +808,7 @@ void ZigLLVMSetCurrentDebugLocation2(LLVMBuilderRef builder, unsigned int line,
808808 unsigned int column, ZigLLVMDIScope *scope, ZigLLVMDILocation *inlined_at)
809809{
810810 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,
812812 reinterpret_cast<DILocation *>(inlined_at), false);
813813 unwrap(builder)->SetCurrentDebugLocation(debug_loc);
814814}
......@@ -1177,9 +1177,14 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV
11771177 return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));
11781178}
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
11801185void ZigLLVMSetTailCall(LLVMValueRef Call) {
11811186 unwrap<CallInst>(Call)->setTailCallKind(CallInst::TCK_MustTail);
1182}
1187}
11831188
11841189void ZigLLVMSetCallSret(LLVMValueRef Call, LLVMTypeRef return_type) {
11851190 CallInst *call_inst = unwrap<CallInst>(Call);
src/zig_llvm.h+2
......@@ -162,6 +162,8 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValu
162162ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
163163 const char *name);
164164
165ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildAllocaInAddressSpace(LLVMBuilderRef builder, LLVMTypeRef Ty, unsigned AddressSpace,
166 const char *Name);
165167
166168ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugPointerType(struct ZigLLVMDIBuilder *dibuilder,
167169 struct ZigLLVMDIType *pointee_type, uint64_t size_in_bits, uint64_t align_in_bits, const char *name);