| ... | @@ -6179,7 +6179,6 @@ pub const FuncGen = struct { | ... | @@ -6179,7 +6179,6 @@ pub const FuncGen = struct { |
| 6179 | const elem_alignment = elem_ty.abiAlignment(mod).toLlvm(); | 6179 | const elem_alignment = elem_ty.abiAlignment(mod).toLlvm(); |
| 6180 | return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal); | 6180 | return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal); |
| 6181 | } else { | 6181 | } else { |
| 6182 | const elem_llvm_ty = try o.lowerType(elem_ty); | | |
| 6183 | if (Air.refToIndex(bin_op.lhs)) |lhs_index| { | 6182 | if (Air.refToIndex(bin_op.lhs)) |lhs_index| { |
| 6184 | if (self.air.instructions.items(.tag)[lhs_index] == .load) { | 6183 | if (self.air.instructions.items(.tag)[lhs_index] == .load) { |
| 6185 | const load_data = self.air.instructions.items(.data)[lhs_index]; | 6184 | const load_data = self.air.instructions.items(.data)[lhs_index]; |
| ... | @@ -6201,7 +6200,7 @@ pub const FuncGen = struct { | ... | @@ -6201,7 +6200,7 @@ pub const FuncGen = struct { |
| 6201 | &indices, | 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 | else => {}, | 6205 | else => {}, |
| 6207 | } | 6206 | } |
| ... | @@ -6210,7 +6209,7 @@ pub const FuncGen = struct { | ... | @@ -6210,7 +6209,7 @@ pub const FuncGen = struct { |
| 6210 | } | 6209 | } |
| 6211 | const elem_ptr = | 6210 | const elem_ptr = |
| 6212 | try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, ""); | 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,13 +6377,12 @@ pub const FuncGen = struct { |
| 6378 | const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align)); | 6377 | const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align)); |
| 6379 | const field_ptr = | 6378 | const field_ptr = |
| 6380 | try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, ""); | 6379 | try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, ""); |
| 6381 | const llvm_field_ty = try o.lowerType(field_ty); | | |
| 6382 | const payload_alignment = layout.payload_align.toLlvm(); | 6380 | const payload_alignment = layout.payload_align.toLlvm(); |
| 6383 | if (isByRef(field_ty, mod)) { | 6381 | if (isByRef(field_ty, mod)) { |
| 6384 | if (canElideLoad(self, body_tail)) return field_ptr; | 6382 | if (canElideLoad(self, body_tail)) return field_ptr; |
| 6385 | return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal); | 6383 | return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal); |
| 6386 | } else { | 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 | else => unreachable, | 6388 | else => unreachable, |
| ... | @@ -10219,8 +10217,7 @@ pub const FuncGen = struct { | ... | @@ -10219,8 +10217,7 @@ pub const FuncGen = struct { |
| 10219 | | 10217 | |
| 10220 | return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal); | 10218 | return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal); |
| 10221 | } | 10219 | } |
| 10222 | const payload_llvm_ty = try o.lowerType(payload_ty); | 10220 | return fg.loadTruncate(.normal, payload_ty, payload_ptr, payload_alignment); |
| 10223 | return fg.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, ""); | | |
| 10224 | } | 10221 | } |
| 10225 | | 10222 | |
| 10226 | assert(!isByRef(payload_ty, mod)); | 10223 | assert(!isByRef(payload_ty, mod)); |
| ... | @@ -10321,6 +10318,36 @@ pub const FuncGen = struct { | ... | @@ -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 | /// Load a by-ref type by constructing a new alloca and performing a memcpy. | 10351 | /// Load a by-ref type by constructing a new alloca and performing a memcpy. |
| 10325 | fn loadByRef( | 10352 | fn loadByRef( |
| 10326 | fg: *FuncGen, | 10353 | fg: *FuncGen, |
| ... | @@ -10378,21 +10405,7 @@ pub const FuncGen = struct { | ... | @@ -10378,21 +10405,7 @@ pub const FuncGen = struct { |
| 10378 | if (isByRef(elem_ty, mod)) { | 10405 | if (isByRef(elem_ty, mod)) { |
| 10379 | return self.loadByRef(ptr, elem_ty, ptr_alignment, access_kind); | 10406 | return self.loadByRef(ptr, elem_ty, ptr_alignment, access_kind); |
| 10380 | } | 10407 | } |
| 10381 | const llvm_elem_ty = try o.lowerType(elem_ty); | 10408 | return self.loadTruncate(access_kind, elem_ty, ptr, ptr_alignment); |
| 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, ""); | | |
| 10396 | } | 10409 | } |
| 10397 | | 10410 | |
| 10398 | const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8)); | 10411 | const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8)); |