/// \file MaterializedValue.cpp // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "llvm/IR/Intrinsics.h" #include "revng/BasicAnalyses/MaterializedValue.h" #include "revng/Support/IRHelpers.h" MaterializedValue MaterializedValue::apply(llvm::Instruction *Operation, llvm::ArrayRef Operands) { using namespace llvm; if (isa(Operation)) { revng_assert(Operands.size() == 1); return Operands[0]; } MaterializedValue Result; Result.IsValid = true; // // Merge AffectedBy sets // for (const MaterializedValue &Value : Operands) for (const MemoryRange &Range : Value.AffectedBy) Result.AffectedBy.push_back(Range); // // Detect symbol name // if (Operands.size() > 0 and Operands[0].hasSymbol()) Result.SymbolName = Operands[0].symbolName(); // Handle add as second operand in add bool IsAdd = false; auto *I = dyn_cast(Operation); if (I != nullptr) { auto Opcode = I->getOpcode(); IsAdd = Opcode == Instruction::Add; } if (not Result.SymbolName.has_value() and IsAdd and Operands[1].hasSymbol()) Result.SymbolName = Operands[1].symbolName(); // Ensure no more than one symbol auto HasSymbol = [](const MaterializedValue &Value) -> bool { return Value.hasSymbol(); }; if (not IsAdd and llvm::any_of(skip_front(Operands), HasSymbol)) return MaterializedValue::invalid(); // Restrict the operations we can perform on symbols to cast, add, // subtraction, masking and bswap if (Result.SymbolName.has_value() and I != nullptr) { auto *Call = dyn_cast(I); // TODO: this is not very nice if (not(I->isCast() or I->getOpcode() == Instruction::Add or I->getOpcode() == Instruction::Sub or I->getOpcode() == Instruction::And or I->getOpcode() == Instruction::ZExt or I->getOpcode() == Instruction::IntToPtr or I->getOpcode() == Instruction::PtrToInt or I->getOpcode() == Instruction::Trunc or I->getOpcode() == Instruction::BitCast or I->getOpcode() == Instruction::Shl or (Call != nullptr and Call->getIntrinsicID() == Intrinsic::bswap))) { return MaterializedValue::invalid(); } } // // Build operands list // SmallVector ConstantOperands; unsigned Index = 0; for (const MaterializedValue &Operand : Operands) { auto *OperandType = Operation->getOperand(Index)->getType(); ConstantOperands.push_back(Operand.toConstant(OperandType)); ++Index; } // // Perform computation // const auto &DL = getModule(Operation)->getDataLayout(); auto *Folded = ConstantFoldInstOperands(Operation, ConstantOperands, DL); revng_assert(Folded != nullptr); Result.Value = cast(Folded)->getValue(); return Result; } MaterializedValue MaterializedValue::fromConstant(llvm::ConstantInt *CI) { return MaterializedValue::fromConstant(CI->getValue()); } llvm::Constant * MaterializedValue::toConstant(llvm::LLVMContext &Context) const { return toConstant(llvm::IntegerType::get(Context, Value.getBitWidth())); } llvm::Constant * MaterializedValue::toConstant(llvm::Type *DestinationType) const { using namespace llvm; if (DestinationType->isPointerTy()) { auto *IntegerValue = toConstant(DestinationType->getContext()); return ConstantExpr::getIntToPtr(IntegerValue, DestinationType); } else if (auto *IT = dyn_cast(DestinationType)) { revng_assert(IT->getBitWidth() == Value.getBitWidth()); return ConstantInt::get(DestinationType, Value); } else { revng_abort(); } }