Files
revng-revng/lib/RemoveExtractValues/RemoveExtractValuesPass.cpp
T
Alvise de Faveri 189fbe4651 Support: Fix the key for OpaqueExtractValue pool
Calls to `OpaqueExtractValue()` are meant to replace `extractvalue`s
found in the LLVM IR. Since the type of an `OpaqueExtractValue` is
identified by both the return type (extracted value) and the first
argument's type (aggregate operand of the `extractvalue` instruction),
we need to consider both when building the associated FunctionPool.

Previously, we were identifying each `OpaqueExtractValue` variant using
only the returned value, which was wrong. In fact, if we have two
`extractvalue` instructions that extract a value of the same type
(e.g. i32) from two different aggregate types (e.g. structA and
structB), we have to define two different `OpaqueExtractValue`: one
that returns an i32 and has a parameter of type structA, and one that
returns an i32 and has a parameter of structB. If we use only the
return type, we are not able to distinguish the two.
2022-06-01 11:05:31 +02:00

80 lines
2.6 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 "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"
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);
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;
// 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() };
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(F.getContext(), 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);
I->replaceAllUsesWith(InjectedCall);
InjectedCall->copyMetadata(*I);
I->eraseFromParent();
}
return true;
}