From 78902db68bbd400f6d84b65280c31d417105f2a8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 4 Oct 2021 23:30:04 -0700 Subject: stage2: fix comptime `@bitCast` Before, Sema for comptime `@bitCast` would return the same Value but change the Type. This gave invalid results because, for example, an integer Value when the Type is a float would be interpreted numerically, but `@bitCast` needs it to reinterpret how they would be stored in memory. This requires a mechanism to serialize a Value to a byte buffer and deserialize a Value from a byte buffer. Not done yet, but needs to happen: comptime dereferencing a pointer to a Decl needs to perform a comptime bitcast on the loaded value. Currently the value is silently wrong in the same way that `@bitCast` was silently wrong before this commit. The logic in Value for handling readFromMemory for large integers is only correct for small integers. It needs to be fleshed out for proper big integers. As part of this change: * std.math.big.Int: initial implementations of readTwosComplement and writeTwosComplement. They only support bit_count <= 128 so far and panic otherwise. * compiler-rt: move the compareXf2 exports over to the stage2 section. Even with the improvements in this commit, I'm still seeing test failures in the widening behavior tests; more investigation is needed. --- src/codegen/llvm.zig | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'src/codegen') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 63960dddba..ec3c955c7b 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const builtin = @import("builtin"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; const Compilation = @import("../Compilation.zig"); @@ -6,6 +7,7 @@ const llvm = @import("llvm/bindings.zig"); const link = @import("../link.zig"); const log = std.log.scoped(.codegen); const math = std.math; +const native_endian = builtin.cpu.arch.endian(); const build_options = @import("build_options"); const Module = @import("../Module.zig"); @@ -958,11 +960,20 @@ pub const DeclGen = struct { return llvm_int; }, .Float => { + const llvm_ty = try self.llvmType(tv.ty); if (tv.ty.floatBits(self.module.getTarget()) <= 64) { - const llvm_ty = try self.llvmType(tv.ty); return llvm_ty.constReal(tv.val.toFloat(f64)); } - return self.todo("bitcast to f128 from an integer", .{}); + + 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 = self.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf); + return int.constBitCast(llvm_ty); }, .Pointer => switch (tv.val.tag()) { .decl_ref => { -- cgit v1.2.3