// // Copyright (c) rev.ng Labs Srl. See LICENSE.md for details. // #include #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "revng/Support/Assert.h" #include "revng/Support/MetaAddress.h" #include "revng-c/Support/FunctionTags.h" #include "revng-c/Support/IRHelpers.h" template concept DerivedValue = std::is_base_of_v; using std::conditional_t; template using PossiblyConstValueT = conditional_t, std::add_const_t, std::remove_const_t>; template concept PossiblyConstInsertValue = std::is_same_v, llvm::InsertValueInst>; template using ValueT = PossiblyConstValueT; template llvm::SmallVector *, 2> getConstQualifiedInsertValueLeafOperands(T *Ins) { using ValT = ValueT; llvm::SmallVector Results; llvm::SmallSet FoundIds; auto *StructTy = llvm::cast(Ins->getType()); unsigned NumFields = StructTy->getNumElements(); Results.resize(NumFields, nullptr); // InsertValues should be present in the IR only when we are returning an // LLVM struct from a function. In particular, there should be a chain of // InsertValues inserting to the same aggregate, followed by a ret of the // aggregate value. auto IsRet = [](const llvm::Value *V) { return isa(V); }; auto FirstUserIsInsertVal = [&Ins]() { return isa(Ins->use_begin()->getUser()); }; revng_assert((Ins->getNumUses() == 1 and FirstUserIsInsertVal()) or llvm::all_of(Ins->users(), IsRet)); while (1) { revng_assert(Ins->getNumIndices() == 1); // It must be the first time that we insert a value at this index of the // aggregate unsigned FieldId = Ins->getIndices()[0]; revng_assert(FieldId < NumFields); revng_assert(FoundIds.count(FieldId) == 0); FoundIds.insert(FieldId); // Save the inserted value ValT *Op = Ins->getInsertedValueOperand(); revng_assert(isa(Op->getType()) or isa(Op->getType())); revng_assert(Results[FieldId] == nullptr); Results[FieldId] = Op; // Go back in the insertValue chain ... ValT *Tmp = Ins->getAggregateOperand(); Ins = llvm::dyn_cast(Tmp); if (not Ins) { // ... until you find an undef or constant aggregate (i.e. you have // reached the first insertValue of the chain) revng_assert(llvm::isa(Tmp) or llvm::isa(Tmp)); break; } } return Results; }; llvm::SmallVector getInsertValueLeafOperands(llvm::InsertValueInst *Ins) { return getConstQualifiedInsertValueLeafOperands(Ins); } llvm::SmallVector getInsertValueLeafOperands(const llvm::InsertValueInst *Ins) { return getConstQualifiedInsertValueLeafOperands(Ins); } template using ExtractValueT = PossiblyConstValueT; template using ExtractValuePtrSet = llvm::SmallPtrSet *, 2>; template llvm::SmallVector, 2> getConstQualifiedExtractedValuesFromInstruction(T *I) { llvm::SmallVector, 2> Results; auto *StructTy = llvm::cast(I->getType()); unsigned NumFields = StructTy->getNumElements(); Results.resize(NumFields, {}); // Find extract value uses transitively, traversing PHIs and markers ExtractValuePtrSet ExtractValues; for (auto *TheUser : I->users()) { if (auto *ExtractV = dyn_cast(TheUser)) { ExtractValues.insert(ExtractV); } else { if (auto *Call = dyn_cast(TheUser)) { if (not FunctionTags::Marker.isTagOf(Call->getCalledFunction())) continue; } // traverse PHIS and markers until we find extractvalues llvm::SmallPtrSet *, 8> Visited = {}; llvm::SmallPtrSet *, 8> ToVisit = { TheUser }; while (not ToVisit.empty()) { llvm::SmallPtrSet *, 8> NextToVisit = {}; for (ValueT *Ident : ToVisit) { Visited.insert(Ident); NextToVisit.erase(Ident); for (auto *User : Ident->users()) { if (auto *ExtractV = llvm::dyn_cast(User)) { ExtractValues.insert(ExtractV); } else if (auto *IdentUser = llvm::dyn_cast(User)) { if (FunctionTags::Marker.isTagOf(IdentUser)) NextToVisit.insert(IdentUser); } else if (auto *PHIUser = llvm::dyn_cast(User)) { if (not Visited.count(PHIUser)) NextToVisit.insert(PHIUser); } } } ToVisit = NextToVisit; } } } for (auto *E : ExtractValues) { revng_assert(E->getNumIndices() == 1); unsigned FieldId = E->getIndices()[0]; revng_assert(FieldId < NumFields); revng_assert(isa(E->getType()) or isa(E->getType())); Results[FieldId].insert(E); } return Results; }; llvm::SmallVector, 2> getExtractedValuesFromInstruction(llvm::Instruction *I) { return getConstQualifiedExtractedValuesFromInstruction(I); } llvm::SmallVector, 2> getExtractedValuesFromInstruction(const llvm::Instruction *I) { return getConstQualifiedExtractedValuesFromInstruction(I); } bool deleteOnlyBody(llvm::Function &F) { bool Result = false; if (not F.empty()) { // deleteBody() also kills all attributes and tags. Since we still // want them, we have to save them and re-add them after deleting the // body of the function. auto Attributes = F.getAttributes(); auto FTags = FunctionTags::TagsSet::from(&F); llvm::SmallVector> AllMetadata; if (F.hasMetadata()) F.getAllMetadata(AllMetadata); // Kill the body. F.deleteBody(); // Restore tags and attributes FTags.set(&F); F.setAttributes(Attributes); F.clearMetadata(); for (const auto &[KindID, MetaData] : AllMetadata) { // Debug metadata is not stripped away by deleteBody() nor by // clearMetadata(), but it is wrong to set it twice (the Module would not // verify anymore). Hence set the metadata only if its not a debug // metadata. if (not F.hasMetadata(KindID) and KindID != llvm::LLVMContext::MD_dbg) F.setMetadata(KindID, MetaData); } Result = true; } return Result; } void setSegmentKeyMetadata(llvm::Function *SegmentRefFunction, MetaAddress StartAddress, uint64_t VirtualSize) { using namespace llvm; auto *M = SegmentRefFunction->getParent(); auto &Ctx = SegmentRefFunction->getContext(); StructType *MetaAddressTy = MetaAddress::getStruct(M); Constant *SAConstant = StartAddress.toConstant(MetaAddressTy); auto *SAMD = ConstantAsMetadata::get(SAConstant); auto *VSConstant = ConstantInt::get(Type::getInt64Ty(Ctx), VirtualSize); auto *VSMD = ConstantAsMetadata::get(VSConstant); auto *Node = MDNode::get(Ctx, { SAMD, VSMD }); SegmentRefFunction->setMetadata(SegmentRefMDName, Node); } std::pair extractSegmentKeyFromMetadata(const llvm::Function &F) { using namespace llvm; auto *Node = F.getMetadata(SegmentRefMDName); revng_assert(Node != nullptr); auto *SAMD = cast(Node->getOperand(0))->getValue(); auto *SAConstant = cast(SAMD); MetaAddress StartAddress = MetaAddress::fromConstant(SAConstant); auto *VSMD = cast(Node->getOperand(1))->getValue(); uint64_t VirtualSize = cast(VSMD)->getZExtValue(); return { StartAddress, VirtualSize }; }