From patchwork Fri Nov 16 21:17:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 999155 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-490333-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gdcproject.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="vi4JRK5P"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42xWL36y1Fz9s9h for ; Sat, 17 Nov 2018 08:18:17 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=mPZzrpC4A0zRRuUqbGHwzJVLqqFLbxoa0pEe3r2fGX3FJC +tlbfqkfjulLUQY4CzduDlQurF9Od2lOo21mcLrbQqZxYzK45z79aNAGiGBLIuf1 bL3eqohMtcqybT+a1DO3OJDQn5Jcrm8GcUiVXpAvsi7XhV8bb5h2tWykwtJpQ= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=L7clhiwWR2yTPOLNudevLtqYhuk=; b=vi4JRK5PatSxiW4JidoA u/d1GeWF/VQHU47PXEXjT0rU14VA/VSiibrjnFZoGegPzHcc2Cserj/l2ByG63pZ HjWFYHK/iKmnM2USiEnH3e43mr2yeq81VStki1gDOC38uKCs5O6hFh3b0OqKCaAY FvYLiP/NuAi/9MdhZ2i0q/0= Received: (qmail 11790 invoked by alias); 16 Nov 2018 21:18:10 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 11777 invoked by uid 89); 16 Nov 2018 21:18:09 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.3 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=trusted, highest, 1013, zeroing X-HELO: mail-qk1-f175.google.com Received: from mail-qk1-f175.google.com (HELO mail-qk1-f175.google.com) (209.85.222.175) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 16 Nov 2018 21:18:07 +0000 Received: by mail-qk1-f175.google.com with SMTP id n12so39724206qkh.11 for ; Fri, 16 Nov 2018 13:18:07 -0800 (PST) MIME-Version: 1.0 From: Iain Buclaw Date: Fri, 16 Nov 2018 22:17:53 +0100 Message-ID: Subject: [PATCH, libphobos] Committed IEEE quadruple support to core.internal.convert To: gcc-patches X-IsSubscribed: yes This patch is backported from druntime 2.083, primarily for beginning to finish off AArch64 library support, but should apply to any targets that use 128-bit IEEE long doubles. Bootstrapped and ran D2 testsuite on x86_64-linux-gnu. Commited to trunk as r266222. diff --git a/libphobos/libdruntime/core/internal/convert.d b/libphobos/libdruntime/core/internal/convert.d index a612707e267..c4745b6f5a7 100644 --- a/libphobos/libdruntime/core/internal/convert.d +++ b/libphobos/libdruntime/core/internal/convert.d @@ -10,13 +10,36 @@ module core.internal.convert; import core.internal.traits : Unqual; +/+ +A @nogc function can allocate memory during CTFE. ++/ +@nogc nothrow pure @trusted +private ubyte[] ctfe_alloc()(size_t n) +{ + if (!__ctfe) + { + assert(0, "CTFE only"); + } + else + { + static ubyte[] alloc(size_t x) nothrow pure + { + if (__ctfe) // Needed to prevent _d_newarray from appearing in compiled prorgam. + return new ubyte[x]; + else + assert(0); + } + return (cast(ubyte[] function(size_t) @nogc nothrow pure) &alloc)(n); + } +} + @trusted pure nothrow -const(ubyte)[] toUbyte(T)(ref T val) if (is(Unqual!T == float) || is(Unqual!T == double) || is(Unqual!T == real) || +const(ubyte)[] toUbyte(T)(const ref T val) if (is(Unqual!T == float) || is(Unqual!T == double) || is(Unqual!T == real) || is(Unqual!T == ifloat) || is(Unqual!T == idouble) || is(Unqual!T == ireal)) { static const(ubyte)[] reverse_(const(ubyte)[] arr) { - ubyte[] buff = new ubyte[arr.length]; + ubyte[] buff = ctfe_alloc(arr.length); foreach (k, v; arr) { buff[$-k-1] = v; @@ -31,17 +54,35 @@ const(ubyte)[] toUbyte(T)(ref T val) if (is(Unqual!T == float) || is(Unqual!T == uint exp = parsed.exponent; uint sign = parsed.sign; - ubyte[T.sizeof] buff; + ubyte[] buff = ctfe_alloc(T.sizeof); size_t off_bytes = 0; size_t off_bits = 0; + // Quadruples won't fit in one ulong, so check for that. + enum mantissaMax = FloatTraits!T.MANTISSA < ulong.sizeof*8 ? + FloatTraits!T.MANTISSA : ulong.sizeof*8; - for (; off_bytes < FloatTraits!T.MANTISSA/8; ++off_bytes) + for (; off_bytes < mantissaMax/8; ++off_bytes) { buff[off_bytes] = cast(ubyte)mantissa; mantissa >>= 8; } - off_bits = FloatTraits!T.MANTISSA%8; - buff[off_bytes] = cast(ubyte)mantissa; + + static if (floatFormat!T == FloatFormat.Quadruple) + { + ulong mantissa2 = parsed.mantissa2; + off_bytes--; // go back one, since mantissa only stored data in 56 + // bits, ie 7 bytes + for(; off_bytes < FloatTraits!T.MANTISSA/8; ++off_bytes) + { + buff[off_bytes] = cast(ubyte)mantissa2; + mantissa2 >>= 8; + } + } + else + { + off_bits = FloatTraits!T.MANTISSA%8; + buff[off_bytes] = cast(ubyte)mantissa; + } for (size_t i=0; i> pow; + return Float(fl.mantissa >> pow, 0, sign); } @safe pure nothrow -private ulong denormalizedMantissa(T)(T x) if (floatFormat!T != FloatFormat.Real80) +private Float denormalizedMantissa(T)(T x, uint sign) + if (floatFormat!T == FloatFormat.Float || floatFormat!T == FloatFormat.Double) { x *= 2.0L^^FloatTraits!T.MANTISSA; auto fl = parse!true(x); ulong mant = fl.mantissa >> (FloatTraits!T.MANTISSA - fl.exponent); - return shiftrRound(mant); + return Float(shiftrRound(mant), 0, sign); +} + +@safe pure nothrow +private Float denormalizedMantissa(T)(T x, uint sign) if (floatFormat!T == FloatFormat.Quadruple) +{ + x *= 2.0L^^FloatTraits!T.MANTISSA; + auto fl = parse!true(x); + uint offset = FloatTraits!T.MANTISSA - fl.exponent + 1; + enum mantissaSize = (ulong.sizeof - 1) * 8; + + if (offset < mantissaSize) + { // Create a new mantissa ulong with the trailing mantissa2 bits that + // need to be shifted into mantissa, by shifting the needed bits left, + // zeroing out the first byte, and then ORing it with mantissa shifted + // right by offset. + + ulong shiftedMantissa = ((fl.mantissa2 << (mantissaSize - offset)) & + 0x00FFFFFFFFFFFFFFUL) | fl.mantissa >> offset; + return Float(shiftedMantissa, 0, sign, fl.mantissa2 >> offset); + } + else if (offset > mantissaSize) + return Float(fl.mantissa2 >> offset - mantissaSize , 0, sign, 0); + else + // Handle special case mentioned in parse() above by zeroing out the + // 57'th bit of mantissa2, "shifting" it into mantissa, and setting the + // first bit of mantissa2. + return Float(fl.mantissa2 & 0x00FFFFFFFFFFFFFFUL , 0, sign, 1); } version (unittest) @@ -403,6 +494,8 @@ version (unittest) testNumberConvert!("real.min_normal/2"); testNumberConvert!("real.min_normal/2UL^^63"); + // check subnormal storage edge case for Quadruple + testNumberConvert!("real.min_normal/2UL^^56"); //testNumberConvert!("real.min_normal/19"); // XGDC: ct[0] == 0, rt[0] == 27 //testNumberConvert!("real.min_normal/17"); // XGDC: ct[0= == 128, rt[0] == 136