authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-07 17:46:07-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-07 18:24:34-07:00
log8d6011361fb088e3e4d1ad649ac196bec101ee78
treed21dbee9ee7f9a9fd4c70656bfc890a48e805b77
parente5e9e5a7aaf4605fcdc4272fb79be42612da694f

LLVM: handle byref combined with multiple_llvm_ints


1 files changed, 50 insertions(+), 48 deletions(-)

src/codegen/llvm.zig+50-48
...@@ -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);
871870
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;
877876
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 }
913906
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");