• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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