xref: /llvm-project/clang/lib/AST/APValue.cpp (revision f3e9e43da4da01907025e19f038fb48a0e7160e2)
1 //===--- APValue.cpp - Union class for APFloat/APSInt/Complex -------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file implements the APValue class.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/AST/APValue.h"
15 #include "clang/AST/CharUnits.h"
16 #include "clang/Basic/Diagnostic.h"
17 #include "llvm/ADT/SmallString.h"
18 #include "llvm/Support/raw_ostream.h"
19 #include "llvm/Support/ErrorHandling.h"
20 using namespace clang;
21 
22 namespace {
23   struct LVBase {
24     const Expr *Base;
25     CharUnits Offset;
26     unsigned PathLength;
27   };
28 }
29 
30 struct APValue::LV : LVBase {
31   static const unsigned InlinePathSpace =
32       (MaxSize - sizeof(LVBase)) / sizeof(LValuePathEntry);
33 
34   /// Path - The sequence of base classes, fields and array indices to follow to
35   /// walk from Base to the subobject. When performing GCC-style folding, there
36   /// may not be such a path.
37   union {
38     LValuePathEntry Path[InlinePathSpace];
39     LValuePathEntry *PathPtr;
40   };
41 
42   LV() { PathLength = (unsigned)-1; }
43   ~LV() { if (hasPathPtr()) delete [] PathPtr; }
44 
45   void allocPath() {
46     if (hasPathPtr()) PathPtr = new LValuePathEntry[PathLength];
47   }
48 
49   bool hasPath() const { return PathLength != (unsigned)-1; }
50   bool hasPathPtr() const { return hasPath() && PathLength > InlinePathSpace; }
51 
52   LValuePathEntry *getPath() { return hasPathPtr() ? PathPtr : Path; }
53   const LValuePathEntry *getPath() const {
54     return hasPathPtr() ? PathPtr : Path;
55   }
56 };
57 
58 // FIXME: Reduce the malloc traffic here.
59 
60 APValue::Arr::Arr(unsigned NumElts, unsigned Size) :
61   Elts(new APValue[NumElts + (NumElts != Size ? 1 : 0)]),
62   NumElts(NumElts), ArrSize(Size) {}
63 APValue::Arr::~Arr() { delete [] Elts; }
64 
65 APValue::APValue(const Expr* B) : Kind(Uninitialized) {
66   MakeLValue();
67   setLValue(B, CharUnits::Zero(), ArrayRef<LValuePathEntry>());
68 }
69 
70 const APValue &APValue::operator=(const APValue &RHS) {
71   if (Kind != RHS.Kind) {
72     MakeUninit();
73     if (RHS.isInt())
74       MakeInt();
75     else if (RHS.isFloat())
76       MakeFloat();
77     else if (RHS.isVector())
78       MakeVector();
79     else if (RHS.isComplexInt())
80       MakeComplexInt();
81     else if (RHS.isComplexFloat())
82       MakeComplexFloat();
83     else if (RHS.isLValue())
84       MakeLValue();
85     else if (RHS.isArray())
86       MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize());
87   }
88   if (isInt())
89     setInt(RHS.getInt());
90   else if (isFloat())
91     setFloat(RHS.getFloat());
92   else if (isVector())
93     setVector(((const Vec *)(const char *)RHS.Data)->Elts,
94               RHS.getVectorLength());
95   else if (isComplexInt())
96     setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag());
97   else if (isComplexFloat())
98     setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag());
99   else if (isLValue()) {
100     if (RHS.hasLValuePath())
101       setLValue(RHS.getLValueBase(), RHS.getLValueOffset(),RHS.getLValuePath());
102     else
103       setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath());
104   } else if (isArray()) {
105     for (unsigned I = 0, N = RHS.getArrayInitializedElts(); I != N; ++I)
106       getArrayInitializedElt(I) = RHS.getArrayInitializedElt(I);
107     if (RHS.hasArrayFiller())
108       getArrayFiller() = RHS.getArrayFiller();
109   }
110   return *this;
111 }
112 
113 void APValue::MakeUninit() {
114   if (Kind == Int)
115     ((APSInt*)(char*)Data)->~APSInt();
116   else if (Kind == Float)
117     ((APFloat*)(char*)Data)->~APFloat();
118   else if (Kind == Vector)
119     ((Vec*)(char*)Data)->~Vec();
120   else if (Kind == ComplexInt)
121     ((ComplexAPSInt*)(char*)Data)->~ComplexAPSInt();
122   else if (Kind == ComplexFloat)
123     ((ComplexAPFloat*)(char*)Data)->~ComplexAPFloat();
124   else if (Kind == LValue)
125     ((LV*)(char*)Data)->~LV();
126   else if (Kind == Array)
127     ((Arr*)(char*)Data)->~Arr();
128   Kind = Uninitialized;
129 }
130 
131 void APValue::dump() const {
132   print(llvm::errs());
133   llvm::errs() << '\n';
134 }
135 
136 static double GetApproxValue(const llvm::APFloat &F) {
137   llvm::APFloat V = F;
138   bool ignored;
139   V.convert(llvm::APFloat::IEEEdouble, llvm::APFloat::rmNearestTiesToEven,
140             &ignored);
141   return V.convertToDouble();
142 }
143 
144 void APValue::print(raw_ostream &OS) const {
145   switch (getKind()) {
146   default: llvm_unreachable("Unknown APValue kind!");
147   case Uninitialized:
148     OS << "Uninitialized";
149     return;
150   case Int:
151     OS << "Int: " << getInt();
152     return;
153   case Float:
154     OS << "Float: " << GetApproxValue(getFloat());
155     return;
156   case Vector:
157     OS << "Vector: " << getVectorElt(0);
158     for (unsigned i = 1; i != getVectorLength(); ++i)
159       OS << ", " << getVectorElt(i);
160     return;
161   case ComplexInt:
162     OS << "ComplexInt: " << getComplexIntReal() << ", " << getComplexIntImag();
163     return;
164   case ComplexFloat:
165     OS << "ComplexFloat: " << GetApproxValue(getComplexFloatReal())
166        << ", " << GetApproxValue(getComplexFloatImag());
167     return;
168   case LValue:
169     OS << "LValue: <todo>";
170     return;
171   case Array:
172     OS << "Array: ";
173     for (unsigned I = 0, N = getArrayInitializedElts(); I != N; ++I) {
174       OS << getArrayInitializedElt(I);
175       if (I != getArraySize() - 1) OS << ", ";
176     }
177     if (hasArrayFiller())
178       OS << getArraySize() - getArrayInitializedElts() << " x "
179          << getArrayFiller();
180     return;
181   }
182 }
183 
184 static void WriteShortAPValueToStream(raw_ostream& Out,
185                                       const APValue& V) {
186   switch (V.getKind()) {
187   default: llvm_unreachable("Unknown APValue kind!");
188   case APValue::Uninitialized:
189     Out << "Uninitialized";
190     break;
191   case APValue::Int:
192     Out << V.getInt();
193     break;
194   case APValue::Float:
195     Out << GetApproxValue(V.getFloat());
196     break;
197   case APValue::Vector:
198     Out << '[';
199     WriteShortAPValueToStream(Out, V.getVectorElt(0));
200     for (unsigned i = 1; i != V.getVectorLength(); ++i) {
201       Out << ", ";
202       WriteShortAPValueToStream(Out, V.getVectorElt(i));
203     }
204     Out << ']';
205     break;
206   case APValue::ComplexInt:
207     Out << V.getComplexIntReal() << "+" << V.getComplexIntImag() << "i";
208     break;
209   case APValue::ComplexFloat:
210     Out << GetApproxValue(V.getComplexFloatReal()) << "+"
211         << GetApproxValue(V.getComplexFloatImag()) << "i";
212     break;
213   case APValue::LValue:
214     Out << "LValue: <todo>";
215     break;
216   case APValue::Array:
217     Out << '{';
218     if (unsigned N = V.getArrayInitializedElts()) {
219       Out << V.getArrayInitializedElt(0);
220       for (unsigned I = 1; I != N; ++I)
221         Out << ", " << V.getArrayInitializedElt(I);
222     }
223     Out << '}';
224     break;
225   }
226 }
227 
228 const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
229                                            const APValue &V) {
230   llvm::SmallString<64> Buffer;
231   llvm::raw_svector_ostream Out(Buffer);
232   WriteShortAPValueToStream(Out, V);
233   return DB << Out.str();
234 }
235 
236 const Expr* APValue::getLValueBase() const {
237   assert(isLValue() && "Invalid accessor");
238   return ((const LV*)(const void*)Data)->Base;
239 }
240 
241 CharUnits &APValue::getLValueOffset() {
242   assert(isLValue() && "Invalid accessor");
243   return ((LV*)(void*)Data)->Offset;
244 }
245 
246 bool APValue::hasLValuePath() const {
247   assert(isLValue() && "Invalid accessor");
248   return ((const LV*)(const char*)Data)->hasPath();
249 }
250 
251 ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const {
252   assert(isLValue() && hasLValuePath() && "Invalid accessor");
253   const LV &LVal = *((const LV*)(const char*)Data);
254   return ArrayRef<LValuePathEntry>(LVal.getPath(), LVal.PathLength);
255 }
256 
257 void APValue::setLValue(const Expr *B, const CharUnits &O, NoLValuePath) {
258   assert(isLValue() && "Invalid accessor");
259   LV &LVal = *((LV*)(char*)Data);
260   LVal.Base = B;
261   LVal.Offset = O;
262   LVal.PathLength = (unsigned)-1;
263 }
264 
265 void APValue::setLValue(const Expr *B, const CharUnits &O,
266                         ArrayRef<LValuePathEntry> Path) {
267   assert(isLValue() && "Invalid accessor");
268   LV &LVal = *((LV*)(char*)Data);
269   LVal.Base = B;
270   LVal.Offset = O;
271   LVal.PathLength = Path.size();
272   LVal.allocPath();
273   memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry));
274 }
275 
276 void APValue::MakeLValue() {
277   assert(isUninit() && "Bad state change");
278   assert(sizeof(LV) <= MaxSize && "LV too big");
279   new ((void*)(char*)Data) LV();
280   Kind = LValue;
281 }
282 
283 void APValue::MakeArray(unsigned InitElts, unsigned Size) {
284   assert(isUninit() && "Bad state change");
285   new ((void*)(char*)Data) Arr(InitElts, Size);
286   Kind = Array;
287 }
288