authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-10 17:36:31-07:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-12 11:18:23+01:00
log166db1a3ed7eca9b04b0626eaea8de0634ab9667
tree958a97baa486eda299dc268a83f3e89fd9a81f63
parentf293fbbeaf6c48e6ce1410743181f89f359eb697

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

4 files changed, 67 insertions(+), 26 deletions(-)

lib/std/math.zig+2-5
......@@ -36,7 +36,6 @@ pub const sqrt2 = 1.414213562373095048801688724209698079;
3636/// 1/sqrt(2)
3737pub const sqrt1_2 = 0.707106781186547524400844362104849039;
3838
39// From a small c++ [program using boost float128](https://github.com/winksaville/cpp_boost_float128)
4039pub const f128_true_min = @bitCast(f128, @as(u128, 0x00000000000000000000000000000001));
4140pub const f128_min = @bitCast(f128, @as(u128, 0x00010000000000000000000000000000));
4241pub const f128_max = @bitCast(f128, @as(u128, 0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF));
......@@ -44,12 +43,10 @@ pub const f128_epsilon = @bitCast(f128, @as(u128, 0x3F8F000000000000000000000000
4443pub const f128_toint = 1.0 / f128_epsilon;
4544
4645pub const F80Repr = if (@import("builtin").cpu.arch.endian() == .Little) extern struct {
47 fraction: u64,
46 fraction: u64 align(@alignOf(f80)),
4847 exp: u16,
49 _pad: u32 = undefined,
5048} else extern struct {
51 exp: u16,
52 _pad: u32 = undefined, // TODO verify compatibility with hardware
49 exp: u16 align(@alignOf(f80)),
5350 fraction: u64,
5451};
5552
src/codegen/llvm.zig+22-12
......@@ -1257,19 +1257,29 @@ pub const DeclGen = struct {
12571257 },
12581258 .Float => {
12591259 const llvm_ty = try dg.llvmType(tv.ty);
1260 if (tv.ty.floatBits(dg.module.getTarget()) <= 64) {
1261 return llvm_ty.constReal(tv.val.toFloat(f64));
1262 }
1263
1264 var buf: [2]u64 = @bitCast([2]u64, tv.val.toFloat(f128));
1265 // LLVM seems to require that the lower half of the f128 be placed first
1266 // in the buffer.
1267 if (native_endian == .Big) {
1268 std.mem.swap(u64, &buf[0], &buf[1]);
1260 switch (tv.ty.floatBits(dg.module.getTarget())) {
1261 16, 32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)),
1262 80 => {
1263 const float = tv.val.toFloat(f80);
1264 const repr = @ptrCast(*const std.math.F80Repr, &float);
1265 const llvm_i80 = dg.context.intType(80);
1266 var x = llvm_i80.constInt(repr.exp, .False);
1267 x = x.constShl(llvm_i80.constInt(64, .False));
1268 x = x.constOr(llvm_i80.constInt(repr.fraction, .False));
1269 return x.constBitCast(llvm_ty);
1270 },
1271 128 => {
1272 var buf: [2]u64 = @bitCast([2]u64, tv.val.toFloat(f128));
1273 // LLVM seems to require that the lower half of the f128 be placed first
1274 // in the buffer.
1275 if (native_endian == .Big) {
1276 std.mem.swap(u64, &buf[0], &buf[1]);
1277 }
1278 const int = dg.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf);
1279 return int.constBitCast(llvm_ty);
1280 },
1281 else => unreachable,
12691282 }
1270
1271 const int = dg.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf);
1272 return int.constBitCast(llvm_ty);
12731283 },
12741284 .Pointer => switch (tv.val.tag()) {
12751285 .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl),
src/stage1/codegen.cpp+17-5
......@@ -9429,17 +9429,29 @@ static void define_builtin_types(CodeGen *g) {
94299429
94309430 {
94319431 ZigType *entry = new_type_table_entry(ZigTypeIdFloat);
9432 unsigned u64_alignment = LLVMABIAlignmentOfType(g->target_data_ref, LLVMInt64Type());
9433
9434 if (u64_alignment >= 8) {
9435 entry->size_in_bits = 128;
9436 entry->abi_size = 16;
9437 entry->abi_align = 16;
9438 } else if (u64_alignment >= 4) {
9439 entry->size_in_bits = 96;
9440 entry->abi_size = 12;
9441 entry->abi_align = 4;
9442 } else {
9443 entry->size_in_bits = 80;
9444 entry->abi_size = 10;
9445 entry->abi_align = 2;
9446 }
94329447 if (target_has_f80(g->zig_target)) {
94339448 entry->llvm_type = LLVMX86FP80Type();
94349449 } else {
9435 // We use i128 here instead of x86_fp80 because on targets such as arm,
9450 // We use an int here instead of x86_fp80 because on targets such as arm,
94369451 // LLVM will give "ERROR: Cannot select" for any instructions involving
94379452 // the x86_fp80 type.
9438 entry->llvm_type = get_int_type(g, false, 128)->llvm_type;
9453 entry->llvm_type = get_int_type(g, false, entry->size_in_bits)->llvm_type;
94399454 }
9440 entry->size_in_bits = 8 * 16;
9441 entry->abi_size = 16; // matches LLVMABISizeOfType(LLVMX86FP80Type())
9442 entry->abi_align = 16; // matches LLVMABIAlignmentOfType(LLVMX86FP80Type())
94439455 buf_init_from_str(&entry->name, "f80");
94449456 entry->data.floating.bit_count = 80;
94459457
src/value.zig+26-4
......@@ -1122,10 +1122,32 @@ pub const Value = extern union {
11221122
11231123 fn floatReadFromMemory(comptime F: type, target: Target, buffer: []const u8) F {
11241124 if (F == f80) {
1125 // TODO: use std.math.F80Repr?
1126 const int = std.mem.readInt(u128, buffer[0..16], target.cpu.arch.endian());
1127 // TODO shouldn't this be a bitcast from u80 to f80 instead of u128 to f80?
1128 return @bitCast(F, int);
1125 switch (target.cpu.arch.endian()) {
1126 .Little => {
1127 const TargetF80Repr = extern struct {
1128 fraction: u64,
1129 exp: u16,
1130 };
1131 const target_repr = @ptrCast(*align(1) const TargetF80Repr, buffer.ptr);
1132 const real_repr: std.math.F80Repr = .{
1133 .fraction = target_repr.fraction,
1134 .exp = target_repr.exp,
1135 };
1136 return @ptrCast(*const f80, &real_repr).*;
1137 },
1138 .Big => {
1139 const TargetF80Repr = extern struct {
1140 exp: u16,
1141 fraction: u64,
1142 };
1143 const target_repr = @ptrCast(*align(1) const TargetF80Repr, buffer.ptr);
1144 const real_repr: std.math.F80Repr = .{
1145 .fraction = target_repr.fraction,
1146 .exp = target_repr.exp,
1147 };
1148 return @ptrCast(*const f80, &real_repr).*;
1149 },
1150 }
11291151 }
11301152 const Int = @Type(.{ .Int = .{
11311153 .signedness = .unsigned,