Skip to content

Commit 395aa00

Browse files
authored
Merge pull request #17274 from ravikandhadai/IntToFloatPR
2 parents 7d8e40b + 193407b commit 395aa00

7 files changed

+118
-37
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,11 @@ WARNING(warning_float_overflows_maxbuiltin, none,
337337
"'%0' overflows to %select{|-}1inf because its magnitude exceeds "
338338
"the limits of a float literal", (StringRef, bool))
339339

340+
// Integer to floating-point conversions
341+
WARNING(warning_int_to_fp_inexact, none,
342+
"'%1' is not exactly representable as %0; it becomes '%2'",
343+
(Type, StringRef, StringRef))
344+
340345
#ifndef DIAG_NO_UNDEF
341346
# if defined(DIAG)
342347
# undef DIAG

lib/SILOptimizer/Utils/ConstantFolding.cpp

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,8 @@ bool isHexLiteralInSource(FloatLiteralInst *flitInst) {
10871087
}
10881088

10891089
bool maybeExplicitFPCons(BuiltinInst *BI, const BuiltinInfo &Builtin) {
1090-
assert(Builtin.ID == BuiltinValueKind::FPTrunc);
1090+
assert(Builtin.ID == BuiltinValueKind::FPTrunc ||
1091+
Builtin.ID == BuiltinValueKind::IntToFPWithOverflow);
10911092

10921093
auto *callExpr = BI->getLoc().getAsASTNode<CallExpr>();
10931094
if (!callExpr || !dyn_cast<ConstructorRefCallExpr>(callExpr->getFn()))
@@ -1253,21 +1254,38 @@ case BuiltinValueKind::id:
12531254
SILLocation Loc = BI->getLoc();
12541255
const ApplyExpr *CE = Loc.getAsASTNode<ApplyExpr>();
12551256

1256-
// Check for overflow.
1257-
if (ConversionStatus & APFloat::opOverflow) {
1258-
// If we overflow and are not asked for diagnostics, just return nullptr.
1259-
if (!ResultsInError.hasValue())
1260-
return nullptr;
1257+
bool overflow = ConversionStatus & APFloat::opOverflow;
1258+
bool inexact = ConversionStatus & APFloat::opInexact;
12611259

1262-
SmallString<10> SrcAsString;
1263-
SrcVal.toString(SrcAsString, /*radix*/10, true /*isSigned*/);
1260+
if (overflow || inexact) {
1261+
// Check if diagnostics is enabled. If so, make sure to suppress
1262+
// warnings for conversions through explicit initializers,
1263+
// but do not suppress errors.
1264+
if (ResultsInError.hasValue() &&
1265+
(overflow || !maybeExplicitFPCons(BI, Builtin))) {
1266+
SmallString<10> SrcAsString;
1267+
SrcVal.toString(SrcAsString, /*radix*/ 10, true /*isSigned*/);
12641268

1265-
// Otherwise emit our diagnostics and then return nullptr.
1266-
diagnose(M.getASTContext(), Loc.getSourceLoc(),
1267-
diag::integer_literal_overflow,
1268-
CE ? CE->getType() : DestTy, SrcAsString);
1269-
ResultsInError = Optional<bool>(true);
1270-
return nullptr;
1269+
if (overflow) {
1270+
diagnose(M.getASTContext(), Loc.getSourceLoc(),
1271+
diag::integer_literal_overflow, CE ? CE->getType() : DestTy,
1272+
SrcAsString);
1273+
} else {
1274+
SmallString<10> destStr;
1275+
unsigned srcBitWidth = SrcVal.getBitWidth();
1276+
// Display the 'TruncVal' like an integer in order to make the
1277+
// imprecision due to floating-point representation obvious.
1278+
TruncVal.toString(destStr, srcBitWidth, srcBitWidth);
1279+
diagnose(M.getASTContext(), Loc.getSourceLoc(),
1280+
diag::warning_int_to_fp_inexact, CE ? CE->getType() : DestTy,
1281+
SrcAsString, destStr);
1282+
}
1283+
ResultsInError = Optional<bool>(true);
1284+
}
1285+
// If there is an overflow, just return nullptr as this is undefined
1286+
// behavior. Otherwise, continue folding as in the normal workflow.
1287+
if (overflow)
1288+
return nullptr;
12711289
}
12721290

12731291
// The call to the builtin should be replaced with the constant value.

test/SILOptimizer/diagnostic_constant_propagation.swift

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -185,49 +185,53 @@ func testConvertOverflow() {
185185
Int64(UInt32(200)) // expected-warning{{unused}}
186186
UInt64(UInt32(200)) // expected-warning{{unused}}
187187

188-
// IEEE binary32 max value = 2^128 * (2^23-1)/2^23
189-
var _ /*float32_max*/ : Float32 = (340282326356119256160033759537265639424)
190-
var _ /*float32_max_p1*/ : Float32 = (340282326356119256160033759537265639425)
191188

192-
// 2^128 * (2^25-1)/2^25 - 1
193-
var _ /*float32_max_not_yet_overflow*/ : Float32 = (340282356779733661637539395458142568447)
194-
// 2^128 * (2^25-1)/2^25
189+
var _ /*float32_max*/ : Float32 = (340282346638528859811704183484516925440) // in hexfloat = 0x1.fffffep127
190+
191+
var _ /*float32_near_max_but_imprecise*/ : Float32 = (340282326356119256160033759537265639425) // expected-warning {{'340282326356119256160033759537265639425' is not exactly representable as 'Float32' (aka 'Float'); it becomes '340282326356119256160033759537265639424'}}
192+
193+
// FIXME: false negative: this should flagged as an overflow error but it doesn't due to a bug (possibly in LLVM::APFloat) <rdar://40079582>
194+
var _ /*float32_max_not_yet_overflow??*/ : Float32 = (340282356779733661637539395458142568447) // expected-warning {{'340282356779733661637539395458142568447' is not exactly representable as 'Float32' (aka 'Float'); it becomes '340282346638528859811704183484516925440'}}
195+
195196
var _ /*float32_max_first_overflow*/ : Float32 = (340282356779733661637539395458142568448) // expected-error {{integer literal '340282356779733661637539395458142568448' overflows when stored into 'Float32'}}
196197

197198
// 2^128
198199
var _ /*float32_max_definitely_overflow*/ : Float32 = (340282366920938463463374607431768211456) // expected-error {{integer literal '340282366920938463463374607431768211456' overflows when stored into 'Float32'}}
199200

200-
// IEEE binary32 min value = -1 * 2^128 * (2^23-1)/2^23
201-
var _ /*float32_min*/ : Float32 = (-340282326356119256160033759537265639424)
202-
var _ /*float32_min_p1*/ : Float32 = (-340282326356119256160033759537265639425)
201+
// IEEE binary32 min value
202+
var _ /*float32_min*/ : Float32 = -340282346638528859811704183484516925440 // (in hexfloat) = -0x1.fffffep127
203+
var _ /*float32_near_min*/ : Float32 = (-340282326356119256160033759537265639424)
204+
var _ /*float32_min_p1*/ : Float32 = (-340282326356119256160033759537265639425) // expected-warning {{'-340282326356119256160033759537265639425' is not exactly representable as 'Float32' (aka 'Float'); it becomes '-340282326356119256160033759537265639424'}}
205+
206+
// FIXME: false negative: this should be flagged by overflow diagnostics
207+
var _ /*float32_min_not_yet_overflow??*/ : Float32 = (-340282356779733661637539395458142568447) // expected-warning {{'-340282356779733661637539395458142568447' is not exactly representable as 'Float32' (aka 'Float'); it becomes '-340282346638528859811704183484516925440'}}
203208

204-
// -1 * 2^128 * (2^25-1)/2^25 - 1
205-
var _ /*float32_min_not_yet_overflow*/ : Float32 = (-340282356779733661637539395458142568447)
206-
// -1 * 2^128 * (2^25-1)/2^25
207209
var _ /*float32_min_first_overflow*/ : Float32 = (-340282356779733661637539395458142568448) // expected-error {{integer literal '-340282356779733661637539395458142568448' overflows when stored into 'Float32'}}
208210

209211
// -1 * 2^128
210212
var _ /*float32_min_definitely_overflow*/ : Float32 = (-340282366920938463463374607431768211456) // expected-error {{integer literal '-340282366920938463463374607431768211456' overflows when stored into 'Float32'}}
211213

212-
// IEEE binary64 max value = 2^1024 * (2^52-1)/2^52
213-
var _ /*float64_max*/ : Float64 = (179769313486231550856124328384506240234343437157459335924404872448581845754556114388470639943126220321960804027157371570809852884964511743044087662767600909594331927728237078876188760579532563768698654064825262115771015791463983014857704008123419459386245141723703148097529108423358883457665451722744025579520)
214-
var _ /*float64_max_p1*/ : Float64 = (179769313486231550856124328384506240234343437157459335924404872448581845754556114388470639943126220321960804027157371570809852884964511743044087662767600909594331927728237078876188760579532563768698654064825262115771015791463983014857704008123419459386245141723703148097529108423358883457665451722744025579520)
214+
// IEEE binary64 max value in hexfloat notation
215+
var _ /*float64_max*/ : Float64 = 0x1.fffffffffffffp1023
216+
var _ /*float64_near_max*/ : Float64 = (179769313486231550856124328384506240234343437157459335924404872448581845754556114388470639943126220321960804027157371570809852884964511743044087662767600909594331927728237078876188760579532563768698654064825262115771015791463983014857704008123419459386245141723703148097529108423358883457665451722744025579520)
217+
var _ /*float64_near_max_p1*/ : Float64 = (179769313486231550856124328384506240234343437157459335924404872448581845754556114388470639943126220321960804027157371570809852884964511743044087662767600909594331927728237078876188760579532563768698654064825262115771015791463983014857704008123419459386245141723703148097529108423358883457665451722744025579520)
218+
219+
// FIXME: false negative: this should be flagged by overflow diagnostics
220+
var _/*float64_max_not_yet_overflo??*/ : Float64 = (179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791)
215221

216-
// 2^1024 * (2^54-1)/2^54 - 1
217-
var _/*float64_max_not_yet_overflow*/ : Float64 = (179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791)
218-
// 2^1024 * (2^54-1)/2^54
219-
var _ /*float64_max_first_overflow*/ : Float64 = (179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792) // expected-error {{integer literal '179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792' overflows when stored into 'Double'}}
222+
var _ /*float64_max_first_overflow*/ : Float64 = (179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792) // expected-error {{integer literal '179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792' overflows when stored into 'Double'}}
220223

221224
// 2^1024
222225
var _/*float64_max_definitely_overflow*/ : Float64 = (179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216) // expected-error {{integer literal '179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216' overflows when stored into 'Double'}}
223226

224227
// IEEE binary64 min value = -1 * 2^1024 * (2^52-1)/2^52
225-
var _/*float64_min*/ : Float64 = (-179769313486231550856124328384506240234343437157459335924404872448581845754556114388470639943126220321960804027157371570809852884964511743044087662767600909594331927728237078876188760579532563768698654064825262115771015791463983014857704008123419459386245141723703148097529108423358883457665451722744025579520)
226-
var _/*float64_min_p1*/ : Float64 = (-179769313486231550856124328384506240234343437157459335924404872448581845754556114388470639943126220321960804027157371570809852884964511743044087662767600909594331927728237078876188760579532563768698654064825262115771015791463983014857704008123419459386245141723703148097529108423358883457665451722744025579520)
228+
var _/*float64_min*/ : Float64 = -0x1.fffffffffffffp1023
229+
var _/*float64_near_min*/ : Float64 = (-179769313486231550856124328384506240234343437157459335924404872448581845754556114388470639943126220321960804027157371570809852884964511743044087662767600909594331927728237078876188760579532563768698654064825262115771015791463983014857704008123419459386245141723703148097529108423358883457665451722744025579520)
230+
var _/*float64_near_min_p1*/ : Float64 = (-179769313486231550856124328384506240234343437157459335924404872448581845754556114388470639943126220321960804027157371570809852884964511743044087662767600909594331927728237078876188760579532563768698654064825262115771015791463983014857704008123419459386245141723703148097529108423358883457665451722744025579520)
227231

228-
// -1 * 2^1024 * (2^54-1)/2^54 - 1
232+
// FIXME: flase negative: this should be flagged by overflow diagnostics
229233
var _/*float64_min_not_yet_overflow*/ : Float64 = (-179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791)
230-
// -1 * 2^1024 * (2^54-1)/2^54
234+
231235
var _/*float64_min_first_overflow*/ : Float64 = (-179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792) // expected-error {{integer literal '-179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792' overflows when stored into 'Double'}}
232236

233237
// -1 * 2^1024

test/SILOptimizer/diagnostic_constant_propagation_floats.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,28 @@ func testFloatArithmetic() {
191191
let b: Float = 10.0
192192
_blackHole(a * b)
193193
}
194+
195+
func testIntToFloatConversion() {
196+
let f1: Float = 16777216
197+
_blackHole(f1)
198+
199+
let f2: Float = 1_000_000_000_000 // expected-warning {{'1000000000000' is not exactly representable as 'Float'; it becomes '999999995904'}}
200+
_blackHole(f2)
201+
202+
// First positive integer that cannot be precisely represented in Float: 2^24 + 1
203+
let f3: Float = 16777217 // expected-warning {{'16777217' is not exactly representable as 'Float'; it becomes '16777216'}}
204+
_blackHole(f3)
205+
206+
let d1: Double = 9_007_199_254_740_992 // This value is 2^53
207+
_blackHole(d1)
208+
209+
// FIXME: False Negative: no warning is produced here since we do not
210+
// distinguish between implicit Double conversion that are within the
211+
// context of an explicit conversion from others.
212+
let d2: Double = 9_007_199_254_740_993
213+
_blackHole(d2)
214+
215+
// No warnings are emitted for conversion through explicit constructor calls.
216+
_blackHole(Float(16777217))
217+
_blackHole(Double(2_147_483_647))
218+
}

test/SILOptimizer/diagnostic_constant_propagation_floats_x86.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,16 @@ func testHexFloatImprecision() {
101101
_blackHole(Double(0x1.00000000000001p-1000))
102102
_blackHole(Float80(0x1p-1075))
103103
}
104+
105+
func testIntToFloatConversion() {
106+
let e1: Float80 = 18_446_744_073_709_551_616 // This value is 2^64
107+
_blackHole(e1)
108+
109+
let e2: Float80 = 18_446_744_073_709_551_617 // expected-warning {{'18446744073709551617' is not exactly representable as 'Float80'; it becomes '18446744073709551616'}}
110+
_blackHole(e2)
111+
112+
// No warnings are emitted for conversion through explicit constructor calls.
113+
// Note that the error here is because of an implicit conversion of the input
114+
// literal to 'Int'.
115+
_blackHole(Float80(18_446_744_073_709_551_617)) // expected-error {{integer literal '18446744073709551617' overflows when stored into 'Int'}}
116+
}

test/SILOptimizer/diagnostic_constant_propagation_int_arch32.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
//
1414
// FIXME: <rdar://problem/39193272> A false negative that happens only in REPL
1515

16+
import StdlibUnittest
17+
1618
func testArithmeticOverflow_Int_32bit() {
1719
do {
1820
// Literals.
@@ -230,3 +232,10 @@ func testArithmeticOverflow_UInt_32bit() {
230232
var _ : UInt = (0x7fff_ffff) | 0x8000_0000
231233
}
232234
}
235+
236+
func testIntToFloatConversion() {
237+
// No warnings are emitted for conversion through explicit constructor calls.
238+
// Note that the error here is because of an implicit conversion of the input
239+
// literal to 'Int', which is 32 bits in arch32.
240+
_blackHole(Double(9_007_199_254_740_993)) // expected-error {{integer literal '9007199254740993' overflows when stored into 'Int'}}
241+
}

test/SILOptimizer/diagnostic_constant_propagation_int_arch64.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
//
1414
// FIXME: <rdar://problem/39193272> A false negative that happens only in REPL
1515

16+
import StdlibUnittest
17+
1618
func testArithmeticOverflow_Int_64bit() {
1719
do {
1820
// Literals.
@@ -233,3 +235,8 @@ func testArithmeticOverflow_UInt_64bit() {
233235
var _ : UInt = (0x7fff_ffff) | 0x8000_0000_0000_0000
234236
}
235237
}
238+
239+
func testIntToFloatConversion() {
240+
// No warnings are emitted for conversion through explicit constructor calls.
241+
_blackHole(Double(9_007_199_254_740_993))
242+
}

0 commit comments

Comments
 (0)