diff options
| author | Matthew Lugg <mlugg@mlugg.co.uk> | 2025-11-17 01:54:49 +0100 |
|---|---|---|
| committer | Alex Rønne Petersen <alex@alexrp.com> | 2025-11-18 11:10:52 +0100 |
| commit | 891f1870320000205291940ba2e276c1fa043cd0 (patch) | |
| tree | 336c97a163394c7795e76794fd2b3811342d7076 /src/codegen | |
| parent | 73f863a6fb1e844ec312345b3160e3987fe6586d (diff) | |
| download | zig-891f1870320000205291940ba2e276c1fa043cd0.tar.gz zig-891f1870320000205291940ba2e276c1fa043cd0.zip | |
cbe: fix big-endian unnatural integer bitcast
Integers with padding bits on big-endian targets cannot quite be bitcast
with a trivial memcpy, because the padding bits (which are zext or sext)
are the most-significant, so are at the *lowest* addresses. So to
bitcast to something which doesn't have padding bits, we need to offset
past the padding.
The logic I've added here definitely doesn't handle all possibilities
correctly; I think that would actually be quite complicated. However, it
handles a common case, and so prevents the Zig compiler itself from
being miscompiled on big-endian targets (hence fixing a bootstrapping
problem on big-endian).
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/c.zig | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig index c4b909d4a9..91614bf2df 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -5084,16 +5084,32 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal } else operand; const local = try f.allocLocal(null, dest_ty); - try w.writeAll("memcpy(&"); - try f.writeCValue(w, local, .Other); - try w.writeAll(", &"); - try f.writeCValue(w, operand_lval, .Other); - try w.writeAll(", sizeof("); - try f.renderType( - w, - if (dest_ty.abiSize(zcu) <= operand_ty.abiSize(zcu)) dest_ty else operand_ty, - ); - try w.writeAll("));"); + // On big-endian targets, copying ABI integers with padding bits is awkward, because the padding bits are at the low bytes of the value. + // We need to offset the source or destination pointer appropriately and copy the right number of bytes. + if (target.cpu.arch.endian() == .big and dest_ty.isAbiInt(zcu) and !operand_ty.isAbiInt(zcu)) { + // e.g. [10]u8 -> u80. We need to offset the destination so that we copy to the least significant bits of the integer. + const offset = dest_ty.abiSize(zcu) - operand_ty.abiSize(zcu); + try w.writeAll("memcpy((char *)&"); + try f.writeCValue(w, local, .Other); + try w.print(" + {d}, &", .{offset}); + try f.writeCValue(w, operand_lval, .Other); + try w.print(", {d});", .{operand_ty.abiSize(zcu)}); + } else if (target.cpu.arch.endian() == .big and operand_ty.isAbiInt(zcu) and !dest_ty.isAbiInt(zcu)) { + // e.g. u80 -> [10]u8. We need to offset the source so that we copy from the least significant bits of the integer. + const offset = operand_ty.abiSize(zcu) - dest_ty.abiSize(zcu); + try w.writeAll("memcpy(&"); + try f.writeCValue(w, local, .Other); + try w.writeAll(", (const char *)&"); + try f.writeCValue(w, operand_lval, .Other); + try w.print(" + {d}, {d});", .{ offset, dest_ty.abiSize(zcu) }); + } else { + try w.writeAll("memcpy(&"); + try f.writeCValue(w, local, .Other); + try w.writeAll(", &"); + try f.writeCValue(w, operand_lval, .Other); + try w.print(", {d});", .{@min(dest_ty.abiSize(zcu), operand_ty.abiSize(zcu))}); + } + try f.object.newline(); // Ensure padding bits have the expected value. |
