Skip to content

Commit 6edbe84

Browse files
committed
Thread Safety Analysis: Compare values of literals
The typical case for literals is an array of mutexes, where we want to distinguish `mutex[0]` from `mutex[1]` and so on. Currently they're treated as the same expression, in fact all literals are treated as the same expression. The infrastructure for literals is already there, although it required some changes, and some simplifications seemed opportune: * The `ValueType` had fields for size and signedness. But Clang doesn't use native types and stores integer and (floating-point) literals as `llvm::APInt` regardless of size, so we don't need these properties. We could use them for characters, but it seems easier to just create different base types for now. * We remove the `BT_Void`: `void` literals don't exist in C++. * We remove `BT_Float` and `BT_ValueRef`: floating-point numbers and complex numbers are probably not used in lock expressions. We turn `Literal` into a pure base class, as it seems to have been intended, and only create `LiteralT` instances of the correct type. Assertions on `as` ensure we're not mixing up types. We print to `llvm::raw_ostream` instead of `std::ostream` because that's required for `CharacterLiteral::print`. Perhaps we should implement that ourselves though. Fixes #58535.
1 parent bfb686b commit 6edbe84

File tree

5 files changed

+190
-232
lines changed

5 files changed

+190
-232
lines changed

clang/include/clang/Analysis/Analyses/ThreadSafetyCommon.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
#include "llvm/ADT/PointerUnion.h"
3636
#include "llvm/ADT/SmallVector.h"
3737
#include "llvm/Support/Casting.h"
38-
#include <sstream>
38+
#include "llvm/Support/raw_ostream.h"
3939
#include <string>
4040
#include <utility>
4141
#include <vector>
@@ -90,9 +90,10 @@ inline bool partiallyMatches(const til::SExpr *E1, const til::SExpr *E2) {
9090
}
9191

9292
inline std::string toString(const til::SExpr *E) {
93-
std::stringstream ss;
93+
std::string s;
94+
llvm::raw_string_ostream ss(s);
9495
til::StdPrinter::print(E, ss);
95-
return ss.str();
96+
return s;
9697
}
9798

9899
} // namespace sx

clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h

Lines changed: 68 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -148,129 +148,63 @@ StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op);
148148
/// All variables and expressions must have a value type.
149149
/// Pointer types are further subdivided into the various heap-allocated
150150
/// types, such as functions, records, etc.
151-
/// Structured types that are passed by value (e.g. complex numbers)
152-
/// require special handling; they use BT_ValueRef, and size ST_0.
153151
struct ValueType {
154152
enum BaseType : unsigned char {
155-
BT_Void = 0,
156153
BT_Bool,
154+
BT_AsciiChar,
155+
BT_WideChar,
156+
BT_UTF16Char,
157+
BT_UTF32Char,
157158
BT_Int,
158-
BT_Float,
159-
BT_String, // String literals
159+
BT_String, // String literals
160160
BT_Pointer,
161-
BT_ValueRef
162161
};
163162

164-
enum SizeType : unsigned char {
165-
ST_0 = 0,
166-
ST_1,
167-
ST_8,
168-
ST_16,
169-
ST_32,
170-
ST_64,
171-
ST_128
172-
};
173-
174-
ValueType(BaseType B, SizeType Sz, bool S, unsigned char VS)
175-
: Base(B), Size(Sz), Signed(S), VectSize(VS) {}
176-
177-
inline static SizeType getSizeType(unsigned nbytes);
163+
ValueType(BaseType B) : Base(B) {}
178164

179165
template <class T>
180166
inline static ValueType getValueType();
181167

182168
BaseType Base;
183-
SizeType Size;
184-
bool Signed;
185-
186-
// 0 for scalar, otherwise num elements in vector
187-
unsigned char VectSize;
188169
};
189170

190-
inline ValueType::SizeType ValueType::getSizeType(unsigned nbytes) {
191-
switch (nbytes) {
192-
case 1: return ST_8;
193-
case 2: return ST_16;
194-
case 4: return ST_32;
195-
case 8: return ST_64;
196-
case 16: return ST_128;
197-
default: return ST_0;
198-
}
199-
}
200-
201-
template<>
202-
inline ValueType ValueType::getValueType<void>() {
203-
return ValueType(BT_Void, ST_0, false, 0);
171+
inline bool operator==(const ValueType &a, const ValueType &b) {
172+
return a.Base == b.Base;
204173
}
205174

206175
template<>
207176
inline ValueType ValueType::getValueType<bool>() {
208-
return ValueType(BT_Bool, ST_1, false, 0);
209-
}
210-
211-
template<>
212-
inline ValueType ValueType::getValueType<int8_t>() {
213-
return ValueType(BT_Int, ST_8, true, 0);
214-
}
215-
216-
template<>
217-
inline ValueType ValueType::getValueType<uint8_t>() {
218-
return ValueType(BT_Int, ST_8, false, 0);
177+
return ValueType(BT_Bool);
219178
}
220179

221-
template<>
222-
inline ValueType ValueType::getValueType<int16_t>() {
223-
return ValueType(BT_Int, ST_16, true, 0);
224-
}
225-
226-
template<>
227-
inline ValueType ValueType::getValueType<uint16_t>() {
228-
return ValueType(BT_Int, ST_16, false, 0);
229-
}
230-
231-
template<>
232-
inline ValueType ValueType::getValueType<int32_t>() {
233-
return ValueType(BT_Int, ST_32, true, 0);
234-
}
235-
236-
template<>
237-
inline ValueType ValueType::getValueType<uint32_t>() {
238-
return ValueType(BT_Int, ST_32, false, 0);
239-
}
240-
241-
template<>
242-
inline ValueType ValueType::getValueType<int64_t>() {
243-
return ValueType(BT_Int, ST_64, true, 0);
180+
template <> inline ValueType ValueType::getValueType<char>() {
181+
return ValueType(BT_AsciiChar);
244182
}
245183

246-
template<>
247-
inline ValueType ValueType::getValueType<uint64_t>() {
248-
return ValueType(BT_Int, ST_64, false, 0);
184+
template <> inline ValueType ValueType::getValueType<wchar_t>() {
185+
return ValueType(BT_WideChar);
249186
}
250187

251-
template<>
252-
inline ValueType ValueType::getValueType<float>() {
253-
return ValueType(BT_Float, ST_32, true, 0);
188+
template <> inline ValueType ValueType::getValueType<char16_t>() {
189+
return ValueType(BT_UTF16Char);
254190
}
255191

256-
template<>
257-
inline ValueType ValueType::getValueType<double>() {
258-
return ValueType(BT_Float, ST_64, true, 0);
192+
template <> inline ValueType ValueType::getValueType<char32_t>() {
193+
return ValueType(BT_UTF32Char);
259194
}
260195

261-
template<>
262-
inline ValueType ValueType::getValueType<long double>() {
263-
return ValueType(BT_Float, ST_128, true, 0);
196+
template <> inline ValueType ValueType::getValueType<llvm::APInt>() {
197+
return ValueType(BT_Int);
264198
}
265199

266200
template<>
267201
inline ValueType ValueType::getValueType<StringRef>() {
268-
return ValueType(BT_String, getSizeType(sizeof(StringRef)), false, 0);
202+
return ValueType(BT_String);
269203
}
270204

271205
template<>
272206
inline ValueType ValueType::getValueType<void*>() {
273-
return ValueType(BT_Pointer, getSizeType(sizeof(void*)), false, 0);
207+
return ValueType(BT_Pointer);
274208
}
275209

276210
/// Base class for AST nodes in the typed intermediate language.
@@ -532,37 +466,29 @@ template <class T> class LiteralT;
532466

533467
// Base class for literal values.
534468
class Literal : public SExpr {
535-
public:
536-
Literal(const Expr *C)
537-
: SExpr(COP_Literal), ValType(ValueType::getValueType<void>()), Cexpr(C) {}
469+
protected:
538470
Literal(ValueType VT) : SExpr(COP_Literal), ValType(VT) {}
539-
Literal(const Literal &) = default;
540471

472+
public:
541473
static bool classof(const SExpr *E) { return E->opcode() == COP_Literal; }
542474

543-
// The clang expression for this literal.
544-
const Expr *clangExpr() const { return Cexpr; }
545-
546475
ValueType valueType() const { return ValType; }
547476

548477
template<class T> const LiteralT<T>& as() const {
478+
assert(ValType == ValueType::getValueType<T>());
549479
return *static_cast<const LiteralT<T>*>(this);
550480
}
551481
template<class T> LiteralT<T>& as() {
482+
assert(ValType == ValueType::getValueType<T>());
552483
return *static_cast<LiteralT<T>*>(this);
553484
}
554485

555486
template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx);
556487

557-
template <class C>
558-
typename C::CType compare(const Literal* E, C& Cmp) const {
559-
// TODO: defer actual comparison to LiteralT
560-
return Cmp.trueResult();
561-
}
488+
template <class C> typename C::CType compare(const Literal *E, C &Cmp) const;
562489

563490
private:
564491
const ValueType ValType;
565-
const Expr *Cexpr = nullptr;
566492
};
567493

568494
// Derived class for literal values, which stores the actual value.
@@ -585,58 +511,55 @@ class LiteralT : public Literal {
585511

586512
template <class V>
587513
typename V::R_SExpr Literal::traverse(V &Vs, typename V::R_Ctx Ctx) {
588-
if (Cexpr)
589-
return Vs.reduceLiteral(*this);
590-
591514
switch (ValType.Base) {
592-
case ValueType::BT_Void:
593-
break;
594515
case ValueType::BT_Bool:
595516
return Vs.reduceLiteralT(as<bool>());
596-
case ValueType::BT_Int: {
597-
switch (ValType.Size) {
598-
case ValueType::ST_8:
599-
if (ValType.Signed)
600-
return Vs.reduceLiteralT(as<int8_t>());
601-
else
602-
return Vs.reduceLiteralT(as<uint8_t>());
603-
case ValueType::ST_16:
604-
if (ValType.Signed)
605-
return Vs.reduceLiteralT(as<int16_t>());
606-
else
607-
return Vs.reduceLiteralT(as<uint16_t>());
608-
case ValueType::ST_32:
609-
if (ValType.Signed)
610-
return Vs.reduceLiteralT(as<int32_t>());
611-
else
612-
return Vs.reduceLiteralT(as<uint32_t>());
613-
case ValueType::ST_64:
614-
if (ValType.Signed)
615-
return Vs.reduceLiteralT(as<int64_t>());
616-
else
617-
return Vs.reduceLiteralT(as<uint64_t>());
618-
default:
619-
break;
620-
}
621-
}
622-
case ValueType::BT_Float: {
623-
switch (ValType.Size) {
624-
case ValueType::ST_32:
625-
return Vs.reduceLiteralT(as<float>());
626-
case ValueType::ST_64:
627-
return Vs.reduceLiteralT(as<double>());
628-
default:
629-
break;
630-
}
631-
}
517+
case ValueType::BT_AsciiChar:
518+
return Vs.reduceLiteralT(as<char>());
519+
case ValueType::BT_WideChar:
520+
return Vs.reduceLiteralT(as<wchar_t>());
521+
case ValueType::BT_UTF16Char:
522+
return Vs.reduceLiteralT(as<char16_t>());
523+
case ValueType::BT_UTF32Char:
524+
return Vs.reduceLiteralT(as<char32_t>());
525+
case ValueType::BT_Int:
526+
return Vs.reduceLiteralT(as<llvm::APInt>());
632527
case ValueType::BT_String:
633528
return Vs.reduceLiteralT(as<StringRef>());
634529
case ValueType::BT_Pointer:
635-
return Vs.reduceLiteralT(as<void*>());
636-
case ValueType::BT_ValueRef:
637-
break;
530+
return Vs.reduceLiteralT(as<void *>());
531+
}
532+
llvm_unreachable("Invalid BaseType");
533+
}
534+
535+
template <class C>
536+
typename C::CType Literal::compare(const Literal *E, C &Cmp) const {
537+
typename C::CType Ct = Cmp.compareIntegers(ValType.Base, E->ValType.Base);
538+
if (Cmp.notTrue(Ct))
539+
return Ct;
540+
switch (ValType.Base) {
541+
case ValueType::BT_Bool:
542+
return Cmp.compareIntegers(as<bool>().value(), E->as<bool>().value());
543+
case ValueType::BT_AsciiChar:
544+
return Cmp.compareIntegers(as<char>().value(), E->as<char>().value());
545+
case ValueType::BT_WideChar:
546+
return Cmp.compareIntegers(as<wchar_t>().value(), E->as<wchar_t>().value());
547+
case ValueType::BT_UTF16Char:
548+
return Cmp.compareIntegers(as<char16_t>().value(),
549+
E->as<char16_t>().value());
550+
case ValueType::BT_UTF32Char:
551+
return Cmp.compareIntegers(as<char32_t>().value(),
552+
E->as<char32_t>().value());
553+
case ValueType::BT_Int:
554+
return Cmp.compareIntegers(as<llvm::APInt>().value(),
555+
E->as<llvm::APInt>().value());
556+
case ValueType::BT_String:
557+
return Cmp.compareStrings(as<StringRef>().value(),
558+
E->as<StringRef>().value());
559+
case ValueType::BT_Pointer:
560+
return Cmp.trueResult();
638561
}
639-
return Vs.reduceLiteral(*this);
562+
llvm_unreachable("Invalid BaseType");
640563
}
641564

642565
/// A Literal pointer to an object allocated in memory.

0 commit comments

Comments
 (0)