| ... | ... | @@ -860,61 +860,63 @@ pub const Object = struct { |
| 860 | 860 | .multiple_llvm_ints => { |
| 861 | 861 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| 862 | 862 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; |
| 863 | | const is_by_ref = isByRef(param_ty); |
| 864 | 863 | switch (param_ty.zigTypeTag()) { |
| 865 | 864 | .Struct => { |
| 866 | 865 | const fields = param_ty.structFields().values(); |
| 867 | | if (is_by_ref) { |
| 868 | | const param_llvm_ty = try dg.lowerType(param_ty); |
| 869 | | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); |
| 870 | | arg_ptr.setAlignment(param_ty.abiAlignment(target)); |
| 871 | | |
| 872 | | var field_i: u32 = 0; |
| 873 | | var field_offset: u32 = 0; |
| 874 | | for (llvm_ints) |int_bits| { |
| 875 | | const param = llvm_func.getParam(llvm_arg_i); |
| 876 | | llvm_arg_i += 1; |
| 877 | | |
| 878 | | const big_int_ty = dg.context.intType(int_bits); |
| 879 | | var bits_used: u32 = 0; |
| 880 | | while (bits_used < int_bits) { |
| 881 | | const field = fields[field_i]; |
| 882 | | const field_alignment = field.normalAlignment(target); |
| 883 | | const prev_offset = field_offset; |
| 884 | | field_offset = std.mem.alignForwardGeneric(u32, field_offset, field_alignment); |
| 885 | | if (field_offset > prev_offset) { |
| 886 | | // Padding counts as bits used. |
| 887 | | bits_used += (field_offset - prev_offset) * 8; |
| 888 | | if (bits_used >= int_bits) break; |
| 889 | | } |
| 890 | | const field_size = @intCast(u16, field.ty.abiSize(target)); |
| 891 | | const field_abi_bits = field_size * 8; |
| 892 | | const field_int_ty = dg.context.intType(field_abi_bits); |
| 893 | | const shifted = if (bits_used == 0) param else s: { |
| 894 | | const shift_amt = big_int_ty.constInt(bits_used, .False); |
| 895 | | break :s builder.buildLShr(param, shift_amt, ""); |
| 896 | | }; |
| 897 | | const field_as_int = builder.buildTrunc(shifted, field_int_ty, ""); |
| 898 | | var ty_buf: Type.Payload.Pointer = undefined; |
| 899 | | const llvm_i = llvmFieldIndex(param_ty, field_i, target, &ty_buf).?; |
| 900 | | const field_ptr = builder.buildStructGEP(arg_ptr, llvm_i, ""); |
| 901 | | const casted_ptr = builder.buildBitCast(field_ptr, field_int_ty.pointerType(0), ""); |
| 902 | | const store_inst = builder.buildStore(field_as_int, casted_ptr); |
| 903 | | store_inst.setAlignment(field_alignment); |
| 904 | | |
| 905 | | field_i += 1; |
| 906 | | if (field_i >= fields.len) break; |
| 907 | | |
| 908 | | bits_used += field_abi_bits; |
| 909 | | field_offset += field_size; |
| 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; |
| 910 | 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; |
| 911 | 905 | if (field_i >= fields.len) break; |
| 912 | | } |
| 913 | 906 | |
| 914 | | try args.append(arg_ptr); |
| 915 | | } else { |
| 916 | | @panic("TODO: LLVM backend: implement C calling convention on x86_64 with byval struct parameter"); |
| 907 | bits_used += field_abi_bits; |
| 908 | field_offset += field_size; |
| 909 | } |
| 910 | if (field_i >= fields.len) break; |
| 917 | 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); |
| 918 | 920 | }, |
| 919 | 921 | .Union => { |
| 920 | 922 | @panic("TODO: LLVM backend: implement C calling convention on x86_64 with union parameter"); |