| ... | ... | @@ -6179,7 +6179,6 @@ pub const FuncGen = struct { |
| 6179 | 6179 | const elem_alignment = elem_ty.abiAlignment(mod).toLlvm(); |
| 6180 | 6180 | return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal); |
| 6181 | 6181 | } else { |
| 6182 | | const elem_llvm_ty = try o.lowerType(elem_ty); |
| 6183 | 6182 | if (Air.refToIndex(bin_op.lhs)) |lhs_index| { |
| 6184 | 6183 | if (self.air.instructions.items(.tag)[lhs_index] == .load) { |
| 6185 | 6184 | const load_data = self.air.instructions.items(.data)[lhs_index]; |
| ... | ... | @@ -6201,7 +6200,7 @@ pub const FuncGen = struct { |
| 6201 | 6200 | &indices, |
| 6202 | 6201 | "", |
| 6203 | 6202 | ); |
| 6204 | | return self.wip.load(.normal, elem_llvm_ty, gep, .default, ""); |
| 6203 | return self.loadTruncate(.normal, elem_ty, gep, .default); |
| 6205 | 6204 | }, |
| 6206 | 6205 | else => {}, |
| 6207 | 6206 | } |
| ... | ... | @@ -6210,7 +6209,7 @@ pub const FuncGen = struct { |
| 6210 | 6209 | } |
| 6211 | 6210 | const elem_ptr = |
| 6212 | 6211 | try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, ""); |
| 6213 | | return self.wip.load(.normal, elem_llvm_ty, elem_ptr, .default, ""); |
| 6212 | return self.loadTruncate(.normal, elem_ty, elem_ptr, .default); |
| 6214 | 6213 | } |
| 6215 | 6214 | } |
| 6216 | 6215 | |
| ... | ... | @@ -6378,13 +6377,12 @@ pub const FuncGen = struct { |
| 6378 | 6377 | const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align)); |
| 6379 | 6378 | const field_ptr = |
| 6380 | 6379 | try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, ""); |
| 6381 | | const llvm_field_ty = try o.lowerType(field_ty); |
| 6382 | 6380 | const payload_alignment = layout.payload_align.toLlvm(); |
| 6383 | 6381 | if (isByRef(field_ty, mod)) { |
| 6384 | 6382 | if (canElideLoad(self, body_tail)) return field_ptr; |
| 6385 | 6383 | return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal); |
| 6386 | 6384 | } else { |
| 6387 | | return self.wip.load(.normal, llvm_field_ty, field_ptr, payload_alignment, ""); |
| 6385 | return self.loadTruncate(.normal, field_ty, field_ptr, payload_alignment); |
| 6388 | 6386 | } |
| 6389 | 6387 | }, |
| 6390 | 6388 | else => unreachable, |
| ... | ... | @@ -10219,8 +10217,7 @@ pub const FuncGen = struct { |
| 10219 | 10217 | |
| 10220 | 10218 | return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal); |
| 10221 | 10219 | } |
| 10222 | | const payload_llvm_ty = try o.lowerType(payload_ty); |
| 10223 | | return fg.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, ""); |
| 10220 | return fg.loadTruncate(.normal, payload_ty, payload_ptr, payload_alignment); |
| 10224 | 10221 | } |
| 10225 | 10222 | |
| 10226 | 10223 | assert(!isByRef(payload_ty, mod)); |
| ... | ... | @@ -10321,6 +10318,36 @@ pub const FuncGen = struct { |
| 10321 | 10318 | } |
| 10322 | 10319 | } |
| 10323 | 10320 | |
| 10321 | /// Load a value and, if needed, mask out padding bits for non byte-sized integer values. |
| 10322 | fn loadTruncate( |
| 10323 | fg: *FuncGen, |
| 10324 | access_kind: Builder.MemoryAccessKind, |
| 10325 | payload_ty: Type, |
| 10326 | payload_ptr: Builder.Value, |
| 10327 | payload_alignment: Builder.Alignment, |
| 10328 | ) !Builder.Value { |
| 10329 | // from https://llvm.org/docs/LangRef.html#load-instruction : |
| 10330 | // "When loading a value of a type like i20 with a size that is not an integral number of bytes, the result is undefined if the value was not originally written using a store of the same type. " |
| 10331 | // => so load the byte aligned value and trunc the unwanted bits. |
| 10332 | |
| 10333 | const o = fg.dg.object; |
| 10334 | const mod = o.module; |
| 10335 | const payload_llvm_ty = try o.lowerType(payload_ty); |
| 10336 | const load_llvm_ty = if (payload_ty.isAbiInt(mod)) |
| 10337 | try o.builder.intType(@intCast(payload_ty.abiSize(mod) * 8)) |
| 10338 | else |
| 10339 | payload_llvm_ty; |
| 10340 | const loaded = try fg.wip.load(access_kind, load_llvm_ty, payload_ptr, payload_alignment, ""); |
| 10341 | const shifted = if (payload_llvm_ty != load_llvm_ty and o.target.cpu.arch.endian() == .Big) |
| 10342 | try fg.wip.bin(.lshr, loaded, try o.builder.intValue( |
| 10343 | load_llvm_ty, |
| 10344 | (payload_ty.abiSize(mod) - (std.math.divCeil(u64, payload_ty.bitSize(mod), 8) catch unreachable)) * 8, |
| 10345 | ), "") |
| 10346 | else |
| 10347 | loaded; |
| 10348 | return fg.wip.conv(.unneeded, shifted, payload_llvm_ty, ""); |
| 10349 | } |
| 10350 | |
| 10324 | 10351 | /// Load a by-ref type by constructing a new alloca and performing a memcpy. |
| 10325 | 10352 | fn loadByRef( |
| 10326 | 10353 | fg: *FuncGen, |
| ... | ... | @@ -10378,21 +10405,7 @@ pub const FuncGen = struct { |
| 10378 | 10405 | if (isByRef(elem_ty, mod)) { |
| 10379 | 10406 | return self.loadByRef(ptr, elem_ty, ptr_alignment, access_kind); |
| 10380 | 10407 | } |
| 10381 | | const llvm_elem_ty = try o.lowerType(elem_ty); |
| 10382 | | const llvm_load_ty = if (elem_ty.isAbiInt(mod)) |
| 10383 | | try o.builder.intType(@intCast(elem_ty.abiSize(mod) * 8)) |
| 10384 | | else |
| 10385 | | llvm_elem_ty; |
| 10386 | | const loaded = try self.wip.load(access_kind, llvm_load_ty, ptr, ptr_alignment, ""); |
| 10387 | | const shifted = if (llvm_elem_ty != llvm_load_ty and o.target.cpu.arch.endian() == .Big) |
| 10388 | | try self.wip.bin(.lshr, loaded, try o.builder.intValue( |
| 10389 | | llvm_load_ty, |
| 10390 | | (elem_ty.abiSize(mod) - (std.math.divCeil(u64, elem_ty.bitSize(mod), 8) catch |
| 10391 | | unreachable)) * 8, |
| 10392 | | ), "") |
| 10393 | | else |
| 10394 | | loaded; |
| 10395 | | return self.wip.conv(.unneeded, shifted, llvm_elem_ty, ""); |
| 10408 | return self.loadTruncate(access_kind, elem_ty, ptr, ptr_alignment); |
| 10396 | 10409 | } |
| 10397 | 10410 | |
| 10398 | 10411 | const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8)); |