| 258 | } |
| 259 | |
| 260 | void LoadStore(Value& val, |
| 261 | const Node& addr_exp, |
| 262 | uint64_t offset, |
| 263 | Opcode opc, |
| 264 | Address align, |
| 265 | Type op_type) { |
| 266 | bool append_type = true; |
| 267 | auto access = lst.GenAccess(offset, addr_exp); |
| 268 | if (!access.empty()) { |
| 269 | if (access == "*") { |
| 270 | // The variable was declared as a typed pointer, so this access |
| 271 | // doesn't need a type. |
| 272 | append_type = false; |
| 273 | } else { |
| 274 | // We can do this load/store as a struct access. |
| 275 | BracketIfNeeded(val, Precedence::Indexing); |
| 276 | val.v.back() += "." + access; |
| 277 | return; |
| 278 | } |
| 279 | } |
| 280 | // Detect absolute addressing, which we try to turn into references to the |
| 281 | // data section when possible. |
| 282 | uint64_t abs_base; |
| 283 | if (ConstIntVal(addr_exp.e, abs_base)) { |
| 284 | // We don't care what part of the absolute address was stored where, |
| 285 | // 1[0] and 0[1] are the same. |
| 286 | abs_base += offset; |
| 287 | // FIXME: make this less expensive with a binary search or whatever. |
| 288 | for (auto dat : mc.module.data_segments) { |
| 289 | uint64_t dat_base; |
| 290 | if (dat->offset.size() == 1 && |
| 291 | ConstIntVal(&dat->offset.front(), dat_base) && |
| 292 | abs_base >= dat_base && abs_base < dat_base + dat->data.size()) { |
| 293 | // We are inside the range of this data segment! |
| 294 | // Turn expression into data_name[index] |
| 295 | val = Value{{dat->name}, Precedence::Atomic}; |
| 296 | // The new offset is from the start of the data segment, instead of |
| 297 | // whatever it was.. this may be a different value from both the |
| 298 | // original const and offset! |
| 299 | offset = abs_base - dat_base; |
| 300 | } |
| 301 | } |
| 302 | } |
| 303 | // Do the load/store as a generalized indexing operation. |
| 304 | // The offset is divisible by the alignment in 99.99% of |
| 305 | // cases, but the spec doesn't guarantee it, so we must |
| 306 | // have a backup syntax. |
| 307 | auto index = offset % align == 0 |
| 308 | ? std::to_string(offset / align) |
| 309 | : cat(std::to_string(offset), "@", std::to_string(align)); |
| 310 | // Detect the very common case of (base + (index << 2))[0]:int etc. |
| 311 | // so we can instead do base[index]:int |
| 312 | // TODO: (index << 2) on the left of + occurs also. |
| 313 | // TODO: sadly this does not address cases where the shift amount > align. |
| 314 | // (which happens for arrays of structs or arrays of long (with align=4)). |
| 315 | // TODO: also very common is (v = base + (index << 2))[0]:int |
| 316 | if (addr_exp.etype == ExprType::Binary) { |
| 317 | auto& pe = *cast<BinaryExpr>(addr_exp.e); |
nothing calls this directly
no test coverage detected