authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2022-08-21 01:32:19+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2022-10-12 20:34:42+02:00
log5f3b91437f5cd23bcae66227932555b7abe32669
tree3d1db6c0e791e7b206ea4eb88abdad252f3901bd
parent3392de87dcf516ed2e3fd1904372195bdc75c0eb
signaturelock-open Commit is signed but in an unrecognized format.

stage2: improve addrspace handling

This commit changes the way Zig is intended to deal with variable declaration for exotic targets. Where previously the idea was to enfore local/global variables to be placed into their respective address spaces, depending on the target, this is now fixed to the generic address space. To facilitate this for targets where local variables _must_ be generated into a specific address space (ex. amdgcn where locals must be generated into the private address space), the variable allocations (alloca) are generated into the right address space and then addrspace-casted back to the generic address space. While this could be less efficient in theory, LLVM will hopefull deal with figuring out the actual correct address space for a pointer for us. HIP seems to do the same thing in this regard. Global variables are handled in a similar way.

4 files changed, 203 insertions(+), 132 deletions(-)

src/codegen/llvm.zig+181-126
...@@ -929,8 +929,7 @@ pub const Object = struct {...@@ -929,8 +929,7 @@ pub const Object = struct {
929 if (isByRef(param_ty)) {929 if (isByRef(param_ty)) {
930 const alignment = param_ty.abiAlignment(target);930 const alignment = param_ty.abiAlignment(target);
931 const param_llvm_ty = param.typeOf();931 const param_llvm_ty = param.typeOf();
932 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);932 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
933 arg_ptr.setAlignment(alignment);
934 const store_inst = builder.buildStore(param, arg_ptr);933 const store_inst = builder.buildStore(param, arg_ptr);
935 store_inst.setAlignment(alignment);934 store_inst.setAlignment(alignment);
936 args.appendAssumeCapacity(arg_ptr);935 args.appendAssumeCapacity(arg_ptr);
...@@ -974,8 +973,7 @@ pub const Object = struct {...@@ -974,8 +973,7 @@ pub const Object = struct {
974 param_ty.abiAlignment(target),973 param_ty.abiAlignment(target),
975 dg.object.target_data.abiAlignmentOfType(int_llvm_ty),974 dg.object.target_data.abiAlignmentOfType(int_llvm_ty),
976 );975 );
977 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);976 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
978 arg_ptr.setAlignment(alignment);
979 const casted_ptr = builder.buildBitCast(arg_ptr, int_ptr_llvm_ty, "");977 const casted_ptr = builder.buildBitCast(arg_ptr, int_ptr_llvm_ty, "");
980 const store_inst = builder.buildStore(param, casted_ptr);978 const store_inst = builder.buildStore(param, casted_ptr);
981 store_inst.setAlignment(alignment);979 store_inst.setAlignment(alignment);
...@@ -1026,8 +1024,7 @@ pub const Object = struct {...@@ -1026,8 +1024,7 @@ pub const Object = struct {
1026 const param_ty = fn_info.param_types[it.zig_index - 1];1024 const param_ty = fn_info.param_types[it.zig_index - 1];
1027 const param_llvm_ty = try dg.lowerType(param_ty);1025 const param_llvm_ty = try dg.lowerType(param_ty);
1028 const param_alignment = param_ty.abiAlignment(target);1026 const param_alignment = param_ty.abiAlignment(target);
1029 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);1027 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, param_alignment, target);
1030 arg_ptr.setAlignment(param_alignment);
1031 var field_types_buf: [8]*llvm.Type = undefined;1028 var field_types_buf: [8]*llvm.Type = undefined;
1032 const field_types = field_types_buf[0..llvm_ints.len];1029 const field_types = field_types_buf[0..llvm_ints.len];
1033 for (llvm_ints) |int_bits, i| {1030 for (llvm_ints) |int_bits, i| {
...@@ -1058,8 +1055,7 @@ pub const Object = struct {...@@ -1058,8 +1055,7 @@ pub const Object = struct {
1058 const param_ty = fn_info.param_types[it.zig_index - 1];1055 const param_ty = fn_info.param_types[it.zig_index - 1];
1059 const param_llvm_ty = try dg.lowerType(param_ty);1056 const param_llvm_ty = try dg.lowerType(param_ty);
1060 const param_alignment = param_ty.abiAlignment(target);1057 const param_alignment = param_ty.abiAlignment(target);
1061 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);1058 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, param_alignment, target);
1062 arg_ptr.setAlignment(param_alignment);
1063 var field_types_buf: [8]*llvm.Type = undefined;1059 var field_types_buf: [8]*llvm.Type = undefined;
1064 const field_types = field_types_buf[0..llvm_floats.len];1060 const field_types = field_types_buf[0..llvm_floats.len];
1065 for (llvm_floats) |float_bits, i| {1061 for (llvm_floats) |float_bits, i| {
...@@ -1103,8 +1099,7 @@ pub const Object = struct {...@@ -1103,8 +1099,7 @@ pub const Object = struct {
1103 llvm_arg_i += 1;1099 llvm_arg_i += 1;
11041100
1105 const alignment = param_ty.abiAlignment(target);1101 const alignment = param_ty.abiAlignment(target);
1106 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);1102 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target);
1107 arg_ptr.setAlignment(alignment);
1108 const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), "");1103 const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), "");
1109 _ = builder.buildStore(param, casted_ptr);1104 _ = builder.buildStore(param, casted_ptr);
11101105
...@@ -2404,21 +2399,27 @@ pub const DeclGen = struct {...@@ -2404,21 +2399,27 @@ pub const DeclGen = struct {
2404 // mismatch, because we don't have the LLVM type until the *value* is created,2399 // mismatch, because we don't have the LLVM type until the *value* is created,
2405 // whereas the global needs to be created based on the type alone, because2400 // whereas the global needs to be created based on the type alone, because
2406 // lowering the value may reference the global as a pointer.2401 // lowering the value may reference the global as a pointer.
2402 const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
2403 const llvm_global_addrspace = toLlvmGlobalAddressSpace(llvm_addrspace, target);
2407 const new_global = dg.object.llvm_module.addGlobalInAddressSpace(2404 const new_global = dg.object.llvm_module.addGlobalInAddressSpace(
2408 llvm_init.typeOf(),2405 llvm_init.typeOf(),
2409 "",2406 "",
2410 dg.llvmAddressSpace(decl.@"addrspace"),2407 llvm_global_addrspace,
2411 );2408 );
2412 new_global.setLinkage(global.getLinkage());2409 new_global.setLinkage(global.getLinkage());
2413 new_global.setUnnamedAddr(global.getUnnamedAddress());2410 new_global.setUnnamedAddr(global.getUnnamedAddress());
2414 new_global.setAlignment(global.getAlignment());2411 new_global.setAlignment(global.getAlignment());
2415 if (decl.@"linksection") |section| new_global.setSection(section);2412 if (decl.@"linksection") |section| new_global.setSection(section);
2416 new_global.setInitializer(llvm_init);2413 new_global.setInitializer(llvm_init);
2417 // replaceAllUsesWith requires the type to be unchanged. So we bitcast2414 // replaceAllUsesWith requires the type to be unchanged. So we convert
2418 // the new global to the old type and use that as the thing to replace2415 // the new global to the old type and use that as the thing to replace
2419 // old uses.2416 // old uses.
2420 const new_global_ptr = new_global.constBitCast(global.typeOf());2417 const new_global_ptr = if (llvm_addrspace != llvm_global_addrspace)
2421 global.replaceAllUsesWith(new_global_ptr);2418 new_global.constAddrSpaceCast(llvm_init.typeOf().pointerType(llvm_addrspace))
2419 else
2420 new_global;
2421 const new_global_casted_ptr = new_global_ptr.constBitCast(global.typeOf());
2422 global.replaceAllUsesWith(new_global_casted_ptr);
2422 dg.object.decl_map.putAssumeCapacity(decl_index, new_global);2423 dg.object.decl_map.putAssumeCapacity(decl_index, new_global);
2423 new_global.takeName(global);2424 new_global.takeName(global);
2424 global.deleteGlobal();2425 global.deleteGlobal();
...@@ -2465,7 +2466,7 @@ pub const DeclGen = struct {...@@ -2465,7 +2466,7 @@ pub const DeclGen = struct {
2465 const fqn = try decl.getFullyQualifiedName(dg.module);2466 const fqn = try decl.getFullyQualifiedName(dg.module);
2466 defer dg.gpa.free(fqn);2467 defer dg.gpa.free(fqn);
24672468
2468 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");2469 const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
2469 const llvm_fn = dg.llvmModule().addFunctionInAddressSpace(fqn, fn_type, llvm_addrspace);2470 const llvm_fn = dg.llvmModule().addFunctionInAddressSpace(fqn, fn_type, llvm_addrspace);
2470 gop.value_ptr.* = llvm_fn;2471 gop.value_ptr.* = llvm_fn;
24712472
...@@ -2613,9 +2614,15 @@ pub const DeclGen = struct {...@@ -2613,9 +2614,15 @@ pub const DeclGen = struct {
2613 const fqn = try decl.getFullyQualifiedName(dg.module);2614 const fqn = try decl.getFullyQualifiedName(dg.module);
2614 defer dg.gpa.free(fqn);2615 defer dg.gpa.free(fqn);
26152616
2617 const target = dg.module.getTarget();
2618
2616 const llvm_type = try dg.lowerType(decl.ty);2619 const llvm_type = try dg.lowerType(decl.ty);
2617 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");2620 const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
2618 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace);2621 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(
2622 llvm_type,
2623 fqn,
2624 toLlvmGlobalAddressSpace(llvm_addrspace, target),
2625 );
2619 gop.value_ptr.* = llvm_global;2626 gop.value_ptr.* = llvm_global;
26202627
2621 // This is needed for declarations created by `@extern`.2628 // This is needed for declarations created by `@extern`.
...@@ -2640,40 +2647,6 @@ pub const DeclGen = struct {...@@ -2640,40 +2647,6 @@ pub const DeclGen = struct {
2640 return llvm_global;2647 return llvm_global;
2641 }2648 }
26422649
2643 fn llvmAddressSpace(self: DeclGen, address_space: std.builtin.AddressSpace) c_uint {
2644 const target = self.module.getTarget();
2645 return switch (target.cpu.arch) {
2646 .i386, .x86_64 => switch (address_space) {
2647 .generic => llvm.address_space.default,
2648 .gs => llvm.address_space.x86.gs,
2649 .fs => llvm.address_space.x86.fs,
2650 .ss => llvm.address_space.x86.ss,
2651 else => unreachable,
2652 },
2653 .nvptx, .nvptx64 => switch (address_space) {
2654 .generic => llvm.address_space.default,
2655 .global => llvm.address_space.nvptx.global,
2656 .constant => llvm.address_space.nvptx.constant,
2657 .param => llvm.address_space.nvptx.param,
2658 .shared => llvm.address_space.nvptx.shared,
2659 .local => llvm.address_space.nvptx.local,
2660 else => unreachable,
2661 },
2662 .amdgcn => switch (address_space) {
2663 .generic => llvm.address_space.flat,
2664 .global => llvm.address_space.amdgpu.global,
2665 .constant => llvm.address_space.amdgpu.constant,
2666 .shared => llvm.address_space.amdgpu.local,
2667 .local => llvm.address_space.amdgpu.private,
2668 else => unreachable,
2669 }.
2670 else => switch (address_space) {
2671 .generic => llvm.address_space.default,
2672 else => unreachable,
2673 },
2674 };
2675 }
2676
2677 fn isUnnamedType(dg: *DeclGen, ty: Type, val: *llvm.Value) bool {2650 fn isUnnamedType(dg: *DeclGen, ty: Type, val: *llvm.Value) bool {
2678 // Once `lowerType` succeeds, successive calls to it with the same Zig type2651 // Once `lowerType` succeeds, successive calls to it with the same Zig type
2679 // are guaranteed to succeed. So if a call to `lowerType` fails here it means2652 // are guaranteed to succeed. So if a call to `lowerType` fails here it means
...@@ -2739,7 +2712,7 @@ pub const DeclGen = struct {...@@ -2739,7 +2712,7 @@ pub const DeclGen = struct {
2739 return dg.context.structType(&fields, fields.len, .False);2712 return dg.context.structType(&fields, fields.len, .False);
2740 }2713 }
2741 const ptr_info = t.ptrInfo().data;2714 const ptr_info = t.ptrInfo().data;
2742 const llvm_addrspace = dg.llvmAddressSpace(ptr_info.@"addrspace");2715 const llvm_addrspace = toLlvmAddressSpace(ptr_info.@"addrspace", target);
2743 if (ptr_info.host_size != 0) {2716 if (ptr_info.host_size != 0) {
2744 return dg.context.intType(ptr_info.host_size * 8).pointerType(llvm_addrspace);2717 return dg.context.intType(ptr_info.host_size * 8).pointerType(llvm_addrspace);
2745 }2718 }
...@@ -3268,11 +3241,18 @@ pub const DeclGen = struct {...@@ -3268,11 +3241,18 @@ pub const DeclGen = struct {
3268 const decl_index = tv.val.castTag(.variable).?.data.owner_decl;3241 const decl_index = tv.val.castTag(.variable).?.data.owner_decl;
3269 const decl = dg.module.declPtr(decl_index);3242 const decl = dg.module.declPtr(decl_index);
3270 dg.module.markDeclAlive(decl);3243 dg.module.markDeclAlive(decl);
3271 const val = try dg.resolveGlobalDecl(decl_index);
3272 const llvm_var_type = try dg.lowerType(tv.ty);3244 const llvm_var_type = try dg.lowerType(tv.ty);
3273 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");3245 const llvm_var_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
3274 const llvm_type = llvm_var_type.pointerType(llvm_addrspace);3246 const llvm_global_addrspace = toLlvmGlobalAddressSpace(llvm_var_addrspace, target);
3275 return val.constBitCast(llvm_type);3247 const llvm_var_ptr_type = llvm_var_type.pointerType(llvm_global_addrspace);
3248
3249 const val = try dg.resolveGlobalDecl(decl_index);
3250 const val_ptr = val.constBitCast(llvm_var_ptr_type);
3251 if (llvm_global_addrspace != llvm_var_addrspace) {
3252 const llvm_ptr_type = llvm_var_type.pointerType(llvm_var_addrspace);
3253 return val_ptr.constAddrSpaceCast(llvm_ptr_type);
3254 }
3255 return val_ptr;
3276 },3256 },
3277 .slice => {3257 .slice => {
3278 const slice = tv.val.castTag(.slice).?.data;3258 const slice = tv.val.castTag(.slice).?.data;
...@@ -4069,11 +4049,20 @@ pub const DeclGen = struct {...@@ -4069,11 +4049,20 @@ pub const DeclGen = struct {
40694049
4070 self.module.markDeclAlive(decl);4050 self.module.markDeclAlive(decl);
40714051
4072 const llvm_val = if (is_fn_body)4052 const llvm_decl_val = if (is_fn_body)
4073 try self.resolveLlvmFunction(decl_index)4053 try self.resolveLlvmFunction(decl_index)
4074 else4054 else
4075 try self.resolveGlobalDecl(decl_index);4055 try self.resolveGlobalDecl(decl_index);
40764056
4057 const target = self.module.getTarget();
4058 const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
4059 const llvm_global_addrspace = toLlvmGlobalAddressSpace(llvm_addrspace, target);
4060 const llvm_val = if (llvm_addrspace != llvm_global_addrspace) blk: {
4061 const llvm_decl_ty = try self.lowerType(decl.ty);
4062 const llvm_decl_ptr_ty = llvm_decl_ty.pointerType(llvm_addrspace);
4063 break :blk llvm_decl_val.constAddrSpaceCast(llvm_decl_ptr_ty);
4064 } else llvm_decl_val;
4065
4077 const llvm_type = try self.lowerType(tv.ty);4066 const llvm_type = try self.lowerType(tv.ty);
4078 if (tv.ty.zigTypeTag() == .Int) {4067 if (tv.ty.zigTypeTag() == .Int) {
4079 return llvm_val.constPtrToInt(llvm_type);4068 return llvm_val.constPtrToInt(llvm_type);
...@@ -4339,7 +4328,9 @@ pub const FuncGen = struct {...@@ -4339,7 +4328,9 @@ pub const FuncGen = struct {
4339 // We have an LLVM value but we need to create a global constant and4328 // We have an LLVM value but we need to create a global constant and
4340 // set the value as its initializer, and then return a pointer to the global.4329 // set the value as its initializer, and then return a pointer to the global.
4341 const target = self.dg.module.getTarget();4330 const target = self.dg.module.getTarget();
4342 const global = self.dg.object.llvm_module.addGlobal(llvm_val.typeOf(), "");4331 const llvm_addrspace = toLlvmAddressSpace(.generic, target);
4332 const llvm_global_addrspace = toLlvmGlobalAddressSpace(llvm_addrspace, target);
4333 const global = self.dg.object.llvm_module.addGlobalInAddressSpace(llvm_val.typeOf(), "", llvm_global_addrspace);
4343 global.setInitializer(llvm_val);4334 global.setInitializer(llvm_val);
4344 global.setLinkage(.Private);4335 global.setLinkage(.Private);
4345 global.setGlobalConstant(.True);4336 global.setGlobalConstant(.True);
...@@ -4349,8 +4340,10 @@ pub const FuncGen = struct {...@@ -4349,8 +4340,10 @@ pub const FuncGen = struct {
4349 // the type of global constants might not match the type it is supposed to4340 // the type of global constants might not match the type it is supposed to
4350 // be, and so we must bitcast the pointer at the usage sites.4341 // be, and so we must bitcast the pointer at the usage sites.
4351 const wanted_llvm_ty = try self.dg.lowerType(ty);4342 const wanted_llvm_ty = try self.dg.lowerType(ty);
4352 const wanted_llvm_ptr_ty = wanted_llvm_ty.pointerType(0);4343 const wanted_bitcasted_llvm_ptr_ty = wanted_llvm_ty.pointerType(llvm_global_addrspace);
4353 const casted_ptr = global.constBitCast(wanted_llvm_ptr_ty);4344 const bitcasted_ptr = global.constBitCast(wanted_bitcasted_llvm_ptr_ty);
4345 const wanted_llvm_ptr_ty = wanted_llvm_ty.pointerType(llvm_addrspace);
4346 const casted_ptr = bitcasted_ptr.constAddrSpaceCast(wanted_llvm_ptr_ty);
4354 gop.value_ptr.* = casted_ptr;4347 gop.value_ptr.* = casted_ptr;
4355 return casted_ptr;4348 return casted_ptr;
4356 }4349 }
...@@ -4606,8 +4599,7 @@ pub const FuncGen = struct {...@@ -4606,8 +4599,7 @@ pub const FuncGen = struct {
46064599
4607 const ret_ptr = if (!sret) null else blk: {4600 const ret_ptr = if (!sret) null else blk: {
4608 const llvm_ret_ty = try self.dg.lowerType(return_type);4601 const llvm_ret_ty = try self.dg.lowerType(return_type);
4609 const ret_ptr = self.buildAlloca(llvm_ret_ty);4602 const ret_ptr = self.buildAlloca(llvm_ret_ty, return_type.abiAlignment(target));
4610 ret_ptr.setAlignment(return_type.abiAlignment(target));
4611 try llvm_args.append(ret_ptr);4603 try llvm_args.append(ret_ptr);
4612 break :blk ret_ptr;4604 break :blk ret_ptr;
4613 };4605 };
...@@ -4654,8 +4646,7 @@ pub const FuncGen = struct {...@@ -4654,8 +4646,7 @@ pub const FuncGen = struct {
4654 } else {4646 } else {
4655 const alignment = param_ty.abiAlignment(target);4647 const alignment = param_ty.abiAlignment(target);
4656 const param_llvm_ty = llvm_arg.typeOf();4648 const param_llvm_ty = llvm_arg.typeOf();
4657 const arg_ptr = self.buildAlloca(param_llvm_ty);4649 const arg_ptr = self.buildAlloca(param_llvm_ty, alignment);
4658 arg_ptr.setAlignment(alignment);
4659 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);4650 const store_inst = self.builder.buildStore(llvm_arg, arg_ptr);
4660 store_inst.setAlignment(alignment);4651 store_inst.setAlignment(alignment);
4661 try llvm_args.append(arg_ptr);4652 try llvm_args.append(arg_ptr);
...@@ -4682,8 +4673,7 @@ pub const FuncGen = struct {...@@ -4682,8 +4673,7 @@ pub const FuncGen = struct {
4682 param_ty.abiAlignment(target),4673 param_ty.abiAlignment(target),
4683 self.dg.object.target_data.abiAlignmentOfType(int_llvm_ty),4674 self.dg.object.target_data.abiAlignmentOfType(int_llvm_ty),
4684 );4675 );
4685 const int_ptr = self.buildAlloca(int_llvm_ty);4676 const int_ptr = self.buildAlloca(int_llvm_ty, alignment);
4686 int_ptr.setAlignment(alignment);
4687 const param_llvm_ty = try self.dg.lowerType(param_ty);4677 const param_llvm_ty = try self.dg.lowerType(param_ty);
4688 const casted_ptr = self.builder.buildBitCast(int_ptr, param_llvm_ty.pointerType(0), "");4678 const casted_ptr = self.builder.buildBitCast(int_ptr, param_llvm_ty.pointerType(0), "");
4689 const store_inst = self.builder.buildStore(llvm_arg, casted_ptr);4679 const store_inst = self.builder.buildStore(llvm_arg, casted_ptr);
...@@ -4709,7 +4699,7 @@ pub const FuncGen = struct {...@@ -4709,7 +4699,7 @@ pub const FuncGen = struct {
4709 const llvm_arg = try self.resolveInst(arg);4699 const llvm_arg = try self.resolveInst(arg);
4710 const is_by_ref = isByRef(param_ty);4700 const is_by_ref = isByRef(param_ty);
4711 const arg_ptr = if (is_by_ref) llvm_arg else p: {4701 const arg_ptr = if (is_by_ref) llvm_arg else p: {
4712 const p = self.buildAlloca(llvm_arg.typeOf());4702 const p = self.buildAlloca(llvm_arg.typeOf(), null);
4713 const store_inst = self.builder.buildStore(llvm_arg, p);4703 const store_inst = self.builder.buildStore(llvm_arg, p);
4714 store_inst.setAlignment(param_ty.abiAlignment(target));4704 store_inst.setAlignment(param_ty.abiAlignment(target));
4715 break :p p;4705 break :p p;
...@@ -4738,7 +4728,7 @@ pub const FuncGen = struct {...@@ -4738,7 +4728,7 @@ pub const FuncGen = struct {
4738 const llvm_arg = try self.resolveInst(arg);4728 const llvm_arg = try self.resolveInst(arg);
4739 const is_by_ref = isByRef(param_ty);4729 const is_by_ref = isByRef(param_ty);
4740 const arg_ptr = if (is_by_ref) llvm_arg else p: {4730 const arg_ptr = if (is_by_ref) llvm_arg else p: {
4741 const p = self.buildAlloca(llvm_arg.typeOf());4731 const p = self.buildAlloca(llvm_arg.typeOf(), null);
4742 const store_inst = self.builder.buildStore(llvm_arg, p);4732 const store_inst = self.builder.buildStore(llvm_arg, p);
4743 store_inst.setAlignment(param_ty.abiAlignment(target));4733 store_inst.setAlignment(param_ty.abiAlignment(target));
4744 break :p p;4734 break :p p;
...@@ -4775,7 +4765,7 @@ pub const FuncGen = struct {...@@ -4775,7 +4765,7 @@ pub const FuncGen = struct {
4775 const arg_ty = self.air.typeOf(arg);4765 const arg_ty = self.air.typeOf(arg);
4776 var llvm_arg = try self.resolveInst(arg);4766 var llvm_arg = try self.resolveInst(arg);
4777 if (!isByRef(arg_ty)) {4767 if (!isByRef(arg_ty)) {
4778 const p = self.buildAlloca(llvm_arg.typeOf());4768 const p = self.buildAlloca(llvm_arg.typeOf(), null);
4779 const store_inst = self.builder.buildStore(llvm_arg, p);4769 const store_inst = self.builder.buildStore(llvm_arg, p);
4780 store_inst.setAlignment(arg_ty.abiAlignment(target));4770 store_inst.setAlignment(arg_ty.abiAlignment(target));
4781 llvm_arg = store_inst;4771 llvm_arg = store_inst;
...@@ -4832,9 +4822,8 @@ pub const FuncGen = struct {...@@ -4832,9 +4822,8 @@ pub const FuncGen = struct {
4832 // In this case the function return type is honoring the calling convention by having4822 // In this case the function return type is honoring the calling convention by having
4833 // a different LLVM type than the usual one. We solve this here at the callsite4823 // a different LLVM type than the usual one. We solve this here at the callsite
4834 // by bitcasting a pointer to our canonical type, then loading it if necessary.4824 // by bitcasting a pointer to our canonical type, then loading it if necessary.
4835 const rp = self.buildAlloca(llvm_ret_ty);
4836 const alignment = return_type.abiAlignment(target);4825 const alignment = return_type.abiAlignment(target);
4837 rp.setAlignment(alignment);4826 const rp = self.buildAlloca(llvm_ret_ty, alignment);
4838 const ptr_abi_ty = abi_ret_ty.pointerType(0);4827 const ptr_abi_ty = abi_ret_ty.pointerType(0);
4839 const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");4828 const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");
4840 const store_inst = self.builder.buildStore(call, casted_ptr);4829 const store_inst = self.builder.buildStore(call, casted_ptr);
...@@ -4851,9 +4840,8 @@ pub const FuncGen = struct {...@@ -4851,9 +4840,8 @@ pub const FuncGen = struct {
4851 if (isByRef(return_type)) {4840 if (isByRef(return_type)) {
4852 // our by-ref status disagrees with sret so we must allocate, store,4841 // our by-ref status disagrees with sret so we must allocate, store,
4853 // and return the allocation pointer.4842 // and return the allocation pointer.
4854 const rp = self.buildAlloca(llvm_ret_ty);
4855 const alignment = return_type.abiAlignment(target);4843 const alignment = return_type.abiAlignment(target);
4856 rp.setAlignment(alignment);4844 const rp = self.buildAlloca(llvm_ret_ty, alignment);
4857 const store_inst = self.builder.buildStore(call, rp);4845 const store_inst = self.builder.buildStore(call, rp);
4858 store_inst.setAlignment(alignment);4846 store_inst.setAlignment(alignment);
4859 return rp;4847 return rp;
...@@ -4912,8 +4900,7 @@ pub const FuncGen = struct {...@@ -4912,8 +4900,7 @@ pub const FuncGen = struct {
4912 return null;4900 return null;
4913 }4901 }
49144902
4915 const rp = self.buildAlloca(llvm_ret_ty);4903 const rp = self.buildAlloca(llvm_ret_ty, alignment);
4916 rp.setAlignment(alignment);
4917 const store_inst = self.builder.buildStore(operand, rp);4904 const store_inst = self.builder.buildStore(operand, rp);
4918 store_inst.setAlignment(alignment);4905 store_inst.setAlignment(alignment);
4919 const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");4906 const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, "");
...@@ -6031,8 +6018,7 @@ pub const FuncGen = struct {...@@ -6031,8 +6018,7 @@ pub const FuncGen = struct {
6031 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();6018 llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf();
6032 } else {6019 } else {
6033 const alignment = arg_ty.abiAlignment(target);6020 const alignment = arg_ty.abiAlignment(target);
6034 const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf());6021 const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf(), alignment);
6035 arg_ptr.setAlignment(alignment);
6036 const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr);6022 const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr);
6037 store_inst.setAlignment(alignment);6023 store_inst.setAlignment(alignment);
6038 llvm_param_values[llvm_param_i] = arg_ptr;6024 llvm_param_values[llvm_param_i] = arg_ptr;
...@@ -6533,8 +6519,7 @@ pub const FuncGen = struct {...@@ -6533,8 +6519,7 @@ pub const FuncGen = struct {
6533 const llvm_optional_ty = try self.dg.lowerType(optional_ty);6519 const llvm_optional_ty = try self.dg.lowerType(optional_ty);
6534 if (isByRef(optional_ty)) {6520 if (isByRef(optional_ty)) {
6535 const target = self.dg.module.getTarget();6521 const target = self.dg.module.getTarget();
6536 const optional_ptr = self.buildAlloca(llvm_optional_ty);6522 const optional_ptr = self.buildAlloca(llvm_optional_ty, optional_ty.abiAlignment(target));
6537 optional_ptr.setAlignment(optional_ty.abiAlignment(target));
6538 const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, "");6523 const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, "");
6539 var ptr_ty_payload: Type.Payload.ElemType = .{6524 var ptr_ty_payload: Type.Payload.ElemType = .{
6540 .base = .{ .tag = .single_mut_pointer },6525 .base = .{ .tag = .single_mut_pointer },
...@@ -6567,8 +6552,7 @@ pub const FuncGen = struct {...@@ -6567,8 +6552,7 @@ pub const FuncGen = struct {
6567 const payload_offset = errUnionPayloadOffset(payload_ty, target);6552 const payload_offset = errUnionPayloadOffset(payload_ty, target);
6568 const error_offset = errUnionErrorOffset(payload_ty, target);6553 const error_offset = errUnionErrorOffset(payload_ty, target);
6569 if (isByRef(err_un_ty)) {6554 if (isByRef(err_un_ty)) {
6570 const result_ptr = self.buildAlloca(err_un_llvm_ty);6555 const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target));
6571 result_ptr.setAlignment(err_un_ty.abiAlignment(target));
6572 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");6556 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
6573 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);6557 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);
6574 store_inst.setAlignment(Type.anyerror.abiAlignment(target));6558 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
...@@ -6602,8 +6586,7 @@ pub const FuncGen = struct {...@@ -6602,8 +6586,7 @@ pub const FuncGen = struct {
6602 const payload_offset = errUnionPayloadOffset(payload_ty, target);6586 const payload_offset = errUnionPayloadOffset(payload_ty, target);
6603 const error_offset = errUnionErrorOffset(payload_ty, target);6587 const error_offset = errUnionErrorOffset(payload_ty, target);
6604 if (isByRef(err_un_ty)) {6588 if (isByRef(err_un_ty)) {
6605 const result_ptr = self.buildAlloca(err_un_llvm_ty);6589 const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target));
6606 result_ptr.setAlignment(err_un_ty.abiAlignment(target));
6607 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");6590 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
6608 const store_inst = self.builder.buildStore(operand, err_ptr);6591 const store_inst = self.builder.buildStore(operand, err_ptr);
6609 store_inst.setAlignment(Type.anyerror.abiAlignment(target));6592 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
...@@ -7021,9 +7004,8 @@ pub const FuncGen = struct {...@@ -7021,9 +7004,8 @@ pub const FuncGen = struct {
70217004
7022 if (isByRef(dest_ty)) {7005 if (isByRef(dest_ty)) {
7023 const target = self.dg.module.getTarget();7006 const target = self.dg.module.getTarget();
7024 const alloca_inst = self.buildAlloca(llvm_dest_ty);
7025 const result_alignment = dest_ty.abiAlignment(target);7007 const result_alignment = dest_ty.abiAlignment(target);
7026 alloca_inst.setAlignment(result_alignment);7008 const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment);
7027 {7009 {
7028 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");7010 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");
7029 const store_inst = self.builder.buildStore(result, field_ptr);7011 const store_inst = self.builder.buildStore(result, field_ptr);
...@@ -7373,9 +7355,8 @@ pub const FuncGen = struct {...@@ -7373,9 +7355,8 @@ pub const FuncGen = struct {
73737355
7374 if (isByRef(dest_ty)) {7356 if (isByRef(dest_ty)) {
7375 const target = self.dg.module.getTarget();7357 const target = self.dg.module.getTarget();
7376 const alloca_inst = self.buildAlloca(llvm_dest_ty);
7377 const result_alignment = dest_ty.abiAlignment(target);7358 const result_alignment = dest_ty.abiAlignment(target);
7378 alloca_inst.setAlignment(result_alignment);7359 const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment);
7379 {7360 {
7380 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");7361 const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, "");
7381 const store_inst = self.builder.buildStore(result, field_ptr);7362 const store_inst = self.builder.buildStore(result, field_ptr);
...@@ -7653,7 +7634,7 @@ pub const FuncGen = struct {...@@ -7653,7 +7634,7 @@ pub const FuncGen = struct {
7653 if (!result_is_ref) {7634 if (!result_is_ref) {
7654 return self.dg.todo("implement bitcast vector to non-ref array", .{});7635 return self.dg.todo("implement bitcast vector to non-ref array", .{});
7655 }7636 }
7656 const array_ptr = self.buildAlloca(llvm_dest_ty);7637 const array_ptr = self.buildAlloca(llvm_dest_ty, null);
7657 const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8;7638 const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8;
7658 if (bitcast_ok) {7639 if (bitcast_ok) {
7659 const llvm_vector_ty = try self.dg.lowerType(operand_ty);7640 const llvm_vector_ty = try self.dg.lowerType(operand_ty);
...@@ -7729,8 +7710,7 @@ pub const FuncGen = struct {...@@ -7729,8 +7710,7 @@ pub const FuncGen = struct {
7729 if (result_is_ref) {7710 if (result_is_ref) {
7730 // Bitcast the result pointer, then store.7711 // Bitcast the result pointer, then store.
7731 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));7712 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
7732 const result_ptr = self.buildAlloca(llvm_dest_ty);7713 const result_ptr = self.buildAlloca(llvm_dest_ty, alignment);
7733 result_ptr.setAlignment(alignment);
7734 const operand_llvm_ty = try self.dg.lowerType(operand_ty);7714 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
7735 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");7715 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
7736 const store_inst = self.builder.buildStore(operand, casted_ptr);7716 const store_inst = self.builder.buildStore(operand, casted_ptr);
...@@ -7743,8 +7723,7 @@ pub const FuncGen = struct {...@@ -7743,8 +7723,7 @@ pub const FuncGen = struct {
7743 // but LLVM won't let us bitcast struct values.7723 // but LLVM won't let us bitcast struct values.
7744 // Therefore, we store operand to bitcasted alloca, then load for result.7724 // Therefore, we store operand to bitcasted alloca, then load for result.
7745 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));7725 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
7746 const result_ptr = self.buildAlloca(llvm_dest_ty);7726 const result_ptr = self.buildAlloca(llvm_dest_ty, alignment);
7747 result_ptr.setAlignment(alignment);
7748 const operand_llvm_ty = try self.dg.lowerType(operand_ty);7727 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
7749 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");7728 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
7750 const store_inst = self.builder.buildStore(operand, casted_ptr);7729 const store_inst = self.builder.buildStore(operand, casted_ptr);
...@@ -7820,11 +7799,9 @@ pub const FuncGen = struct {...@@ -7820,11 +7799,9 @@ pub const FuncGen = struct {
7820 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);7799 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
78217800
7822 const pointee_llvm_ty = try self.dg.lowerType(pointee_type);7801 const pointee_llvm_ty = try self.dg.lowerType(pointee_type);
7823 const alloca_inst = self.buildAlloca(pointee_llvm_ty);
7824 const target = self.dg.module.getTarget();7802 const target = self.dg.module.getTarget();
7825 const alignment = ptr_ty.ptrAlignment(target);7803 const alignment = ptr_ty.ptrAlignment(target);
7826 alloca_inst.setAlignment(alignment);7804 return self.buildAlloca(pointee_llvm_ty, alignment);
7827 return alloca_inst;
7828 }7805 }
78297806
7830 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7807 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
...@@ -7835,15 +7812,13 @@ pub const FuncGen = struct {...@@ -7835,15 +7812,13 @@ pub const FuncGen = struct {
7835 if (self.ret_ptr) |ret_ptr| return ret_ptr;7812 if (self.ret_ptr) |ret_ptr| return ret_ptr;
7836 const ret_llvm_ty = try self.dg.lowerType(ret_ty);7813 const ret_llvm_ty = try self.dg.lowerType(ret_ty);
7837 const target = self.dg.module.getTarget();7814 const target = self.dg.module.getTarget();
7838 const alloca_inst = self.buildAlloca(ret_llvm_ty);7815 return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(target));
7839 alloca_inst.setAlignment(ptr_ty.ptrAlignment(target));
7840 return alloca_inst;
7841 }7816 }
78427817
7843 /// Use this instead of builder.buildAlloca, because this function makes sure to7818 /// Use this instead of builder.buildAlloca, because this function makes sure to
7844 /// put the alloca instruction at the top of the function!7819 /// put the alloca instruction at the top of the function!
7845 fn buildAlloca(self: *FuncGen, llvm_ty: *llvm.Type) *llvm.Value {7820 fn buildAlloca(self: *FuncGen, llvm_ty: *llvm.Type, alignment: ?c_uint) *llvm.Value {
7846 return buildAllocaInner(self.builder, self.llvm_func, self.di_scope != null, llvm_ty);7821 return buildAllocaInner(self.builder, self.llvm_func, self.di_scope != null, llvm_ty, alignment, self.dg.module.getTarget());
7847 }7822 }
78487823
7849 fn airStore(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {7824 fn airStore(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
...@@ -8801,10 +8776,9 @@ pub const FuncGen = struct {...@@ -8801,10 +8776,9 @@ pub const FuncGen = struct {
88018776
8802 if (isByRef(result_ty)) {8777 if (isByRef(result_ty)) {
8803 const llvm_u32 = self.context.intType(32);8778 const llvm_u32 = self.context.intType(32);
8804 const alloca_inst = self.buildAlloca(llvm_result_ty);
8805 // TODO in debug builds init to undef so that the padding will be 0xaa8779 // TODO in debug builds init to undef so that the padding will be 0xaa
8806 // even if we fully populate the fields.8780 // even if we fully populate the fields.
8807 alloca_inst.setAlignment(result_ty.abiAlignment(target));8781 const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(target));
88088782
8809 var indices: [2]*llvm.Value = .{ llvm_u32.constNull(), undefined };8783 var indices: [2]*llvm.Value = .{ llvm_u32.constNull(), undefined };
8810 for (elements) |elem, i| {8784 for (elements) |elem, i| {
...@@ -8842,8 +8816,7 @@ pub const FuncGen = struct {...@@ -8842,8 +8816,7 @@ pub const FuncGen = struct {
8842 assert(isByRef(result_ty));8816 assert(isByRef(result_ty));
88438817
8844 const llvm_usize = try self.dg.lowerType(Type.usize);8818 const llvm_usize = try self.dg.lowerType(Type.usize);
8845 const alloca_inst = self.buildAlloca(llvm_result_ty);8819 const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(target));
8846 alloca_inst.setAlignment(result_ty.abiAlignment(target));
88478820
8848 const array_info = result_ty.arrayInfo();8821 const array_info = result_ty.arrayInfo();
8849 var elem_ptr_payload: Type.Payload.Pointer = .{8822 var elem_ptr_payload: Type.Payload.Pointer = .{
...@@ -8918,7 +8891,7 @@ pub const FuncGen = struct {...@@ -8918,7 +8891,7 @@ pub const FuncGen = struct {
8918 // necessarily match the format that we need, depending on which tag is active. We8891 // necessarily match the format that we need, depending on which tag is active. We
8919 // must construct the correct unnamed struct type here and bitcast, in order to8892 // must construct the correct unnamed struct type here and bitcast, in order to
8920 // then set the fields appropriately.8893 // then set the fields appropriately.
8921 const result_ptr = self.buildAlloca(union_llvm_ty);8894 const result_ptr = self.buildAlloca(union_llvm_ty, null);
8922 const llvm_payload = try self.resolveInst(extra.init);8895 const llvm_payload = try self.resolveInst(extra.init);
8923 assert(union_obj.haveFieldTypes());8896 assert(union_obj.haveFieldTypes());
8924 const field = union_obj.fields.values()[extra.field_index];8897 const field = union_obj.fields.values()[extra.field_index];
...@@ -9234,9 +9207,8 @@ pub const FuncGen = struct {...@@ -9234,9 +9207,8 @@ pub const FuncGen = struct {
92349207
9235 if (isByRef(optional_ty)) {9208 if (isByRef(optional_ty)) {
9236 const target = self.dg.module.getTarget();9209 const target = self.dg.module.getTarget();
9237 const alloca_inst = self.buildAlloca(optional_llvm_ty);
9238 const payload_alignment = optional_ty.abiAlignment(target);9210 const payload_alignment = optional_ty.abiAlignment(target);
9239 alloca_inst.setAlignment(payload_alignment);9211 const alloca_inst = self.buildAlloca(optional_llvm_ty, payload_alignment);
92409212
9241 {9213 {
9242 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 0, "");9214 const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 0, "");
...@@ -9360,8 +9332,7 @@ pub const FuncGen = struct {...@@ -9360,8 +9332,7 @@ pub const FuncGen = struct {
9360 if (isByRef(info.pointee_type)) {9332 if (isByRef(info.pointee_type)) {
9361 const result_align = info.pointee_type.abiAlignment(target);9333 const result_align = info.pointee_type.abiAlignment(target);
9362 const max_align = @maximum(result_align, ptr_alignment);9334 const max_align = @maximum(result_align, ptr_alignment);
9363 const result_ptr = self.buildAlloca(elem_llvm_ty);9335 const result_ptr = self.buildAlloca(elem_llvm_ty, max_align);
9364 result_ptr.setAlignment(max_align);
9365 const llvm_ptr_u8 = self.context.intType(8).pointerType(0);9336 const llvm_ptr_u8 = self.context.intType(8).pointerType(0);
9366 const llvm_usize = self.context.intType(Type.usize.intInfo(target).bits);9337 const llvm_usize = self.context.intType(Type.usize.intInfo(target).bits);
9367 const size_bytes = info.pointee_type.abiSize(target);9338 const size_bytes = info.pointee_type.abiSize(target);
...@@ -9394,8 +9365,7 @@ pub const FuncGen = struct {...@@ -9394,8 +9365,7 @@ pub const FuncGen = struct {
93949365
9395 if (isByRef(info.pointee_type)) {9366 if (isByRef(info.pointee_type)) {
9396 const result_align = info.pointee_type.abiAlignment(target);9367 const result_align = info.pointee_type.abiAlignment(target);
9397 const result_ptr = self.buildAlloca(elem_llvm_ty);9368 const result_ptr = self.buildAlloca(elem_llvm_ty, result_align);
9398 result_ptr.setAlignment(result_align);
93999369
9400 const same_size_int = self.context.intType(elem_bits);9370 const same_size_int = self.context.intType(elem_bits);
9401 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");9371 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
...@@ -9519,8 +9489,7 @@ pub const FuncGen = struct {...@@ -9519,8 +9489,7 @@ pub const FuncGen = struct {
9519 .x86_64 => {9489 .x86_64 => {
9520 const array_llvm_ty = usize_llvm_ty.arrayType(6);9490 const array_llvm_ty = usize_llvm_ty.arrayType(6);
9521 const array_ptr = fg.valgrind_client_request_array orelse a: {9491 const array_ptr = fg.valgrind_client_request_array orelse a: {
9522 const array_ptr = fg.buildAlloca(array_llvm_ty);9492 const array_ptr = fg.buildAlloca(array_llvm_ty, usize_alignment);
9523 array_ptr.setAlignment(usize_alignment);
9524 fg.valgrind_client_request_array = array_ptr;9493 fg.valgrind_client_request_array = array_ptr;
9525 break :a array_ptr;9494 break :a array_ptr;
9526 };9495 };
...@@ -9822,6 +9791,74 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca...@@ -9822,6 +9791,74 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca
9822 };9791 };
9823}9792}
98249793
9794/// Convert a zig-address space to an llvm address space.
9795fn toLlvmAddressSpace(address_space: std.builtin.AddressSpace, target: std.Target) c_uint {
9796 return switch (target.cpu.arch) {
9797 .i386, .x86_64 => switch (address_space) {
9798 .generic => llvm.address_space.default,
9799 .gs => llvm.address_space.x86.gs,
9800 .fs => llvm.address_space.x86.fs,
9801 .ss => llvm.address_space.x86.ss,
9802 else => unreachable,
9803 },
9804 .nvptx, .nvptx64 => switch (address_space) {
9805 .generic => llvm.address_space.default,
9806 .global => llvm.address_space.nvptx.global,
9807 .constant => llvm.address_space.nvptx.constant,
9808 .param => llvm.address_space.nvptx.param,
9809 .shared => llvm.address_space.nvptx.shared,
9810 .local => llvm.address_space.nvptx.local,
9811 else => unreachable,
9812 },
9813 .amdgcn => switch (address_space) {
9814 .generic => llvm.address_space.amdgpu.flat,
9815 .global => llvm.address_space.amdgpu.global,
9816 .constant => llvm.address_space.amdgpu.constant,
9817 .shared => llvm.address_space.amdgpu.local,
9818 .local => llvm.address_space.amdgpu.private,
9819 else => unreachable,
9820 },
9821 else => switch (address_space) {
9822 .generic => llvm.address_space.default,
9823 else => unreachable,
9824 },
9825 };
9826}
9827
9828/// On some targets, local values that are in the generic address space must be generated into a
9829/// different address, space and then cast back to the generic address space.
9830/// For example, on GPUs local variable declarations must be generated into the local address space.
9831/// This function returns the address space local values should be generated into.
9832fn llvmAllocaAddressSpace(target: std.Target) c_uint {
9833 return switch (target.cpu.arch) {
9834 // On amdgcn, locals should be generated into the private address space.
9835 // To make Zig not impossible to use, these are then converted to addresses in the
9836 // generic address space and treates as regular pointers. This is the way that HIP also does it.
9837 .amdgcn => llvm.address_space.amdgpu.private,
9838 else => llvm.address_space.default,
9839 };
9840}
9841
9842/// On some targets, global values that are in the generic address space must be generated into a
9843/// different address space, and then cast back to the generic address space.
9844fn llvmDefaultGlobalAddressSpace(target: std.Target) c_uint {
9845 return switch (target.cpu.arch) {
9846 // On amdgcn, globals must be explicitly allocated and uploaded so that the program can access
9847 // them.
9848 .amdgcn => llvm.address_space.amdgpu.global,
9849 else => llvm.address_space.default,
9850 };
9851}
9852
9853/// If `llvm_addrspace` is generic, convert it to the actual address space that globals
9854/// should be stored in by default.
9855fn toLlvmGlobalAddressSpace(llvm_addrspace: c_uint, target: std.Target) c_uint {
9856 return if (llvm_addrspace == llvm.address_space.default)
9857 llvmDefaultGlobalAddressSpace(target)
9858 else
9859 llvm_addrspace;
9860}
9861
9825/// Take into account 0 bit fields and padding. Returns null if an llvm9862/// Take into account 0 bit fields and padding. Returns null if an llvm
9826/// field could not be found.9863/// field could not be found.
9827/// This only happens if you want the field index of a zero sized field at9864/// This only happens if you want the field index of a zero sized field at
...@@ -10523,25 +10560,43 @@ fn buildAllocaInner(...@@ -10523,25 +10560,43 @@ fn buildAllocaInner(
10523 llvm_func: *llvm.Value,10560 llvm_func: *llvm.Value,
10524 di_scope_non_null: bool,10561 di_scope_non_null: bool,
10525 llvm_ty: *llvm.Type,10562 llvm_ty: *llvm.Type,
10563 maybe_alignment: ?c_uint,
10564 target: std.Target,
10526) *llvm.Value {10565) *llvm.Value {
10527 const prev_block = builder.getInsertBlock();10566 const address_space = llvmAllocaAddressSpace(target);
10528 const prev_debug_location = builder.getCurrentDebugLocation2();10567
10529 defer {10568 const alloca = blk: {
10530 builder.positionBuilderAtEnd(prev_block);10569 const prev_block = builder.getInsertBlock();
10531 if (di_scope_non_null) {10570 const prev_debug_location = builder.getCurrentDebugLocation2();
10532 builder.setCurrentDebugLocation2(prev_debug_location);10571 defer {
10572 builder.positionBuilderAtEnd(prev_block);
10573 if (di_scope_non_null) {
10574 builder.setCurrentDebugLocation2(prev_debug_location);
10575 }
10576 }
10577
10578 const entry_block = llvm_func.getFirstBasicBlock().?;
10579 if (entry_block.getFirstInstruction()) |first_inst| {
10580 builder.positionBuilder(entry_block, first_inst);
10581 } else {
10582 builder.positionBuilderAtEnd(entry_block);
10533 }10583 }
10584 builder.clearCurrentDebugLocation();
10585
10586 break :blk builder.buildAllocaInAddressSpace(llvm_ty, address_space, "");
10587 };
10588
10589 if (maybe_alignment) |alignment| {
10590 alloca.setAlignment(alignment);
10534 }10591 }
1053510592
10536 const entry_block = llvm_func.getFirstBasicBlock().?;10593 // The pointer returned from this function should have the generic address space,
10537 if (entry_block.getFirstInstruction()) |first_inst| {10594 // if this isn't the case then cast it to the generic address space.
10538 builder.positionBuilder(entry_block, first_inst);10595 if (address_space != llvm.address_space.default) {
10539 } else {10596 return builder.buildAddrSpaceCast(alloca, llvm_ty.pointerType(llvm.address_space.default), "");
10540 builder.positionBuilderAtEnd(entry_block);
10541 }10597 }
10542 builder.clearCurrentDebugLocation();
1054310598
10544 return builder.buildAlloca(llvm_ty, "");10599 return alloca;
10545}10600}
1054610601
10547fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u1 {10602fn 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/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);