| ... | ... | @@ -858,71 +858,34 @@ pub const Object = struct { |
| 858 | 858 | try args.append(aggregate); |
| 859 | 859 | }, |
| 860 | 860 | .multiple_llvm_ints => { |
| 861 | | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| 862 | 861 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; |
| 863 | | switch (param_ty.zigTypeTag()) { |
| 864 | | .Struct => { |
| 865 | | const fields = param_ty.structFields().values(); |
| 866 | | const param_llvm_ty = try dg.lowerType(param_ty); |
| 867 | | const param_alignment = param_ty.abiAlignment(target); |
| 868 | | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); |
| 869 | | arg_ptr.setAlignment(param_alignment); |
| 870 | | |
| 871 | | var field_i: u32 = 0; |
| 872 | | var field_offset: u32 = 0; |
| 873 | | for (llvm_ints) |int_bits| { |
| 874 | | const param = llvm_func.getParam(llvm_arg_i); |
| 875 | | llvm_arg_i += 1; |
| 876 | | |
| 877 | | const big_int_ty = dg.context.intType(int_bits); |
| 878 | | var bits_used: u32 = 0; |
| 879 | | while (bits_used < int_bits) { |
| 880 | | const field = fields[field_i]; |
| 881 | | const field_alignment = field.normalAlignment(target); |
| 882 | | const prev_offset = field_offset; |
| 883 | | field_offset = std.mem.alignForwardGeneric(u32, field_offset, field_alignment); |
| 884 | | if (field_offset > prev_offset) { |
| 885 | | // Padding counts as bits used. |
| 886 | | bits_used += (field_offset - prev_offset) * 8; |
| 887 | | if (bits_used >= int_bits) break; |
| 888 | | } |
| 889 | | const field_size = @intCast(u16, field.ty.abiSize(target)); |
| 890 | | const field_abi_bits = field_size * 8; |
| 891 | | const field_int_ty = dg.context.intType(field_abi_bits); |
| 892 | | const shifted = if (bits_used == 0) param else s: { |
| 893 | | const shift_amt = big_int_ty.constInt(bits_used, .False); |
| 894 | | break :s builder.buildLShr(param, shift_amt, ""); |
| 895 | | }; |
| 896 | | const field_as_int = builder.buildTrunc(shifted, field_int_ty, ""); |
| 897 | | var ty_buf: Type.Payload.Pointer = undefined; |
| 898 | | const llvm_i = llvmFieldIndex(param_ty, field_i, target, &ty_buf).?; |
| 899 | | const field_ptr = builder.buildStructGEP(arg_ptr, llvm_i, ""); |
| 900 | | const casted_ptr = builder.buildBitCast(field_ptr, field_int_ty.pointerType(0), ""); |
| 901 | | const store_inst = builder.buildStore(field_as_int, casted_ptr); |
| 902 | | store_inst.setAlignment(field_alignment); |
| 903 | | |
| 904 | | field_i += 1; |
| 905 | | if (field_i >= fields.len) break; |
| 906 | | |
| 907 | | bits_used += field_abi_bits; |
| 908 | | field_offset += field_size; |
| 909 | | } |
| 910 | | if (field_i >= fields.len) break; |
| 911 | | } |
| 912 | | |
| 913 | | const is_by_ref = isByRef(param_ty); |
| 914 | | const loaded = if (is_by_ref) arg_ptr else l: { |
| 915 | | const load_inst = builder.buildLoad(arg_ptr, ""); |
| 916 | | load_inst.setAlignment(param_alignment); |
| 917 | | break :l load_inst; |
| 918 | | }; |
| 919 | | try args.append(loaded); |
| 920 | | }, |
| 921 | | .Union => { |
| 922 | | @panic("TODO: LLVM backend: implement C calling convention on x86_64 with union parameter"); |
| 923 | | }, |
| 924 | | else => unreachable, |
| 862 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| 863 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 864 | const param_alignment = param_ty.abiAlignment(target); |
| 865 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); |
| 866 | arg_ptr.setAlignment(param_alignment); |
| 867 | var field_types_buf: [8]*const llvm.Type = undefined; |
| 868 | const field_types = field_types_buf[0..llvm_ints.len]; |
| 869 | for (llvm_ints) |int_bits, i| { |
| 870 | field_types[i] = dg.context.intType(int_bits); |
| 871 | } |
| 872 | const ints_llvm_ty = dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False); |
| 873 | const casted_ptr = builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), ""); |
| 874 | for (llvm_ints) |_, i_usize| { |
| 875 | const i = @intCast(c_uint, i_usize); |
| 876 | const param = llvm_func.getParam(i); |
| 877 | const field_ptr = builder.buildStructGEP(casted_ptr, i, ""); |
| 878 | const store_inst = builder.buildStore(param, field_ptr); |
| 879 | store_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8); |
| 925 | 880 | } |
| 881 | |
| 882 | const is_by_ref = isByRef(param_ty); |
| 883 | const loaded = if (is_by_ref) arg_ptr else l: { |
| 884 | const load_inst = builder.buildLoad(arg_ptr, ""); |
| 885 | load_inst.setAlignment(param_alignment); |
| 886 | break :l load_inst; |
| 887 | }; |
| 888 | try args.append(loaded); |
| 926 | 889 | }, |
| 927 | 890 | }; |
| 928 | 891 | } |
| ... | ... | @@ -2821,65 +2784,11 @@ pub const DeclGen = struct { |
| 2821 | 2784 | llvm_params.appendAssumeCapacity(len_llvm_ty); |
| 2822 | 2785 | }, |
| 2823 | 2786 | .multiple_llvm_ints => { |
| 2824 | | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| 2825 | 2787 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; |
| 2826 | 2788 | try llvm_params.ensureUnusedCapacity(it.llvm_types_len); |
| 2827 | | |
| 2828 | | // The reason we have all this logic instead of simply appending |
| 2829 | | // big_int_ty is for the special case of a pointer type; |
| 2830 | | // we want to use a pointer type instead of inttoptr at the callsites, |
| 2831 | | // which may prevent optimization. |
| 2832 | | switch (param_ty.zigTypeTag()) { |
| 2833 | | .Struct => { |
| 2834 | | const fields = param_ty.structFields().values(); |
| 2835 | | var field_i: u32 = 0; |
| 2836 | | var field_offset: u32 = 0; |
| 2837 | | llvm_arg: for (llvm_ints) |int_bits| { |
| 2838 | | const big_int_ty = dg.context.intType(int_bits); |
| 2839 | | var bits_used: u32 = 0; |
| 2840 | | while (bits_used < int_bits) { |
| 2841 | | const field = fields[field_i]; |
| 2842 | | const field_alignment = field.normalAlignment(target); |
| 2843 | | const prev_offset = field_offset; |
| 2844 | | field_offset = std.mem.alignForwardGeneric(u32, field_offset, field_alignment); |
| 2845 | | if (field_offset > prev_offset) { |
| 2846 | | // Padding counts as bits used. |
| 2847 | | bits_used += (field_offset - prev_offset) * 8; |
| 2848 | | if (bits_used >= int_bits) break; |
| 2849 | | } |
| 2850 | | const field_size = @intCast(u16, field.ty.abiSize(target)); |
| 2851 | | const field_abi_bits = field_size * 8; |
| 2852 | | |
| 2853 | | // Special case for when the entire LLVM integer represents |
| 2854 | | // one field; in this case keep the type information |
| 2855 | | // to avoid the potentially costly ptrtoint/bitcast. |
| 2856 | | if (bits_used == 0 and field_abi_bits == int_bits) { |
| 2857 | | const llvm_field_ty = try dg.lowerType(field.ty); |
| 2858 | | llvm_params.appendAssumeCapacity(llvm_field_ty); |
| 2859 | | field_i += 1; |
| 2860 | | if (field_i >= fields.len) { |
| 2861 | | break :llvm_arg; |
| 2862 | | } else { |
| 2863 | | continue :llvm_arg; |
| 2864 | | } |
| 2865 | | } |
| 2866 | | |
| 2867 | | field_i += 1; |
| 2868 | | if (field_i >= fields.len) break; |
| 2869 | | |
| 2870 | | bits_used += field_abi_bits; |
| 2871 | | field_offset += field_size; |
| 2872 | | } |
| 2873 | | llvm_params.appendAssumeCapacity(big_int_ty); |
| 2874 | | if (field_i >= fields.len) break; |
| 2875 | | } |
| 2876 | | }, |
| 2877 | | else => { |
| 2878 | | for (llvm_ints) |int_bits| { |
| 2879 | | const big_int_ty = dg.context.intType(int_bits); |
| 2880 | | llvm_params.appendAssumeCapacity(big_int_ty); |
| 2881 | | } |
| 2882 | | }, |
| 2789 | for (llvm_ints) |int_bits| { |
| 2790 | const big_int_ty = dg.context.intType(int_bits); |
| 2791 | llvm_params.appendAssumeCapacity(big_int_ty); |
| 2883 | 2792 | } |
| 2884 | 2793 | }, |
| 2885 | 2794 | }; |
| ... | ... | @@ -4299,80 +4208,27 @@ pub const FuncGen = struct { |
| 4299 | 4208 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; |
| 4300 | 4209 | const llvm_arg = try self.resolveInst(arg); |
| 4301 | 4210 | const is_by_ref = isByRef(param_ty); |
| 4302 | | try llvm_args.ensureUnusedCapacity(it.llvm_types_len); |
| 4303 | | switch (param_ty.zigTypeTag()) { |
| 4304 | | .Struct => { |
| 4305 | | const fields = param_ty.structFields().values(); |
| 4306 | | var field_i: u32 = 0; |
| 4307 | | var field_offset: u32 = 0; |
| 4308 | | for (llvm_ints) |int_bits| { |
| 4309 | | const big_int_ty = self.dg.context.intType(int_bits); |
| 4310 | | var int_arg: *const llvm.Value = undefined; |
| 4311 | | var bits_used: u32 = 0; |
| 4312 | | while (bits_used < int_bits) { |
| 4313 | | const field = fields[field_i]; |
| 4314 | | const field_alignment = field.normalAlignment(target); |
| 4315 | | const prev_offset = field_offset; |
| 4316 | | field_offset = std.mem.alignForwardGeneric(u32, field_offset, field_alignment); |
| 4317 | | if (field_offset > prev_offset) { |
| 4318 | | // Padding counts as bits used. |
| 4319 | | bits_used += (field_offset - prev_offset) * 8; |
| 4320 | | if (bits_used >= int_bits) break; |
| 4321 | | } |
| 4322 | | var ty_buf: Type.Payload.Pointer = undefined; |
| 4323 | | const llvm_i = llvmFieldIndex(param_ty, field_i, target, &ty_buf).?; |
| 4324 | | const field_size = @intCast(u16, field.ty.abiSize(target)); |
| 4325 | | const field_abi_bits = field_size * 8; |
| 4326 | | |
| 4327 | | // Special case for when the entire LLVM integer represents |
| 4328 | | // one field; in this case keep the type information |
| 4329 | | // to avoid the potentially costly ptrtoint/bitcast. |
| 4330 | | if (bits_used == 0 and field_abi_bits == int_bits) { |
| 4331 | | int_arg = if (is_by_ref) f: { |
| 4332 | | const field_ptr = self.builder.buildStructGEP(llvm_arg, llvm_i, ""); |
| 4333 | | const load_inst = self.builder.buildLoad(field_ptr, ""); |
| 4334 | | load_inst.setAlignment(field_alignment); |
| 4335 | | break :f load_inst; |
| 4336 | | } else self.builder.buildExtractValue(llvm_arg, llvm_i, ""); |
| 4337 | | field_i += 1; |
| 4338 | | break; |
| 4339 | | } |
| 4340 | | |
| 4341 | | const field_int_ty = self.dg.context.intType(field_abi_bits); |
| 4342 | | const llvm_field = if (is_by_ref) f: { |
| 4343 | | const field_ptr = self.builder.buildStructGEP(llvm_arg, llvm_i, ""); |
| 4344 | | const casted_ptr = self.builder.buildBitCast(field_ptr, field_int_ty.pointerType(0), ""); |
| 4345 | | const load_inst = self.builder.buildLoad(casted_ptr, ""); |
| 4346 | | load_inst.setAlignment(field_alignment); |
| 4347 | | break :f load_inst; |
| 4348 | | } else f: { |
| 4349 | | const llvm_field = self.builder.buildExtractValue(llvm_arg, llvm_i, ""); |
| 4350 | | break :f self.builder.buildBitCast(llvm_field, field_int_ty, ""); |
| 4351 | | }; |
| 4352 | | |
| 4353 | | const extended = self.builder.buildZExt(llvm_field, big_int_ty, ""); |
| 4354 | | if (bits_used == 0) { |
| 4355 | | int_arg = extended; |
| 4356 | | } else { |
| 4357 | | const shift_amt = big_int_ty.constInt(bits_used, .False); |
| 4358 | | const shifted = self.builder.buildShl(extended, shift_amt, ""); |
| 4359 | | int_arg = self.builder.buildOr(int_arg, shifted, ""); |
| 4360 | | } |
| 4361 | | |
| 4362 | | field_i += 1; |
| 4363 | | if (field_i >= fields.len) break; |
| 4211 | const arg_ptr = if (is_by_ref) llvm_arg else p: { |
| 4212 | const p = self.buildAlloca(llvm_arg.typeOf()); |
| 4213 | const store_inst = self.builder.buildStore(llvm_arg, p); |
| 4214 | store_inst.setAlignment(param_ty.abiAlignment(target)); |
| 4215 | break :p p; |
| 4216 | }; |
| 4364 | 4217 | |
| 4365 | | bits_used += field_abi_bits; |
| 4366 | | field_offset += field_size; |
| 4367 | | } |
| 4368 | | llvm_args.appendAssumeCapacity(int_arg); |
| 4369 | | if (field_i >= fields.len) break; |
| 4370 | | } |
| 4371 | | }, |
| 4372 | | .Union => { |
| 4373 | | return self.todo("airCall C calling convention on x86_64 with union argument ", .{}); |
| 4374 | | }, |
| 4375 | | else => unreachable, |
| 4218 | var field_types_buf: [8]*const llvm.Type = undefined; |
| 4219 | const field_types = field_types_buf[0..llvm_ints.len]; |
| 4220 | for (llvm_ints) |int_bits, i| { |
| 4221 | field_types[i] = self.dg.context.intType(int_bits); |
| 4222 | } |
| 4223 | const ints_llvm_ty = self.dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False); |
| 4224 | const casted_ptr = self.builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), ""); |
| 4225 | try llvm_args.ensureUnusedCapacity(it.llvm_types_len); |
| 4226 | for (llvm_ints) |_, i_usize| { |
| 4227 | const i = @intCast(c_uint, i_usize); |
| 4228 | const field_ptr = self.builder.buildStructGEP(casted_ptr, i, ""); |
| 4229 | const load_inst = self.builder.buildLoad(field_ptr, ""); |
| 4230 | load_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8); |
| 4231 | llvm_args.appendAssumeCapacity(load_inst); |
| 4376 | 4232 | } |
| 4377 | 4233 | }, |
| 4378 | 4234 | }; |