From 04770f6124fef4adae5b86bc4dc4650585b0a44e Mon Sep 17 00:00:00 2001 From: Ravi Kandhadai Date: Tue, 5 Mar 2019 15:40:14 -0800 Subject: [PATCH] [SIL Diagnostics] Fix undefined behavior due to bit shifting in ConstantFolding.cpp --- lib/SILOptimizer/Utils/ConstantFolding.cpp | 7 +++++-- .../diagnostic_constant_propagation_floats.swift | 8 ++++++++ .../diagnostic_constant_propagation_floats_x86.swift | 9 +++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/SILOptimizer/Utils/ConstantFolding.cpp b/lib/SILOptimizer/Utils/ConstantFolding.cpp index adfe7814fda80..cfebd85d79662 100644 --- a/lib/SILOptimizer/Utils/ConstantFolding.cpp +++ b/lib/SILOptimizer/Utils/ConstantFolding.cpp @@ -995,11 +995,14 @@ bool isLossyUnderflow(int srcExponent, uint64_t srcSignificand, : srcSignificand; // Compute the significand bits lost due to subnormal form. Note that the - // integer part: 1 will use up a significand bit in denormal form. + // integer part: 1 will use up a significand bit in subnormal form. unsigned additionalLoss = destSem.minExponent - srcExponent + 1; + // Lost bits cannot exceed Double.minExponent - Double.significandWidth = 53. + // This can happen when truncating from Float80 to Double. + assert(additionalLoss <= 53); // Check whether a set LSB is lost due to subnormal representation. - unsigned lostLSBBitMask = (1 << additionalLoss) - 1; + uint64_t lostLSBBitMask = ((uint64_t)1 << additionalLoss) - 1; return (truncSignificand & lostLSBBitMask); } diff --git a/test/SILOptimizer/diagnostic_constant_propagation_floats.swift b/test/SILOptimizer/diagnostic_constant_propagation_floats.swift index fe7bd1a4ea1fa..5f708afa63292 100644 --- a/test/SILOptimizer/diagnostic_constant_propagation_floats.swift +++ b/test/SILOptimizer/diagnostic_constant_propagation_floats.swift @@ -171,6 +171,14 @@ func testHexFloatImprecision() { // Smallest non-zero number representable in Double. let d2: Double = 0x0.0000000000001p-1022 _blackHole(d2) + let d3: Double = 0x1p-1074 + _blackHole(d3) + + // Test the case where conversion results in subnormality in the destination. + let d4: Float = 0x1p-149 + _blackHole(d4) + let d5: Float = 0x1.8p-149 // expected-warning {{'0x1.8p-149' loses precision during conversion to 'Float}} + _blackHole(d5) // All warnings are disabled during explict conversions. _blackHole(Float(0x1.000002p-126)) diff --git a/test/SILOptimizer/diagnostic_constant_propagation_floats_x86.swift b/test/SILOptimizer/diagnostic_constant_propagation_floats_x86.swift index d71773940cd81..04a4fe3906f25 100644 --- a/test/SILOptimizer/diagnostic_constant_propagation_floats_x86.swift +++ b/test/SILOptimizer/diagnostic_constant_propagation_floats_x86.swift @@ -67,11 +67,20 @@ func testFloatConvertUnderflow() { let d4: Double = 5E-324 // expected-warning {{'5E-324' underflows and loses precision during conversion to 'Double'}} _blackHole(d4) + let e4: Float80 = 0x1p-16445 + _blackHole(e4) + // FIXME: if a number is so tiny that it underflows even Float80, // nothing is reported let e1: Float80 = 0x1p-16446 _blackHole(e1) + // Test the case where conversion results in subnormality in the destination. + let e2: Double = 0x1p-1074 + _blackHole(e2) + let e3: Double = 0x11p-1074 // expected-warning {{'0x11p-1074' underflows and loses precision during conversion to 'Double'}} + _blackHole(e3) + // All warnings are disabled during explict conversions _blackHole(Float(1E-400)) _blackHole(Double(1E-309))