ConstantRange ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp, const ConstantRange &Other, unsigned NoWrapKind) { typedef OverflowingBinaryOperator OBO; // Computes the intersection of CR0 and CR1. It is different from // intersectWith in that the ConstantRange returned will only contain elements // in both CR0 and CR1 (i.e. SubsetIntersect(X, Y) is a *subset*, proper or // not, of both X and Y). auto SubsetIntersect = [](const ConstantRange &CR0, const ConstantRange &CR1) { return CR0.inverse().unionWith(CR1.inverse()).inverse(); }; assert(BinOp >= Instruction::BinaryOpsBegin && BinOp < Instruction::BinaryOpsEnd && "Binary operators only!"); assert((NoWrapKind == OBO::NoSignedWrap || NoWrapKind == OBO::NoUnsignedWrap || NoWrapKind == (OBO::NoUnsignedWrap | OBO::NoSignedWrap)) && "NoWrapKind invalid!"); unsigned BitWidth = Other.getBitWidth(); if (BinOp != Instruction::Add) // Conservative answer: empty set return ConstantRange(BitWidth, false); if (auto *C = Other.getSingleElement()) if (C->isMinValue()) // Full set: nothing signed / unsigned wraps when added to 0. return ConstantRange(BitWidth); ConstantRange Result(BitWidth); if (NoWrapKind & OBO::NoUnsignedWrap) Result = SubsetIntersect(Result, ConstantRange(APInt::getNullValue(BitWidth), -Other.getUnsignedMax())); if (NoWrapKind & OBO::NoSignedWrap) { APInt SignedMin = Other.getSignedMin(); APInt SignedMax = Other.getSignedMax(); if (SignedMax.isStrictlyPositive()) Result = SubsetIntersect( Result, ConstantRange(APInt::getSignedMinValue(BitWidth), APInt::getSignedMinValue(BitWidth) - SignedMax)); if (SignedMin.isNegative()) Result = SubsetIntersect( Result, ConstantRange(APInt::getSignedMinValue(BitWidth) - SignedMin, APInt::getSignedMinValue(BitWidth))); } return Result; }
/** Converts v to mpz_class. Assumes that v is signed */ inline mpz_class toMpz (const APInt &v) { // Based on: // https://llvm.org/svn/llvm-project/polly/trunk/lib/Support/GICHelper.cpp // return v.getSExtValue (); APInt abs; abs = v.isNegative () ? v.abs () : v; const uint64_t *rawdata = abs.getRawData (); unsigned numWords = abs.getNumWords (); // TODO: Check if this is true for all platforms. mpz_class res; mpz_import(res.get_mpz_t (), numWords, 1, sizeof (uint64_t), 0, 0, rawdata); return v.isNegative () ? mpz_class(-res) : res; }
/// lowerSDIV - Given an SDiv expressing a divide by constant, /// replace it by multiplying by a magic number. See: /// <http://the.wall.riscom.net/books/proc/ppc/cwg/code2.html> bool lowerSDiv(Instruction *inst) const { ConstantInt *Op1 = dyn_cast<ConstantInt>(inst->getOperand(1)); // check if dividing by a constant and not by a power of 2 if (!Op1 || inst->getType()->getPrimitiveSizeInBits() != 32 || Op1->getValue().isPowerOf2()) { return false; } BasicBlock::iterator ii(inst); Value *Op0 = inst->getOperand(0); APInt d = Op1->getValue(); APInt::ms magics = Op1->getValue().magic(); IntegerType * type64 = IntegerType::get(Mod->getContext(), 64); Instruction *sext = CastInst::CreateSExtOrBitCast(Op0, type64, "", inst); APInt m = APInt(64, magics.m.getSExtValue()); Constant *magicNum = ConstantInt::get(type64, m); Instruction *magInst = BinaryOperator::CreateNSWMul(sext, magicNum, "", inst); APInt ap = APInt(64, 32); Constant *movHiConst = ConstantInt::get(type64, ap); Instruction *movHi = BinaryOperator::Create(Instruction::AShr, magInst, movHiConst, "", inst); Instruction *trunc = CastInst::CreateTruncOrBitCast(movHi, inst->getType(), "", inst); if (d.isStrictlyPositive() && magics.m.isNegative()) { trunc = BinaryOperator::Create(Instruction::Add, trunc, Op0, "", inst); } else if (d.isNegative() && magics.m.isStrictlyPositive()) { trunc = BinaryOperator::Create(Instruction::Sub, trunc, Op0, "", inst); } if (magics.s > 0) { APInt apS = APInt(32, magics.s); Constant *magicShift = ConstantInt::get(inst->getType(), apS); trunc = BinaryOperator::Create(Instruction::AShr, trunc, magicShift, "", inst); } APInt ap31 = APInt(32, 31); Constant *thirtyOne = ConstantInt::get(inst->getType(), ap31); // get sign bit Instruction *sign = BinaryOperator::Create(Instruction::LShr, trunc, thirtyOne, "", inst); Instruction *result = BinaryOperator::Create(Instruction::Add, trunc, sign, ""); ReplaceInstWithInst(inst->getParent()->getInstList(), ii, result); return true; }
int ARMTTIImpl::getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm, Type *Ty) { // Division by a constant can be turned into multiplication, but only if we // know it's constant. So it's not so much that the immediate is cheap (it's // not), but that the alternative is worse. // FIXME: this is probably unneeded with GlobalISel. if ((Opcode == Instruction::SDiv || Opcode == Instruction::UDiv || Opcode == Instruction::SRem || Opcode == Instruction::URem) && Idx == 1) return 0; if (Opcode == Instruction::And) { // UXTB/UXTH if (Imm == 255 || Imm == 65535) return 0; // Conversion to BIC is free, and means we can use ~Imm instead. return std::min(getIntImmCost(Imm, Ty), getIntImmCost(~Imm, Ty)); } if (Opcode == Instruction::Add) // Conversion to SUB is free, and means we can use -Imm instead. return std::min(getIntImmCost(Imm, Ty), getIntImmCost(-Imm, Ty)); if (Opcode == Instruction::ICmp && Imm.isNegative() && Ty->getIntegerBitWidth() == 32) { int64_t NegImm = -Imm.getSExtValue(); if (ST->isThumb2() && NegImm < 1<<12) // icmp X, #-C -> cmn X, #C return 0; if (ST->isThumb() && NegImm < 1<<8) // icmp X, #-C -> adds X, #C return 0; } // xor a, -1 can always be folded to MVN if (Opcode == Instruction::Xor && Imm.isAllOnesValue()) return 0; return getIntImmCost(Imm, Ty); }
static std::string toString(const APFloat &FP) { // Print NaNs with custom payloads specially. if (FP.isNaN() && !FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) && !FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) { APInt AI = FP.bitcastToAPInt(); return std::string(AI.isNegative() ? "-" : "") + "nan:0x" + utohexstr(AI.getZExtValue() & (AI.getBitWidth() == 32 ? INT64_C(0x007fffff) : INT64_C(0x000fffffffffffff)), /*LowerCase=*/true); } // Use C99's hexadecimal floating-point representation. static const size_t BufBytes = 128; char buf[BufBytes]; auto Written = FP.convertToHexString( buf, /*hexDigits=*/0, /*upperCase=*/false, APFloat::rmNearestTiesToEven); (void)Written; assert(Written != 0); assert(Written < BufBytes); return buf; }
static SILInstruction *constantFoldBuiltin(BuiltinInst *BI, Optional<bool> &ResultsInError) { const IntrinsicInfo &Intrinsic = BI->getIntrinsicInfo(); SILModule &M = BI->getModule(); // If it's an llvm intrinsic, fold the intrinsic. if (Intrinsic.ID != llvm::Intrinsic::not_intrinsic) return constantFoldIntrinsic(BI, Intrinsic.ID, ResultsInError); // Otherwise, it should be one of the builtin functions. OperandValueArrayRef Args = BI->getArguments(); const BuiltinInfo &Builtin = BI->getBuiltinInfo(); switch (Builtin.ID) { default: break; // Check and fold binary arithmetic with overflow. #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(id, name, _, attrs, overload) \ case BuiltinValueKind::id: #include "swift/AST/Builtins.def" return constantFoldBinaryWithOverflow(BI, Builtin.ID, ResultsInError); #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) \ case BuiltinValueKind::id: #include "swift/AST/Builtins.def" return constantFoldBinary(BI, Builtin.ID, ResultsInError); // Fold comparison predicates. #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_PREDICATE(id, name, attrs, overload) \ case BuiltinValueKind::id: #include "swift/AST/Builtins.def" return constantFoldCompare(BI, Builtin.ID); case BuiltinValueKind::Trunc: case BuiltinValueKind::ZExt: case BuiltinValueKind::SExt: case BuiltinValueKind::TruncOrBitCast: case BuiltinValueKind::ZExtOrBitCast: case BuiltinValueKind::SExtOrBitCast: { // We can fold if the value being cast is a constant. auto *V = dyn_cast<IntegerLiteralInst>(Args[0]); if (!V) return nullptr; APInt CastResV = constantFoldCast(V->getValue(), Builtin); // Add the literal instruction to represent the result of the cast. SILBuilderWithScope B(BI); return B.createIntegerLiteral(BI->getLoc(), BI->getType(), CastResV); } // Process special builtins that are designed to check for overflows in // integer conversions. case BuiltinValueKind::SToSCheckedTrunc: case BuiltinValueKind::UToUCheckedTrunc: case BuiltinValueKind::SToUCheckedTrunc: case BuiltinValueKind::UToSCheckedTrunc: case BuiltinValueKind::SUCheckedConversion: case BuiltinValueKind::USCheckedConversion: { return constantFoldAndCheckIntegerConversions(BI, Builtin, ResultsInError); } case BuiltinValueKind::IntToFPWithOverflow: { // Get the value. It should be a constant in most cases. // Note, this will not always be a constant, for example, when analyzing // _convertFromBuiltinIntegerLiteral function itself. auto *V = dyn_cast<IntegerLiteralInst>(Args[0]); if (!V) return nullptr; APInt SrcVal = V->getValue(); Type DestTy = Builtin.Types[1]; APFloat TruncVal( DestTy->castTo<BuiltinFloatType>()->getAPFloatSemantics()); APFloat::opStatus ConversionStatus = TruncVal.convertFromAPInt( SrcVal, /*isSigned=*/true, APFloat::rmNearestTiesToEven); SILLocation Loc = BI->getLoc(); const ApplyExpr *CE = Loc.getAsASTNode<ApplyExpr>(); // Check for overflow. if (ConversionStatus & APFloat::opOverflow) { // If we overflow and are not asked for diagnostics, just return nullptr. if (!ResultsInError.hasValue()) return nullptr; SmallString<10> SrcAsString; SrcVal.toString(SrcAsString, /*radix*/10, true /*isSigned*/); // Otherwise emit our diagnostics and then return nullptr. diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_literal_overflow, CE ? CE->getType() : DestTy, SrcAsString); ResultsInError = Optional<bool>(true); return nullptr; } // The call to the builtin should be replaced with the constant value. SILBuilderWithScope B(BI); return B.createFloatLiteral(Loc, BI->getType(), TruncVal); } case BuiltinValueKind::FPTrunc: { // Get the value. It should be a constant in most cases. auto *V = dyn_cast<FloatLiteralInst>(Args[0]); if (!V) return nullptr; APFloat TruncVal = V->getValue(); Type DestTy = Builtin.Types[1]; bool losesInfo; APFloat::opStatus ConversionStatus = TruncVal.convert( DestTy->castTo<BuiltinFloatType>()->getAPFloatSemantics(), APFloat::rmNearestTiesToEven, &losesInfo); SILLocation Loc = BI->getLoc(); // Check if conversion was successful. if (ConversionStatus != APFloat::opStatus::opOK && ConversionStatus != APFloat::opStatus::opInexact) { return nullptr; } // The call to the builtin should be replaced with the constant value. SILBuilderWithScope B(BI); return B.createFloatLiteral(Loc, BI->getType(), TruncVal); } case BuiltinValueKind::AssumeNonNegative: { auto *V = dyn_cast<IntegerLiteralInst>(Args[0]); if (!V) return nullptr; APInt VInt = V->getValue(); if (VInt.isNegative() && ResultsInError.hasValue()) { diagnose(M.getASTContext(), BI->getLoc().getSourceLoc(), diag::wrong_non_negative_assumption, VInt.toString(/*Radix*/ 10, /*Signed*/ true)); ResultsInError = Optional<bool>(true); } return V; } } return nullptr; }
static SILInstruction * constantFoldAndCheckIntegerConversions(BuiltinInst *BI, const BuiltinInfo &Builtin, Optional<bool> &ResultsInError) { assert(Builtin.ID == BuiltinValueKind::SToSCheckedTrunc || Builtin.ID == BuiltinValueKind::UToUCheckedTrunc || Builtin.ID == BuiltinValueKind::SToUCheckedTrunc || Builtin.ID == BuiltinValueKind::UToSCheckedTrunc || Builtin.ID == BuiltinValueKind::SUCheckedConversion || Builtin.ID == BuiltinValueKind::USCheckedConversion); // Check if we are converting a constant integer. OperandValueArrayRef Args = BI->getArguments(); auto *V = dyn_cast<IntegerLiteralInst>(Args[0]); if (!V) return nullptr; APInt SrcVal = V->getValue(); // Get source type and bit width. Type SrcTy = Builtin.Types[0]; uint32_t SrcBitWidth = Builtin.Types[0]->castTo<BuiltinIntegerType>()->getGreatestWidth(); // Compute the destination (for SrcBitWidth < DestBitWidth) and enough info // to check for overflow. APInt Result; bool OverflowError; Type DstTy; // Process conversions signed <-> unsigned for same size integers. if (Builtin.ID == BuiltinValueKind::SUCheckedConversion || Builtin.ID == BuiltinValueKind::USCheckedConversion) { DstTy = SrcTy; Result = SrcVal; // Report an error if the sign bit is set. OverflowError = SrcVal.isNegative(); // Process truncation from unsigned to signed. } else if (Builtin.ID != BuiltinValueKind::UToSCheckedTrunc) { assert(Builtin.Types.size() == 2); DstTy = Builtin.Types[1]; uint32_t DstBitWidth = DstTy->castTo<BuiltinIntegerType>()->getGreatestWidth(); // Result = trunc_IntFrom_IntTo(Val) // For signed destination: // sext_IntFrom(Result) == Val ? Result : overflow_error // For signed destination: // zext_IntFrom(Result) == Val ? Result : overflow_error Result = SrcVal.trunc(DstBitWidth); // Get the signedness of the destination. bool Signed = (Builtin.ID == BuiltinValueKind::SToSCheckedTrunc); APInt Ext = Signed ? Result.sext(SrcBitWidth) : Result.zext(SrcBitWidth); OverflowError = (SrcVal != Ext); // Process the rest of truncations. } else { assert(Builtin.Types.size() == 2); DstTy = Builtin.Types[1]; uint32_t DstBitWidth = Builtin.Types[1]->castTo<BuiltinIntegerType>()->getGreatestWidth(); // Compute the destination (for SrcBitWidth < DestBitWidth): // Result = trunc_IntTo(Val) // Trunc = trunc_'IntTo-1bit'(Val) // zext_IntFrom(Trunc) == Val ? Result : overflow_error Result = SrcVal.trunc(DstBitWidth); APInt TruncVal = SrcVal.trunc(DstBitWidth - 1); OverflowError = (SrcVal != TruncVal.zext(SrcBitWidth)); } // Check for overflow. if (OverflowError) { // If we are not asked to emit overflow diagnostics, just return nullptr on // overflow. if (!ResultsInError.hasValue()) return nullptr; SILLocation Loc = BI->getLoc(); SILModule &M = BI->getModule(); const ApplyExpr *CE = Loc.getAsASTNode<ApplyExpr>(); Type UserSrcTy; Type UserDstTy; // Primitive heuristics to get the user-written type. // Eventually we might be able to use SILLocation (when it contains info // about inlined call chains). if (CE) { if (const TupleType *RTy = CE->getArg()->getType()->getAs<TupleType>()) { if (RTy->getNumElements() == 1) { UserSrcTy = RTy->getElementType(0); UserDstTy = CE->getType(); } } else { UserSrcTy = CE->getArg()->getType(); UserDstTy = CE->getType(); } } // Assume that we are converting from a literal if the Source size is // 2048. Is there a better way to identify conversions from literals? bool Literal = (SrcBitWidth == 2048); // FIXME: This will prevent hard error in cases the error is coming // from ObjC interoperability code. Currently, we treat NSUInteger as // Int. if (Loc.getSourceLoc().isInvalid()) { // Otherwise emit the appropriate diagnostic and set ResultsInError. if (Literal) diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_literal_overflow_warn, UserDstTy.isNull() ? DstTy : UserDstTy); else diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_conversion_overflow_warn, UserSrcTy.isNull() ? SrcTy : UserSrcTy, UserDstTy.isNull() ? DstTy : UserDstTy); ResultsInError = Optional<bool>(true); return nullptr; } // Otherwise report the overflow error. if (Literal) { bool SrcTySigned, DstTySigned; std::tie(SrcTySigned, DstTySigned) = getTypeSignedness(Builtin); SmallString<10> SrcAsString; SrcVal.toString(SrcAsString, /*radix*/10, SrcTySigned); // Try to print user-visible types if they are available. if (!UserDstTy.isNull()) { auto diagID = diag::integer_literal_overflow; // If this is a negative literal in an unsigned type, use a specific // diagnostic. if (SrcTySigned && !DstTySigned && SrcVal.isNegative()) diagID = diag::negative_integer_literal_overflow_unsigned; diagnose(M.getASTContext(), Loc.getSourceLoc(), diagID, UserDstTy, SrcAsString); // Otherwise, print the Builtin Types. } else { bool SrcTySigned, DstTySigned; std::tie(SrcTySigned, DstTySigned) = getTypeSignedness(Builtin); diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_literal_overflow_builtin_types, DstTySigned, DstTy, SrcAsString); } } else { if (Builtin.ID == BuiltinValueKind::SUCheckedConversion) { diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_conversion_sign_error, UserDstTy.isNull() ? DstTy : UserDstTy); } else { // Try to print user-visible types if they are available. if (!UserSrcTy.isNull()) { diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_conversion_overflow, UserSrcTy, UserDstTy); // Otherwise, print the Builtin Types. } else { // Since builtin types are sign-agnostic, print the signedness // separately. bool SrcTySigned, DstTySigned; std::tie(SrcTySigned, DstTySigned) = getTypeSignedness(Builtin); diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_conversion_overflow_builtin_types, SrcTySigned, SrcTy, DstTySigned, DstTy); } } } ResultsInError = Optional<bool>(true); return nullptr; } // The call to the builtin should be replaced with the constant value. return constructResultWithOverflowTuple(BI, Result, false); }