Skip to content

Commit b6bd8b5

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 only integer have signedness, and the size is irrelevant if we don't want to emit machine code. For the abstract semantics that we're interested in, only the number matters. * 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 replace `BT_Pointer` with `BT_NullPointer`. There are no pointer literals, only null pointer literals. It seems to me that `ValueType` was intended to assign types to any node in the TIL, but it is currently only used for literals. I was trying to come up with reasons to assign types everywhere, but we're not trying to type check anything, and we don't support overloading. The comparison of expressions surely doesn't need it. But maybe this should be clarified at some point. (Including the fact that it is called Typed Intermediate Language.) 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`. Fixes #58535.
1 parent bfb686b commit b6bd8b5

File tree

5 files changed

+157
-240
lines changed

5 files changed

+157
-240
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: 57 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -148,129 +148,54 @@ 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,
157-
BT_Int,
158-
BT_Float,
159-
BT_String, // String literals
160-
BT_Pointer,
161-
BT_ValueRef
154+
BT_Char,
155+
BT_SInt,
156+
BT_UInt,
157+
BT_String, // String literals
158+
BT_NullPointer,
162159
};
163160

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);
161+
ValueType(BaseType B) : Base(B) {}
178162

179163
template <class T>
180164
inline static ValueType getValueType();
181165

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

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);
169+
inline bool operator==(const ValueType &a, const ValueType &b) {
170+
return a.Base == b.Base;
204171
}
205172

206173
template<>
207174
inline ValueType ValueType::getValueType<bool>() {
208-
return ValueType(BT_Bool, ST_1, false, 0);
175+
return ValueType(BT_Bool);
209176
}
210177

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);
219-
}
220-
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);
178+
template <> inline ValueType ValueType::getValueType<char32_t>() {
179+
return ValueType(BT_Char);
239180
}
240181

241182
template<>
242183
inline ValueType ValueType::getValueType<int64_t>() {
243-
return ValueType(BT_Int, ST_64, true, 0);
184+
return ValueType(BT_SInt);
244185
}
245186

246187
template<>
247188
inline ValueType ValueType::getValueType<uint64_t>() {
248-
return ValueType(BT_Int, ST_64, false, 0);
249-
}
250-
251-
template<>
252-
inline ValueType ValueType::getValueType<float>() {
253-
return ValueType(BT_Float, ST_32, true, 0);
254-
}
255-
256-
template<>
257-
inline ValueType ValueType::getValueType<double>() {
258-
return ValueType(BT_Float, ST_64, true, 0);
259-
}
260-
261-
template<>
262-
inline ValueType ValueType::getValueType<long double>() {
263-
return ValueType(BT_Float, ST_128, true, 0);
189+
return ValueType(BT_UInt);
264190
}
265191

266192
template<>
267193
inline ValueType ValueType::getValueType<StringRef>() {
268-
return ValueType(BT_String, getSizeType(sizeof(StringRef)), false, 0);
194+
return ValueType(BT_String);
269195
}
270196

271-
template<>
272-
inline ValueType ValueType::getValueType<void*>() {
273-
return ValueType(BT_Pointer, getSizeType(sizeof(void*)), false, 0);
197+
template <> inline ValueType ValueType::getValueType<std::nullptr_t>() {
198+
return ValueType(BT_NullPointer);
274199
}
275200

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

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

463+
public:
541464
static bool classof(const SExpr *E) { return E->opcode() == COP_Literal; }
542465

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

548468
template<class T> const LiteralT<T>& as() const {
469+
assert(ValType == ValueType::getValueType<T>());
549470
return *static_cast<const LiteralT<T>*>(this);
550471
}
551472
template<class T> LiteralT<T>& as() {
473+
assert(ValType == ValueType::getValueType<T>());
552474
return *static_cast<LiteralT<T>*>(this);
553475
}
554476

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

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-
}
479+
template <class C> typename C::CType compare(const Literal *E, C &Cmp) const;
562480

563481
private:
564482
const ValueType ValType;
565-
const Expr *Cexpr = nullptr;
566483
};
567484

568485
// Derived class for literal values, which stores the actual value.
@@ -583,60 +500,50 @@ class LiteralT : public Literal {
583500
T Val;
584501
};
585502

503+
template <class T> LiteralT(T) -> LiteralT<T>;
504+
586505
template <class V>
587506
typename V::R_SExpr Literal::traverse(V &Vs, typename V::R_Ctx Ctx) {
588-
if (Cexpr)
589-
return Vs.reduceLiteral(*this);
590-
591507
switch (ValType.Base) {
592-
case ValueType::BT_Void:
593-
break;
594508
case ValueType::BT_Bool:
595509
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-
}
510+
case ValueType::BT_Char:
511+
return Vs.reduceLiteralT(as<char32_t>());
512+
case ValueType::BT_SInt:
513+
return Vs.reduceLiteralT(as<int64_t>());
514+
case ValueType::BT_UInt:
515+
return Vs.reduceLiteralT(as<uint64_t>());
632516
case ValueType::BT_String:
633517
return Vs.reduceLiteralT(as<StringRef>());
634-
case ValueType::BT_Pointer:
635-
return Vs.reduceLiteralT(as<void*>());
636-
case ValueType::BT_ValueRef:
637-
break;
518+
case ValueType::BT_NullPointer:
519+
return Vs.reduceLiteralT(as<std::nullptr_t>());
520+
}
521+
llvm_unreachable("Invalid BaseType");
522+
}
523+
524+
template <class C>
525+
typename C::CType Literal::compare(const Literal *E, C &Cmp) const {
526+
typename C::CType Ct = Cmp.compareIntegers(ValType.Base, E->ValType.Base);
527+
if (Cmp.notTrue(Ct))
528+
return Ct;
529+
switch (ValType.Base) {
530+
case ValueType::BT_Bool:
531+
return Cmp.compareIntegers(as<bool>().value(), E->as<bool>().value());
532+
case ValueType::BT_Char:
533+
return Cmp.compareIntegers(as<char32_t>().value(),
534+
E->as<char32_t>().value());
535+
case ValueType::BT_SInt:
536+
return Cmp.compareIntegers(as<int64_t>().value(), E->as<int64_t>().value());
537+
case ValueType::BT_UInt:
538+
return Cmp.compareIntegers(as<uint64_t>().value(),
539+
E->as<uint64_t>().value());
540+
case ValueType::BT_String:
541+
return Cmp.compareStrings(as<StringRef>().value(),
542+
E->as<StringRef>().value());
543+
case ValueType::BT_NullPointer:
544+
return Cmp.trueResult();
638545
}
639-
return Vs.reduceLiteral(*this);
546+
llvm_unreachable("Invalid BaseType");
640547
}
641548

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

0 commit comments

Comments
 (0)