Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 1 | //== SMTConv.h --------------------------------------------------*- C++ -*--==// |
| 2 | // |
||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
||
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
||
| 6 | // |
||
| 7 | //===----------------------------------------------------------------------===// |
||
| 8 | // |
||
| 9 | // This file defines a set of functions to create SMT expressions |
||
| 10 | // |
||
| 11 | //===----------------------------------------------------------------------===// |
||
| 12 | |||
| 13 | #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONV_H |
||
| 14 | #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONV_H |
||
| 15 | |||
| 16 | #include "clang/AST/Expr.h" |
||
| 17 | #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" |
||
| 18 | #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" |
||
| 19 | #include "llvm/Support/SMTAPI.h" |
||
| 20 | |||
| 21 | namespace clang { |
||
| 22 | namespace ento { |
||
| 23 | |||
| 24 | class SMTConv { |
||
| 25 | public: |
||
| 26 | // Returns an appropriate sort, given a QualType and it's bit width. |
||
| 27 | static inline llvm::SMTSortRef mkSort(llvm::SMTSolverRef &Solver, |
||
| 28 | const QualType &Ty, unsigned BitWidth) { |
||
| 29 | if (Ty->isBooleanType()) |
||
| 30 | return Solver->getBoolSort(); |
||
| 31 | |||
| 32 | if (Ty->isRealFloatingType()) |
||
| 33 | return Solver->getFloatSort(BitWidth); |
||
| 34 | |||
| 35 | return Solver->getBitvectorSort(BitWidth); |
||
| 36 | } |
||
| 37 | |||
| 38 | /// Constructs an SMTSolverRef from an unary operator. |
||
| 39 | static inline llvm::SMTExprRef fromUnOp(llvm::SMTSolverRef &Solver, |
||
| 40 | const UnaryOperator::Opcode Op, |
||
| 41 | const llvm::SMTExprRef &Exp) { |
||
| 42 | switch (Op) { |
||
| 43 | case UO_Minus: |
||
| 44 | return Solver->mkBVNeg(Exp); |
||
| 45 | |||
| 46 | case UO_Not: |
||
| 47 | return Solver->mkBVNot(Exp); |
||
| 48 | |||
| 49 | case UO_LNot: |
||
| 50 | return Solver->mkNot(Exp); |
||
| 51 | |||
| 52 | default:; |
||
| 53 | } |
||
| 54 | llvm_unreachable("Unimplemented opcode"); |
||
| 55 | } |
||
| 56 | |||
| 57 | /// Constructs an SMTSolverRef from a floating-point unary operator. |
||
| 58 | static inline llvm::SMTExprRef fromFloatUnOp(llvm::SMTSolverRef &Solver, |
||
| 59 | const UnaryOperator::Opcode Op, |
||
| 60 | const llvm::SMTExprRef &Exp) { |
||
| 61 | switch (Op) { |
||
| 62 | case UO_Minus: |
||
| 63 | return Solver->mkFPNeg(Exp); |
||
| 64 | |||
| 65 | case UO_LNot: |
||
| 66 | return fromUnOp(Solver, Op, Exp); |
||
| 67 | |||
| 68 | default:; |
||
| 69 | } |
||
| 70 | llvm_unreachable("Unimplemented opcode"); |
||
| 71 | } |
||
| 72 | |||
| 73 | /// Construct an SMTSolverRef from a n-ary binary operator. |
||
| 74 | static inline llvm::SMTExprRef |
||
| 75 | fromNBinOp(llvm::SMTSolverRef &Solver, const BinaryOperator::Opcode Op, |
||
| 76 | const std::vector<llvm::SMTExprRef> &ASTs) { |
||
| 77 | assert(!ASTs.empty()); |
||
| 78 | |||
| 79 | if (Op != BO_LAnd && Op != BO_LOr) |
||
| 80 | llvm_unreachable("Unimplemented opcode"); |
||
| 81 | |||
| 82 | llvm::SMTExprRef res = ASTs.front(); |
||
| 83 | for (std::size_t i = 1; i < ASTs.size(); ++i) |
||
| 84 | res = (Op == BO_LAnd) ? Solver->mkAnd(res, ASTs[i]) |
||
| 85 | : Solver->mkOr(res, ASTs[i]); |
||
| 86 | return res; |
||
| 87 | } |
||
| 88 | |||
| 89 | /// Construct an SMTSolverRef from a binary operator. |
||
| 90 | static inline llvm::SMTExprRef fromBinOp(llvm::SMTSolverRef &Solver, |
||
| 91 | const llvm::SMTExprRef &LHS, |
||
| 92 | const BinaryOperator::Opcode Op, |
||
| 93 | const llvm::SMTExprRef &RHS, |
||
| 94 | bool isSigned) { |
||
| 95 | assert(*Solver->getSort(LHS) == *Solver->getSort(RHS) && |
||
| 96 | "AST's must have the same sort!"); |
||
| 97 | |||
| 98 | switch (Op) { |
||
| 99 | // Multiplicative operators |
||
| 100 | case BO_Mul: |
||
| 101 | return Solver->mkBVMul(LHS, RHS); |
||
| 102 | |||
| 103 | case BO_Div: |
||
| 104 | return isSigned ? Solver->mkBVSDiv(LHS, RHS) : Solver->mkBVUDiv(LHS, RHS); |
||
| 105 | |||
| 106 | case BO_Rem: |
||
| 107 | return isSigned ? Solver->mkBVSRem(LHS, RHS) : Solver->mkBVURem(LHS, RHS); |
||
| 108 | |||
| 109 | // Additive operators |
||
| 110 | case BO_Add: |
||
| 111 | return Solver->mkBVAdd(LHS, RHS); |
||
| 112 | |||
| 113 | case BO_Sub: |
||
| 114 | return Solver->mkBVSub(LHS, RHS); |
||
| 115 | |||
| 116 | // Bitwise shift operators |
||
| 117 | case BO_Shl: |
||
| 118 | return Solver->mkBVShl(LHS, RHS); |
||
| 119 | |||
| 120 | case BO_Shr: |
||
| 121 | return isSigned ? Solver->mkBVAshr(LHS, RHS) : Solver->mkBVLshr(LHS, RHS); |
||
| 122 | |||
| 123 | // Relational operators |
||
| 124 | case BO_LT: |
||
| 125 | return isSigned ? Solver->mkBVSlt(LHS, RHS) : Solver->mkBVUlt(LHS, RHS); |
||
| 126 | |||
| 127 | case BO_GT: |
||
| 128 | return isSigned ? Solver->mkBVSgt(LHS, RHS) : Solver->mkBVUgt(LHS, RHS); |
||
| 129 | |||
| 130 | case BO_LE: |
||
| 131 | return isSigned ? Solver->mkBVSle(LHS, RHS) : Solver->mkBVUle(LHS, RHS); |
||
| 132 | |||
| 133 | case BO_GE: |
||
| 134 | return isSigned ? Solver->mkBVSge(LHS, RHS) : Solver->mkBVUge(LHS, RHS); |
||
| 135 | |||
| 136 | // Equality operators |
||
| 137 | case BO_EQ: |
||
| 138 | return Solver->mkEqual(LHS, RHS); |
||
| 139 | |||
| 140 | case BO_NE: |
||
| 141 | return fromUnOp(Solver, UO_LNot, |
||
| 142 | fromBinOp(Solver, LHS, BO_EQ, RHS, isSigned)); |
||
| 143 | |||
| 144 | // Bitwise operators |
||
| 145 | case BO_And: |
||
| 146 | return Solver->mkBVAnd(LHS, RHS); |
||
| 147 | |||
| 148 | case BO_Xor: |
||
| 149 | return Solver->mkBVXor(LHS, RHS); |
||
| 150 | |||
| 151 | case BO_Or: |
||
| 152 | return Solver->mkBVOr(LHS, RHS); |
||
| 153 | |||
| 154 | // Logical operators |
||
| 155 | case BO_LAnd: |
||
| 156 | return Solver->mkAnd(LHS, RHS); |
||
| 157 | |||
| 158 | case BO_LOr: |
||
| 159 | return Solver->mkOr(LHS, RHS); |
||
| 160 | |||
| 161 | default:; |
||
| 162 | } |
||
| 163 | llvm_unreachable("Unimplemented opcode"); |
||
| 164 | } |
||
| 165 | |||
| 166 | /// Construct an SMTSolverRef from a special floating-point binary |
||
| 167 | /// operator. |
||
| 168 | static inline llvm::SMTExprRef |
||
| 169 | fromFloatSpecialBinOp(llvm::SMTSolverRef &Solver, const llvm::SMTExprRef &LHS, |
||
| 170 | const BinaryOperator::Opcode Op, |
||
| 171 | const llvm::APFloat::fltCategory &RHS) { |
||
| 172 | switch (Op) { |
||
| 173 | // Equality operators |
||
| 174 | case BO_EQ: |
||
| 175 | switch (RHS) { |
||
| 176 | case llvm::APFloat::fcInfinity: |
||
| 177 | return Solver->mkFPIsInfinite(LHS); |
||
| 178 | |||
| 179 | case llvm::APFloat::fcNaN: |
||
| 180 | return Solver->mkFPIsNaN(LHS); |
||
| 181 | |||
| 182 | case llvm::APFloat::fcNormal: |
||
| 183 | return Solver->mkFPIsNormal(LHS); |
||
| 184 | |||
| 185 | case llvm::APFloat::fcZero: |
||
| 186 | return Solver->mkFPIsZero(LHS); |
||
| 187 | } |
||
| 188 | break; |
||
| 189 | |||
| 190 | case BO_NE: |
||
| 191 | return fromFloatUnOp(Solver, UO_LNot, |
||
| 192 | fromFloatSpecialBinOp(Solver, LHS, BO_EQ, RHS)); |
||
| 193 | |||
| 194 | default:; |
||
| 195 | } |
||
| 196 | |||
| 197 | llvm_unreachable("Unimplemented opcode"); |
||
| 198 | } |
||
| 199 | |||
| 200 | /// Construct an SMTSolverRef from a floating-point binary operator. |
||
| 201 | static inline llvm::SMTExprRef fromFloatBinOp(llvm::SMTSolverRef &Solver, |
||
| 202 | const llvm::SMTExprRef &LHS, |
||
| 203 | const BinaryOperator::Opcode Op, |
||
| 204 | const llvm::SMTExprRef &RHS) { |
||
| 205 | assert(*Solver->getSort(LHS) == *Solver->getSort(RHS) && |
||
| 206 | "AST's must have the same sort!"); |
||
| 207 | |||
| 208 | switch (Op) { |
||
| 209 | // Multiplicative operators |
||
| 210 | case BO_Mul: |
||
| 211 | return Solver->mkFPMul(LHS, RHS); |
||
| 212 | |||
| 213 | case BO_Div: |
||
| 214 | return Solver->mkFPDiv(LHS, RHS); |
||
| 215 | |||
| 216 | case BO_Rem: |
||
| 217 | return Solver->mkFPRem(LHS, RHS); |
||
| 218 | |||
| 219 | // Additive operators |
||
| 220 | case BO_Add: |
||
| 221 | return Solver->mkFPAdd(LHS, RHS); |
||
| 222 | |||
| 223 | case BO_Sub: |
||
| 224 | return Solver->mkFPSub(LHS, RHS); |
||
| 225 | |||
| 226 | // Relational operators |
||
| 227 | case BO_LT: |
||
| 228 | return Solver->mkFPLt(LHS, RHS); |
||
| 229 | |||
| 230 | case BO_GT: |
||
| 231 | return Solver->mkFPGt(LHS, RHS); |
||
| 232 | |||
| 233 | case BO_LE: |
||
| 234 | return Solver->mkFPLe(LHS, RHS); |
||
| 235 | |||
| 236 | case BO_GE: |
||
| 237 | return Solver->mkFPGe(LHS, RHS); |
||
| 238 | |||
| 239 | // Equality operators |
||
| 240 | case BO_EQ: |
||
| 241 | return Solver->mkFPEqual(LHS, RHS); |
||
| 242 | |||
| 243 | case BO_NE: |
||
| 244 | return fromFloatUnOp(Solver, UO_LNot, |
||
| 245 | fromFloatBinOp(Solver, LHS, BO_EQ, RHS)); |
||
| 246 | |||
| 247 | // Logical operators |
||
| 248 | case BO_LAnd: |
||
| 249 | case BO_LOr: |
||
| 250 | return fromBinOp(Solver, LHS, Op, RHS, /*isSigned=*/false); |
||
| 251 | |||
| 252 | default:; |
||
| 253 | } |
||
| 254 | |||
| 255 | llvm_unreachable("Unimplemented opcode"); |
||
| 256 | } |
||
| 257 | |||
| 258 | /// Construct an SMTSolverRef from a QualType FromTy to a QualType ToTy, |
||
| 259 | /// and their bit widths. |
||
| 260 | static inline llvm::SMTExprRef fromCast(llvm::SMTSolverRef &Solver, |
||
| 261 | const llvm::SMTExprRef &Exp, |
||
| 262 | QualType ToTy, uint64_t ToBitWidth, |
||
| 263 | QualType FromTy, |
||
| 264 | uint64_t FromBitWidth) { |
||
| 265 | if ((FromTy->isIntegralOrEnumerationType() && |
||
| 266 | ToTy->isIntegralOrEnumerationType()) || |
||
| 267 | (FromTy->isAnyPointerType() ^ ToTy->isAnyPointerType()) || |
||
| 268 | (FromTy->isBlockPointerType() ^ ToTy->isBlockPointerType()) || |
||
| 269 | (FromTy->isReferenceType() ^ ToTy->isReferenceType())) { |
||
| 270 | |||
| 271 | if (FromTy->isBooleanType()) { |
||
| 272 | assert(ToBitWidth > 0 && "BitWidth must be positive!"); |
||
| 273 | return Solver->mkIte( |
||
| 274 | Exp, Solver->mkBitvector(llvm::APSInt("1"), ToBitWidth), |
||
| 275 | Solver->mkBitvector(llvm::APSInt("0"), ToBitWidth)); |
||
| 276 | } |
||
| 277 | |||
| 278 | if (ToBitWidth > FromBitWidth) |
||
| 279 | return FromTy->isSignedIntegerOrEnumerationType() |
||
| 280 | ? Solver->mkBVSignExt(ToBitWidth - FromBitWidth, Exp) |
||
| 281 | : Solver->mkBVZeroExt(ToBitWidth - FromBitWidth, Exp); |
||
| 282 | |||
| 283 | if (ToBitWidth < FromBitWidth) |
||
| 284 | return Solver->mkBVExtract(ToBitWidth - 1, 0, Exp); |
||
| 285 | |||
| 286 | // Both are bitvectors with the same width, ignore the type cast |
||
| 287 | return Exp; |
||
| 288 | } |
||
| 289 | |||
| 290 | if (FromTy->isRealFloatingType() && ToTy->isRealFloatingType()) { |
||
| 291 | if (ToBitWidth != FromBitWidth) |
||
| 292 | return Solver->mkFPtoFP(Exp, Solver->getFloatSort(ToBitWidth)); |
||
| 293 | |||
| 294 | return Exp; |
||
| 295 | } |
||
| 296 | |||
| 297 | if (FromTy->isIntegralOrEnumerationType() && ToTy->isRealFloatingType()) { |
||
| 298 | llvm::SMTSortRef Sort = Solver->getFloatSort(ToBitWidth); |
||
| 299 | return FromTy->isSignedIntegerOrEnumerationType() |
||
| 300 | ? Solver->mkSBVtoFP(Exp, Sort) |
||
| 301 | : Solver->mkUBVtoFP(Exp, Sort); |
||
| 302 | } |
||
| 303 | |||
| 304 | if (FromTy->isRealFloatingType() && ToTy->isIntegralOrEnumerationType()) |
||
| 305 | return ToTy->isSignedIntegerOrEnumerationType() |
||
| 306 | ? Solver->mkFPtoSBV(Exp, ToBitWidth) |
||
| 307 | : Solver->mkFPtoUBV(Exp, ToBitWidth); |
||
| 308 | |||
| 309 | llvm_unreachable("Unsupported explicit type cast!"); |
||
| 310 | } |
||
| 311 | |||
| 312 | // Callback function for doCast parameter on APSInt type. |
||
| 313 | static inline llvm::APSInt castAPSInt(llvm::SMTSolverRef &Solver, |
||
| 314 | const llvm::APSInt &V, QualType ToTy, |
||
| 315 | uint64_t ToWidth, QualType FromTy, |
||
| 316 | uint64_t FromWidth) { |
||
| 317 | APSIntType TargetType(ToWidth, !ToTy->isSignedIntegerOrEnumerationType()); |
||
| 318 | return TargetType.convert(V); |
||
| 319 | } |
||
| 320 | |||
| 321 | /// Construct an SMTSolverRef from a SymbolData. |
||
| 322 | static inline llvm::SMTExprRef |
||
| 323 | fromData(llvm::SMTSolverRef &Solver, ASTContext &Ctx, const SymbolData *Sym) { |
||
| 324 | const SymbolID ID = Sym->getSymbolID(); |
||
| 325 | const QualType Ty = Sym->getType(); |
||
| 326 | const uint64_t BitWidth = Ctx.getTypeSize(Ty); |
||
| 327 | |||
| 328 | llvm::SmallString<16> Str; |
||
| 329 | llvm::raw_svector_ostream OS(Str); |
||
| 330 | OS << Sym->getKindStr() << ID; |
||
| 331 | return Solver->mkSymbol(Str.c_str(), mkSort(Solver, Ty, BitWidth)); |
||
| 332 | } |
||
| 333 | |||
| 334 | // Wrapper to generate SMTSolverRef from SymbolCast data. |
||
| 335 | static inline llvm::SMTExprRef getCastExpr(llvm::SMTSolverRef &Solver, |
||
| 336 | ASTContext &Ctx, |
||
| 337 | const llvm::SMTExprRef &Exp, |
||
| 338 | QualType FromTy, QualType ToTy) { |
||
| 339 | return fromCast(Solver, Exp, ToTy, Ctx.getTypeSize(ToTy), FromTy, |
||
| 340 | Ctx.getTypeSize(FromTy)); |
||
| 341 | } |
||
| 342 | |||
| 343 | // Wrapper to generate SMTSolverRef from unpacked binary symbolic |
||
| 344 | // expression. Sets the RetTy parameter. See getSMTSolverRef(). |
||
| 345 | static inline llvm::SMTExprRef |
||
| 346 | getBinExpr(llvm::SMTSolverRef &Solver, ASTContext &Ctx, |
||
| 347 | const llvm::SMTExprRef &LHS, QualType LTy, |
||
| 348 | BinaryOperator::Opcode Op, const llvm::SMTExprRef &RHS, |
||
| 349 | QualType RTy, QualType *RetTy) { |
||
| 350 | llvm::SMTExprRef NewLHS = LHS; |
||
| 351 | llvm::SMTExprRef NewRHS = RHS; |
||
| 352 | doTypeConversion(Solver, Ctx, NewLHS, NewRHS, LTy, RTy); |
||
| 353 | |||
| 354 | // Update the return type parameter if the output type has changed. |
||
| 355 | if (RetTy) { |
||
| 356 | // A boolean result can be represented as an integer type in C/C++, but at |
||
| 357 | // this point we only care about the SMT sorts. Set it as a boolean type |
||
| 358 | // to avoid subsequent SMT errors. |
||
| 359 | if (BinaryOperator::isComparisonOp(Op) || |
||
| 360 | BinaryOperator::isLogicalOp(Op)) { |
||
| 361 | *RetTy = Ctx.BoolTy; |
||
| 362 | } else { |
||
| 363 | *RetTy = LTy; |
||
| 364 | } |
||
| 365 | |||
| 366 | // If the two operands are pointers and the operation is a subtraction, |
||
| 367 | // the result is of type ptrdiff_t, which is signed |
||
| 368 | if (LTy->isAnyPointerType() && RTy->isAnyPointerType() && Op == BO_Sub) { |
||
| 369 | *RetTy = Ctx.getPointerDiffType(); |
||
| 370 | } |
||
| 371 | } |
||
| 372 | |||
| 373 | return LTy->isRealFloatingType() |
||
| 374 | ? fromFloatBinOp(Solver, NewLHS, Op, NewRHS) |
||
| 375 | : fromBinOp(Solver, NewLHS, Op, NewRHS, |
||
| 376 | LTy->isSignedIntegerOrEnumerationType()); |
||
| 377 | } |
||
| 378 | |||
| 379 | // Wrapper to generate SMTSolverRef from BinarySymExpr. |
||
| 380 | // Sets the hasComparison and RetTy parameters. See getSMTSolverRef(). |
||
| 381 | static inline llvm::SMTExprRef getSymBinExpr(llvm::SMTSolverRef &Solver, |
||
| 382 | ASTContext &Ctx, |
||
| 383 | const BinarySymExpr *BSE, |
||
| 384 | bool *hasComparison, |
||
| 385 | QualType *RetTy) { |
||
| 386 | QualType LTy, RTy; |
||
| 387 | BinaryOperator::Opcode Op = BSE->getOpcode(); |
||
| 388 | |||
| 389 | if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE)) { |
||
| 390 | llvm::SMTExprRef LHS = |
||
| 391 | getSymExpr(Solver, Ctx, SIE->getLHS(), <y, hasComparison); |
||
| 392 | llvm::APSInt NewRInt; |
||
| 393 | std::tie(NewRInt, RTy) = fixAPSInt(Ctx, SIE->getRHS()); |
||
| 394 | llvm::SMTExprRef RHS = |
||
| 395 | Solver->mkBitvector(NewRInt, NewRInt.getBitWidth()); |
||
| 396 | return getBinExpr(Solver, Ctx, LHS, LTy, Op, RHS, RTy, RetTy); |
||
| 397 | } |
||
| 398 | |||
| 399 | if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE)) { |
||
| 400 | llvm::APSInt NewLInt; |
||
| 401 | std::tie(NewLInt, LTy) = fixAPSInt(Ctx, ISE->getLHS()); |
||
| 402 | llvm::SMTExprRef LHS = |
||
| 403 | Solver->mkBitvector(NewLInt, NewLInt.getBitWidth()); |
||
| 404 | llvm::SMTExprRef RHS = |
||
| 405 | getSymExpr(Solver, Ctx, ISE->getRHS(), &RTy, hasComparison); |
||
| 406 | return getBinExpr(Solver, Ctx, LHS, LTy, Op, RHS, RTy, RetTy); |
||
| 407 | } |
||
| 408 | |||
| 409 | if (const SymSymExpr *SSM = dyn_cast<SymSymExpr>(BSE)) { |
||
| 410 | llvm::SMTExprRef LHS = |
||
| 411 | getSymExpr(Solver, Ctx, SSM->getLHS(), <y, hasComparison); |
||
| 412 | llvm::SMTExprRef RHS = |
||
| 413 | getSymExpr(Solver, Ctx, SSM->getRHS(), &RTy, hasComparison); |
||
| 414 | return getBinExpr(Solver, Ctx, LHS, LTy, Op, RHS, RTy, RetTy); |
||
| 415 | } |
||
| 416 | |||
| 417 | llvm_unreachable("Unsupported BinarySymExpr type!"); |
||
| 418 | } |
||
| 419 | |||
| 420 | // Recursive implementation to unpack and generate symbolic expression. |
||
| 421 | // Sets the hasComparison and RetTy parameters. See getExpr(). |
||
| 422 | static inline llvm::SMTExprRef getSymExpr(llvm::SMTSolverRef &Solver, |
||
| 423 | ASTContext &Ctx, SymbolRef Sym, |
||
| 424 | QualType *RetTy, |
||
| 425 | bool *hasComparison) { |
||
| 426 | if (const SymbolData *SD = dyn_cast<SymbolData>(Sym)) { |
||
| 427 | if (RetTy) |
||
| 428 | *RetTy = Sym->getType(); |
||
| 429 | |||
| 430 | return fromData(Solver, Ctx, SD); |
||
| 431 | } |
||
| 432 | |||
| 433 | if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) { |
||
| 434 | if (RetTy) |
||
| 435 | *RetTy = Sym->getType(); |
||
| 436 | |||
| 437 | QualType FromTy; |
||
| 438 | llvm::SMTExprRef Exp = |
||
| 439 | getSymExpr(Solver, Ctx, SC->getOperand(), &FromTy, hasComparison); |
||
| 440 | |||
| 441 | // Casting an expression with a comparison invalidates it. Note that this |
||
| 442 | // must occur after the recursive call above. |
||
| 443 | // e.g. (signed char) (x > 0) |
||
| 444 | if (hasComparison) |
||
| 445 | *hasComparison = false; |
||
| 446 | return getCastExpr(Solver, Ctx, Exp, FromTy, Sym->getType()); |
||
| 447 | } |
||
| 448 | |||
| 449 | if (const UnarySymExpr *USE = dyn_cast<UnarySymExpr>(Sym)) { |
||
| 450 | if (RetTy) |
||
| 451 | *RetTy = Sym->getType(); |
||
| 452 | |||
| 453 | QualType OperandTy; |
||
| 454 | llvm::SMTExprRef OperandExp = |
||
| 455 | getSymExpr(Solver, Ctx, USE->getOperand(), &OperandTy, hasComparison); |
||
| 456 | llvm::SMTExprRef UnaryExp = |
||
| 457 | OperandTy->isRealFloatingType() |
||
| 458 | ? fromFloatUnOp(Solver, USE->getOpcode(), OperandExp) |
||
| 459 | : fromUnOp(Solver, USE->getOpcode(), OperandExp); |
||
| 460 | |||
| 461 | // Currently, without the `support-symbolic-integer-casts=true` option, |
||
| 462 | // we do not emit `SymbolCast`s for implicit casts. |
||
| 463 | // One such implicit cast is missing if the operand of the unary operator |
||
| 464 | // has a different type than the unary itself. |
||
| 465 | if (Ctx.getTypeSize(OperandTy) != Ctx.getTypeSize(Sym->getType())) { |
||
| 466 | if (hasComparison) |
||
| 467 | *hasComparison = false; |
||
| 468 | return getCastExpr(Solver, Ctx, UnaryExp, OperandTy, Sym->getType()); |
||
| 469 | } |
||
| 470 | return UnaryExp; |
||
| 471 | } |
||
| 472 | |||
| 473 | if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) { |
||
| 474 | llvm::SMTExprRef Exp = |
||
| 475 | getSymBinExpr(Solver, Ctx, BSE, hasComparison, RetTy); |
||
| 476 | // Set the hasComparison parameter, in post-order traversal order. |
||
| 477 | if (hasComparison) |
||
| 478 | *hasComparison = BinaryOperator::isComparisonOp(BSE->getOpcode()); |
||
| 479 | return Exp; |
||
| 480 | } |
||
| 481 | |||
| 482 | llvm_unreachable("Unsupported SymbolRef type!"); |
||
| 483 | } |
||
| 484 | |||
| 485 | // Generate an SMTSolverRef that represents the given symbolic expression. |
||
| 486 | // Sets the hasComparison parameter if the expression has a comparison |
||
| 487 | // operator. Sets the RetTy parameter to the final return type after |
||
| 488 | // promotions and casts. |
||
| 489 | static inline llvm::SMTExprRef getExpr(llvm::SMTSolverRef &Solver, |
||
| 490 | ASTContext &Ctx, SymbolRef Sym, |
||
| 491 | QualType *RetTy = nullptr, |
||
| 492 | bool *hasComparison = nullptr) { |
||
| 493 | if (hasComparison) { |
||
| 494 | *hasComparison = false; |
||
| 495 | } |
||
| 496 | |||
| 497 | return getSymExpr(Solver, Ctx, Sym, RetTy, hasComparison); |
||
| 498 | } |
||
| 499 | |||
| 500 | // Generate an SMTSolverRef that compares the expression to zero. |
||
| 501 | static inline llvm::SMTExprRef getZeroExpr(llvm::SMTSolverRef &Solver, |
||
| 502 | ASTContext &Ctx, |
||
| 503 | const llvm::SMTExprRef &Exp, |
||
| 504 | QualType Ty, bool Assumption) { |
||
| 505 | if (Ty->isRealFloatingType()) { |
||
| 506 | llvm::APFloat Zero = |
||
| 507 | llvm::APFloat::getZero(Ctx.getFloatTypeSemantics(Ty)); |
||
| 508 | return fromFloatBinOp(Solver, Exp, Assumption ? BO_EQ : BO_NE, |
||
| 509 | Solver->mkFloat(Zero)); |
||
| 510 | } |
||
| 511 | |||
| 512 | if (Ty->isIntegralOrEnumerationType() || Ty->isAnyPointerType() || |
||
| 513 | Ty->isBlockPointerType() || Ty->isReferenceType()) { |
||
| 514 | |||
| 515 | // Skip explicit comparison for boolean types |
||
| 516 | bool isSigned = Ty->isSignedIntegerOrEnumerationType(); |
||
| 517 | if (Ty->isBooleanType()) |
||
| 518 | return Assumption ? fromUnOp(Solver, UO_LNot, Exp) : Exp; |
||
| 519 | |||
| 520 | return fromBinOp( |
||
| 521 | Solver, Exp, Assumption ? BO_EQ : BO_NE, |
||
| 522 | Solver->mkBitvector(llvm::APSInt("0"), Ctx.getTypeSize(Ty)), |
||
| 523 | isSigned); |
||
| 524 | } |
||
| 525 | |||
| 526 | llvm_unreachable("Unsupported type for zero value!"); |
||
| 527 | } |
||
| 528 | |||
| 529 | // Wrapper to generate SMTSolverRef from a range. If From == To, an |
||
| 530 | // equality will be created instead. |
||
| 531 | static inline llvm::SMTExprRef |
||
| 532 | getRangeExpr(llvm::SMTSolverRef &Solver, ASTContext &Ctx, SymbolRef Sym, |
||
| 533 | const llvm::APSInt &From, const llvm::APSInt &To, bool InRange) { |
||
| 534 | // Convert lower bound |
||
| 535 | QualType FromTy; |
||
| 536 | llvm::APSInt NewFromInt; |
||
| 537 | std::tie(NewFromInt, FromTy) = fixAPSInt(Ctx, From); |
||
| 538 | llvm::SMTExprRef FromExp = |
||
| 539 | Solver->mkBitvector(NewFromInt, NewFromInt.getBitWidth()); |
||
| 540 | |||
| 541 | // Convert symbol |
||
| 542 | QualType SymTy; |
||
| 543 | llvm::SMTExprRef Exp = getExpr(Solver, Ctx, Sym, &SymTy); |
||
| 544 | |||
| 545 | // Construct single (in)equality |
||
| 546 | if (From == To) |
||
| 547 | return getBinExpr(Solver, Ctx, Exp, SymTy, InRange ? BO_EQ : BO_NE, |
||
| 548 | FromExp, FromTy, /*RetTy=*/nullptr); |
||
| 549 | |||
| 550 | QualType ToTy; |
||
| 551 | llvm::APSInt NewToInt; |
||
| 552 | std::tie(NewToInt, ToTy) = fixAPSInt(Ctx, To); |
||
| 553 | llvm::SMTExprRef ToExp = |
||
| 554 | Solver->mkBitvector(NewToInt, NewToInt.getBitWidth()); |
||
| 555 | assert(FromTy == ToTy && "Range values have different types!"); |
||
| 556 | |||
| 557 | // Construct two (in)equalities, and a logical and/or |
||
| 558 | llvm::SMTExprRef LHS = |
||
| 559 | getBinExpr(Solver, Ctx, Exp, SymTy, InRange ? BO_GE : BO_LT, FromExp, |
||
| 560 | FromTy, /*RetTy=*/nullptr); |
||
| 561 | llvm::SMTExprRef RHS = getBinExpr(Solver, Ctx, Exp, SymTy, |
||
| 562 | InRange ? BO_LE : BO_GT, ToExp, ToTy, |
||
| 563 | /*RetTy=*/nullptr); |
||
| 564 | |||
| 565 | return fromBinOp(Solver, LHS, InRange ? BO_LAnd : BO_LOr, RHS, |
||
| 566 | SymTy->isSignedIntegerOrEnumerationType()); |
||
| 567 | } |
||
| 568 | |||
| 569 | // Recover the QualType of an APSInt. |
||
| 570 | // TODO: Refactor to put elsewhere |
||
| 571 | static inline QualType getAPSIntType(ASTContext &Ctx, |
||
| 572 | const llvm::APSInt &Int) { |
||
| 573 | return Ctx.getIntTypeForBitwidth(Int.getBitWidth(), Int.isSigned()); |
||
| 574 | } |
||
| 575 | |||
| 576 | // Get the QualTy for the input APSInt, and fix it if it has a bitwidth of 1. |
||
| 577 | static inline std::pair<llvm::APSInt, QualType> |
||
| 578 | fixAPSInt(ASTContext &Ctx, const llvm::APSInt &Int) { |
||
| 579 | llvm::APSInt NewInt; |
||
| 580 | |||
| 581 | // FIXME: This should be a cast from a 1-bit integer type to a boolean type, |
||
| 582 | // but the former is not available in Clang. Instead, extend the APSInt |
||
| 583 | // directly. |
||
| 584 | if (Int.getBitWidth() == 1 && getAPSIntType(Ctx, Int).isNull()) { |
||
| 585 | NewInt = Int.extend(Ctx.getTypeSize(Ctx.BoolTy)); |
||
| 586 | } else |
||
| 587 | NewInt = Int; |
||
| 588 | |||
| 589 | return std::make_pair(NewInt, getAPSIntType(Ctx, NewInt)); |
||
| 590 | } |
||
| 591 | |||
| 592 | // Perform implicit type conversion on binary symbolic expressions. |
||
| 593 | // May modify all input parameters. |
||
| 594 | // TODO: Refactor to use built-in conversion functions |
||
| 595 | static inline void doTypeConversion(llvm::SMTSolverRef &Solver, |
||
| 596 | ASTContext &Ctx, llvm::SMTExprRef &LHS, |
||
| 597 | llvm::SMTExprRef &RHS, QualType <y, |
||
| 598 | QualType &RTy) { |
||
| 599 | assert(!LTy.isNull() && !RTy.isNull() && "Input type is null!"); |
||
| 600 | |||
| 601 | // Perform type conversion |
||
| 602 | if ((LTy->isIntegralOrEnumerationType() && |
||
| 603 | RTy->isIntegralOrEnumerationType()) && |
||
| 604 | (LTy->isArithmeticType() && RTy->isArithmeticType())) { |
||
| 605 | SMTConv::doIntTypeConversion<llvm::SMTExprRef, &fromCast>( |
||
| 606 | Solver, Ctx, LHS, LTy, RHS, RTy); |
||
| 607 | return; |
||
| 608 | } |
||
| 609 | |||
| 610 | if (LTy->isRealFloatingType() || RTy->isRealFloatingType()) { |
||
| 611 | SMTConv::doFloatTypeConversion<llvm::SMTExprRef, &fromCast>( |
||
| 612 | Solver, Ctx, LHS, LTy, RHS, RTy); |
||
| 613 | return; |
||
| 614 | } |
||
| 615 | |||
| 616 | if ((LTy->isAnyPointerType() || RTy->isAnyPointerType()) || |
||
| 617 | (LTy->isBlockPointerType() || RTy->isBlockPointerType()) || |
||
| 618 | (LTy->isReferenceType() || RTy->isReferenceType())) { |
||
| 619 | // TODO: Refactor to Sema::FindCompositePointerType(), and |
||
| 620 | // Sema::CheckCompareOperands(). |
||
| 621 | |||
| 622 | uint64_t LBitWidth = Ctx.getTypeSize(LTy); |
||
| 623 | uint64_t RBitWidth = Ctx.getTypeSize(RTy); |
||
| 624 | |||
| 625 | // Cast the non-pointer type to the pointer type. |
||
| 626 | // TODO: Be more strict about this. |
||
| 627 | if ((LTy->isAnyPointerType() ^ RTy->isAnyPointerType()) || |
||
| 628 | (LTy->isBlockPointerType() ^ RTy->isBlockPointerType()) || |
||
| 629 | (LTy->isReferenceType() ^ RTy->isReferenceType())) { |
||
| 630 | if (LTy->isNullPtrType() || LTy->isBlockPointerType() || |
||
| 631 | LTy->isReferenceType()) { |
||
| 632 | LHS = fromCast(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth); |
||
| 633 | LTy = RTy; |
||
| 634 | } else { |
||
| 635 | RHS = fromCast(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth); |
||
| 636 | RTy = LTy; |
||
| 637 | } |
||
| 638 | } |
||
| 639 | |||
| 640 | // Cast the void pointer type to the non-void pointer type. |
||
| 641 | // For void types, this assumes that the casted value is equal to the |
||
| 642 | // value of the original pointer, and does not account for alignment |
||
| 643 | // requirements. |
||
| 644 | if (LTy->isVoidPointerType() ^ RTy->isVoidPointerType()) { |
||
| 645 | assert((Ctx.getTypeSize(LTy) == Ctx.getTypeSize(RTy)) && |
||
| 646 | "Pointer types have different bitwidths!"); |
||
| 647 | if (RTy->isVoidPointerType()) |
||
| 648 | RTy = LTy; |
||
| 649 | else |
||
| 650 | LTy = RTy; |
||
| 651 | } |
||
| 652 | |||
| 653 | if (LTy == RTy) |
||
| 654 | return; |
||
| 655 | } |
||
| 656 | |||
| 657 | // Fallback: for the solver, assume that these types don't really matter |
||
| 658 | if ((LTy.getCanonicalType() == RTy.getCanonicalType()) || |
||
| 659 | (LTy->isObjCObjectPointerType() && RTy->isObjCObjectPointerType())) { |
||
| 660 | LTy = RTy; |
||
| 661 | return; |
||
| 662 | } |
||
| 663 | |||
| 664 | // TODO: Refine behavior for invalid type casts |
||
| 665 | } |
||
| 666 | |||
| 667 | // Perform implicit integer type conversion. |
||
| 668 | // May modify all input parameters. |
||
| 669 | // TODO: Refactor to use Sema::handleIntegerConversion() |
||
| 670 | template <typename T, T (*doCast)(llvm::SMTSolverRef &Solver, const T &, |
||
| 671 | QualType, uint64_t, QualType, uint64_t)> |
||
| 672 | static inline void doIntTypeConversion(llvm::SMTSolverRef &Solver, |
||
| 673 | ASTContext &Ctx, T &LHS, QualType <y, |
||
| 674 | T &RHS, QualType &RTy) { |
||
| 675 | uint64_t LBitWidth = Ctx.getTypeSize(LTy); |
||
| 676 | uint64_t RBitWidth = Ctx.getTypeSize(RTy); |
||
| 677 | |||
| 678 | assert(!LTy.isNull() && !RTy.isNull() && "Input type is null!"); |
||
| 679 | // Always perform integer promotion before checking type equality. |
||
| 680 | // Otherwise, e.g. (bool) a + (bool) b could trigger a backend assertion |
||
| 681 | if (Ctx.isPromotableIntegerType(LTy)) { |
||
| 682 | QualType NewTy = Ctx.getPromotedIntegerType(LTy); |
||
| 683 | uint64_t NewBitWidth = Ctx.getTypeSize(NewTy); |
||
| 684 | LHS = (*doCast)(Solver, LHS, NewTy, NewBitWidth, LTy, LBitWidth); |
||
| 685 | LTy = NewTy; |
||
| 686 | LBitWidth = NewBitWidth; |
||
| 687 | } |
||
| 688 | if (Ctx.isPromotableIntegerType(RTy)) { |
||
| 689 | QualType NewTy = Ctx.getPromotedIntegerType(RTy); |
||
| 690 | uint64_t NewBitWidth = Ctx.getTypeSize(NewTy); |
||
| 691 | RHS = (*doCast)(Solver, RHS, NewTy, NewBitWidth, RTy, RBitWidth); |
||
| 692 | RTy = NewTy; |
||
| 693 | RBitWidth = NewBitWidth; |
||
| 694 | } |
||
| 695 | |||
| 696 | if (LTy == RTy) |
||
| 697 | return; |
||
| 698 | |||
| 699 | // Perform integer type conversion |
||
| 700 | // Note: Safe to skip updating bitwidth because this must terminate |
||
| 701 | bool isLSignedTy = LTy->isSignedIntegerOrEnumerationType(); |
||
| 702 | bool isRSignedTy = RTy->isSignedIntegerOrEnumerationType(); |
||
| 703 | |||
| 704 | int order = Ctx.getIntegerTypeOrder(LTy, RTy); |
||
| 705 | if (isLSignedTy == isRSignedTy) { |
||
| 706 | // Same signedness; use the higher-ranked type |
||
| 707 | if (order == 1) { |
||
| 708 | RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth); |
||
| 709 | RTy = LTy; |
||
| 710 | } else { |
||
| 711 | LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth); |
||
| 712 | LTy = RTy; |
||
| 713 | } |
||
| 714 | } else if (order != (isLSignedTy ? 1 : -1)) { |
||
| 715 | // The unsigned type has greater than or equal rank to the |
||
| 716 | // signed type, so use the unsigned type |
||
| 717 | if (isRSignedTy) { |
||
| 718 | RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth); |
||
| 719 | RTy = LTy; |
||
| 720 | } else { |
||
| 721 | LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth); |
||
| 722 | LTy = RTy; |
||
| 723 | } |
||
| 724 | } else if (LBitWidth != RBitWidth) { |
||
| 725 | // The two types are different widths; if we are here, that |
||
| 726 | // means the signed type is larger than the unsigned type, so |
||
| 727 | // use the signed type. |
||
| 728 | if (isLSignedTy) { |
||
| 729 | RHS = (doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth); |
||
| 730 | RTy = LTy; |
||
| 731 | } else { |
||
| 732 | LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth); |
||
| 733 | LTy = RTy; |
||
| 734 | } |
||
| 735 | } else { |
||
| 736 | // The signed type is higher-ranked than the unsigned type, |
||
| 737 | // but isn't actually any bigger (like unsigned int and long |
||
| 738 | // on most 32-bit systems). Use the unsigned type corresponding |
||
| 739 | // to the signed type. |
||
| 740 | QualType NewTy = |
||
| 741 | Ctx.getCorrespondingUnsignedType(isLSignedTy ? LTy : RTy); |
||
| 742 | RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth); |
||
| 743 | RTy = NewTy; |
||
| 744 | LHS = (doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth); |
||
| 745 | LTy = NewTy; |
||
| 746 | } |
||
| 747 | } |
||
| 748 | |||
| 749 | // Perform implicit floating-point type conversion. |
||
| 750 | // May modify all input parameters. |
||
| 751 | // TODO: Refactor to use Sema::handleFloatConversion() |
||
| 752 | template <typename T, T (*doCast)(llvm::SMTSolverRef &Solver, const T &, |
||
| 753 | QualType, uint64_t, QualType, uint64_t)> |
||
| 754 | static inline void |
||
| 755 | doFloatTypeConversion(llvm::SMTSolverRef &Solver, ASTContext &Ctx, T &LHS, |
||
| 756 | QualType <y, T &RHS, QualType &RTy) { |
||
| 757 | uint64_t LBitWidth = Ctx.getTypeSize(LTy); |
||
| 758 | uint64_t RBitWidth = Ctx.getTypeSize(RTy); |
||
| 759 | |||
| 760 | // Perform float-point type promotion |
||
| 761 | if (!LTy->isRealFloatingType()) { |
||
| 762 | LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth); |
||
| 763 | LTy = RTy; |
||
| 764 | LBitWidth = RBitWidth; |
||
| 765 | } |
||
| 766 | if (!RTy->isRealFloatingType()) { |
||
| 767 | RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth); |
||
| 768 | RTy = LTy; |
||
| 769 | RBitWidth = LBitWidth; |
||
| 770 | } |
||
| 771 | |||
| 772 | if (LTy == RTy) |
||
| 773 | return; |
||
| 774 | |||
| 775 | // If we have two real floating types, convert the smaller operand to the |
||
| 776 | // bigger result |
||
| 777 | // Note: Safe to skip updating bitwidth because this must terminate |
||
| 778 | int order = Ctx.getFloatingTypeOrder(LTy, RTy); |
||
| 779 | if (order > 0) { |
||
| 780 | RHS = (*doCast)(Solver, RHS, LTy, LBitWidth, RTy, RBitWidth); |
||
| 781 | RTy = LTy; |
||
| 782 | } else if (order == 0) { |
||
| 783 | LHS = (*doCast)(Solver, LHS, RTy, RBitWidth, LTy, LBitWidth); |
||
| 784 | LTy = RTy; |
||
| 785 | } else { |
||
| 786 | llvm_unreachable("Unsupported floating-point type cast!"); |
||
| 787 | } |
||
| 788 | } |
||
| 789 | }; |
||
| 790 | } // namespace ento |
||
| 791 | } // namespace clang |
||
| 792 | |||
| 793 | #endif |