// // 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-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); }