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