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     APValue::LValueBase 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   void freePath() { if (hasPathPtr()) delete [] PathPtr; }
49 
50   bool hasPath() const { return PathLength != (unsigned)-1; }
51   bool hasPathPtr() const { return hasPath() && PathLength > InlinePathSpace; }
52 
53   LValuePathEntry *getPath() { return hasPathPtr() ? PathPtr : Path; }
54   const LValuePathEntry *getPath() const {
55     return hasPathPtr() ? PathPtr : Path;
56   }
57 };
58 
59 // FIXME: Reduce the malloc traffic here.
60 
61 APValue::Arr::Arr(unsigned NumElts, unsigned Size) :
62   Elts(new APValue[NumElts + (NumElts != Size ? 1 : 0)]),
63   NumElts(NumElts), ArrSize(Size) {}
64 APValue::Arr::~Arr() { delete [] Elts; }
65 
66 APValue::StructData::StructData(unsigned NumBases, unsigned NumFields) :
67   Elts(new APValue[NumBases+NumFields]),
68   NumBases(NumBases), NumFields(NumFields) {}
69 APValue::StructData::~StructData() {
70   delete [] Elts;
71 }
72 
73 APValue::UnionData::UnionData() : Field(0), Value(new APValue) {}
74 APValue::UnionData::~UnionData () {
75   delete Value;
76 }
77 
78 const APValue &APValue::operator=(const APValue &RHS) {
79   if (this == &RHS)
80     return *this;
81   if (Kind != RHS.Kind || Kind == Array || Kind == Struct) {
82     MakeUninit();
83     if (RHS.isInt())
84       MakeInt();
85     else if (RHS.isFloat())
86       MakeFloat();
87     else if (RHS.isVector())
88       MakeVector();
89     else if (RHS.isComplexInt())
90       MakeComplexInt();
91     else if (RHS.isComplexFloat())
92       MakeComplexFloat();
93     else if (RHS.isLValue())
94       MakeLValue();
95     else if (RHS.isArray())
96       MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize());
97     else if (RHS.isStruct())
98       MakeStruct(RHS.getStructNumBases(), RHS.getStructNumFields());
99     else if (RHS.isUnion())
100       MakeUnion();
101   }
102   if (isInt())
103     setInt(RHS.getInt());
104   else if (isFloat())
105     setFloat(RHS.getFloat());
106   else if (isVector())
107     setVector(((const Vec *)(const char *)RHS.Data)->Elts,
108               RHS.getVectorLength());
109   else if (isComplexInt())
110     setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag());
111   else if (isComplexFloat())
112     setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag());
113   else if (isLValue()) {
114     if (RHS.hasLValuePath())
115       setLValue(RHS.getLValueBase(), RHS.getLValueOffset(),RHS.getLValuePath());
116     else
117       setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath());
118   } else if (isArray()) {
119     for (unsigned I = 0, N = RHS.getArrayInitializedElts(); I != N; ++I)
120       getArrayInitializedElt(I) = RHS.getArrayInitializedElt(I);
121     if (RHS.hasArrayFiller())
122       getArrayFiller() = RHS.getArrayFiller();
123   } else if (isStruct()) {
124     for (unsigned I = 0, N = RHS.getStructNumBases(); I != N; ++I)
125       getStructBase(I) = RHS.getStructBase(I);
126     for (unsigned I = 0, N = RHS.getStructNumFields(); I != N; ++I)
127       getStructField(I) = RHS.getStructField(I);
128   } else if (isUnion())
129     setUnion(RHS.getUnionField(), RHS.getUnionValue());
130   return *this;
131 }
132 
133 void APValue::MakeUninit() {
134   if (Kind == Int)
135     ((APSInt*)(char*)Data)->~APSInt();
136   else if (Kind == Float)
137     ((APFloat*)(char*)Data)->~APFloat();
138   else if (Kind == Vector)
139     ((Vec*)(char*)Data)->~Vec();
140   else if (Kind == ComplexInt)
141     ((ComplexAPSInt*)(char*)Data)->~ComplexAPSInt();
142   else if (Kind == ComplexFloat)
143     ((ComplexAPFloat*)(char*)Data)->~ComplexAPFloat();
144   else if (Kind == LValue)
145     ((LV*)(char*)Data)->~LV();
146   else if (Kind == Array)
147     ((Arr*)(char*)Data)->~Arr();
148   else if (Kind == Struct)
149     ((StructData*)(char*)Data)->~StructData();
150   else if (Kind == Union)
151     ((UnionData*)(char*)Data)->~UnionData();
152   Kind = Uninitialized;
153 }
154 
155 void APValue::dump() const {
156   print(llvm::errs());
157   llvm::errs() << '\n';
158 }
159 
160 static double GetApproxValue(const llvm::APFloat &F) {
161   llvm::APFloat V = F;
162   bool ignored;
163   V.convert(llvm::APFloat::IEEEdouble, llvm::APFloat::rmNearestTiesToEven,
164             &ignored);
165   return V.convertToDouble();
166 }
167 
168 void APValue::print(raw_ostream &OS) const {
169   switch (getKind()) {
170   case Uninitialized:
171     OS << "Uninitialized";
172     return;
173   case Int:
174     OS << "Int: " << getInt();
175     return;
176   case Float:
177     OS << "Float: " << GetApproxValue(getFloat());
178     return;
179   case Vector:
180     OS << "Vector: " << getVectorElt(0);
181     for (unsigned i = 1; i != getVectorLength(); ++i)
182       OS << ", " << getVectorElt(i);
183     return;
184   case ComplexInt:
185     OS << "ComplexInt: " << getComplexIntReal() << ", " << getComplexIntImag();
186     return;
187   case ComplexFloat:
188     OS << "ComplexFloat: " << GetApproxValue(getComplexFloatReal())
189        << ", " << GetApproxValue(getComplexFloatImag());
190     return;
191   case LValue:
192     OS << "LValue: <todo>";
193     return;
194   case Array:
195     OS << "Array: ";
196     for (unsigned I = 0, N = getArrayInitializedElts(); I != N; ++I) {
197       OS << getArrayInitializedElt(I);
198       if (I != getArraySize() - 1) OS << ", ";
199     }
200     if (hasArrayFiller())
201       OS << getArraySize() - getArrayInitializedElts() << " x "
202          << getArrayFiller();
203     return;
204   case Struct:
205     OS << "Struct ";
206     if (unsigned N = getStructNumBases()) {
207       OS << " bases: " << getStructBase(0);
208       for (unsigned I = 1; I != N; ++I)
209         OS << ", " << getStructBase(I);
210     }
211     if (unsigned N = getStructNumFields()) {
212       OS << " fields: " << getStructField(0);
213       for (unsigned I = 1; I != N; ++I)
214         OS << ", " << getStructField(I);
215     }
216     return;
217   case Union:
218     OS << "Union: " << getUnionValue();
219     return;
220   }
221   llvm_unreachable("Unknown APValue kind!");
222 }
223 
224 static void WriteShortAPValueToStream(raw_ostream& Out,
225                                       const APValue& V) {
226   switch (V.getKind()) {
227   case APValue::Uninitialized:
228     Out << "Uninitialized";
229     return;
230   case APValue::Int:
231     Out << V.getInt();
232     return;
233   case APValue::Float:
234     Out << GetApproxValue(V.getFloat());
235     return;
236   case APValue::Vector:
237     Out << '[';
238     WriteShortAPValueToStream(Out, V.getVectorElt(0));
239     for (unsigned i = 1; i != V.getVectorLength(); ++i) {
240       Out << ", ";
241       WriteShortAPValueToStream(Out, V.getVectorElt(i));
242     }
243     Out << ']';
244     return;
245   case APValue::ComplexInt:
246     Out << V.getComplexIntReal() << "+" << V.getComplexIntImag() << "i";
247     return;
248   case APValue::ComplexFloat:
249     Out << GetApproxValue(V.getComplexFloatReal()) << "+"
250         << GetApproxValue(V.getComplexFloatImag()) << "i";
251     return;
252   case APValue::LValue:
253     Out << "LValue: <todo>";
254     return;
255   case APValue::Array:
256     Out << '{';
257     if (unsigned N = V.getArrayInitializedElts()) {
258       Out << V.getArrayInitializedElt(0);
259       for (unsigned I = 1; I != N; ++I)
260         Out << ", " << V.getArrayInitializedElt(I);
261     }
262     Out << '}';
263     return;
264   case APValue::Struct:
265     Out << '{';
266     if (unsigned N = V.getStructNumBases()) {
267       Out << V.getStructBase(0);
268       for (unsigned I = 1; I != N; ++I)
269         Out << ", " << V.getStructBase(I);
270       if (V.getStructNumFields())
271         Out << ", ";
272     }
273     if (unsigned N = V.getStructNumFields()) {
274       Out << V.getStructField(0);
275       for (unsigned I = 1; I != N; ++I)
276         Out << ", " << V.getStructField(I);
277     }
278     Out << '}';
279     return;
280   case APValue::Union:
281     Out << '{' << V.getUnionValue() << '}';
282     return;
283   }
284   llvm_unreachable("Unknown APValue kind!");
285 }
286 
287 const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
288                                            const APValue &V) {
289   llvm::SmallString<64> Buffer;
290   llvm::raw_svector_ostream Out(Buffer);
291   WriteShortAPValueToStream(Out, V);
292   return DB << Out.str();
293 }
294 
295 const APValue::LValueBase APValue::getLValueBase() const {
296   assert(isLValue() && "Invalid accessor");
297   return ((const LV*)(const void*)Data)->Base;
298 }
299 
300 CharUnits &APValue::getLValueOffset() {
301   assert(isLValue() && "Invalid accessor");
302   return ((LV*)(void*)Data)->Offset;
303 }
304 
305 bool APValue::hasLValuePath() const {
306   assert(isLValue() && "Invalid accessor");
307   return ((const LV*)(const char*)Data)->hasPath();
308 }
309 
310 ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const {
311   assert(isLValue() && hasLValuePath() && "Invalid accessor");
312   const LV &LVal = *((const LV*)(const char*)Data);
313   return ArrayRef<LValuePathEntry>(LVal.getPath(), LVal.PathLength);
314 }
315 
316 void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath) {
317   assert(isLValue() && "Invalid accessor");
318   LV &LVal = *((LV*)(char*)Data);
319   LVal.freePath();
320   LVal.Base = B;
321   LVal.Offset = O;
322   LVal.PathLength = (unsigned)-1;
323 }
324 
325 void APValue::setLValue(LValueBase B, const CharUnits &O,
326                         ArrayRef<LValuePathEntry> Path) {
327   assert(isLValue() && "Invalid accessor");
328   LV &LVal = *((LV*)(char*)Data);
329   LVal.freePath();
330   LVal.Base = B;
331   LVal.Offset = O;
332   LVal.PathLength = Path.size();
333   LVal.allocPath();
334   memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry));
335 }
336 
337 void APValue::MakeLValue() {
338   assert(isUninit() && "Bad state change");
339   assert(sizeof(LV) <= MaxSize && "LV too big");
340   new ((void*)(char*)Data) LV();
341   Kind = LValue;
342 }
343 
344 void APValue::MakeArray(unsigned InitElts, unsigned Size) {
345   assert(isUninit() && "Bad state change");
346   new ((void*)(char*)Data) Arr(InitElts, Size);
347   Kind = Array;
348 }
349