| ... | @@ -858,71 +858,34 @@ pub const Object = struct { | ... | @@ -858,71 +858,34 @@ pub const Object = struct { |
| 858 | try args.append(aggregate); | 858 | try args.append(aggregate); |
| 859 | }, | 859 | }, |
| 860 | .multiple_llvm_ints => { | 860 | .multiple_llvm_ints => { |
| 861 | const param_ty = fn_info.param_types[it.zig_index - 1]; | | |
| 862 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; | 861 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; |
| 863 | switch (param_ty.zigTypeTag()) { | 862 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| 864 | .Struct => { | 863 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 865 | const fields = param_ty.structFields().values(); | 864 | const param_alignment = param_ty.abiAlignment(target); |
| 866 | const param_llvm_ty = try dg.lowerType(param_ty); | 865 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); |
| 867 | const param_alignment = param_ty.abiAlignment(target); | 866 | arg_ptr.setAlignment(param_alignment); |
| 868 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); | 867 | var field_types_buf: [8]*const llvm.Type = undefined; |
| 869 | arg_ptr.setAlignment(param_alignment); | 868 | const field_types = field_types_buf[0..llvm_ints.len]; |
| 870 | | 869 | for (llvm_ints) |int_bits, i| { |
| 871 | var field_i: u32 = 0; | 870 | field_types[i] = dg.context.intType(int_bits); |
| 872 | var field_offset: u32 = 0; | 871 | } |
| 873 | for (llvm_ints) |int_bits| { | 872 | const ints_llvm_ty = dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False); |
| 874 | const param = llvm_func.getParam(llvm_arg_i); | 873 | const casted_ptr = builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), ""); |
| 875 | llvm_arg_i += 1; | 874 | for (llvm_ints) |_, i_usize| { |
| 876 | | 875 | const i = @intCast(c_uint, i_usize); |
| 877 | const big_int_ty = dg.context.intType(int_bits); | 876 | const param = llvm_func.getParam(i); |
| 878 | var bits_used: u32 = 0; | 877 | const field_ptr = builder.buildStructGEP(casted_ptr, i, ""); |
| 879 | while (bits_used < int_bits) { | 878 | const store_inst = builder.buildStore(param, field_ptr); |
| 880 | const field = fields[field_i]; | 879 | store_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8); |
| 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, | | |
| 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,65 +2784,11 @@ pub const DeclGen = struct { |
| 2821 | llvm_params.appendAssumeCapacity(len_llvm_ty); | 2784 | llvm_params.appendAssumeCapacity(len_llvm_ty); |
| 2822 | }, | 2785 | }, |
| 2823 | .multiple_llvm_ints => { | 2786 | .multiple_llvm_ints => { |
| 2824 | const param_ty = fn_info.param_types[it.zig_index - 1]; | | |
| 2825 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; | 2787 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; |
| 2826 | try llvm_params.ensureUnusedCapacity(it.llvm_types_len); | 2788 | try llvm_params.ensureUnusedCapacity(it.llvm_types_len); |
| 2827 | | 2789 | for (llvm_ints) |int_bits| { |
| 2828 | // The reason we have all this logic instead of simply appending | 2790 | const big_int_ty = dg.context.intType(int_bits); |
| 2829 | // big_int_ty is for the special case of a pointer type; | 2791 | llvm_params.appendAssumeCapacity(big_int_ty); |
| 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 | }, | | |
| 2883 | } | 2792 | } |
| 2884 | }, | 2793 | }, |
| 2885 | }; | 2794 | }; |
| ... | @@ -4299,80 +4208,27 @@ pub const FuncGen = struct { | ... | @@ -4299,80 +4208,27 @@ pub const FuncGen = struct { |
| 4299 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; | 4208 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; |
| 4300 | const llvm_arg = try self.resolveInst(arg); | 4209 | const llvm_arg = try self.resolveInst(arg); |
| 4301 | const is_by_ref = isByRef(param_ty); | 4210 | const is_by_ref = isByRef(param_ty); |
| 4302 | try llvm_args.ensureUnusedCapacity(it.llvm_types_len); | 4211 | const arg_ptr = if (is_by_ref) llvm_arg else p: { |
| 4303 | switch (param_ty.zigTypeTag()) { | 4212 | const p = self.buildAlloca(llvm_arg.typeOf()); |
| 4304 | .Struct => { | 4213 | const store_inst = self.builder.buildStore(llvm_arg, p); |
| 4305 | const fields = param_ty.structFields().values(); | 4214 | store_inst.setAlignment(param_ty.abiAlignment(target)); |
| 4306 | var field_i: u32 = 0; | 4215 | break :p p; |
| 4307 | var field_offset: u32 = 0; | 4216 | }; |
| 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; | | |
| 4364 | | 4217 | |
| 4365 | bits_used += field_abi_bits; | 4218 | var field_types_buf: [8]*const llvm.Type = undefined; |
| 4366 | field_offset += field_size; | 4219 | const field_types = field_types_buf[0..llvm_ints.len]; |
| 4367 | } | 4220 | for (llvm_ints) |int_bits, i| { |
| 4368 | llvm_args.appendAssumeCapacity(int_arg); | 4221 | field_types[i] = self.dg.context.intType(int_bits); |
| 4369 | if (field_i >= fields.len) break; | 4222 | } |
| 4370 | } | 4223 | const ints_llvm_ty = self.dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False); |
| 4371 | }, | 4224 | const casted_ptr = self.builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), ""); |
| 4372 | .Union => { | 4225 | try llvm_args.ensureUnusedCapacity(it.llvm_types_len); |
| 4373 | return self.todo("airCall C calling convention on x86_64 with union argument ", .{}); | 4226 | for (llvm_ints) |_, i_usize| { |
| 4374 | }, | 4227 | const i = @intCast(c_uint, i_usize); |
| 4375 | else => unreachable, | 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 | }; |