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