APValue.cpp revision 1bf9a9e6a5bdc0de7939908855dcddf46b661800
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"
20using namespace clang;
21
22namespace {
23  struct LVBase {
24    APValue::LValueBase Base;
25    CharUnits Offset;
26    unsigned PathLength;
27  };
28}
29
30struct 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
61APValue::Arr::Arr(unsigned NumElts, unsigned Size) :
62  Elts(new APValue[NumElts + (NumElts != Size ? 1 : 0)]),
63  NumElts(NumElts), ArrSize(Size) {}
64APValue::Arr::~Arr() { delete [] Elts; }
65
66APValue::StructData::StructData(unsigned NumBases, unsigned NumFields) :
67  Elts(new APValue[NumBases+NumFields]),
68  NumBases(NumBases), NumFields(NumFields) {}
69APValue::StructData::~StructData() {
70  delete [] Elts;
71}
72
73APValue::UnionData::UnionData() : Field(0), Value(new APValue) {}
74APValue::UnionData::~UnionData () {
75  delete Value;
76}
77
78const 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
133void 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
155void APValue::dump() const {
156  print(llvm::errs());
157  llvm::errs() << '\n';
158}
159
160static 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
168void 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
224static 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
287const 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
295const APValue::LValueBase APValue::getLValueBase() const {
296  assert(isLValue() && "Invalid accessor");
297  return ((const LV*)(const void*)Data)->Base;
298}
299
300CharUnits &APValue::getLValueOffset() {
301  assert(isLValue() && "Invalid accessor");
302  return ((LV*)(void*)Data)->Offset;
303}
304
305bool APValue::hasLValuePath() const {
306  assert(isLValue() && "Invalid accessor");
307  return ((const LV*)(const char*)Data)->hasPath();
308}
309
310ArrayRef<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
316void 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
325void 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
337void 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
344void 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