| ... | ... | @@ -929,8 +929,7 @@ pub const Object = struct { |
| 929 | 929 | if (isByRef(param_ty)) { |
| 930 | 930 | const alignment = param_ty.abiAlignment(target); |
| 931 | 931 | const param_llvm_ty = param.typeOf(); |
| 932 | | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); |
| 933 | | arg_ptr.setAlignment(alignment); |
| 932 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target); |
| 934 | 933 | const store_inst = builder.buildStore(param, arg_ptr); |
| 935 | 934 | store_inst.setAlignment(alignment); |
| 936 | 935 | args.appendAssumeCapacity(arg_ptr); |
| ... | ... | @@ -974,8 +973,7 @@ pub const Object = struct { |
| 974 | 973 | param_ty.abiAlignment(target), |
| 975 | 974 | dg.object.target_data.abiAlignmentOfType(int_llvm_ty), |
| 976 | 975 | ); |
| 977 | | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); |
| 978 | | arg_ptr.setAlignment(alignment); |
| 976 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target); |
| 979 | 977 | const casted_ptr = builder.buildBitCast(arg_ptr, int_ptr_llvm_ty, ""); |
| 980 | 978 | const store_inst = builder.buildStore(param, casted_ptr); |
| 981 | 979 | store_inst.setAlignment(alignment); |
| ... | ... | @@ -1026,8 +1024,7 @@ pub const Object = struct { |
| 1026 | 1024 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| 1027 | 1025 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 1028 | 1026 | const param_alignment = param_ty.abiAlignment(target); |
| 1029 | | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); |
| 1030 | | arg_ptr.setAlignment(param_alignment); |
| 1027 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, param_alignment, target); |
| 1031 | 1028 | var field_types_buf: [8]*llvm.Type = undefined; |
| 1032 | 1029 | const field_types = field_types_buf[0..llvm_ints.len]; |
| 1033 | 1030 | for (llvm_ints) |int_bits, i| { |
| ... | ... | @@ -1058,8 +1055,7 @@ pub const Object = struct { |
| 1058 | 1055 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| 1059 | 1056 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 1060 | 1057 | const param_alignment = param_ty.abiAlignment(target); |
| 1061 | | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); |
| 1062 | | arg_ptr.setAlignment(param_alignment); |
| 1058 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, param_alignment, target); |
| 1063 | 1059 | var field_types_buf: [8]*llvm.Type = undefined; |
| 1064 | 1060 | const field_types = field_types_buf[0..llvm_floats.len]; |
| 1065 | 1061 | for (llvm_floats) |float_bits, i| { |
| ... | ... | @@ -1103,8 +1099,7 @@ pub const Object = struct { |
| 1103 | 1099 | llvm_arg_i += 1; |
| 1104 | 1100 | |
| 1105 | 1101 | const alignment = param_ty.abiAlignment(target); |
| 1106 | | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); |
| 1107 | | arg_ptr.setAlignment(alignment); |
| 1102 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty, alignment, target); |
| 1108 | 1103 | const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), ""); |
| 1109 | 1104 | _ = builder.buildStore(param, casted_ptr); |
| 1110 | 1105 | |
| ... | ... | @@ -2404,21 +2399,27 @@ pub const DeclGen = struct { |
| 2404 | 2399 | // mismatch, because we don't have the LLVM type until the *value* is created, |
| 2405 | 2400 | // whereas the global needs to be created based on the type alone, because |
| 2406 | 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 | 2404 | const new_global = dg.object.llvm_module.addGlobalInAddressSpace( |
| 2408 | 2405 | llvm_init.typeOf(), |
| 2409 | 2406 | "", |
| 2410 | | dg.llvmAddressSpace(decl.@"addrspace"), |
| 2407 | llvm_global_addrspace, |
| 2411 | 2408 | ); |
| 2412 | 2409 | new_global.setLinkage(global.getLinkage()); |
| 2413 | 2410 | new_global.setUnnamedAddr(global.getUnnamedAddress()); |
| 2414 | 2411 | new_global.setAlignment(global.getAlignment()); |
| 2415 | 2412 | if (decl.@"linksection") |section| new_global.setSection(section); |
| 2416 | 2413 | new_global.setInitializer(llvm_init); |
| 2417 | | // replaceAllUsesWith requires the type to be unchanged. So we bitcast |
| 2414 | // replaceAllUsesWith requires the type to be unchanged. So we convert |
| 2418 | 2415 | // the new global to the old type and use that as the thing to replace |
| 2419 | 2416 | // old uses. |
| 2420 | | const new_global_ptr = new_global.constBitCast(global.typeOf()); |
| 2421 | | global.replaceAllUsesWith(new_global_ptr); |
| 2417 | const new_global_ptr = if (llvm_addrspace != llvm_global_addrspace) |
| 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 | 2423 | dg.object.decl_map.putAssumeCapacity(decl_index, new_global); |
| 2423 | 2424 | new_global.takeName(global); |
| 2424 | 2425 | global.deleteGlobal(); |
| ... | ... | @@ -2465,7 +2466,7 @@ pub const DeclGen = struct { |
| 2465 | 2466 | const fqn = try decl.getFullyQualifiedName(dg.module); |
| 2466 | 2467 | defer dg.gpa.free(fqn); |
| 2467 | 2468 | |
| 2468 | | const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace"); |
| 2469 | const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); |
| 2469 | 2470 | const llvm_fn = dg.llvmModule().addFunctionInAddressSpace(fqn, fn_type, llvm_addrspace); |
| 2470 | 2471 | gop.value_ptr.* = llvm_fn; |
| 2471 | 2472 | |
| ... | ... | @@ -2613,9 +2614,15 @@ pub const DeclGen = struct { |
| 2613 | 2614 | const fqn = try decl.getFullyQualifiedName(dg.module); |
| 2614 | 2615 | defer dg.gpa.free(fqn); |
| 2615 | 2616 | |
| 2617 | const target = dg.module.getTarget(); |
| 2618 | |
| 2616 | 2619 | const llvm_type = try dg.lowerType(decl.ty); |
| 2617 | | const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace"); |
| 2618 | | const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace); |
| 2620 | const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); |
| 2621 | const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace( |
| 2622 | llvm_type, |
| 2623 | fqn, |
| 2624 | toLlvmGlobalAddressSpace(llvm_addrspace, target), |
| 2625 | ); |
| 2619 | 2626 | gop.value_ptr.* = llvm_global; |
| 2620 | 2627 | |
| 2621 | 2628 | // This is needed for declarations created by `@extern`. |
| ... | ... | @@ -2640,40 +2647,6 @@ pub const DeclGen = struct { |
| 2640 | 2647 | return llvm_global; |
| 2641 | 2648 | } |
| 2642 | 2649 | |
| 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 | 2650 | fn isUnnamedType(dg: *DeclGen, ty: Type, val: *llvm.Value) bool { |
| 2678 | 2651 | // Once `lowerType` succeeds, successive calls to it with the same Zig type |
| 2679 | 2652 | // are guaranteed to succeed. So if a call to `lowerType` fails here it means |
| ... | ... | @@ -2739,7 +2712,7 @@ pub const DeclGen = struct { |
| 2739 | 2712 | return dg.context.structType(&fields, fields.len, .False); |
| 2740 | 2713 | } |
| 2741 | 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 | 2716 | if (ptr_info.host_size != 0) { |
| 2744 | 2717 | return dg.context.intType(ptr_info.host_size * 8).pointerType(llvm_addrspace); |
| 2745 | 2718 | } |
| ... | ... | @@ -3268,11 +3241,18 @@ pub const DeclGen = struct { |
| 3268 | 3241 | const decl_index = tv.val.castTag(.variable).?.data.owner_decl; |
| 3269 | 3242 | const decl = dg.module.declPtr(decl_index); |
| 3270 | 3243 | dg.module.markDeclAlive(decl); |
| 3271 | | const val = try dg.resolveGlobalDecl(decl_index); |
| 3272 | 3244 | const llvm_var_type = try dg.lowerType(tv.ty); |
| 3273 | | const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace"); |
| 3274 | | const llvm_type = llvm_var_type.pointerType(llvm_addrspace); |
| 3275 | | return val.constBitCast(llvm_type); |
| 3245 | const llvm_var_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); |
| 3246 | const llvm_global_addrspace = toLlvmGlobalAddressSpace(llvm_var_addrspace, target); |
| 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 | 3257 | .slice => { |
| 3278 | 3258 | const slice = tv.val.castTag(.slice).?.data; |
| ... | ... | @@ -4069,11 +4049,20 @@ pub const DeclGen = struct { |
| 4069 | 4049 | |
| 4070 | 4050 | self.module.markDeclAlive(decl); |
| 4071 | 4051 | |
| 4072 | | const llvm_val = if (is_fn_body) |
| 4052 | const llvm_decl_val = if (is_fn_body) |
| 4073 | 4053 | try self.resolveLlvmFunction(decl_index) |
| 4074 | 4054 | else |
| 4075 | 4055 | try self.resolveGlobalDecl(decl_index); |
| 4076 | 4056 | |
| 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 | 4066 | const llvm_type = try self.lowerType(tv.ty); |
| 4078 | 4067 | if (tv.ty.zigTypeTag() == .Int) { |
| 4079 | 4068 | return llvm_val.constPtrToInt(llvm_type); |
| ... | ... | @@ -4339,7 +4328,9 @@ pub const FuncGen = struct { |
| 4339 | 4328 | // We have an LLVM value but we need to create a global constant and |
| 4340 | 4329 | // set the value as its initializer, and then return a pointer to the global. |
| 4341 | 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 | 4334 | global.setInitializer(llvm_val); |
| 4344 | 4335 | global.setLinkage(.Private); |
| 4345 | 4336 | global.setGlobalConstant(.True); |
| ... | ... | @@ -4349,8 +4340,10 @@ pub const FuncGen = struct { |
| 4349 | 4340 | // the type of global constants might not match the type it is supposed to |
| 4350 | 4341 | // be, and so we must bitcast the pointer at the usage sites. |
| 4351 | 4342 | const wanted_llvm_ty = try self.dg.lowerType(ty); |
| 4352 | | const wanted_llvm_ptr_ty = wanted_llvm_ty.pointerType(0); |
| 4353 | | const casted_ptr = global.constBitCast(wanted_llvm_ptr_ty); |
| 4343 | const wanted_bitcasted_llvm_ptr_ty = wanted_llvm_ty.pointerType(llvm_global_addrspace); |
| 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 | 4347 | gop.value_ptr.* = casted_ptr; |
| 4355 | 4348 | return casted_ptr; |
| 4356 | 4349 | } |
| ... | ... | @@ -4606,8 +4599,7 @@ pub const FuncGen = struct { |
| 4606 | 4599 | |
| 4607 | 4600 | const ret_ptr = if (!sret) null else blk: { |
| 4608 | 4601 | const llvm_ret_ty = try self.dg.lowerType(return_type); |
| 4609 | | const ret_ptr = self.buildAlloca(llvm_ret_ty); |
| 4610 | | ret_ptr.setAlignment(return_type.abiAlignment(target)); |
| 4602 | const ret_ptr = self.buildAlloca(llvm_ret_ty, return_type.abiAlignment(target)); |
| 4611 | 4603 | try llvm_args.append(ret_ptr); |
| 4612 | 4604 | break :blk ret_ptr; |
| 4613 | 4605 | }; |
| ... | ... | @@ -4654,8 +4646,7 @@ pub const FuncGen = struct { |
| 4654 | 4646 | } else { |
| 4655 | 4647 | const alignment = param_ty.abiAlignment(target); |
| 4656 | 4648 | const param_llvm_ty = llvm_arg.typeOf(); |
| 4657 | | const arg_ptr = self.buildAlloca(param_llvm_ty); |
| 4658 | | arg_ptr.setAlignment(alignment); |
| 4649 | const arg_ptr = self.buildAlloca(param_llvm_ty, alignment); |
| 4659 | 4650 | const store_inst = self.builder.buildStore(llvm_arg, arg_ptr); |
| 4660 | 4651 | store_inst.setAlignment(alignment); |
| 4661 | 4652 | try llvm_args.append(arg_ptr); |
| ... | ... | @@ -4682,8 +4673,7 @@ pub const FuncGen = struct { |
| 4682 | 4673 | param_ty.abiAlignment(target), |
| 4683 | 4674 | self.dg.object.target_data.abiAlignmentOfType(int_llvm_ty), |
| 4684 | 4675 | ); |
| 4685 | | const int_ptr = self.buildAlloca(int_llvm_ty); |
| 4686 | | int_ptr.setAlignment(alignment); |
| 4676 | const int_ptr = self.buildAlloca(int_llvm_ty, alignment); |
| 4687 | 4677 | const param_llvm_ty = try self.dg.lowerType(param_ty); |
| 4688 | 4678 | const casted_ptr = self.builder.buildBitCast(int_ptr, param_llvm_ty.pointerType(0), ""); |
| 4689 | 4679 | const store_inst = self.builder.buildStore(llvm_arg, casted_ptr); |
| ... | ... | @@ -4709,7 +4699,7 @@ pub const FuncGen = struct { |
| 4709 | 4699 | const llvm_arg = try self.resolveInst(arg); |
| 4710 | 4700 | const is_by_ref = isByRef(param_ty); |
| 4711 | 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 | 4703 | const store_inst = self.builder.buildStore(llvm_arg, p); |
| 4714 | 4704 | store_inst.setAlignment(param_ty.abiAlignment(target)); |
| 4715 | 4705 | break :p p; |
| ... | ... | @@ -4738,7 +4728,7 @@ pub const FuncGen = struct { |
| 4738 | 4728 | const llvm_arg = try self.resolveInst(arg); |
| 4739 | 4729 | const is_by_ref = isByRef(param_ty); |
| 4740 | 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 | 4732 | const store_inst = self.builder.buildStore(llvm_arg, p); |
| 4743 | 4733 | store_inst.setAlignment(param_ty.abiAlignment(target)); |
| 4744 | 4734 | break :p p; |
| ... | ... | @@ -4775,7 +4765,7 @@ pub const FuncGen = struct { |
| 4775 | 4765 | const arg_ty = self.air.typeOf(arg); |
| 4776 | 4766 | var llvm_arg = try self.resolveInst(arg); |
| 4777 | 4767 | if (!isByRef(arg_ty)) { |
| 4778 | | const p = self.buildAlloca(llvm_arg.typeOf()); |
| 4768 | const p = self.buildAlloca(llvm_arg.typeOf(), null); |
| 4779 | 4769 | const store_inst = self.builder.buildStore(llvm_arg, p); |
| 4780 | 4770 | store_inst.setAlignment(arg_ty.abiAlignment(target)); |
| 4781 | 4771 | llvm_arg = store_inst; |
| ... | ... | @@ -4832,9 +4822,8 @@ pub const FuncGen = struct { |
| 4832 | 4822 | // In this case the function return type is honoring the calling convention by having |
| 4833 | 4823 | // a different LLVM type than the usual one. We solve this here at the callsite |
| 4834 | 4824 | // by bitcasting a pointer to our canonical type, then loading it if necessary. |
| 4835 | | const rp = self.buildAlloca(llvm_ret_ty); |
| 4836 | 4825 | const alignment = return_type.abiAlignment(target); |
| 4837 | | rp.setAlignment(alignment); |
| 4826 | const rp = self.buildAlloca(llvm_ret_ty, alignment); |
| 4838 | 4827 | const ptr_abi_ty = abi_ret_ty.pointerType(0); |
| 4839 | 4828 | const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, ""); |
| 4840 | 4829 | const store_inst = self.builder.buildStore(call, casted_ptr); |
| ... | ... | @@ -4851,9 +4840,8 @@ pub const FuncGen = struct { |
| 4851 | 4840 | if (isByRef(return_type)) { |
| 4852 | 4841 | // our by-ref status disagrees with sret so we must allocate, store, |
| 4853 | 4842 | // and return the allocation pointer. |
| 4854 | | const rp = self.buildAlloca(llvm_ret_ty); |
| 4855 | 4843 | const alignment = return_type.abiAlignment(target); |
| 4856 | | rp.setAlignment(alignment); |
| 4844 | const rp = self.buildAlloca(llvm_ret_ty, alignment); |
| 4857 | 4845 | const store_inst = self.builder.buildStore(call, rp); |
| 4858 | 4846 | store_inst.setAlignment(alignment); |
| 4859 | 4847 | return rp; |
| ... | ... | @@ -4912,8 +4900,7 @@ pub const FuncGen = struct { |
| 4912 | 4900 | return null; |
| 4913 | 4901 | } |
| 4914 | 4902 | |
| 4915 | | const rp = self.buildAlloca(llvm_ret_ty); |
| 4916 | | rp.setAlignment(alignment); |
| 4903 | const rp = self.buildAlloca(llvm_ret_ty, alignment); |
| 4917 | 4904 | const store_inst = self.builder.buildStore(operand, rp); |
| 4918 | 4905 | store_inst.setAlignment(alignment); |
| 4919 | 4906 | const casted_ptr = self.builder.buildBitCast(rp, ptr_abi_ty, ""); |
| ... | ... | @@ -6031,8 +6018,7 @@ pub const FuncGen = struct { |
| 6031 | 6018 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf(); |
| 6032 | 6019 | } else { |
| 6033 | 6020 | const alignment = arg_ty.abiAlignment(target); |
| 6034 | | const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf()); |
| 6035 | | arg_ptr.setAlignment(alignment); |
| 6021 | const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf(), alignment); |
| 6036 | 6022 | const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr); |
| 6037 | 6023 | store_inst.setAlignment(alignment); |
| 6038 | 6024 | llvm_param_values[llvm_param_i] = arg_ptr; |
| ... | ... | @@ -6533,8 +6519,7 @@ pub const FuncGen = struct { |
| 6533 | 6519 | const llvm_optional_ty = try self.dg.lowerType(optional_ty); |
| 6534 | 6520 | if (isByRef(optional_ty)) { |
| 6535 | 6521 | const target = self.dg.module.getTarget(); |
| 6536 | | const optional_ptr = self.buildAlloca(llvm_optional_ty); |
| 6537 | | optional_ptr.setAlignment(optional_ty.abiAlignment(target)); |
| 6522 | const optional_ptr = self.buildAlloca(llvm_optional_ty, optional_ty.abiAlignment(target)); |
| 6538 | 6523 | const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, ""); |
| 6539 | 6524 | var ptr_ty_payload: Type.Payload.ElemType = .{ |
| 6540 | 6525 | .base = .{ .tag = .single_mut_pointer }, |
| ... | ... | @@ -6567,8 +6552,7 @@ pub const FuncGen = struct { |
| 6567 | 6552 | const payload_offset = errUnionPayloadOffset(payload_ty, target); |
| 6568 | 6553 | const error_offset = errUnionErrorOffset(payload_ty, target); |
| 6569 | 6554 | if (isByRef(err_un_ty)) { |
| 6570 | | const result_ptr = self.buildAlloca(err_un_llvm_ty); |
| 6571 | | result_ptr.setAlignment(err_un_ty.abiAlignment(target)); |
| 6555 | const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target)); |
| 6572 | 6556 | const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, ""); |
| 6573 | 6557 | const store_inst = self.builder.buildStore(ok_err_code, err_ptr); |
| 6574 | 6558 | store_inst.setAlignment(Type.anyerror.abiAlignment(target)); |
| ... | ... | @@ -6602,8 +6586,7 @@ pub const FuncGen = struct { |
| 6602 | 6586 | const payload_offset = errUnionPayloadOffset(payload_ty, target); |
| 6603 | 6587 | const error_offset = errUnionErrorOffset(payload_ty, target); |
| 6604 | 6588 | if (isByRef(err_un_ty)) { |
| 6605 | | const result_ptr = self.buildAlloca(err_un_llvm_ty); |
| 6606 | | result_ptr.setAlignment(err_un_ty.abiAlignment(target)); |
| 6589 | const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target)); |
| 6607 | 6590 | const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, ""); |
| 6608 | 6591 | const store_inst = self.builder.buildStore(operand, err_ptr); |
| 6609 | 6592 | store_inst.setAlignment(Type.anyerror.abiAlignment(target)); |
| ... | ... | @@ -7021,9 +7004,8 @@ pub const FuncGen = struct { |
| 7021 | 7004 | |
| 7022 | 7005 | if (isByRef(dest_ty)) { |
| 7023 | 7006 | const target = self.dg.module.getTarget(); |
| 7024 | | const alloca_inst = self.buildAlloca(llvm_dest_ty); |
| 7025 | 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 | 7010 | const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, ""); |
| 7029 | 7011 | const store_inst = self.builder.buildStore(result, field_ptr); |
| ... | ... | @@ -7373,9 +7355,8 @@ pub const FuncGen = struct { |
| 7373 | 7355 | |
| 7374 | 7356 | if (isByRef(dest_ty)) { |
| 7375 | 7357 | const target = self.dg.module.getTarget(); |
| 7376 | | const alloca_inst = self.buildAlloca(llvm_dest_ty); |
| 7377 | 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 | 7361 | const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, ""); |
| 7381 | 7362 | const store_inst = self.builder.buildStore(result, field_ptr); |
| ... | ... | @@ -7653,7 +7634,7 @@ pub const FuncGen = struct { |
| 7653 | 7634 | if (!result_is_ref) { |
| 7654 | 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 | 7638 | const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8; |
| 7658 | 7639 | if (bitcast_ok) { |
| 7659 | 7640 | const llvm_vector_ty = try self.dg.lowerType(operand_ty); |
| ... | ... | @@ -7729,8 +7710,7 @@ pub const FuncGen = struct { |
| 7729 | 7710 | if (result_is_ref) { |
| 7730 | 7711 | // Bitcast the result pointer, then store. |
| 7731 | 7712 | const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target)); |
| 7732 | | const result_ptr = self.buildAlloca(llvm_dest_ty); |
| 7733 | | result_ptr.setAlignment(alignment); |
| 7713 | const result_ptr = self.buildAlloca(llvm_dest_ty, alignment); |
| 7734 | 7714 | const operand_llvm_ty = try self.dg.lowerType(operand_ty); |
| 7735 | 7715 | const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), ""); |
| 7736 | 7716 | const store_inst = self.builder.buildStore(operand, casted_ptr); |
| ... | ... | @@ -7743,8 +7723,7 @@ pub const FuncGen = struct { |
| 7743 | 7723 | // but LLVM won't let us bitcast struct values. |
| 7744 | 7724 | // Therefore, we store operand to bitcasted alloca, then load for result. |
| 7745 | 7725 | const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target)); |
| 7746 | | const result_ptr = self.buildAlloca(llvm_dest_ty); |
| 7747 | | result_ptr.setAlignment(alignment); |
| 7726 | const result_ptr = self.buildAlloca(llvm_dest_ty, alignment); |
| 7748 | 7727 | const operand_llvm_ty = try self.dg.lowerType(operand_ty); |
| 7749 | 7728 | const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), ""); |
| 7750 | 7729 | const store_inst = self.builder.buildStore(operand, casted_ptr); |
| ... | ... | @@ -7820,11 +7799,9 @@ pub const FuncGen = struct { |
| 7820 | 7799 | if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty); |
| 7821 | 7800 | |
| 7822 | 7801 | const pointee_llvm_ty = try self.dg.lowerType(pointee_type); |
| 7823 | | const alloca_inst = self.buildAlloca(pointee_llvm_ty); |
| 7824 | 7802 | const target = self.dg.module.getTarget(); |
| 7825 | 7803 | const alignment = ptr_ty.ptrAlignment(target); |
| 7826 | | alloca_inst.setAlignment(alignment); |
| 7827 | | return alloca_inst; |
| 7804 | return self.buildAlloca(pointee_llvm_ty, alignment); |
| 7828 | 7805 | } |
| 7829 | 7806 | |
| 7830 | 7807 | fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | ... | @@ -7835,15 +7812,13 @@ pub const FuncGen = struct { |
| 7835 | 7812 | if (self.ret_ptr) |ret_ptr| return ret_ptr; |
| 7836 | 7813 | const ret_llvm_ty = try self.dg.lowerType(ret_ty); |
| 7837 | 7814 | const target = self.dg.module.getTarget(); |
| 7838 | | const alloca_inst = self.buildAlloca(ret_llvm_ty); |
| 7839 | | alloca_inst.setAlignment(ptr_ty.ptrAlignment(target)); |
| 7840 | | return alloca_inst; |
| 7815 | return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(target)); |
| 7841 | 7816 | } |
| 7842 | 7817 | |
| 7843 | 7818 | /// Use this instead of builder.buildAlloca, because this function makes sure to |
| 7844 | 7819 | /// put the alloca instruction at the top of the function! |
| 7845 | | fn buildAlloca(self: *FuncGen, llvm_ty: *llvm.Type) *llvm.Value { |
| 7846 | | return buildAllocaInner(self.builder, self.llvm_func, self.di_scope != null, llvm_ty); |
| 7820 | fn buildAlloca(self: *FuncGen, llvm_ty: *llvm.Type, alignment: ?c_uint) *llvm.Value { |
| 7821 | return buildAllocaInner(self.builder, self.llvm_func, self.di_scope != null, llvm_ty, alignment, self.dg.module.getTarget()); |
| 7847 | 7822 | } |
| 7848 | 7823 | |
| 7849 | 7824 | fn airStore(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| ... | ... | @@ -8801,10 +8776,9 @@ pub const FuncGen = struct { |
| 8801 | 8776 | |
| 8802 | 8777 | if (isByRef(result_ty)) { |
| 8803 | 8778 | const llvm_u32 = self.context.intType(32); |
| 8804 | | const alloca_inst = self.buildAlloca(llvm_result_ty); |
| 8805 | 8779 | // TODO in debug builds init to undef so that the padding will be 0xaa |
| 8806 | 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)); |
| 8808 | 8782 | |
| 8809 | 8783 | var indices: [2]*llvm.Value = .{ llvm_u32.constNull(), undefined }; |
| 8810 | 8784 | for (elements) |elem, i| { |
| ... | ... | @@ -8842,8 +8816,7 @@ pub const FuncGen = struct { |
| 8842 | 8816 | assert(isByRef(result_ty)); |
| 8843 | 8817 | |
| 8844 | 8818 | const llvm_usize = try self.dg.lowerType(Type.usize); |
| 8845 | | const alloca_inst = self.buildAlloca(llvm_result_ty); |
| 8846 | | alloca_inst.setAlignment(result_ty.abiAlignment(target)); |
| 8819 | const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(target)); |
| 8847 | 8820 | |
| 8848 | 8821 | const array_info = result_ty.arrayInfo(); |
| 8849 | 8822 | var elem_ptr_payload: Type.Payload.Pointer = .{ |
| ... | ... | @@ -8918,7 +8891,7 @@ pub const FuncGen = struct { |
| 8918 | 8891 | // necessarily match the format that we need, depending on which tag is active. We |
| 8919 | 8892 | // must construct the correct unnamed struct type here and bitcast, in order to |
| 8920 | 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 | 8895 | const llvm_payload = try self.resolveInst(extra.init); |
| 8923 | 8896 | assert(union_obj.haveFieldTypes()); |
| 8924 | 8897 | const field = union_obj.fields.values()[extra.field_index]; |
| ... | ... | @@ -9234,9 +9207,8 @@ pub const FuncGen = struct { |
| 9234 | 9207 | |
| 9235 | 9208 | if (isByRef(optional_ty)) { |
| 9236 | 9209 | const target = self.dg.module.getTarget(); |
| 9237 | | const alloca_inst = self.buildAlloca(optional_llvm_ty); |
| 9238 | 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); |
| 9240 | 9212 | |
| 9241 | 9213 | { |
| 9242 | 9214 | const field_ptr = self.builder.buildStructGEP(optional_llvm_ty, alloca_inst, 0, ""); |
| ... | ... | @@ -9360,8 +9332,7 @@ pub const FuncGen = struct { |
| 9360 | 9332 | if (isByRef(info.pointee_type)) { |
| 9361 | 9333 | const result_align = info.pointee_type.abiAlignment(target); |
| 9362 | 9334 | const max_align = @maximum(result_align, ptr_alignment); |
| 9363 | | const result_ptr = self.buildAlloca(elem_llvm_ty); |
| 9364 | | result_ptr.setAlignment(max_align); |
| 9335 | const result_ptr = self.buildAlloca(elem_llvm_ty, max_align); |
| 9365 | 9336 | const llvm_ptr_u8 = self.context.intType(8).pointerType(0); |
| 9366 | 9337 | const llvm_usize = self.context.intType(Type.usize.intInfo(target).bits); |
| 9367 | 9338 | const size_bytes = info.pointee_type.abiSize(target); |
| ... | ... | @@ -9394,8 +9365,7 @@ pub const FuncGen = struct { |
| 9394 | 9365 | |
| 9395 | 9366 | if (isByRef(info.pointee_type)) { |
| 9396 | 9367 | const result_align = info.pointee_type.abiAlignment(target); |
| 9397 | | const result_ptr = self.buildAlloca(elem_llvm_ty); |
| 9398 | | result_ptr.setAlignment(result_align); |
| 9368 | const result_ptr = self.buildAlloca(elem_llvm_ty, result_align); |
| 9399 | 9369 | |
| 9400 | 9370 | const same_size_int = self.context.intType(elem_bits); |
| 9401 | 9371 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); |
| ... | ... | @@ -9519,8 +9489,7 @@ pub const FuncGen = struct { |
| 9519 | 9489 | .x86_64 => { |
| 9520 | 9490 | const array_llvm_ty = usize_llvm_ty.arrayType(6); |
| 9521 | 9491 | const array_ptr = fg.valgrind_client_request_array orelse a: { |
| 9522 | | const array_ptr = fg.buildAlloca(array_llvm_ty); |
| 9523 | | array_ptr.setAlignment(usize_alignment); |
| 9492 | const array_ptr = fg.buildAlloca(array_llvm_ty, usize_alignment); |
| 9524 | 9493 | fg.valgrind_client_request_array = array_ptr; |
| 9525 | 9494 | break :a array_ptr; |
| 9526 | 9495 | }; |
| ... | ... | @@ -9822,6 +9791,74 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca |
| 9822 | 9791 | }; |
| 9823 | 9792 | } |
| 9824 | 9793 | |
| 9794 | /// Convert a zig-address space to an llvm address space. |
| 9795 | fn 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. |
| 9832 | fn 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. |
| 9844 | fn 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. |
| 9855 | fn 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 | 9862 | /// Take into account 0 bit fields and padding. Returns null if an llvm |
| 9826 | 9863 | /// field could not be found. |
| 9827 | 9864 | /// This only happens if you want the field index of a zero sized field at |
| ... | ... | @@ -10523,25 +10560,43 @@ fn buildAllocaInner( |
| 10523 | 10560 | llvm_func: *llvm.Value, |
| 10524 | 10561 | di_scope_non_null: bool, |
| 10525 | 10562 | llvm_ty: *llvm.Type, |
| 10563 | maybe_alignment: ?c_uint, |
| 10564 | target: std.Target, |
| 10526 | 10565 | ) *llvm.Value { |
| 10527 | | const prev_block = builder.getInsertBlock(); |
| 10528 | | const prev_debug_location = builder.getCurrentDebugLocation2(); |
| 10529 | | defer { |
| 10530 | | builder.positionBuilderAtEnd(prev_block); |
| 10531 | | if (di_scope_non_null) { |
| 10532 | | builder.setCurrentDebugLocation2(prev_debug_location); |
| 10566 | const address_space = llvmAllocaAddressSpace(target); |
| 10567 | |
| 10568 | const alloca = blk: { |
| 10569 | const prev_block = builder.getInsertBlock(); |
| 10570 | const prev_debug_location = builder.getCurrentDebugLocation2(); |
| 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 | } |
| 10535 | 10592 | |
| 10536 | | const entry_block = llvm_func.getFirstBasicBlock().?; |
| 10537 | | if (entry_block.getFirstInstruction()) |first_inst| { |
| 10538 | | builder.positionBuilder(entry_block, first_inst); |
| 10539 | | } else { |
| 10540 | | builder.positionBuilderAtEnd(entry_block); |
| 10593 | // The pointer returned from this function should have the generic address space, |
| 10594 | // if this isn't the case then cast it to the generic address space. |
| 10595 | if (address_space != llvm.address_space.default) { |
| 10596 | return builder.buildAddrSpaceCast(alloca, llvm_ty.pointerType(llvm.address_space.default), ""); |
| 10541 | 10597 | } |
| 10542 | | builder.clearCurrentDebugLocation(); |
| 10543 | 10598 | |
| 10544 | | return builder.buildAlloca(llvm_ty, ""); |
| 10599 | return alloca; |
| 10545 | 10600 | } |
| 10546 | 10601 | |
| 10547 | 10602 | fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u1 { |