make f80 less hacky; lower as u80 on non-x86
Get rid of `std.math.F80Repr`. Instead of trying to match the memory layout of f80, we treat it as a value, same as the other floating point types. The functions `make_f80` and `break_f80` are introduced to compose an f80 value out of its parts, and the inverse operation. stage2 LLVM backend: fix pointer to zero length array tripping LLVM assertion. It now checks for when the element type is a zero-bit type and lowers such thing the same way that pointers to other zero-bit types are lowered. Both stage1 and stage2 LLVM backends are adjusted so that f80 is lowered as x86_fp80 on x86_64 and i386 architectures, and identical to a u80 on others. LLVM constants are lowered in a less hacky way now that #10860 is fixed, by using the expression `(exp << 64) | fraction` using llvm constants. Sema is improved to handle c_longdouble by recursively handling it correctly for whatever the float bit width is. In both stage1 and stage2.
This commit is contained in:
committed by
Jakub Konka
parent
1c23321d03
commit
a024aff932
@@ -1112,6 +1112,19 @@ pub const Value = extern union {
|
||||
}
|
||||
|
||||
fn floatWriteToMemory(comptime F: type, f: F, target: Target, buffer: []u8) void {
|
||||
if (F == f80) {
|
||||
switch (target.cpu.arch) {
|
||||
.i386, .x86_64 => {
|
||||
const repr = std.math.break_f80(f);
|
||||
std.mem.writeIntLittle(u64, buffer[0..8], repr.fraction);
|
||||
std.mem.writeIntLittle(u16, buffer[8..10], repr.exp);
|
||||
// TODO set the rest of the bytes to undefined. should we use 0xaa
|
||||
// or is there a different way?
|
||||
return;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
const Int = @Type(.{ .Int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = @typeInfo(F).Float.bits,
|
||||
@@ -1122,41 +1135,43 @@ pub const Value = extern union {
|
||||
|
||||
fn floatReadFromMemory(comptime F: type, target: Target, buffer: []const u8) F {
|
||||
if (F == f80) {
|
||||
switch (target.cpu.arch.endian()) {
|
||||
.Little => {
|
||||
const TargetF80Repr = extern struct {
|
||||
fraction: u64,
|
||||
exp: u16,
|
||||
};
|
||||
const target_repr = @ptrCast(*align(1) const TargetF80Repr, buffer.ptr);
|
||||
const real_repr: std.math.F80Repr = .{
|
||||
.fraction = target_repr.fraction,
|
||||
.exp = target_repr.exp,
|
||||
};
|
||||
return @ptrCast(*const f80, &real_repr).*;
|
||||
},
|
||||
.Big => {
|
||||
const TargetF80Repr = extern struct {
|
||||
exp: u16,
|
||||
fraction: u64,
|
||||
};
|
||||
const target_repr = @ptrCast(*align(1) const TargetF80Repr, buffer.ptr);
|
||||
const real_repr: std.math.F80Repr = .{
|
||||
.fraction = target_repr.fraction,
|
||||
.exp = target_repr.exp,
|
||||
};
|
||||
return @ptrCast(*const f80, &real_repr).*;
|
||||
},
|
||||
switch (target.cpu.arch) {
|
||||
.i386, .x86_64 => return std.math.make_f80(.{
|
||||
.fraction = std.mem.readIntLittle(u64, buffer[0..8]),
|
||||
.exp = std.mem.readIntLittle(u16, buffer[8..10]),
|
||||
}),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
const Int = @Type(.{ .Int = .{
|
||||
.signedness = .unsigned,
|
||||
.bits = @typeInfo(F).Float.bits,
|
||||
} });
|
||||
const int = std.mem.readInt(Int, buffer[0..@sizeOf(Int)], target.cpu.arch.endian());
|
||||
const int = readInt(Int, buffer[0..@sizeOf(Int)], target.cpu.arch.endian());
|
||||
return @bitCast(F, int);
|
||||
}
|
||||
|
||||
fn readInt(comptime Int: type, buffer: *const [@sizeOf(Int)]u8, endian: std.builtin.Endian) Int {
|
||||
var result: Int = 0;
|
||||
switch (endian) {
|
||||
.Big => {
|
||||
for (buffer) |byte| {
|
||||
result <<= 8;
|
||||
result |= byte;
|
||||
}
|
||||
},
|
||||
.Little => {
|
||||
var i: usize = buffer.len;
|
||||
while (i != 0) {
|
||||
i -= 1;
|
||||
result <<= 8;
|
||||
result |= buffer[i];
|
||||
}
|
||||
},
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Asserts that the value is a float or an integer.
|
||||
pub fn toFloat(val: Value, comptime T: type) T {
|
||||
return switch (val.tag()) {
|
||||
|
||||
Reference in New Issue
Block a user