mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
124 lines
3.8 KiB
C++
124 lines
3.8 KiB
C++
/// \file MaterializedValue.cpp
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/Intrinsics.h"
|
|
|
|
#include "revng/BasicAnalyses/MaterializedValue.h"
|
|
#include "revng/Support/IRHelpers.h"
|
|
|
|
MaterializedValue
|
|
MaterializedValue::apply(llvm::Instruction *Operation,
|
|
llvm::ArrayRef<MaterializedValue> Operands) {
|
|
using namespace llvm;
|
|
|
|
if (isa<AllocaInst>(Operation))
|
|
return MaterializedValue::invalid();
|
|
|
|
if (isa<IntToPtrInst>(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<Instruction>(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<CallInst>(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<Constant *, 4> 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<ConstantInt>(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<IntegerType>(DestinationType)) {
|
|
revng_assert(IT->getBitWidth() == Value.getBitWidth());
|
|
return ConstantInt::get(DestinationType, Value);
|
|
} else {
|
|
revng_abort();
|
|
}
|
|
}
|