@@ -457,17 +457,38 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) {
457
457
auto dstBitWidth =
458
458
builtin.Types [1 ]->castTo <BuiltinIntegerType>()->getGreatestWidth ();
459
459
460
- APInt result = operandVal.trunc (dstBitWidth);
460
+ // Get source type and bit width.
461
+ auto SrcTy = builtin.Types [0 ]->castTo <AnyBuiltinIntegerType>();
462
+ assert ((srcSigned || !isa<BuiltinIntegerLiteralType>(SrcTy)) &&
463
+ " only the signed intrinsics can be used with integer literals" );
464
+
465
+ assert ((dstBitWidth < srcBitWidth || !SrcTy->getWidth ().isFixedWidth ()) &&
466
+ " preconditions on builtin trunc operations should prevent"
467
+ " fixed-width truncations that actually extend" );
468
+ APInt result;
469
+ bool overflowed;
470
+ if (dstBitWidth > srcBitWidth) {
471
+ // The only way a true extension can overflow is if the value is
472
+ // negative and the result is unsigned.
473
+ overflowed = (srcSigned && !dstSigned && operandVal.isNegative ());
474
+ result =
475
+ srcSigned ? operandVal.sext (dstBitWidth) : operandVal.zext (dstBitWidth);
476
+ } else if (dstBitWidth == srcBitWidth) {
477
+ // A same-width change can overflow if the top bit disagrees.
478
+ overflowed = (srcSigned != dstSigned && operandVal.isNegative ());
479
+ } else {
480
+ // Truncate the result and check for overflow.
481
+ result = operandVal.trunc (dstBitWidth);
461
482
462
- // Compute the overflow by re-extending the value back to its source and
463
- // checking for loss of value.
464
- APInt reextended =
483
+ // Compute the overflow by re-extending the value back to its source and
484
+ // checking for loss of value.
485
+ APInt reextended =
465
486
dstSigned ? result.sext (srcBitWidth) : result.zext (srcBitWidth);
466
- bool overflowed = (operandVal != reextended);
467
-
468
- if (builtin.ID == BuiltinValueKind::UToSCheckedTrunc)
469
- overflowed |= result.isSignBitSet ();
487
+ overflowed = (operandVal != reextended);
470
488
489
+ if (builtin.ID == BuiltinValueKind::UToSCheckedTrunc)
490
+ overflowed |= result.isSignBitSet ();
491
+ }
471
492
if (overflowed)
472
493
return evaluator.getUnknown (SILValue (inst), UnknownReason::Overflow);
473
494
0 commit comments