• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 panda::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 // TODO(vdyadov): correct handling of values origins during LUB operation
38 
39 class RegContext {
40 public:
41     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 
48     RegContext operator&(const RegContext &rhs) const
49     {
50         RegContext result(std::max(Regs_.size(), rhs.Regs_.size()));
51         auto result_it = result.Regs_.begin();
52         auto lhs_it = Regs_.begin();
53         auto rhs_it = rhs.Regs_.begin();
54         while (lhs_it != Regs_.end() && rhs_it != rhs.Regs_.end()) {
55             if (!(*lhs_it).IsNone() && !(*rhs_it).IsNone()) {
56                 *result_it = *lhs_it & *rhs_it;
57             }
58             ++lhs_it;
59             ++rhs_it;
60             ++result_it;
61         }
62         return result;
63     }
64     RegContext &operator&=(const RegContext &rhs)
65     {
66         auto lhs_it = Regs_.begin();
67         auto rhs_it = rhs.Regs_.begin();
68         while (lhs_it != Regs_.end() && rhs_it != rhs.Regs_.end()) {
69             if (!(*lhs_it).IsNone() && !(*rhs_it).IsNone()) {
70                 *lhs_it = *lhs_it & *rhs_it;
71             } else {
72                 *lhs_it = AbstractTypedValue {};
73             }
74             ++lhs_it;
75             ++rhs_it;
76         }
77         while (lhs_it != Regs_.end()) {
78             *lhs_it = AbstractTypedValue {};
79             ++lhs_it;
80         }
81         return *this;
82     }
ChangeValuesOfSameOrigin(int idx,const AbstractTypedValue & atv)83     void ChangeValuesOfSameOrigin(int idx, const AbstractTypedValue &atv)
84     {
85         if (!Regs_.InValidRange(idx)) {
86             Regs_[idx] = atv;
87             return;
88         }
89         auto old_atv = Regs_[idx];
90         if (old_atv.IsNone()) {
91             Regs_[idx] = atv;
92             return;
93         }
94         const auto &old_origin = old_atv.GetOrigin();
95         if (!old_origin.IsValid()) {
96             Regs_[idx] = atv;
97             return;
98         }
99         auto it = Regs_.begin();
100         while (it != Regs_.end()) {
101             if (!(*it).IsNone()) {
102                 const auto &origin = (*it).GetOrigin();
103                 if (origin.IsValid() && origin == old_origin) {
104                     *it = atv;
105                 }
106             }
107             ++it;
108         }
109     }
110     AbstractTypedValue &operator[](int idx)
111     {
112         if (!Regs_.InValidRange(idx)) {
113             Regs_.ExtendToInclude(idx);
114         }
115         return Regs_[idx];
116     }
117     AbstractTypedValue operator[](int idx) const
118     {
119         ASSERT(IsRegDefined(idx) && Regs_.InValidRange(idx));
120         return Regs_[idx];
121     }
Size()122     size_t Size() const
123     {
124         size_t size = 0;
125         EnumerateAllRegs([&size](auto, auto) {
126             ++size;
127             return true;
128         });
129         return size;
130     }
131     template <typename Callback>
EnumerateAllRegs(Callback cb)132     void EnumerateAllRegs(Callback cb) const
133     {
134         for (int idx = Regs_.begin_index(); idx < Regs_.end_index(); ++idx) {
135             if (!Regs_[idx].IsNone()) {
136                 const auto &atv = Regs_[idx];
137                 if (!cb(idx, atv)) {
138                     return;
139                 }
140             }
141         }
142     }
143     template <typename Callback>
EnumerateAllRegs(Callback cb)144     void EnumerateAllRegs(Callback cb)
145     {
146         for (int idx = Regs_.begin_index(); idx < Regs_.end_index(); ++idx) {
147             if (!Regs_[idx].IsNone()) {
148                 auto &atv = Regs_[idx];
149                 if (!cb(idx, atv)) {
150                     return;
151                 }
152             }
153         }
154     }
HasInconsistentRegs()155     bool HasInconsistentRegs() const
156     {
157         bool result = false;
158         EnumerateAllRegs([&result](int, const auto &av) {
159             if (!av.IsConsistent()) {
160                 result = true;
161                 return false;
162             }
163             return true;
164         });
165         return result;
166     }
InconsistentRegsNums()167     auto InconsistentRegsNums() const
168     {
169         PandaVector<int> result;
170         EnumerateAllRegs([&result](int num, const auto &av) {
171             if (!av.IsConsistent()) {
172                 result.push_back(num);
173             }
174             return true;
175         });
176         return result;
177     }
IsRegDefined(int num)178     bool IsRegDefined(int num) const
179     {
180         return Regs_.InValidRange(num) && !Regs_[num].IsNone();
181     }
WasConflictOnReg(int num)182     bool WasConflictOnReg(int num) const
183     {
184         return ConflictingRegs_.count(num) > 0;
185     }
Clear()186     void Clear()
187     {
188         Regs_.clear();
189         ConflictingRegs_.clear();
190     }
RemoveInconsistentRegs()191     void RemoveInconsistentRegs()
192     {
193         EnumerateAllRegs([this](int num, auto &atv) {
194             if (!atv.IsConsistent()) {
195                 ConflictingRegs_.insert(num);
196                 atv = AbstractTypedValue {};
197             } else {
198                 ConflictingRegs_.erase(num);
199             }
200             return true;
201         });
202     }
203     template <typename ImageFunc>
DumpRegs(ImageFunc img)204     PandaString DumpRegs(ImageFunc img) const
205     {
206         PandaString log_string {""};
207         bool comma = false;
208         EnumerateAllRegs([&comma, &log_string, &img](int num, const auto &abs_type_val) {
209             PandaString result {num == -1 ? "acc" : "v" + NumToStr(num)};
210             result += " : ";
211             result += abs_type_val.Image(img);
212             if (comma) {
213                 log_string += ", ";
214             }
215             log_string += result;
216             comma = true;
217             return true;
218         });
219         return log_string;
220     }
221 
222 private:
223     ShiftedVector<1, AbstractTypedValue> Regs_;
224 
225     // TODO(vdyadov): After introducing sparse bit-vectors, change ConflictingRegs_ type.
226     PandaUnorderedSet<int> ConflictingRegs_;
227 };
228 }  // namespace panda::verifier
229 
230 #endif  // !PANDA_VERIFIER_ABSINT_REG_CONTEXT_HPP_
231