mirror of
https://github.com/ziglang/zig.git
synced 2024-11-26 23:22:44 +00:00
stage1: fix f80 size and alignment on x86 and arm
* F80Repr extern struct needs no explicit padding; let's match the target padding. * stage2: fix lowering of f80 constants. * stage1: decide ABI size and alignment of f80 based on alignment of u64. x86 has alignof u64 equal to 4 but arm has it as 8. * stage2: fix Value.floatReadFromMemory to use F80Repr
This commit is contained in:
parent
f293fbbeaf
commit
166db1a3ed
@ -36,7 +36,6 @@ pub const sqrt2 = 1.414213562373095048801688724209698079;
|
||||
/// 1/sqrt(2)
|
||||
pub const sqrt1_2 = 0.707106781186547524400844362104849039;
|
||||
|
||||
// From a small c++ [program using boost float128](https://github.com/winksaville/cpp_boost_float128)
|
||||
pub const f128_true_min = @bitCast(f128, @as(u128, 0x00000000000000000000000000000001));
|
||||
pub const f128_min = @bitCast(f128, @as(u128, 0x00010000000000000000000000000000));
|
||||
pub const f128_max = @bitCast(f128, @as(u128, 0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF));
|
||||
@ -44,12 +43,10 @@ pub const f128_epsilon = @bitCast(f128, @as(u128, 0x3F8F000000000000000000000000
|
||||
pub const f128_toint = 1.0 / f128_epsilon;
|
||||
|
||||
pub const F80Repr = if (@import("builtin").cpu.arch.endian() == .Little) extern struct {
|
||||
fraction: u64,
|
||||
fraction: u64 align(@alignOf(f80)),
|
||||
exp: u16,
|
||||
_pad: u32 = undefined,
|
||||
} else extern struct {
|
||||
exp: u16,
|
||||
_pad: u32 = undefined, // TODO verify compatibility with hardware
|
||||
exp: u16 align(@alignOf(f80)),
|
||||
fraction: u64,
|
||||
};
|
||||
|
||||
|
@ -1257,19 +1257,29 @@ pub const DeclGen = struct {
|
||||
},
|
||||
.Float => {
|
||||
const llvm_ty = try dg.llvmType(tv.ty);
|
||||
if (tv.ty.floatBits(dg.module.getTarget()) <= 64) {
|
||||
return llvm_ty.constReal(tv.val.toFloat(f64));
|
||||
switch (tv.ty.floatBits(dg.module.getTarget())) {
|
||||
16, 32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)),
|
||||
80 => {
|
||||
const float = tv.val.toFloat(f80);
|
||||
const repr = @ptrCast(*const std.math.F80Repr, &float);
|
||||
const llvm_i80 = dg.context.intType(80);
|
||||
var x = llvm_i80.constInt(repr.exp, .False);
|
||||
x = x.constShl(llvm_i80.constInt(64, .False));
|
||||
x = x.constOr(llvm_i80.constInt(repr.fraction, .False));
|
||||
return x.constBitCast(llvm_ty);
|
||||
},
|
||||
128 => {
|
||||
var buf: [2]u64 = @bitCast([2]u64, tv.val.toFloat(f128));
|
||||
// LLVM seems to require that the lower half of the f128 be placed first
|
||||
// in the buffer.
|
||||
if (native_endian == .Big) {
|
||||
std.mem.swap(u64, &buf[0], &buf[1]);
|
||||
}
|
||||
const int = dg.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf);
|
||||
return int.constBitCast(llvm_ty);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
var buf: [2]u64 = @bitCast([2]u64, tv.val.toFloat(f128));
|
||||
// LLVM seems to require that the lower half of the f128 be placed first
|
||||
// in the buffer.
|
||||
if (native_endian == .Big) {
|
||||
std.mem.swap(u64, &buf[0], &buf[1]);
|
||||
}
|
||||
|
||||
const int = dg.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf);
|
||||
return int.constBitCast(llvm_ty);
|
||||
},
|
||||
.Pointer => switch (tv.val.tag()) {
|
||||
.decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl),
|
||||
|
@ -9429,17 +9429,29 @@ static void define_builtin_types(CodeGen *g) {
|
||||
|
||||
{
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdFloat);
|
||||
unsigned u64_alignment = LLVMABIAlignmentOfType(g->target_data_ref, LLVMInt64Type());
|
||||
|
||||
if (u64_alignment >= 8) {
|
||||
entry->size_in_bits = 128;
|
||||
entry->abi_size = 16;
|
||||
entry->abi_align = 16;
|
||||
} else if (u64_alignment >= 4) {
|
||||
entry->size_in_bits = 96;
|
||||
entry->abi_size = 12;
|
||||
entry->abi_align = 4;
|
||||
} else {
|
||||
entry->size_in_bits = 80;
|
||||
entry->abi_size = 10;
|
||||
entry->abi_align = 2;
|
||||
}
|
||||
if (target_has_f80(g->zig_target)) {
|
||||
entry->llvm_type = LLVMX86FP80Type();
|
||||
} else {
|
||||
// We use i128 here instead of x86_fp80 because on targets such as arm,
|
||||
// We use an int here instead of x86_fp80 because on targets such as arm,
|
||||
// LLVM will give "ERROR: Cannot select" for any instructions involving
|
||||
// the x86_fp80 type.
|
||||
entry->llvm_type = get_int_type(g, false, 128)->llvm_type;
|
||||
entry->llvm_type = get_int_type(g, false, entry->size_in_bits)->llvm_type;
|
||||
}
|
||||
entry->size_in_bits = 8 * 16;
|
||||
entry->abi_size = 16; // matches LLVMABISizeOfType(LLVMX86FP80Type())
|
||||
entry->abi_align = 16; // matches LLVMABIAlignmentOfType(LLVMX86FP80Type())
|
||||
buf_init_from_str(&entry->name, "f80");
|
||||
entry->data.floating.bit_count = 80;
|
||||
|
||||
|
@ -1122,10 +1122,32 @@ pub const Value = extern union {
|
||||
|
||||
fn floatReadFromMemory(comptime F: type, target: Target, buffer: []const u8) F {
|
||||
if (F == f80) {
|
||||
// TODO: use std.math.F80Repr?
|
||||
const int = std.mem.readInt(u128, buffer[0..16], target.cpu.arch.endian());
|
||||
// TODO shouldn't this be a bitcast from u80 to f80 instead of u128 to f80?
|
||||
return @bitCast(F, int);
|
||||
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).*;
|
||||
},
|
||||
}
|
||||
}
|
||||
const Int = @Type(.{ .Int = .{
|
||||
.signedness = .unsigned,
|
||||
|
Loading…
Reference in New Issue
Block a user