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 OS << FloatVal;
49 break;
50 case StorageKind::Pointer:
51 PtrVal.print(OS);
52 break;
53 case StorageKind::Poison:
54 OS << "poison";
55 break;
56 case StorageKind::None:
57 OS << "none";
58 break;
59 case StorageKind::Aggregate:
60 OS << "{ ";
61 for (size_t I = 0, E = AggVal.size(); I != E; ++I) {
62 if (I != 0)
63 OS << ", ";
64 AggVal[I].print(OS);
65 }
66 OS << " }";
67 break;
68 }
69}
70
71void AnyValue::destroy() {
72 switch (Kind) {
73 case StorageKind::Integer:
74 IntVal.~APInt();
75 break;
76 case StorageKind::Float:
77 FloatVal.~APFloat();
78 break;
79 case StorageKind::Pointer:
80 PtrVal.~Pointer();
81 break;
82 case StorageKind::Poison:
83 case StorageKind::None:
84 break;
85 case StorageKind::Aggregate:
86 AggVal.~vector();
87 break;
88 }
89}
90
91AnyValue::AnyValue(const AnyValue &Other) : Kind(Other.Kind) {
92 switch (Other.Kind) {
93 case StorageKind::Integer:
94 new (&IntVal) APInt(Other.IntVal);
95 break;
96 case StorageKind::Float:
97 new (&FloatVal) APFloat(Other.FloatVal);
98 break;
99 case StorageKind::Pointer:
100 new (&PtrVal) Pointer(Other.PtrVal);
101 break;
102 case StorageKind::Poison:
103 case StorageKind::None:
104 break;
105 case StorageKind::Aggregate:
106 new (&AggVal) std::vector<AnyValue>(Other.AggVal);
107 break;
108 }
109}
110AnyValue::AnyValue(AnyValue &&Other) : Kind(Other.Kind) {
111 switch (Other.Kind) {
112 case StorageKind::Integer:
113 new (&IntVal) APInt(std::move(Other.IntVal));
114 break;
115 case StorageKind::Float:
116 new (&FloatVal) APFloat(std::move(Other.FloatVal));
117 break;
118 case StorageKind::Pointer:
119 new (&PtrVal) Pointer(std::move(Other.PtrVal));
120 break;
121 case StorageKind::Poison:
122 case StorageKind::None:
123 break;
124 case StorageKind::Aggregate:
125 new (&AggVal) std::vector<AnyValue>(std::move(Other.AggVal));
126 break;
127 }
128}
129
130AnyValue &AnyValue::operator=(const AnyValue &Other) {
131 if (&Other == this)
132 return *this;
133
134 destroy();
135 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
154 return *this;
155}
156AnyValue &AnyValue::operator=(AnyValue &&Other) {
157 if (&Other == this)
158 return *this;
159 destroy();
160 Kind = Other.Kind;
161 switch (Other.Kind) {
162 case StorageKind::Integer:
163 new (&IntVal) APInt(std::move(Other.IntVal));
164 break;
165 case StorageKind::Float:
166 new (&FloatVal) APFloat(std::move(Other.FloatVal));
167 break;
168 case StorageKind::Pointer:
169 new (&PtrVal) Pointer(std::move(Other.PtrVal));
170 break;
171 case StorageKind::Poison:
172 case StorageKind::None:
173 break;
174 case StorageKind::Aggregate:
175 new (&AggVal) std::vector<AnyValue>(std::move(Other.AggVal));
176 break;
177 }
178
179 return *this;
180}
181
182AnyValue AnyValue::getPoisonValue(Context &Ctx, Type *Ty) {
183 if (Ty->isFloatingPointTy() || Ty->isIntegerTy() || Ty->isPointerTy())
184 return AnyValue::poison();
185 if (auto *VecTy = dyn_cast<VectorType>(Val: Ty)) {
186 uint32_t NumElements = Ctx.getEVL(EC: VecTy->getElementCount());
187 return AnyValue(std::vector<AnyValue>(NumElements, AnyValue::poison()));
188 }
189 if (auto *ArrTy = dyn_cast<ArrayType>(Val: Ty)) {
190 uint64_t NumElements = ArrTy->getNumElements();
191 return AnyValue(std::vector<AnyValue>(
192 NumElements, getPoisonValue(Ctx, Ty: ArrTy->getElementType())));
193 }
194 if (auto *StructTy = dyn_cast<StructType>(Val: Ty)) {
195 std::vector<AnyValue> Elements;
196 Elements.reserve(n: StructTy->getNumElements());
197 for (uint32_t I = 0, E = StructTy->getNumElements(); I != E; ++I)
198 Elements.push_back(x: getPoisonValue(Ctx, Ty: StructTy->getElementType(N: I)));
199 return AnyValue(std::move(Elements));
200 }
201 llvm_unreachable("Unsupported type");
202}
203AnyValue AnyValue::getNullValue(Context &Ctx, Type *Ty) {
204 if (Ty->isIntegerTy())
205 return AnyValue(APInt::getZero(numBits: Ty->getIntegerBitWidth()));
206 if (Ty->isFloatingPointTy())
207 return AnyValue(APFloat::getZero(Sem: Ty->getFltSemantics()));
208 if (Ty->isPointerTy())
209 return Pointer::null(
210 BitWidth: Ctx.getDataLayout().getPointerSizeInBits(AS: Ty->getPointerAddressSpace()));
211 if (auto *VecTy = dyn_cast<VectorType>(Val: Ty)) {
212 uint32_t NumElements = Ctx.getEVL(EC: VecTy->getElementCount());
213 return AnyValue(std::vector<AnyValue>(
214 NumElements, getNullValue(Ctx, Ty: VecTy->getElementType())));
215 }
216 if (auto *ArrTy = dyn_cast<ArrayType>(Val: Ty)) {
217 uint64_t NumElements = ArrTy->getNumElements();
218 return AnyValue(std::vector<AnyValue>(
219 NumElements, getNullValue(Ctx, Ty: ArrTy->getElementType())));
220 }
221 if (auto *StructTy = dyn_cast<StructType>(Val: Ty)) {
222 std::vector<AnyValue> Elements;
223 Elements.reserve(n: StructTy->getNumElements());
224 for (uint32_t I = 0, E = StructTy->getNumElements(); I != E; ++I)
225 Elements.push_back(x: getNullValue(Ctx, Ty: StructTy->getElementType(N: I)));
226 return AnyValue(std::move(Elements));
227 }
228 llvm_unreachable("Unsupported type");
229}
230
231AnyValue AnyValue::getVectorSplat(const AnyValue &Scalar, size_t NumElements) {
232 assert(!Scalar.isAggregate() && !Scalar.isNone() && "Expect a scalar value");
233 return AnyValue(std::vector<AnyValue>(NumElements, Scalar));
234}
235
236} // namespace llvm::ubi
237