1//===- Value.cpp - Value Representation for llubi -------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements utility functions for the value representation.
10//
11//===----------------------------------------------------------------------===//
12
13#include "Value.h"
14#include "Context.h"
15#include "llvm/ADT/SmallString.h"
16
17namespace llvm::ubi {
18
19void Pointer::print(raw_ostream &OS) const {
20 SmallString<32> AddrStr;
21 Address.toStringUnsigned(Str&: AddrStr, Radix: 16);
22 OS << "ptr 0x" << AddrStr << " [";
23 if (Obj && Obj->getState() != MemoryObjectState::Freed) {
24 OS << Obj->getName();
25 // TODO: print " (dead)" if the stack object is out of lifetime.
26 if (Address != Obj->getAddress())
27 OS << " + " << (Address - Obj->getAddress());
28 } else {
29 OS << "dangling";
30 }
31 OS << "]";
32}
33
34AnyValue Pointer::null(unsigned BitWidth) {
35 return AnyValue(Pointer(nullptr, APInt::getZero(numBits: BitWidth)));
36}
37
38void AnyValue::print(raw_ostream &OS) const {
39 switch (Kind) {
40 case StorageKind::Integer:
41 if (IntVal.getBitWidth() == 1) {
42 OS << (IntVal.getBoolValue() ? "T" : "F");
43 break;
44 }
45 OS << "i" << IntVal.getBitWidth() << ' ' << IntVal;
46 break;
47 case StorageKind::Float: {
48 switch (APFloat::SemanticsToEnum(Sem: FloatVal.getSemantics())) {
49 default:
50 llvm_unreachable("invalid fltSemantics");
51 case APFloatBase::S_IEEEhalf:
52 OS << "half ";
53 break;
54 case APFloatBase::S_BFloat:
55 OS << "bfloat ";
56 break;
57 case APFloatBase::S_IEEEsingle:
58 OS << "float ";
59 break;
60 case APFloatBase::S_IEEEdouble:
61 OS << "double ";
62 break;
63 case APFloatBase::S_x87DoubleExtended:
64 OS << "x86_fp80 ";
65 break;
66 case APFloatBase::S_IEEEquad:
67 OS << "fp128 ";
68 break;
69 case APFloatBase::S_PPCDoubleDouble:
70 OS << "ppc_fp128 ";
71 break;
72 }
73 // We cannot reuse Value::print due to lack of LLVMContext here.
74 // Similar to writeAPFloatInternal, output the FP constant value in
75 // exponential notation if it is lossless, otherwise output it in
76 // hexadecimal notation.
77 SmallString<16> StrVal;
78 FloatVal.toString(Str&: StrVal, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
79 /*TruncateZero=*/false);
80 if (APFloat(FloatVal.getSemantics(), StrVal).bitwiseIsEqual(RHS: FloatVal)) {
81 OS << StrVal;
82 } else {
83 StrVal.clear();
84 APInt Bits = FloatVal.bitcastToAPInt();
85 Bits.toStringUnsigned(Str&: StrVal, Radix: 16);
86 size_t MaxDigits = divideCeil(Numerator: Bits.getBitWidth(), Denominator: 4);
87 OS << "0x";
88 for (size_t Digits = StrVal.size(); Digits != MaxDigits; ++Digits)
89 OS << '0';
90 OS << StrVal;
91 }
92 break;
93 }
94 case StorageKind::Pointer:
95 PtrVal.print(OS);
96 break;
97 case StorageKind::Poison:
98 OS << "poison";
99 break;
100 case StorageKind::None:
101 OS << "none";
102 break;
103 case StorageKind::Aggregate:
104 OS << "{ ";
105 for (size_t I = 0, E = AggVal.size(); I != E; ++I) {
106 if (I != 0)
107 OS << ", ";
108 AggVal[I].print(OS);
109 }
110 OS << " }";
111 break;
112 }
113}
114
115void AnyValue::destroy() {
116 switch (Kind) {
117 case StorageKind::Integer:
118 IntVal.~APInt();
119 break;
120 case StorageKind::Float:
121 FloatVal.~APFloat();
122 break;
123 case StorageKind::Pointer:
124 PtrVal.~Pointer();
125 break;
126 case StorageKind::Poison:
127 case StorageKind::None:
128 break;
129 case StorageKind::Aggregate:
130 AggVal.~vector();
131 break;
132 }
133}
134
135AnyValue::AnyValue(const AnyValue &Other) : Kind(Other.Kind) {
136 switch (Other.Kind) {
137 case StorageKind::Integer:
138 new (&IntVal) APInt(Other.IntVal);
139 break;
140 case StorageKind::Float:
141 new (&FloatVal) APFloat(Other.FloatVal);
142 break;
143 case StorageKind::Pointer:
144 new (&PtrVal) Pointer(Other.PtrVal);
145 break;
146 case StorageKind::Poison:
147 case StorageKind::None:
148 break;
149 case StorageKind::Aggregate:
150 new (&AggVal) std::vector<AnyValue>(Other.AggVal);
151 break;
152 }
153}
154AnyValue::AnyValue(AnyValue &&Other) : Kind(Other.Kind) {
155 switch (Other.Kind) {
156 case StorageKind::Integer:
157 new (&IntVal) APInt(std::move(Other.IntVal));
158 break;
159 case StorageKind::Float:
160 new (&FloatVal) APFloat(std::move(Other.FloatVal));
161 break;
162 case StorageKind::Pointer:
163 new (&PtrVal) Pointer(std::move(Other.PtrVal));
164 break;
165 case StorageKind::Poison:
166 case StorageKind::None:
167 break;
168 case StorageKind::Aggregate:
169 new (&AggVal) std::vector<AnyValue>(std::move(Other.AggVal));
170 break;
171 }
172}
173
174AnyValue &AnyValue::operator=(const AnyValue &Other) {
175 if (&Other == this)
176 return *this;
177
178 destroy();
179 Kind = Other.Kind;
180 switch (Other.Kind) {
181 case StorageKind::Integer:
182 new (&IntVal) APInt(Other.IntVal);
183 break;
184 case StorageKind::Float:
185 new (&FloatVal) APFloat(Other.FloatVal);
186 break;
187 case StorageKind::Pointer:
188 new (&PtrVal) Pointer(Other.PtrVal);
189 break;
190 case StorageKind::Poison:
191 case StorageKind::None:
192 break;
193 case StorageKind::Aggregate:
194 new (&AggVal) std::vector<AnyValue>(Other.AggVal);
195 break;
196 }
197
198 return *this;
199}
200AnyValue &AnyValue::operator=(AnyValue &&Other) {
201 if (&Other == this)
202 return *this;
203 destroy();
204 Kind = Other.Kind;
205 switch (Other.Kind) {
206 case StorageKind::Integer:
207 new (&IntVal) APInt(std::move(Other.IntVal));
208 break;
209 case StorageKind::Float:
210 new (&FloatVal) APFloat(std::move(Other.FloatVal));
211 break;
212 case StorageKind::Pointer:
213 new (&PtrVal) Pointer(std::move(Other.PtrVal));
214 break;
215 case StorageKind::Poison:
216 case StorageKind::None:
217 break;
218 case StorageKind::Aggregate:
219 new (&AggVal) std::vector<AnyValue>(std::move(Other.AggVal));
220 break;
221 }
222
223 return *this;
224}
225
226AnyValue AnyValue::getPoisonValue(Context &Ctx, Type *Ty) {
227 if (Ty->isFloatingPointTy() || Ty->isIntegerTy() || Ty->isPointerTy())
228 return AnyValue::poison();
229 if (auto *VecTy = dyn_cast<VectorType>(Val: Ty)) {
230 uint32_t NumElements = Ctx.getEVL(EC: VecTy->getElementCount());
231 return AnyValue(std::vector<AnyValue>(NumElements, AnyValue::poison()));
232 }
233 if (auto *ArrTy = dyn_cast<ArrayType>(Val: Ty)) {
234 uint64_t NumElements = ArrTy->getNumElements();
235 return AnyValue(std::vector<AnyValue>(
236 NumElements, getPoisonValue(Ctx, Ty: ArrTy->getElementType())));
237 }
238 if (auto *StructTy = dyn_cast<StructType>(Val: Ty)) {
239 std::vector<AnyValue> Elements;
240 Elements.reserve(n: StructTy->getNumElements());
241 for (uint32_t I = 0, E = StructTy->getNumElements(); I != E; ++I)
242 Elements.push_back(x: getPoisonValue(Ctx, Ty: StructTy->getElementType(N: I)));
243 return AnyValue(std::move(Elements));
244 }
245 llvm_unreachable("Unsupported type");
246}
247AnyValue AnyValue::getNullValue(Context &Ctx, Type *Ty) {
248 if (Ty->isIntegerTy())
249 return AnyValue(APInt::getZero(numBits: Ty->getIntegerBitWidth()));
250 if (Ty->isFloatingPointTy())
251 return AnyValue(APFloat::getZero(Sem: Ty->getFltSemantics()));
252 if (Ty->isPointerTy())
253 return Pointer::null(
254 BitWidth: Ctx.getDataLayout().getPointerSizeInBits(AS: Ty->getPointerAddressSpace()));
255 if (auto *VecTy = dyn_cast<VectorType>(Val: Ty)) {
256 uint32_t NumElements = Ctx.getEVL(EC: VecTy->getElementCount());
257 return AnyValue(std::vector<AnyValue>(
258 NumElements, getNullValue(Ctx, Ty: VecTy->getElementType())));
259 }
260 if (auto *ArrTy = dyn_cast<ArrayType>(Val: Ty)) {
261 uint64_t NumElements = ArrTy->getNumElements();
262 return AnyValue(std::vector<AnyValue>(
263 NumElements, getNullValue(Ctx, Ty: ArrTy->getElementType())));
264 }
265 if (auto *StructTy = dyn_cast<StructType>(Val: Ty)) {
266 std::vector<AnyValue> Elements;
267 Elements.reserve(n: StructTy->getNumElements());
268 for (uint32_t I = 0, E = StructTy->getNumElements(); I != E; ++I)
269 Elements.push_back(x: getNullValue(Ctx, Ty: StructTy->getElementType(N: I)));
270 return AnyValue(std::move(Elements));
271 }
272 llvm_unreachable("Unsupported type");
273}
274
275AnyValue AnyValue::getVectorSplat(const AnyValue &Scalar, size_t NumElements) {
276 assert(!Scalar.isAggregate() && !Scalar.isNone() && "Expect a scalar value");
277 return AnyValue(std::vector<AnyValue>(NumElements, Scalar));
278}
279
280} // namespace llvm::ubi
281