| author | |
| committer | |
| log | 166db1a3ed7eca9b04b0626eaea8de0634ab9667 |
| tree | 958a97baa486eda299dc268a83f3e89fd9a81f63 |
| parent | f293fbbeaf6c48e6ce1410743181f89f359eb697 |
* 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 F80Repr4 files changed, 67 insertions(+), 26 deletions(-)
lib/std/math.zig+2-5| ... | ... | @@ -36,7 +36,6 @@ pub const sqrt2 = 1.414213562373095048801688724209698079; |
| 36 | 36 | /// 1/sqrt(2) |
| 37 | 37 | pub const sqrt1_2 = 0.707106781186547524400844362104849039; |
| 38 | 38 | |
| 39 | // From a small c++ [program using boost float128](https://github.com/winksaville/cpp_boost_float128) | |
| 40 | 39 | pub const f128_true_min = @bitCast(f128, @as(u128, 0x00000000000000000000000000000001)); |
| 41 | 40 | pub const f128_min = @bitCast(f128, @as(u128, 0x00010000000000000000000000000000)); |
| 42 | 41 | pub const f128_max = @bitCast(f128, @as(u128, 0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF)); |
| ... | ... | @@ -44,12 +43,10 @@ pub const f128_epsilon = @bitCast(f128, @as(u128, 0x3F8F000000000000000000000000 |
| 44 | 43 | pub const f128_toint = 1.0 / f128_epsilon; |
| 45 | 44 | |
| 46 | 45 | pub const F80Repr = if (@import("builtin").cpu.arch.endian() == .Little) extern struct { |
| 47 | fraction: u64, | |
| 46 | fraction: u64 align(@alignOf(f80)), | |
| 48 | 47 | exp: u16, |
| 49 | _pad: u32 = undefined, | |
| 50 | 48 | } else extern struct { |
| 51 | exp: u16, | |
| 52 | _pad: u32 = undefined, // TODO verify compatibility with hardware | |
| 49 | exp: u16 align(@alignOf(f80)), | |
| 53 | 50 | fraction: u64, |
| 54 | 51 | }; |
| 55 | 52 |
src/codegen/llvm.zig+22-12| ... | ... | @@ -1257,19 +1257,29 @@ pub const DeclGen = struct { |
| 1257 | 1257 | }, |
| 1258 | 1258 | .Float => { |
| 1259 | 1259 | 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, | |
| 1269 | 1282 | } |
| 1270 | ||
| 1271 | const int = dg.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf); | |
| 1272 | return int.constBitCast(llvm_ty); | |
| 1273 | 1283 | }, |
| 1274 | 1284 | .Pointer => switch (tv.val.tag()) { |
| 1275 | 1285 | .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) { |
| 9429 | 9429 | |
| 9430 | 9430 | { |
| 9431 | 9431 | 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 | } | |
| 9432 | 9447 | if (target_has_f80(g->zig_target)) { |
| 9433 | 9448 | entry->llvm_type = LLVMX86FP80Type(); |
| 9434 | 9449 | } 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, | |
| 9436 | 9451 | // LLVM will give "ERROR: Cannot select" for any instructions involving |
| 9437 | 9452 | // 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; | |
| 9439 | 9454 | } |
| 9440 | entry->size_in_bits = 8 * 16; | |
| 9441 | entry->abi_size = 16; // matches LLVMABISizeOfType(LLVMX86FP80Type()) | |
| 9442 | entry->abi_align = 16; // matches LLVMABIAlignmentOfType(LLVMX86FP80Type()) | |
| 9443 | 9455 | buf_init_from_str(&entry->name, "f80"); |
| 9444 | 9456 | entry->data.floating.bit_count = 80; |
| 9445 | 9457 |
src/value.zig+26-4| ... | ... | @@ -1122,10 +1122,32 @@ pub const Value = extern union { |
| 1122 | 1122 | |
| 1123 | 1123 | fn floatReadFromMemory(comptime F: type, target: Target, buffer: []const u8) F { |
| 1124 | 1124 | 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 | } | |
| 1129 | 1151 | } |
| 1130 | 1152 | const Int = @Type(.{ .Int = .{ |
| 1131 | 1153 | .signedness = .unsigned, |