| ... | @@ -764,15 +764,25 @@ pub const Object = struct { | ... | @@ -764,15 +764,25 @@ pub const Object = struct { |
| 764 | arg_ptr.setAlignment(param_ty.abiAlignment(target)); | 764 | arg_ptr.setAlignment(param_ty.abiAlignment(target)); |
| 765 | | 765 | |
| 766 | var field_i: u32 = 0; | 766 | var field_i: u32 = 0; |
| | 767 | var field_offset: u32 = 0; |
| 767 | for (llvm_ints) |int_bits| { | 768 | for (llvm_ints) |int_bits| { |
| 768 | const param = llvm_func.getParam(llvm_arg_i); | 769 | const param = llvm_func.getParam(llvm_arg_i); |
| 769 | llvm_arg_i += 1; | 770 | llvm_arg_i += 1; |
| 770 | | 771 | |
| 771 | const big_int_ty = dg.context.intType(int_bits); | 772 | const big_int_ty = dg.context.intType(int_bits); |
| 772 | var bits_used: u16 = 0; | 773 | var bits_used: u32 = 0; |
| 773 | while (bits_used < int_bits) { | 774 | while (bits_used < int_bits) { |
| 774 | const field = fields[field_i]; | 775 | const field = fields[field_i]; |
| 775 | const field_abi_bits = @intCast(u16, field.ty.abiSize(target)) * 8; | 776 | const field_alignment = field.normalAlignment(target); |
| | 777 | const prev_offset = field_offset; |
| | 778 | field_offset = std.mem.alignForwardGeneric(u32, field_offset, field_alignment); |
| | 779 | if (field_offset > prev_offset) { |
| | 780 | // Padding counts as bits used. |
| | 781 | bits_used += (field_offset - prev_offset) * 8; |
| | 782 | if (bits_used >= int_bits) break; |
| | 783 | } |
| | 784 | const field_size = @intCast(u16, field.ty.abiSize(target)); |
| | 785 | const field_abi_bits = field_size * 8; |
| 776 | const field_int_ty = dg.context.intType(field_abi_bits); | 786 | const field_int_ty = dg.context.intType(field_abi_bits); |
| 777 | const shifted = if (bits_used == 0) param else s: { | 787 | const shifted = if (bits_used == 0) param else s: { |
| 778 | const shift_amt = big_int_ty.constInt(bits_used, .False); | 788 | const shift_amt = big_int_ty.constInt(bits_used, .False); |
| ... | @@ -782,14 +792,15 @@ pub const Object = struct { | ... | @@ -782,14 +792,15 @@ pub const Object = struct { |
| 782 | var ty_buf: Type.Payload.Pointer = undefined; | 792 | var ty_buf: Type.Payload.Pointer = undefined; |
| 783 | const llvm_i = llvmFieldIndex(param_ty, field_i, target, &ty_buf).?; | 793 | const llvm_i = llvmFieldIndex(param_ty, field_i, target, &ty_buf).?; |
| 784 | const field_ptr = builder.buildStructGEP(arg_ptr, llvm_i, ""); | 794 | const field_ptr = builder.buildStructGEP(arg_ptr, llvm_i, ""); |
| 785 | const field_alignment = field.normalAlignment(target); | | |
| 786 | const casted_ptr = builder.buildBitCast(field_ptr, field_int_ty.pointerType(0), ""); | 795 | const casted_ptr = builder.buildBitCast(field_ptr, field_int_ty.pointerType(0), ""); |
| 787 | const store_inst = builder.buildStore(field_as_int, casted_ptr); | 796 | const store_inst = builder.buildStore(field_as_int, casted_ptr); |
| 788 | store_inst.setAlignment(field_alignment); | 797 | store_inst.setAlignment(field_alignment); |
| 789 | | 798 | |
| 790 | bits_used += field_abi_bits; | | |
| 791 | field_i += 1; | 799 | field_i += 1; |
| 792 | if (field_i >= fields.len) break; | 800 | if (field_i >= fields.len) break; |
| | 801 | |
| | 802 | bits_used += field_abi_bits; |
| | 803 | field_offset += field_size; |
| 793 | } | 804 | } |
| 794 | if (field_i >= fields.len) break; | 805 | if (field_i >= fields.len) break; |
| 795 | } | 806 | } |
| ... | @@ -2689,9 +2700,65 @@ pub const DeclGen = struct { | ... | @@ -2689,9 +2700,65 @@ pub const DeclGen = struct { |
| 2689 | try llvm_params.append(dg.context.intType(abi_size * 8)); | 2700 | try llvm_params.append(dg.context.intType(abi_size * 8)); |
| 2690 | }, | 2701 | }, |
| 2691 | .multiple_llvm_ints => { | 2702 | .multiple_llvm_ints => { |
| | 2703 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| | 2704 | const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len]; |
| 2692 | try llvm_params.ensureUnusedCapacity(it.llvm_types_len); | 2705 | try llvm_params.ensureUnusedCapacity(it.llvm_types_len); |
| 2693 | for (it.llvm_types_buffer[0..it.llvm_types_len]) |int_bits| { | 2706 | |
| 2694 | llvm_params.appendAssumeCapacity(dg.context.intType(int_bits)); | 2707 | // The reason we have all this logic instead of simply appending |
| | 2708 | // big_int_ty is for the special case of a pointer type; |
| | 2709 | // we want to use a pointer type instead of inttoptr at the callsites, |
| | 2710 | // which may prevent optimization. |
| | 2711 | switch (param_ty.zigTypeTag()) { |
| | 2712 | .Struct => { |
| | 2713 | const fields = param_ty.structFields().values(); |
| | 2714 | var field_i: u32 = 0; |
| | 2715 | var field_offset: u32 = 0; |
| | 2716 | llvm_arg: for (llvm_ints) |int_bits| { |
| | 2717 | const big_int_ty = dg.context.intType(int_bits); |
| | 2718 | var bits_used: u32 = 0; |
| | 2719 | while (bits_used < int_bits) { |
| | 2720 | const field = fields[field_i]; |
| | 2721 | const field_alignment = field.normalAlignment(target); |
| | 2722 | const prev_offset = field_offset; |
| | 2723 | field_offset = std.mem.alignForwardGeneric(u32, field_offset, field_alignment); |
| | 2724 | if (field_offset > prev_offset) { |
| | 2725 | // Padding counts as bits used. |
| | 2726 | bits_used += (field_offset - prev_offset) * 8; |
| | 2727 | if (bits_used >= int_bits) break; |
| | 2728 | } |
| | 2729 | const field_size = @intCast(u16, field.ty.abiSize(target)); |
| | 2730 | const field_abi_bits = field_size * 8; |
| | 2731 | |
| | 2732 | // Special case for when the entire LLVM integer represents |
| | 2733 | // one field; in this case keep the type information |
| | 2734 | // to avoid the potentially costly ptrtoint/bitcast. |
| | 2735 | if (bits_used == 0 and field_abi_bits == int_bits) { |
| | 2736 | const llvm_field_ty = try dg.llvmType(field.ty); |
| | 2737 | llvm_params.appendAssumeCapacity(llvm_field_ty); |
| | 2738 | field_i += 1; |
| | 2739 | if (field_i >= fields.len) { |
| | 2740 | break :llvm_arg; |
| | 2741 | } else { |
| | 2742 | continue :llvm_arg; |
| | 2743 | } |
| | 2744 | } |
| | 2745 | |
| | 2746 | field_i += 1; |
| | 2747 | if (field_i >= fields.len) break; |
| | 2748 | |
| | 2749 | bits_used += field_abi_bits; |
| | 2750 | field_offset += field_size; |
| | 2751 | } |
| | 2752 | llvm_params.appendAssumeCapacity(big_int_ty); |
| | 2753 | if (field_i >= fields.len) break; |
| | 2754 | } |
| | 2755 | }, |
| | 2756 | else => { |
| | 2757 | for (llvm_ints) |int_bits| { |
| | 2758 | const big_int_ty = dg.context.intType(int_bits); |
| | 2759 | llvm_params.appendAssumeCapacity(big_int_ty); |
| | 2760 | } |
| | 2761 | }, |
| 2695 | } | 2762 | } |
| 2696 | }, | 2763 | }, |
| 2697 | }; | 2764 | }; |
| ... | @@ -4070,22 +4137,46 @@ pub const FuncGen = struct { | ... | @@ -4070,22 +4137,46 @@ pub const FuncGen = struct { |
| 4070 | .Struct => { | 4137 | .Struct => { |
| 4071 | const fields = param_ty.structFields().values(); | 4138 | const fields = param_ty.structFields().values(); |
| 4072 | var field_i: u32 = 0; | 4139 | var field_i: u32 = 0; |
| | 4140 | var field_offset: u32 = 0; |
| 4073 | for (llvm_ints) |int_bits| { | 4141 | for (llvm_ints) |int_bits| { |
| 4074 | const big_int_ty = self.dg.context.intType(int_bits); | 4142 | const big_int_ty = self.dg.context.intType(int_bits); |
| 4075 | var int_arg: *const llvm.Value = undefined; | 4143 | var int_arg: *const llvm.Value = undefined; |
| 4076 | var bits_used: u16 = 0; | 4144 | var bits_used: u32 = 0; |
| 4077 | while (bits_used < int_bits) { | 4145 | while (bits_used < int_bits) { |
| 4078 | const field = fields[field_i]; | 4146 | const field = fields[field_i]; |
| | 4147 | const field_alignment = field.normalAlignment(target); |
| | 4148 | const prev_offset = field_offset; |
| | 4149 | field_offset = std.mem.alignForwardGeneric(u32, field_offset, field_alignment); |
| | 4150 | if (field_offset > prev_offset) { |
| | 4151 | // Padding counts as bits used. |
| | 4152 | bits_used += (field_offset - prev_offset) * 8; |
| | 4153 | if (bits_used >= int_bits) break; |
| | 4154 | } |
| 4079 | var ty_buf: Type.Payload.Pointer = undefined; | 4155 | var ty_buf: Type.Payload.Pointer = undefined; |
| 4080 | const llvm_i = llvmFieldIndex(param_ty, field_i, target, &ty_buf).?; | 4156 | const llvm_i = llvmFieldIndex(param_ty, field_i, target, &ty_buf).?; |
| 4081 | const field_abi_bits = @intCast(u16, field.ty.abiSize(target)) * 8; | 4157 | const field_size = @intCast(u16, field.ty.abiSize(target)); |
| | 4158 | const field_abi_bits = field_size * 8; |
| | 4159 | |
| | 4160 | // Special case for when the entire LLVM integer represents |
| | 4161 | // one field; in this case keep the type information |
| | 4162 | // to avoid the potentially costly ptrtoint/bitcast. |
| | 4163 | if (bits_used == 0 and field_abi_bits == int_bits) { |
| | 4164 | int_arg = if (is_by_ref) f: { |
| | 4165 | const field_ptr = self.builder.buildStructGEP(llvm_arg, llvm_i, ""); |
| | 4166 | const load_inst = self.builder.buildLoad(field_ptr, ""); |
| | 4167 | load_inst.setAlignment(field_alignment); |
| | 4168 | break :f load_inst; |
| | 4169 | } else self.builder.buildExtractValue(llvm_arg, llvm_i, ""); |
| | 4170 | field_i += 1; |
| | 4171 | break; |
| | 4172 | } |
| | 4173 | |
| 4082 | const field_int_ty = self.dg.context.intType(field_abi_bits); | 4174 | const field_int_ty = self.dg.context.intType(field_abi_bits); |
| 4083 | const llvm_field = if (is_by_ref) f: { | 4175 | const llvm_field = if (is_by_ref) f: { |
| 4084 | const field_ptr = self.builder.buildStructGEP(llvm_arg, llvm_i, ""); | 4176 | const field_ptr = self.builder.buildStructGEP(llvm_arg, llvm_i, ""); |
| 4085 | const alignment = field.normalAlignment(target); | | |
| 4086 | const casted_ptr = self.builder.buildBitCast(field_ptr, field_int_ty.pointerType(0), ""); | 4177 | const casted_ptr = self.builder.buildBitCast(field_ptr, field_int_ty.pointerType(0), ""); |
| 4087 | const load_inst = self.builder.buildLoad(casted_ptr, ""); | 4178 | const load_inst = self.builder.buildLoad(casted_ptr, ""); |
| 4088 | load_inst.setAlignment(alignment); | 4179 | load_inst.setAlignment(field_alignment); |
| 4089 | break :f load_inst; | 4180 | break :f load_inst; |
| 4090 | } else f: { | 4181 | } else f: { |
| 4091 | const llvm_field = self.builder.buildExtractValue(llvm_arg, llvm_i, ""); | 4182 | const llvm_field = self.builder.buildExtractValue(llvm_arg, llvm_i, ""); |
| ... | @@ -4101,9 +4192,11 @@ pub const FuncGen = struct { | ... | @@ -4101,9 +4192,11 @@ pub const FuncGen = struct { |
| 4101 | int_arg = self.builder.buildOr(int_arg, shifted, ""); | 4192 | int_arg = self.builder.buildOr(int_arg, shifted, ""); |
| 4102 | } | 4193 | } |
| 4103 | | 4194 | |
| 4104 | bits_used += field_abi_bits; | | |
| 4105 | field_i += 1; | 4195 | field_i += 1; |
| 4106 | if (field_i >= fields.len) break; | 4196 | if (field_i >= fields.len) break; |
| | 4197 | |
| | 4198 | bits_used += field_abi_bits; |
| | 4199 | field_offset += field_size; |
| 4107 | } | 4200 | } |
| 4108 | llvm_args.appendAssumeCapacity(int_arg); | 4201 | llvm_args.appendAssumeCapacity(int_arg); |
| 4109 | if (field_i >= fields.len) break; | 4202 | if (field_i >= fields.len) break; |