| ... | @@ -860,61 +860,63 @@ pub const Object = struct { | ... | @@ -860,61 +860,63 @@ pub const Object = struct { |
| 860 | .multiple_llvm_ints => { | 860 | .multiple_llvm_ints => { |
| 861 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 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]; | 862 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; |
| 863 | const is_by_ref = isByRef(param_ty); | | |
| 864 | switch (param_ty.zigTypeTag()) { | 863 | switch (param_ty.zigTypeTag()) { |
| 865 | .Struct => { | 864 | .Struct => { |
| 866 | const fields = param_ty.structFields().values(); | 865 | const fields = param_ty.structFields().values(); |
| 867 | if (is_by_ref) { | 866 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 868 | const param_llvm_ty = try dg.lowerType(param_ty); | 867 | const param_alignment = param_ty.abiAlignment(target); |
| 869 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); | 868 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); |
| 870 | arg_ptr.setAlignment(param_ty.abiAlignment(target)); | 869 | arg_ptr.setAlignment(param_alignment); |
| 871 | | 870 | |
| 872 | var field_i: u32 = 0; | 871 | var field_i: u32 = 0; |
| 873 | var field_offset: u32 = 0; | 872 | var field_offset: u32 = 0; |
| 874 | for (llvm_ints) |int_bits| { | 873 | for (llvm_ints) |int_bits| { |
| 875 | const param = llvm_func.getParam(llvm_arg_i); | 874 | const param = llvm_func.getParam(llvm_arg_i); |
| 876 | llvm_arg_i += 1; | 875 | llvm_arg_i += 1; |
| 877 | | 876 | |
| 878 | const big_int_ty = dg.context.intType(int_bits); | 877 | const big_int_ty = dg.context.intType(int_bits); |
| 879 | var bits_used: u32 = 0; | 878 | var bits_used: u32 = 0; |
| 880 | while (bits_used < int_bits) { | 879 | while (bits_used < int_bits) { |
| 881 | const field = fields[field_i]; | 880 | const field = fields[field_i]; |
| 882 | const field_alignment = field.normalAlignment(target); | 881 | const field_alignment = field.normalAlignment(target); |
| 883 | const prev_offset = field_offset; | 882 | const prev_offset = field_offset; |
| 884 | field_offset = std.mem.alignForwardGeneric(u32, field_offset, field_alignment); | 883 | field_offset = std.mem.alignForwardGeneric(u32, field_offset, field_alignment); |
| 885 | if (field_offset > prev_offset) { | 884 | if (field_offset > prev_offset) { |
| 886 | // Padding counts as bits used. | 885 | // Padding counts as bits used. |
| 887 | bits_used += (field_offset - prev_offset) * 8; | 886 | bits_used += (field_offset - prev_offset) * 8; |
| 888 | if (bits_used >= int_bits) break; | 887 | 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; | | |
| 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 | if (field_i >= fields.len) break; | 905 | if (field_i >= fields.len) break; |
| 912 | } | | |
| 913 | | 906 | |
| 914 | try args.append(arg_ptr); | 907 | bits_used += field_abi_bits; |
| 915 | } else { | 908 | field_offset += field_size; |
| 916 | @panic("TODO: LLVM backend: implement C calling convention on x86_64 with byval struct parameter"); | 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 | .Union => { | 921 | .Union => { |
| 920 | @panic("TODO: LLVM backend: implement C calling convention on x86_64 with union parameter"); | 922 | @panic("TODO: LLVM backend: implement C calling convention on x86_64 with union parameter"); |