1 //== SMTConv.h --------------------------------------------------*- C++ -*--==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines a set of functions to create SMT expressions
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONV_H
15 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONV_H
17 #include "clang/AST/Expr.h"
18 #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
27 // Returns an appropriate sort, given a QualType and it's bit width.
28 static inline SMTSortRef mkSort(SMTSolverRef &Solver, const QualType &Ty,
30 if (Ty->isBooleanType())
31 return Solver->getBoolSort();
33 if (Ty->isRealFloatingType())
34 return Solver->getFloatSort(BitWidth);
36 return Solver->getBitvectorSort(BitWidth);
39 /// Constructs an SMTExprRef from an unary operator.
40 static inline SMTExprRef fromUnOp(SMTSolverRef &Solver,
41 const UnaryOperator::Opcode Op,
42 const SMTExprRef &Exp) {
45 return Solver->mkBVNeg(Exp);
48 return Solver->mkBVNot(Exp);
51 return Solver->mkNot(Exp);
55 llvm_unreachable("Unimplemented opcode");
58 /// Constructs an SMTExprRef from a floating-point unary operator.
59 static inline SMTExprRef fromFloatUnOp(SMTSolverRef &Solver,
60 const UnaryOperator::Opcode Op,
61 const SMTExprRef &Exp) {
64 return Solver->mkFPNeg(Exp);
67 return fromUnOp(Solver, Op, Exp);
71 llvm_unreachable("Unimplemented opcode");
74 /// Construct an SMTExprRef from a n-ary binary operator.
75 static inline SMTExprRef fromNBinOp(SMTSolverRef &Solver,
76 const BinaryOperator::Opcode Op,
77 const std::vector<SMTExprRef> &ASTs) {
78 assert(!ASTs.empty());
80 if (Op != BO_LAnd && Op != BO_LOr)
81 llvm_unreachable("Unimplemented opcode");
83 SMTExprRef res = ASTs.front();
84 for (std::size_t i = 1; i < ASTs.size(); ++i)
85 res = (Op == BO_LAnd) ? Solver->mkAnd(res, ASTs[i])
86 : Solver->mkOr(res, ASTs[i]);
90 /// Construct an SMTExprRef from a binary operator.
91 static inline SMTExprRef fromBinOp(SMTSolverRef &Solver,
92 const SMTExprRef &LHS,
93 const BinaryOperator::Opcode Op,
94 const SMTExprRef &RHS, bool isSigned) {
95 assert(*Solver->getSort(LHS) == *Solver->getSort(RHS) &&
96 "AST's must have the same sort!");
99 // Multiplicative operators
101 return Solver->mkBVMul(LHS, RHS);
104 return isSigned ? Solver->mkBVSDiv(LHS, RHS) : Solver->mkBVUDiv(LHS, RHS);
107 return isSigned ? Solver->mkBVSRem(LHS, RHS) : Solver->mkBVURem(LHS, RHS);
109 // Additive operators
111 return Solver->mkBVAdd(LHS, RHS);
114 return Solver->mkBVSub(LHS, RHS);
116 // Bitwise shift operators
118 return Solver->mkBVShl(LHS, RHS);
121 return isSigned ? Solver->mkBVAshr(LHS, RHS) : Solver->mkBVLshr(LHS, RHS);
123 // Relational operators
125 return isSigned ? Solver->mkBVSlt(LHS, RHS) : Solver->mkBVUlt(LHS, RHS);
128 return isSigned ? Solver->mkBVSgt(LHS, RHS) : Solver->mkBVUgt(LHS, RHS);
131 return isSigned ? Solver->mkBVSle(LHS, RHS) : Solver->mkBVUle(LHS, RHS);
134 return isSigned ? Solver->mkBVSge(LHS, RHS) : Solver->mkBVUge(LHS, RHS);
136 // Equality operators
138 return Solver->mkEqual(LHS, RHS);
141 return fromUnOp(Solver, UO_LNot,
142 fromBinOp(Solver, LHS, BO_EQ, RHS, isSigned));
146 return Solver->mkBVAnd(LHS, RHS);
149 return Solver->mkBVXor(LHS, RHS);
152 return Solver->mkBVOr(LHS, RHS);
156 return Solver->mkAnd(LHS, RHS);
159 return Solver->mkOr(LHS, RHS);
163 llvm_unreachable("Unimplemented opcode");
166 /// Construct an SMTExprRef from a special floating-point binary operator.
167 static inline SMTExprRef
168 fromFloatSpecialBinOp(SMTSolverRef &Solver, const SMTExprRef &LHS,
169 const BinaryOperator::Opcode Op,
170 const llvm::APFloat::fltCategory &RHS) {
172 // Equality operators
175 case llvm::APFloat::fcInfinity:
176 return Solver->mkFPIsInfinite(LHS);
178 case llvm::APFloat::fcNaN:
179 return Solver->mkFPIsNaN(LHS);
181 case llvm::APFloat::fcNormal:
182 return Solver->mkFPIsNormal(LHS);
184 case llvm::APFloat::fcZero:
185 return Solver->mkFPIsZero(LHS);
190 return fromFloatUnOp(Solver, UO_LNot,
191 fromFloatSpecialBinOp(Solver, LHS, BO_EQ, RHS));
196 llvm_unreachable("Unimplemented opcode");
199 /// Construct an SMTExprRef from a floating-point binary operator.
200 static inline SMTExprRef fromFloatBinOp(SMTSolverRef &Solver,
201 const SMTExprRef &LHS,
202 const BinaryOperator::Opcode Op,
203 const SMTExprRef &RHS) {
204 assert(*Solver->getSort(LHS) == *Solver->getSort(RHS) &&
205 "AST's must have the same sort!");
208 // Multiplicative operators
210 return Solver->mkFPMul(LHS, RHS);
213 return Solver->mkFPDiv(LHS, RHS);
216 return Solver->mkFPRem(LHS, RHS);
218 // Additive operators
220 return Solver->mkFPAdd(LHS, RHS);
223 return Solver->mkFPSub(LHS, RHS);
225 // Relational operators
227 return Solver->mkFPLt(LHS, RHS);
230 return Solver->mkFPGt(LHS, RHS);
233 return Solver->mkFPLe(LHS, RHS);
236 return Solver->mkFPGe(LHS, RHS);
238 // Equality operators
240 return Solver->mkFPEqual(LHS, RHS);
243 return fromFloatUnOp(Solver, UO_LNot,
244 fromFloatBinOp(Solver, LHS, BO_EQ, RHS));
249 return fromBinOp(Solver, LHS, Op, RHS, /*isSigned=*/false);
254 llvm_unreachable("Unimplemented opcode");
257 /// Construct an SMTExprRef from a QualType FromTy to a QualType ToTy, and
258 /// their bit widths.
259 static inline SMTExprRef fromCast(SMTSolverRef &Solver, const SMTExprRef &Exp,
260 QualType ToTy, uint64_t ToBitWidth,
261 QualType FromTy, uint64_t FromBitWidth) {
262 if ((FromTy->isIntegralOrEnumerationType() &&
263 ToTy->isIntegralOrEnumerationType()) ||
264 (FromTy->isAnyPointerType() ^ ToTy->isAnyPointerType()) ||
265 (FromTy->isBlockPointerType() ^ ToTy->isBlockPointerType()) ||
266 (FromTy->isReferenceType() ^ ToTy->isReferenceType())) {
268 if (FromTy->isBooleanType()) {
269 assert(ToBitWidth > 0 && "BitWidth must be positive!");
270 return Solver->mkIte(
271 Exp, Solver->mkBitvector(llvm::APSInt("1"), ToBitWidth),
272 Solver->mkBitvector(llvm::APSInt("0"), ToBitWidth));
275 if (ToBitWidth > FromBitWidth)
276 return FromTy->isSignedIntegerOrEnumerationType()
277 ? Solver->mkBVSignExt(ToBitWidth - FromBitWidth, Exp)
278 : Solver->mkBVZeroExt(ToBitWidth - FromBitWidth, Exp);
280 if (ToBitWidth < FromBitWidth)
281 return Solver->mkBVExtract(ToBitWidth - 1, 0, Exp);
283 // Both are bitvectors with the same width, ignore the type cast
287 if (FromTy->isRealFloatingType() && ToTy->isRealFloatingType()) {
288 if (ToBitWidth != FromBitWidth)
289 return Solver->mkFPtoFP(Exp, Solver->getFloatSort(ToBitWidth));
294 if (FromTy->isIntegralOrEnumerationType() && ToTy->isRealFloatingType()) {
295 SMTSortRef Sort = Solver->getFloatSort(ToBitWidth);
296 return FromTy->isSignedIntegerOrEnumerationType()
297 ? Solver->mkSBVtoFP(Exp, Sort)
298 : Solver->mkUBVtoFP(Exp, Sort);
301 if (FromTy->isRealFloatingType() && ToTy->isIntegralOrEnumerationType())
302 return ToTy->isSignedIntegerOrEnumerationType()
303 ? Solver->mkFPtoSBV(Exp, ToBitWidth)
304 : Solver->mkFPtoUBV(Exp, ToBitWidth);
306 llvm_unreachable("Unsupported explicit type cast!");
309 // Callback function for doCast parameter on APSInt type.
310 static inline llvm::APSInt castAPSInt(SMTSolverRef &Solver,
311 const llvm::APSInt &V, QualType ToTy,
312 uint64_t ToWidth, QualType FromTy,
313 uint64_t FromWidth) {
314 APSIntType TargetType(ToWidth, !ToTy->isSignedIntegerOrEnumerationType());
315 return TargetType.convert(V);
318 /// Construct an SMTExprRef from a SymbolData.
319 static inline SMTExprRef fromData(SMTSolverRef &Solver, const SymbolID ID,
320 const QualType &Ty, uint64_t BitWidth) {
321 llvm::Twine Name = "$" + llvm::Twine(ID);
322 return Solver->mkSymbol(Name.str().c_str(), mkSort(Solver, Ty, BitWidth));
325 // Wrapper to generate SMTExprRef from SymbolCast data.
326 static inline SMTExprRef getCastExpr(SMTSolverRef &Solver, ASTContext &Ctx,
327 const SMTExprRef &Exp, QualType FromTy,
329 return fromCast(Solver, Exp, ToTy, Ctx.getTypeSize(ToTy), FromTy,
330 Ctx.getTypeSize(FromTy));
333 // Wrapper to generate SMTExprRef from unpacked binary symbolic expression.
334 // Sets the RetTy parameter. See getSMTExprRef().
335 static inline SMTExprRef getBinExpr(SMTSolverRef &Solver, ASTContext &Ctx,
336 const SMTExprRef &LHS, QualType LTy,
337 BinaryOperator::Opcode Op,
338 const SMTExprRef &RHS, QualType RTy,
340 SMTExprRef NewLHS = LHS;
341 SMTExprRef NewRHS = RHS;
342 doTypeConversion(Solver, Ctx, NewLHS, NewRHS, LTy, RTy);
344 // Update the return type parameter if the output type has changed.
346 // A boolean result can be represented as an integer type in C/C++, but at
347 // this point we only care about the SMT sorts. Set it as a boolean type
348 // to avoid subsequent SMT errors.
349 if (BinaryOperator::isComparisonOp(Op) ||
350 BinaryOperator::isLogicalOp(Op)) {
356 // If the two operands are pointers and the operation is a subtraction,
357 // the result is of type ptrdiff_t, which is signed
358 if (LTy->isAnyPointerType() && RTy->isAnyPointerType() && Op == BO_Sub) {
359 *RetTy = Ctx.getPointerDiffType();
363 return LTy->isRealFloatingType()
364 ? fromFloatBinOp(Solver, NewLHS, Op, NewRHS)
365 : fromBinOp(Solver, NewLHS, Op, NewRHS,
366 LTy->isSignedIntegerOrEnumerationType());
369 // Wrapper to generate SMTExprRef from BinarySymExpr.
370 // Sets the hasComparison and RetTy parameters. See getSMTExprRef().
371 static inline SMTExprRef getSymBinExpr(SMTSolverRef &Solver, ASTContext &Ctx,
372 const BinarySymExpr *BSE,
373 bool *hasComparison, QualType *RetTy) {
375 BinaryOperator::Opcode Op = BSE->getOpcode();
377 if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE)) {
379 getSymExpr(Solver, Ctx, SIE->getLHS(), <y, hasComparison);
380 llvm::APSInt NewRInt;
381 std::tie(NewRInt, RTy) = fixAPSInt(Ctx, SIE->getRHS());
382 SMTExprRef RHS = Solver->mkBitvector(NewRInt, NewRInt.getBitWidth());
383 return getBinExpr(Solver, Ctx, LHS, LTy, Op, RHS, RTy, RetTy);
386 if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE)) {
387 llvm::APSInt NewLInt;
388 std::tie(NewLInt, LTy) = fixAPSInt(Ctx, ISE->getLHS());
389 SMTExprRef LHS = Solver->mkBitvector(NewLInt, NewLInt.getBitWidth());
391 getSymExpr(Solver, Ctx, ISE->getRHS(), &RTy, hasComparison);
392 return getBinExpr(Solver, Ctx, LHS, LTy, Op, RHS, RTy, RetTy);
395 if (const SymSymExpr *SSM = dyn_cast<SymSymExpr>(BSE)) {
397 getSymExpr(Solver, Ctx, SSM->getLHS(), <y, hasComparison);
399 getSymExpr(Solver, Ctx, SSM->getRHS(), &RTy, hasComparison);
400 return getBinExpr(Solver, Ctx, LHS, LTy, Op, RHS, RTy, RetTy);
403 llvm_unreachable("Unsupported BinarySymExpr type!");
406 // Recursive implementation to unpack and generate symbolic expression.
407 // Sets the hasComparison and RetTy parameters. See getExpr().
408 static inline SMTExprRef getSymExpr(SMTSolverRef &Solver, ASTContext &Ctx,
409 SymbolRef Sym, QualType *RetTy,
410 bool *hasComparison) {
411 if (const SymbolData *SD = dyn_cast<SymbolData>(Sym)) {
413 *RetTy = Sym->getType();
415 return fromData(Solver, SD->getSymbolID(), Sym->getType(),
416 Ctx.getTypeSize(Sym->getType()));
419 if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) {
421 *RetTy = Sym->getType();
425 getSymExpr(Solver, Ctx, SC->getOperand(), &FromTy, hasComparison);
427 // Casting an expression with a comparison invalidates it. Note that this
428 // must occur after the recursive call above.
429 // e.g. (signed char) (x > 0)
431 *hasComparison = false;
432 return getCastExpr(Solver, Ctx, Exp, FromTy, Sym->getType());
435 if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
436 SMTExprRef Exp = getSymBinExpr(Solver, Ctx, BSE, hasComparison, RetTy);
437 // Set the hasComparison parameter, in post-order traversal order.
439 *hasComparison = BinaryOperator::isComparisonOp(BSE->getOpcode());
443 llvm_unreachable("Unsupported SymbolRef type!");
446 // Generate an SMTExprRef that represents the given symbolic expression.
447 // Sets the hasComparison parameter if the expression has a comparison
448 // operator. Sets the RetTy parameter to the final return type after
449 // promotions and casts.
450 static inline SMTExprRef getExpr(SMTSolverRef &Solver, ASTContext &Ctx,
451 SymbolRef Sym, QualType *RetTy = nullptr,
452 bool *hasComparison = nullptr) {
454 *hasComparison = false;
457 return getSymExpr(Solver, Ctx, Sym, RetTy, hasComparison);
460 // Generate an SMTExprRef that compares the expression to zero.
461 static inline SMTExprRef getZeroExpr(SMTSolverRef &Solver, ASTContext &Ctx,
462 const SMTExprRef &Exp, QualType Ty,
465 if (Ty->isRealFloatingType()) {
467 llvm::APFloat::getZero(Ctx.getFloatTypeSemantics(Ty));
468 return fromFloatBinOp(Solver, Exp, Assumption ? BO_EQ : BO_NE,
469 Solver->mkFloat(Zero));
472 if (Ty->isIntegralOrEnumerationType() || Ty->isAnyPointerType() ||
473 Ty->isBlockPointerType() || Ty->isReferenceType()) {
475 // Skip explicit comparison for boolean types
476 bool isSigned = Ty->isSignedIntegerOrEnumerationType();
477 if (Ty->isBooleanType())
478 return Assumption ? fromUnOp(Solver, UO_LNot, Exp) : Exp;
481 Solver, Exp, Assumption ? BO_EQ : BO_NE,
482 Solver->mkBitvector(llvm::APSInt("0"), Ctx.getTypeSize(Ty)),
486 llvm_unreachable("Unsupported type for zero value!");
489 // Wrapper to generate SMTExprRef from a range. If From == To, an equality
490 // will be created instead.
491 static inline SMTExprRef getRangeExpr(SMTSolverRef &Solver, ASTContext &Ctx,
492 SymbolRef Sym, const llvm::APSInt &From,
493 const llvm::APSInt &To, bool InRange) {
494 // Convert lower bound
496 llvm::APSInt NewFromInt;
497 std::tie(NewFromInt, FromTy) = fixAPSInt(Ctx, From);
499 Solver->mkBitvector(NewFromInt, NewFromInt.getBitWidth());
503 SMTExprRef Exp = getExpr(Solver, Ctx, Sym, &SymTy);
505 // Construct single (in)equality
507 return getBinExpr(Solver, Ctx, Exp, SymTy, InRange ? BO_EQ : BO_NE,
508 FromExp, FromTy, /*RetTy=*/nullptr);
511 llvm::APSInt NewToInt;
512 std::tie(NewToInt, ToTy) = fixAPSInt(Ctx, To);
513 SMTExprRef ToExp = Solver->mkBitvector(NewToInt, NewToInt.getBitWidth());
514 assert(FromTy == ToTy && "Range values have different types!");
516 // Construct two (in)equalities, and a logical and/or
518 getBinExpr(Solver, Ctx, Exp, SymTy, InRange ? BO_GE : BO_LT, FromExp,
519 FromTy, /*RetTy=*/nullptr);
520 SMTExprRef RHS = getBinExpr(Solver, Ctx, Exp, SymTy,
521 InRange ? BO_LE : BO_GT, ToExp, ToTy,
524 return fromBinOp(Solver, LHS, InRange ? BO_LAnd : BO_LOr, RHS,
525 SymTy->isSignedIntegerOrEnumerationType());
528 // Recover the QualType of an APSInt.
529 // TODO: Refactor to put elsewhere
530 static inline QualType getAPSIntType(ASTContext &Ctx,
531 const llvm::APSInt &Int) {
532 return Ctx.getIntTypeForBitwidth(Int.getBitWidth(), Int.isSigned());
535 // Get the QualTy for the input APSInt, and fix it if it has a bitwidth of 1.
536 static inline std::pair<llvm::APSInt, QualType>
537 fixAPSInt(ASTContext &Ctx, const llvm::APSInt &Int) {
540 // FIXME: This should be a cast from a 1-bit integer type to a boolean type,
541 // but the former is not available in Clang. Instead, extend the APSInt
543 if (Int.getBitWidth() == 1 && getAPSIntType(Ctx, Int).isNull()) {
544 NewInt = Int.extend(Ctx.getTypeSize(Ctx.BoolTy));
548 return std::make_pair(NewInt, getAPSIntType(Ctx, NewInt));
551 // Perform implicit type conversion on binary symbolic expressions.
552 // May modify all input parameters.
553 // TODO: Refactor to use built-in conversion functions
554 static inline void doTypeConversion(SMTSolverRef &Solver, ASTContext &Ctx,
555 SMTExprRef &LHS, SMTExprRef &RHS,
556 QualType <y, QualType &RTy) {
557 assert(!LTy.isNull() && !RTy.isNull() && "Input type is null!");
559 // Perform type conversion
560 if ((LTy->isIntegralOrEnumerationType() &&
561 RTy->isIntegralOrEnumerationType()) &&
562 (LTy->isArithmeticType() && RTy->isArithmeticType())) {
563 SMTConv::doIntTypeConversion<SMTExprRef, &fromCast>(Solver, Ctx, LHS, LTy,
568 if (LTy->isRealFloatingType() || RTy->isRealFloatingType()) {
569 SMTConv::doFloatTypeConversion<SMTExprRef, &fromCast>(Solver, Ctx, LHS,
574 if ((LTy->isAnyPointerType() || RTy->isAnyPointerType()) ||
575 (LTy->isBlockPointerType() || RTy->isBlockPointerType()) ||
576 (LTy->isReferenceType() || RTy->isReferenceType())) {
577 // TODO: Refactor to Sema::FindCompositePointerType(), and
578 // Sema::CheckCompareOperands().
580 uint64_t LBitWidth = Ctx.getTypeSize(LTy);
581 uint64_t RBitWidth = Ctx.getTypeSize(RTy);
583 // Cast the non-pointer type to the pointer type.
584 // TODO: Be more strict about this.
585 if ((LTy->isAnyPointerType() ^ RTy->isAnyPointerType()) ||
586 (LTy->isBlockPointerType() ^ RTy->isBlockPointerType()) ||
587 (LTy->isReferenceType() ^ RTy->isReferenceType())) {
588 if (LTy->isNullPtrType() || LTy->isBlockPointerType() ||
589 LTy->isReferenceType()) {
590 LHS = fromCast(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
593 RHS = fromCast(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
598 // Cast the void pointer type to the non-void pointer type.
599 // For void types, this assumes that the casted value is equal to the
600 // value of the original pointer, and does not account for alignment
602 if (LTy->isVoidPointerType() ^ RTy->isVoidPointerType()) {
603 assert((Ctx.getTypeSize(LTy) == Ctx.getTypeSize(RTy)) &&
604 "Pointer types have different bitwidths!");
605 if (RTy->isVoidPointerType())
615 // Fallback: for the solver, assume that these types don't really matter
616 if ((LTy.getCanonicalType() == RTy.getCanonicalType()) ||
617 (LTy->isObjCObjectPointerType() && RTy->isObjCObjectPointerType())) {
622 // TODO: Refine behavior for invalid type casts
625 // Perform implicit integer type conversion.
626 // May modify all input parameters.
627 // TODO: Refactor to use Sema::handleIntegerConversion()
628 template <typename T, T (*doCast)(SMTSolverRef &Solver, const T &, QualType,
629 uint64_t, QualType, uint64_t)>
630 static inline void doIntTypeConversion(SMTSolverRef &Solver, ASTContext &Ctx,
631 T &LHS, QualType <y, T &RHS,
634 uint64_t LBitWidth = Ctx.getTypeSize(LTy);
635 uint64_t RBitWidth = Ctx.getTypeSize(RTy);
637 assert(!LTy.isNull() && !RTy.isNull() && "Input type is null!");
638 // Always perform integer promotion before checking type equality.
639 // Otherwise, e.g. (bool) a + (bool) b could trigger a backend assertion
640 if (LTy->isPromotableIntegerType()) {
641 QualType NewTy = Ctx.getPromotedIntegerType(LTy);
642 uint64_t NewBitWidth = Ctx.getTypeSize(NewTy);
643 LHS = (*doCast)(Solver, LHS, NewTy, NewBitWidth, LTy, LBitWidth);
645 LBitWidth = NewBitWidth;
647 if (RTy->isPromotableIntegerType()) {
648 QualType NewTy = Ctx.getPromotedIntegerType(RTy);
649 uint64_t NewBitWidth = Ctx.getTypeSize(NewTy);
650 RHS = (*doCast)(Solver, RHS, NewTy, NewBitWidth, RTy, RBitWidth);
652 RBitWidth = NewBitWidth;
658 // Perform integer type conversion
659 // Note: Safe to skip updating bitwidth because this must terminate
660 bool isLSignedTy = LTy->isSignedIntegerOrEnumerationType();
661 bool isRSignedTy = RTy->isSignedIntegerOrEnumerationType();
663 int order = Ctx.getIntegerTypeOrder(LTy, RTy);
664 if (isLSignedTy == isRSignedTy) {
665 // Same signedness; use the higher-ranked type
667 RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
670 LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
673 } else if (order != (isLSignedTy ? 1 : -1)) {
674 // The unsigned type has greater than or equal rank to the
675 // signed type, so use the unsigned type
677 RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
680 LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
683 } else if (LBitWidth != RBitWidth) {
684 // The two types are different widths; if we are here, that
685 // means the signed type is larger than the unsigned type, so
686 // use the signed type.
688 RHS = (doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
691 LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
695 // The signed type is higher-ranked than the unsigned type,
696 // but isn't actually any bigger (like unsigned int and long
697 // on most 32-bit systems). Use the unsigned type corresponding
698 // to the signed type.
700 Ctx.getCorrespondingUnsignedType(isLSignedTy ? LTy : RTy);
701 RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
703 LHS = (doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
708 // Perform implicit floating-point type conversion.
709 // May modify all input parameters.
710 // TODO: Refactor to use Sema::handleFloatConversion()
711 template <typename T, T (*doCast)(SMTSolverRef &Solver, const T &, QualType,
712 uint64_t, QualType, uint64_t)>
714 doFloatTypeConversion(SMTSolverRef &Solver, ASTContext &Ctx, T &LHS,
715 QualType <y, T &RHS, QualType &RTy) {
717 uint64_t LBitWidth = Ctx.getTypeSize(LTy);
718 uint64_t RBitWidth = Ctx.getTypeSize(RTy);
720 // Perform float-point type promotion
721 if (!LTy->isRealFloatingType()) {
722 LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
724 LBitWidth = RBitWidth;
726 if (!RTy->isRealFloatingType()) {
727 RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
729 RBitWidth = LBitWidth;
735 // If we have two real floating types, convert the smaller operand to the
737 // Note: Safe to skip updating bitwidth because this must terminate
738 int order = Ctx.getFloatingTypeOrder(LTy, RTy);
740 RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth);
742 } else if (order == 0) {
743 LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth);
746 llvm_unreachable("Unsupported floating-point type cast!");