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