#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "revng/Support/Debug.h" #include "revng/Support/MetaAddress.h" /// Class representing either a constant value or an offset from a symbol class MaterializedValue { public: class MemoryRange { public: MetaAddress Address; unsigned Size = 0; }; private: bool IsValid = false; std::optional SymbolName; llvm::APInt Value; llvm::SmallVector AffectedBy; private: MaterializedValue(const llvm::APInt &Value) : IsValid(true), Value(Value) {} MaterializedValue(llvm::StringRef SymbolName, const llvm::APInt &Offset) : IsValid(true), SymbolName(SymbolName.str()), Value(Offset) {} public: MaterializedValue() = default; MaterializedValue(const MaterializedValue &) = default; MaterializedValue(MaterializedValue &&) = default; MaterializedValue &operator=(const MaterializedValue &) = default; MaterializedValue &operator=(MaterializedValue &&) = default; public: static MaterializedValue invalid() { return MaterializedValue(); } static MaterializedValue fromConstant(const llvm::APInt &API) { return MaterializedValue(API); } static MaterializedValue fromConstant(llvm::ConstantInt *CI); static MaterializedValue fromSymbol(llvm::StringRef SymbolName, const llvm::APInt &Offset) { return MaterializedValue(SymbolName, Offset); } static MaterializedValue apply(llvm::Instruction *Operation, llvm::ArrayRef Operands); public: template MaterializedValue load(T &MemoryOracle, unsigned Size) const { // Cannot load symbols or invalid values if (hasSymbol() or not IsValid) return MaterializedValue::invalid(); return MemoryOracle.load(Value.getLimitedValue(), Size); } MaterializedValue byteSwap() const { MaterializedValue Result = *this; Result.Value = Value.byteSwap(); return Result; } public: bool operator==(const MaterializedValue &Other) const { auto MaxBitWidth = std::max(Value.getBitWidth(), Other.Value.getBitWidth()); auto ZExtValue = Value.zext(MaxBitWidth); auto ZExtOther = Other.Value.zext(MaxBitWidth); auto This = std::tie(IsValid, SymbolName, ZExtValue); auto That = std::tie(Other.IsValid, Other.SymbolName, ZExtOther); return This == That; } bool operator<(const MaterializedValue &Other) const { auto MaxBitWidth = std::max(Value.getBitWidth(), Other.Value.getBitWidth()); if (Value.zext(MaxBitWidth).ult(Other.Value.zext(MaxBitWidth))) return true; auto This = std::tie(IsValid, SymbolName); auto That = std::tie(Other.IsValid, Other.SymbolName); return This < That; } const llvm::APInt &value() const { revng_assert(isValid()); return Value; } bool isValid() const { return IsValid; } bool hasSymbol() const { return SymbolName.has_value(); } std::string symbolName() const { revng_assert(isValid()); revng_assert(hasSymbol()); revng_assert(not llvm::StringRef(*SymbolName).contains('\0')); return *SymbolName; } llvm::Constant *toConstant(llvm::LLVMContext &Context) const; llvm::Constant *toConstant(llvm::Type *DestinationType) const; void dump() const debug_function { dump(dbg); } template void dump(T &Output) const { if (not isValid()) { Output << "(invalid)"; } else { if (hasSymbol()) Output << symbolName().data() << "+"; llvm::SmallString<40> String; value().toStringUnsigned(String, 16); Output << "0x" << String.c_str(); } } }; using MaterializedValues = std::vector;