mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
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).
This commit is contained in:
parent
73f863a6fb
commit
891f187032
1 changed files with 26 additions and 10 deletions
|
|
@ -5084,16 +5084,32 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal
|
||||||
} else operand;
|
} else operand;
|
||||||
|
|
||||||
const local = try f.allocLocal(null, dest_ty);
|
const local = try f.allocLocal(null, dest_ty);
|
||||||
try w.writeAll("memcpy(&");
|
// On big-endian targets, copying ABI integers with padding bits is awkward, because the padding bits are at the low bytes of the value.
|
||||||
try f.writeCValue(w, local, .Other);
|
// We need to offset the source or destination pointer appropriately and copy the right number of bytes.
|
||||||
try w.writeAll(", &");
|
if (target.cpu.arch.endian() == .big and dest_ty.isAbiInt(zcu) and !operand_ty.isAbiInt(zcu)) {
|
||||||
try f.writeCValue(w, operand_lval, .Other);
|
// e.g. [10]u8 -> u80. We need to offset the destination so that we copy to the least significant bits of the integer.
|
||||||
try w.writeAll(", sizeof(");
|
const offset = dest_ty.abiSize(zcu) - operand_ty.abiSize(zcu);
|
||||||
try f.renderType(
|
try w.writeAll("memcpy((char *)&");
|
||||||
w,
|
try f.writeCValue(w, local, .Other);
|
||||||
if (dest_ty.abiSize(zcu) <= operand_ty.abiSize(zcu)) dest_ty else operand_ty,
|
try w.print(" + {d}, &", .{offset});
|
||||||
);
|
try f.writeCValue(w, operand_lval, .Other);
|
||||||
try w.writeAll("));");
|
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();
|
try f.object.newline();
|
||||||
|
|
||||||
// Ensure padding bits have the expected value.
|
// Ensure padding bits have the expected value.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue