1 /**
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef PANDA_VERIFIER_ABSINT_REG_CONTEXT_HPP_
17 #define PANDA_VERIFIER_ABSINT_REG_CONTEXT_HPP_
18
19 #include "value/abstract_typed_value.h"
20
21 #include "util/index.h"
22 #include "util/lazy.h"
23 #include "util/str.h"
24 #include "util/shifted_vector.h"
25
26 #include "macros.h"
27
28 #include <algorithm>
29
30 namespace ark::verifier {
31 /*
32 Design decisions:
33 1. regs - unordered map, for speed (compared to map) and space efficiency (compared to vector)
34 after implementing sparse vectors - rebase on them (taking into consideration immutability, see immer)
35 */
36
37 // NOTE(vdyadov): correct handling of values origins during LUB operation
38
39 class RegContext {
40 public:
41 explicit RegContext() = default;
RegContext(size_t size)42 explicit RegContext(size_t size) : regs_(size) {}
43 ~RegContext() = default;
44
45 DEFAULT_MOVE_SEMANTIC(RegContext);
46 DEFAULT_COPY_SEMANTIC(RegContext);
47
UnionWith(RegContext const * rhs,TypeSystem * tsys)48 bool UnionWith(RegContext const *rhs, TypeSystem *tsys)
49 {
50 bool updated = false;
51 auto lhsIt = regs_.begin();
52 auto rhsIt = rhs->regs_.begin();
53 while (lhsIt != regs_.end() && rhsIt != rhs->regs_.end()) {
54 if (!(*lhsIt).IsNone() && !(*rhsIt).IsNone()) {
55 auto before = *lhsIt;
56 auto result = AtvJoin(&*lhsIt, &*rhsIt, tsys);
57 updated |= (result.GetAbstractType() != before.GetAbstractType());
58 *lhsIt = result;
59 } else {
60 updated |= !(*lhsIt).IsNone();
61 *lhsIt = AbstractTypedValue {};
62 }
63 ++lhsIt;
64 ++rhsIt;
65 }
66 while (lhsIt != regs_.end()) {
67 updated = true;
68 *lhsIt = AbstractTypedValue {};
69 ++lhsIt;
70 }
71 return updated;
72 }
ChangeValuesOfSameOrigin(int idx,const AbstractTypedValue & atv)73 void ChangeValuesOfSameOrigin(int idx, const AbstractTypedValue &atv)
74 {
75 if (!regs_.InValidRange(idx)) {
76 regs_[idx] = atv;
77 return;
78 }
79 auto oldAtv = regs_[idx];
80 if (oldAtv.IsNone()) {
81 regs_[idx] = atv;
82 return;
83 }
84 const auto &oldOrigin = oldAtv.GetOrigin();
85 if (!oldOrigin.IsValid()) {
86 regs_[idx] = atv;
87 return;
88 }
89 auto it = regs_.begin();
90 while (it != regs_.end()) {
91 if (!(*it).IsNone()) {
92 const auto &origin = (*it).GetOrigin();
93 if (origin.IsValid() && origin == oldOrigin) {
94 *it = atv;
95 }
96 }
97 ++it;
98 }
99 }
100 AbstractTypedValue &operator[](int idx)
101 {
102 if (!regs_.InValidRange(idx)) {
103 regs_.ExtendToInclude(idx);
104 }
105 return regs_[idx];
106 }
107 AbstractTypedValue operator[](int idx) const
108 {
109 ASSERT(IsRegDefined(idx) && regs_.InValidRange(idx));
110 return regs_[idx];
111 }
Size()112 size_t Size() const
113 {
114 size_t size = 0;
115 EnumerateAllRegs([&size](auto, auto) {
116 ++size;
117 return true;
118 });
119 return size;
120 }
121 template <typename Callback>
EnumerateAllRegs(Callback cb)122 void EnumerateAllRegs(Callback cb) const
123 {
124 for (int idx = regs_.BeginIndex(); idx < regs_.EndIndex(); ++idx) {
125 if (!regs_[idx].IsNone()) {
126 const auto &atv = regs_[idx];
127 if (!cb(idx, atv)) {
128 return;
129 }
130 }
131 }
132 }
133 template <typename Callback>
EnumerateAllRegs(Callback cb)134 void EnumerateAllRegs(Callback cb)
135 {
136 for (int idx = regs_.BeginIndex(); idx < regs_.EndIndex(); ++idx) {
137 if (!regs_[idx].IsNone()) {
138 auto &atv = regs_[idx];
139 if (!cb(idx, atv)) {
140 return;
141 }
142 }
143 }
144 }
HasInconsistentRegs()145 bool HasInconsistentRegs() const
146 {
147 bool result = false;
148
149 EnumerateAllRegs([&](int, const auto &av) {
150 if (!av.IsConsistent()) {
151 result = true;
152 return false;
153 }
154 return true;
155 });
156 return result;
157 }
InconsistentRegsNums()158 auto InconsistentRegsNums() const
159 {
160 PandaVector<int> result;
161 EnumerateAllRegs([&](int num, const auto &av) {
162 if (!av.IsConsistent()) {
163 result.push_back(num);
164 }
165 return true;
166 });
167 return result;
168 }
IsRegDefined(int num)169 bool IsRegDefined(int num) const
170 {
171 return regs_.InValidRange(num) && !regs_[num].IsNone();
172 }
IsValid(int num)173 bool IsValid(int num) const
174 {
175 return regs_.InValidRange(num);
176 }
WasConflictOnReg(int num)177 bool WasConflictOnReg(int num) const
178 {
179 return conflictingRegs_.count(num) > 0;
180 }
Clear()181 void Clear()
182 {
183 regs_.clear();
184 conflictingRegs_.clear();
185 }
RemoveInconsistentRegs()186 void RemoveInconsistentRegs()
187 {
188 EnumerateAllRegs([this](int num, auto &atv) {
189 if (!atv.IsConsistent()) {
190 conflictingRegs_.insert(num);
191 atv = AbstractTypedValue {};
192 } else {
193 conflictingRegs_.erase(num);
194 }
195 return true;
196 });
197 }
DumpRegs(TypeSystem const * tsys)198 PandaString DumpRegs(TypeSystem const *tsys) const
199 {
200 PandaString logString {};
201 bool comma = false;
202 EnumerateAllRegs([&comma, &logString, &tsys](int num, const auto &absTypeVal) {
203 PandaString result {num == -1 ? "acc" : "v" + NumToStr(num)};
204 result += " : ";
205 result += absTypeVal.ToString(tsys);
206 if (comma) {
207 logString += ", ";
208 }
209 logString += result;
210 comma = true;
211 return true;
212 });
213 return logString;
214 }
215
216 private:
217 ShiftedVector<1, AbstractTypedValue> regs_;
218
219 // NOTE(vdyadov): After introducing sparse bit-vectors, change ConflictingRegs_ type.
220 PandaUnorderedSet<int> conflictingRegs_;
221
222 friend RegContext RcUnion(RegContext const *lhs, RegContext const *rhs, TypeSystem * /* tsys */);
223 };
224
RcUnion(RegContext const * lhs,RegContext const * rhs,TypeSystem * tsys)225 inline RegContext RcUnion(RegContext const *lhs, RegContext const *rhs, TypeSystem *tsys)
226 {
227 RegContext result(std::max(lhs->regs_.size(), rhs->regs_.size()));
228 auto resultIt = result.regs_.begin();
229 for (auto lhsIt = lhs->regs_.begin(), rhsIt = rhs->regs_.begin();
230 lhsIt != lhs->regs_.end() && rhsIt != rhs->regs_.end(); ++lhsIt, ++rhsIt, ++resultIt) {
231 if (!(*lhsIt).IsNone() && !(*rhsIt).IsNone()) {
232 *resultIt = AtvJoin(&*lhsIt, &*rhsIt, tsys);
233 }
234 }
235 return result;
236 }
237
238 } // namespace ark::verifier
239
240 #endif // !PANDA_VERIFIER_ABSINT_REG_CONTEXT_HPP_
241