// // Copyright (c) rev.ng Srls. See LICENSE.md for details. // #include #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" #include "revng/Support/Assert.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 PHINodeT = 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 ExtractValuePtrSet ExtractValues; for (auto *TheUser : I->users()) { if (auto *ExtractV = dyn_cast(TheUser)) { ExtractValues.insert(ExtractV); } else if (auto *ThePHI = dyn_cast(TheUser)) { // traverse PHIS until we find extractvalues llvm::SmallPtrSet *, 8> Visited = {}; llvm::SmallPtrSet *, 8> ToVisit = { ThePHI }; while (not ToVisit.empty()) { llvm::SmallPtrSet *, 8> NextToVisit = {}; for (PHINodeT *PHI : ToVisit) { Visited.insert(PHI); NextToVisit.erase(PHI); for (auto *User : PHI->users()) { if (auto *EUser = llvm::dyn_cast(User)) { ExtractValues.insert(EUser); } else if (auto *PHIUser = llvm::dyn_cast(User)) { if (not Visited.count(PHIUser)) NextToVisit.insert(PHIUser); } else if (auto *RetUser = llvm::dyn_cast(User)) { revng_abort("TODO: handle ret user"); } else { revng_abort(); } } } 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); }