From 11efa58a6c875df2e07fb0c165feb9a05a3b3a09 Mon Sep 17 00:00:00 2001 From: Ravi Kandhadai Date: Fri, 21 Jun 2019 19:26:54 -0700 Subject: [PATCH] [Const Evaluator] Make compile-time constant evaluator correctly handle s_to_s_checked_trunc_IntLiteral_IntNN where the bit width of the source symbolic value (an APInt) could be smaller than the destination bits. --- lib/SILOptimizer/Utils/ConstExpr.cpp | 29 +++++++++++-------- test/SILOptimizer/constant_evaluator_test.sil | 9 ++++++ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/lib/SILOptimizer/Utils/ConstExpr.cpp b/lib/SILOptimizer/Utils/ConstExpr.cpp index 911f7e31456fc..0c5846835fda5 100644 --- a/lib/SILOptimizer/Utils/ConstExpr.cpp +++ b/lib/SILOptimizer/Utils/ConstExpr.cpp @@ -448,30 +448,35 @@ ConstExprFunctionState::computeConstantValueBuiltin(BuiltinInst *inst) { if (operand.getKind() != SymbolicValue::Integer) return unknownResult(); - auto operandVal = operand.getIntegerValue(); + APInt operandVal = operand.getIntegerValue(); uint32_t srcBitWidth = operandVal.getBitWidth(); auto dstBitWidth = builtin.Types[1]->castTo()->getGreatestWidth(); - APInt result = operandVal.trunc(dstBitWidth); + // Note that the if the source type is a Builtin.IntLiteral, operandVal + // could have fewer bits than the destination bit width and may only + // require a sign extension. + APInt result = operandVal.sextOrTrunc(dstBitWidth); - // Compute the overflow by re-extending the value back to its source and - // checking for loss of value. - APInt reextended = - dstSigned ? result.sext(srcBitWidth) : result.zext(srcBitWidth); - bool overflowed = (operandVal != reextended); + // Determine if there is a overflow. + if (operandVal.getBitWidth() > dstBitWidth) { + // Re-extend the value back to its source and check for loss of value. + APInt reextended = + dstSigned ? result.sext(srcBitWidth) : result.zext(srcBitWidth); + bool overflowed = (operandVal != reextended); - if (!srcSigned && dstSigned) - overflowed |= result.isSignBitSet(); + if (!srcSigned && dstSigned) + overflowed |= result.isSignBitSet(); - if (overflowed) - return evaluator.getUnknown(SILValue(inst), UnknownReason::Overflow); + if (overflowed) + return evaluator.getUnknown(SILValue(inst), UnknownReason::Overflow); + } auto &allocator = evaluator.getAllocator(); // Build the Symbolic value result for our truncated value. return SymbolicValue::getAggregate( {SymbolicValue::getInteger(result, allocator), - SymbolicValue::getInteger(APInt(1, overflowed), allocator)}, + SymbolicValue::getInteger(APInt(1, false), allocator)}, allocator); }; diff --git a/test/SILOptimizer/constant_evaluator_test.sil b/test/SILOptimizer/constant_evaluator_test.sil index 0d8a344d7ed6b..abb0d701e931b 100644 --- a/test/SILOptimizer/constant_evaluator_test.sil +++ b/test/SILOptimizer/constant_evaluator_test.sil @@ -153,6 +153,15 @@ bb0: return %2 : $(Builtin.Int8) } // CHECK: Returns int: -1 +// CHECK-LABEL: @interpretSignedTruncWithIntLiteral +sil @interpretSignedTruncWithIntLiteral : $@convention(thin) () -> Builtin.Int64 { +bb0: + %0 = integer_literal $Builtin.IntLiteral, 5 + %1 = builtin "s_to_s_checked_trunc_IntLiteral_Int64"(%0 : $Builtin.IntLiteral) : $(Builtin.Int64, Builtin.Int1) + %2 = tuple_extract %1 : $(Builtin.Int64, Builtin.Int1), 0 + return %2 : $(Builtin.Int64) +} // CHECK: Returns int: 5 + // CHECK-LABEL: @interpretSignedExtend sil @interpretSignedExtend : $@convention(thin) () -> Builtin.Int64 { bb0: