mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
08939f2ae8
This commit sets a name for types we use in OpaqueExtractValues. These are StructTypes that can only be returned from isolated functions with RawFunctionType prototype on the model, or from helpers that do not represent isolated functions. The name is required because when we will converto to MLIR LLVM Dialect, there are checks in place that forbid unnamed types. The code re-uses code that is used to print C code, in order to make sure that the struct names we use for this are the same as those we emit in C, to ease debugging. This commit also cleans up the unittest to make it more concise, while still testing the same things.
118 lines
4.3 KiB
C++
118 lines
4.3 KiB
C++
//
|
|
// Copyright rev.ng Labs Srl. See LICENSE.md for details.
|
|
//
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/IR/Constants.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/IRBuilder.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/Type.h"
|
|
#include "llvm/Transforms/Utils/Local.h"
|
|
|
|
#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h"
|
|
#include "revng/Model/IRHelpers.h"
|
|
#include "revng/Model/LoadModelPass.h"
|
|
#include "revng/Support/Assert.h"
|
|
#include "revng/Support/FunctionTags.h"
|
|
#include "revng/Support/IRHelpers.h"
|
|
#include "revng/Support/OpaqueFunctionsPool.h"
|
|
|
|
#include "revng-c/RemoveExtractValues/RemoveExtractValuesPass.h"
|
|
#include "revng-c/Support/FunctionTags.h"
|
|
#include "revng-c/Support/PTMLC.h"
|
|
#include "revng-c/TypeNames/LLVMTypeNames.h"
|
|
#include "revng-c/TypeNames/ModelTypeNames.h"
|
|
|
|
using namespace llvm;
|
|
|
|
char RemoveExtractValues::ID = 0;
|
|
using Reg = RegisterPass<RemoveExtractValues>;
|
|
static Reg X("remove-extractvalues",
|
|
"Substitute extractvalues with opaque calls so that they don't "
|
|
"get optimized",
|
|
true,
|
|
true);
|
|
|
|
void RemoveExtractValues::getAnalysisUsage(llvm::AnalysisUsage &AU) const {
|
|
AU.setPreservesAll();
|
|
AU.addRequired<LoadModelWrapperPass>();
|
|
AU.addRequired<FunctionMetadataCachePass>();
|
|
}
|
|
|
|
bool RemoveExtractValues::runOnFunction(llvm::Function &F) {
|
|
using namespace llvm;
|
|
|
|
// Collect all ExtractValues
|
|
SmallVector<ExtractValueInst *, 16> ToReplace;
|
|
for (auto &BB : F)
|
|
for (auto &I : BB)
|
|
if (auto *ExtractVal = llvm::dyn_cast<llvm::ExtractValueInst>(&I))
|
|
ToReplace.push_back(ExtractVal);
|
|
|
|
if (ToReplace.empty())
|
|
return false;
|
|
|
|
auto &Cache = getAnalysis<FunctionMetadataCachePass>().get();
|
|
auto &Model = getAnalysis<LoadModelWrapperPass>().get().getReadOnlyModel();
|
|
|
|
// Create a pool of functions with the same behavior: we will need a different
|
|
// function for each different struct
|
|
OpaqueFunctionsPool<TypePair> OpaqueEVPool(F.getParent(),
|
|
/* PurgeOnDestruction */ false);
|
|
initOpaqueEVPool(OpaqueEVPool, F.getParent());
|
|
|
|
llvm::LLVMContext &LLVMCtx = F.getContext();
|
|
IRBuilder<> Builder(LLVMCtx);
|
|
for (ExtractValueInst *I : ToReplace) {
|
|
Builder.SetInsertPoint(I);
|
|
|
|
// Collect arguments of the ExtractValue
|
|
SmallVector<Value *, 8> ArgValues = { I->getAggregateOperand() };
|
|
revng_assert(I->getNumIndices() == 1);
|
|
for (auto Idx : I->indices()) {
|
|
auto *IndexVal = ConstantInt::get(IntegerType::getInt64Ty(LLVMCtx), Idx);
|
|
ArgValues.push_back(IndexVal);
|
|
}
|
|
|
|
// Get or generate the function
|
|
auto *EVFunctionType = getOpaqueEVFunctionType(I);
|
|
const TypePair &Key = { I->getType(), I->getAggregateOperand()->getType() };
|
|
auto *ExtractValueFunction = OpaqueEVPool.get(Key,
|
|
EVFunctionType,
|
|
"OpaqueExtractvalue");
|
|
|
|
// Emit a call to the new function
|
|
CallInst *InjectedCall = Builder.CreateCall(ExtractValueFunction,
|
|
ArgValues);
|
|
using PTMLCBuilder = ptml::PTMLCBuilder;
|
|
PTMLCBuilder B(/*GeneratePlainC*/ true);
|
|
std::string StructName;
|
|
revng_assert(isa<CallInst>(I->getAggregateOperand()));
|
|
auto *CallReturningAggregate = cast<CallInst>(I->getAggregateOperand());
|
|
if (isCallToIsolatedFunction(CallReturningAggregate)) {
|
|
auto Prototype = Cache.getCallSitePrototype(*Model,
|
|
CallReturningAggregate);
|
|
revng_assert(Prototype.get());
|
|
StructName = std::string(getReturnTypeName(*Prototype.get(), B));
|
|
} else {
|
|
// If it is not a isolated function, it must be a helper function.
|
|
auto CalledFunction = CallReturningAggregate->getCalledFunction();
|
|
revng_assert(CalledFunction);
|
|
StructName = getReturnTypeLocationDefinition(CalledFunction, B);
|
|
}
|
|
|
|
auto AggregateType = I->getAggregateOperand()->getType();
|
|
auto *TheStructType = llvm::cast<llvm::StructType>(AggregateType);
|
|
if (not TheStructType->isLiteral())
|
|
TheStructType->setName(StructName);
|
|
|
|
I->replaceAllUsesWith(InjectedCall);
|
|
InjectedCall->copyMetadata(*I);
|
|
llvm::RecursivelyDeleteTriviallyDeadInstructions(I);
|
|
}
|
|
|
|
return true;
|
|
}
|