|
| 1 | +//===- Context.cpp - State Tracking for llubi -----------------------------===// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | +// |
| 9 | +// This file tracks the global states (e.g., memory) of the interpreter. |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | + |
| 13 | +#include "Context.h" |
| 14 | +#include "llvm/Support/MathExtras.h" |
| 15 | + |
| 16 | +namespace llvm::ubi { |
| 17 | + |
| 18 | +Context::Context(Module &M) |
| 19 | + : Ctx(M.getContext()), M(M), DL(M.getDataLayout()), |
| 20 | + TLIImpl(M.getTargetTriple()) {} |
| 21 | + |
| 22 | +Context::~Context() = default; |
| 23 | + |
| 24 | +AnyValue Context::getConstantValueImpl(Constant *C) { |
| 25 | + if (isa<PoisonValue>(C)) |
| 26 | + return AnyValue::getPoisonValue(*this, C->getType()); |
| 27 | + |
| 28 | + // TODO: Handle ConstantInt vector. |
| 29 | + if (auto *CI = dyn_cast<ConstantInt>(C)) |
| 30 | + return CI->getValue(); |
| 31 | + |
| 32 | + llvm_unreachable("Unrecognized constant"); |
| 33 | +} |
| 34 | + |
| 35 | +const AnyValue &Context::getConstantValue(Constant *C) { |
| 36 | + auto It = ConstCache.find(C); |
| 37 | + if (It != ConstCache.end()) |
| 38 | + return It->second; |
| 39 | + |
| 40 | + return ConstCache.emplace(C, getConstantValueImpl(C)).first->second; |
| 41 | +} |
| 42 | + |
| 43 | +MemoryObject::~MemoryObject() = default; |
| 44 | +MemoryObject::MemoryObject(uint64_t Addr, uint64_t Size, StringRef Name, |
| 45 | + unsigned AS, MemInitKind InitKind) |
| 46 | + : Address(Addr), Size(Size), Name(Name), AS(AS), |
| 47 | + State(InitKind != MemInitKind::Poisoned ? MemoryObjectState::Alive |
| 48 | + : MemoryObjectState::Dead) { |
| 49 | + switch (InitKind) { |
| 50 | + case MemInitKind::Zeroed: |
| 51 | + Bytes.resize(Size, Byte{0, ByteKind::Concrete}); |
| 52 | + break; |
| 53 | + case MemInitKind::Uninitialized: |
| 54 | + Bytes.resize(Size, Byte{0, ByteKind::Undef}); |
| 55 | + break; |
| 56 | + case MemInitKind::Poisoned: |
| 57 | + Bytes.resize(Size, Byte{0, ByteKind::Poison}); |
| 58 | + break; |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +IntrusiveRefCntPtr<MemoryObject> Context::allocate(uint64_t Size, |
| 63 | + uint64_t Align, |
| 64 | + StringRef Name, unsigned AS, |
| 65 | + MemInitKind InitKind) { |
| 66 | + if (MaxMem != 0 && SaturatingAdd(UsedMem, Size) >= MaxMem) |
| 67 | + return nullptr; |
| 68 | + uint64_t AlignedAddr = alignTo(AllocationBase, Align); |
| 69 | + auto MemObj = |
| 70 | + makeIntrusiveRefCnt<MemoryObject>(AlignedAddr, Size, Name, AS, InitKind); |
| 71 | + MemoryObjects[AlignedAddr] = MemObj; |
| 72 | + AllocationBase = AlignedAddr + Size; |
| 73 | + UsedMem += Size; |
| 74 | + return MemObj; |
| 75 | +} |
| 76 | + |
| 77 | +bool Context::free(uint64_t Address) { |
| 78 | + auto It = MemoryObjects.find(Address); |
| 79 | + if (It == MemoryObjects.end()) |
| 80 | + return false; |
| 81 | + UsedMem -= It->second->getSize(); |
| 82 | + It->second->markAsFreed(); |
| 83 | + MemoryObjects.erase(It); |
| 84 | + return true; |
| 85 | +} |
| 86 | + |
| 87 | +Pointer Context::deriveFromMemoryObject(IntrusiveRefCntPtr<MemoryObject> Obj) { |
| 88 | + assert(Obj && "Cannot determine the address space of a null memory object"); |
| 89 | + return Pointer( |
| 90 | + Obj, |
| 91 | + APInt(DL.getPointerSizeInBits(Obj->getAddressSpace()), Obj->getAddress()), |
| 92 | + /*Offset=*/0); |
| 93 | +} |
| 94 | + |
| 95 | +void MemoryObject::markAsFreed() { |
| 96 | + State = MemoryObjectState::Freed; |
| 97 | + Bytes.clear(); |
| 98 | +} |
| 99 | + |
| 100 | +void MemoryObject::writeRawBytes(uint64_t Offset, const void *Data, |
| 101 | + uint64_t Length) { |
| 102 | + assert(SaturatingAdd(Offset, Length) <= Size && "Write out of bounds"); |
| 103 | + const uint8_t *ByteData = static_cast<const uint8_t *>(Data); |
| 104 | + for (uint64_t I = 0; I < Length; ++I) |
| 105 | + Bytes[Offset + I].set(ByteData[I]); |
| 106 | +} |
| 107 | + |
| 108 | +void MemoryObject::writeInteger(uint64_t Offset, const APInt &Int, |
| 109 | + const DataLayout &DL) { |
| 110 | + uint64_t BitWidth = Int.getBitWidth(); |
| 111 | + uint64_t IntSize = divideCeil(BitWidth, 8); |
| 112 | + assert(SaturatingAdd(Offset, IntSize) <= Size && "Write out of bounds"); |
| 113 | + for (uint64_t I = 0; I < IntSize; ++I) { |
| 114 | + uint64_t ByteIndex = DL.isLittleEndian() ? I : (IntSize - 1 - I); |
| 115 | + uint64_t Bits = std::min(BitWidth - ByteIndex * 8, uint64_t(8)); |
| 116 | + Bytes[Offset + I].set(Int.extractBitsAsZExtValue(Bits, ByteIndex * 8)); |
| 117 | + } |
| 118 | +} |
| 119 | +void MemoryObject::writeFloat(uint64_t Offset, const APFloat &Float, |
| 120 | + const DataLayout &DL) { |
| 121 | + writeInteger(Offset, Float.bitcastToAPInt(), DL); |
| 122 | +} |
| 123 | +void MemoryObject::writePointer(uint64_t Offset, const Pointer &Ptr, |
| 124 | + const DataLayout &DL) { |
| 125 | + writeInteger(Offset, Ptr.address(), DL); |
| 126 | + // TODO: provenance |
| 127 | +} |
| 128 | + |
| 129 | +} // namespace llvm::ubi |
0 commit comments