mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
Canonicalize: ban pointers
In order to ensure there are no `alloca`s containing pointers, we change the passes that emit them to emit instead integer scalars of the same type.
This commit is contained in:
@@ -4,11 +4,26 @@
|
||||
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
//
|
||||
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
|
||||
#include "revng/Support/Assert.h"
|
||||
#include "revng/Support/Debug.h"
|
||||
|
||||
inline llvm::Type *getVariableType(const llvm::Value *Variable) {
|
||||
if (auto *Alloca = llvm::dyn_cast<llvm::AllocaInst>(Variable))
|
||||
return Alloca->getAllocatedType();
|
||||
else if (auto *GV = llvm::dyn_cast<llvm::GlobalVariable>(Variable))
|
||||
return GV->getValueType();
|
||||
else
|
||||
revng_abort("Either GlobalVariable or AllocaInst expected");
|
||||
}
|
||||
|
||||
namespace revng {
|
||||
|
||||
class IRBuilder;
|
||||
@@ -44,6 +59,13 @@ using LLVMBuilderBase = llvm::IRBuilder<llvm::ConstantFolder,
|
||||
|
||||
} // namespace detail
|
||||
|
||||
inline bool
|
||||
sameSize(llvm::Type *LHS, llvm::Type *RHS, const llvm::DataLayout &DL) {
|
||||
auto LHSSize = DL.getTypeStoreSize(LHS).getFixedValue();
|
||||
auto RHSSize = DL.getTypeStoreSize(RHS).getFixedValue();
|
||||
return LHSSize == RHSSize;
|
||||
}
|
||||
|
||||
/// This is a wrapper over llvm's IR builder that force-sets a debug location
|
||||
/// even when its insertion point is a basic block.
|
||||
///
|
||||
@@ -120,6 +142,47 @@ public:
|
||||
getInserter().checkImpl();
|
||||
}
|
||||
|
||||
public:
|
||||
/// Create an `alloca` of integer type or byte array capable to hold \p T
|
||||
llvm::AllocaInst *createSimpleAlloca(llvm::Type *T) {
|
||||
using namespace llvm;
|
||||
const DataLayout &DL = GetInsertBlock()->getModule()->getDataLayout();
|
||||
|
||||
if (T->isPointerTy()) {
|
||||
auto Size = DL.getPointerSizeInBits(T->getPointerAddressSpace());
|
||||
return CreateAlloca(this->getIntNTy(Size));
|
||||
}
|
||||
|
||||
if (T->isIntegerTy())
|
||||
return CreateAlloca(T);
|
||||
|
||||
auto Size = DL.getTypeStoreSize(T).getFixedValue();
|
||||
return CreateAlloca(ArrayType::get(this->getInt8Ty(), Size));
|
||||
}
|
||||
|
||||
/// Load a value of type \p DesiredType from \p Variable (an `AllocaInst` or
|
||||
/// `GlobalVariable`). The variable's allocated type and \p DesiredType must
|
||||
/// have the same store size.
|
||||
llvm::LoadInst *createLoadFromVariable(llvm::Value *Variable,
|
||||
llvm::Type *DesiredType) {
|
||||
using namespace llvm;
|
||||
Type *AllocatedType = getVariableType(Variable);
|
||||
const DataLayout &DL = GetInsertBlock()->getModule()->getDataLayout();
|
||||
revng_assert(sameSize(DesiredType, AllocatedType, DL));
|
||||
return this->CreateLoad(DesiredType, Variable);
|
||||
}
|
||||
|
||||
/// Store \p V into \p Variable (an `AllocaInst` or `GlobalVariable`). The
|
||||
/// variable's allocated type and \p V's type must have the same store size.
|
||||
llvm::StoreInst *createStoreToVariable(llvm::Value *V,
|
||||
llvm::Value *Variable) {
|
||||
using namespace llvm;
|
||||
Type *AllocatedType = getVariableType(Variable);
|
||||
const DataLayout &DL = GetInsertBlock()->getModule()->getDataLayout();
|
||||
revng_assert(sameSize(V->getType(), AllocatedType, DL));
|
||||
return CreateStore(V, Variable);
|
||||
}
|
||||
|
||||
protected:
|
||||
// NOLINTNEXTLINE
|
||||
explicit IRBuilder(bool EnableDebugInformationChecks, llvm::LLVMContext &C) :
|
||||
|
||||
@@ -1531,15 +1531,6 @@ inline llvm::Instruction *createLoadVariable(revng::IRBuilder &Builder,
|
||||
revng_abort("Either GlobalVariable or AllocaInst expected");
|
||||
}
|
||||
|
||||
inline llvm::Type *getVariableType(const llvm::Value *Variable) {
|
||||
if (auto *Alloca = llvm::dyn_cast<llvm::AllocaInst>(Variable))
|
||||
return Alloca->getAllocatedType();
|
||||
else if (auto *GV = llvm::dyn_cast<llvm::GlobalVariable>(Variable))
|
||||
return GV->getValueType();
|
||||
else
|
||||
revng_abort("Either GlobalVariable or AllocaInst expected");
|
||||
}
|
||||
|
||||
void pruneDICompileUnits(llvm::Module &M);
|
||||
|
||||
llvm::SmallSet<llvm::Value *, 2> findPhiTreeLeaves(llvm::Value *Root);
|
||||
|
||||
@@ -273,7 +273,7 @@ buildStore(BasicBlock *StoreBlock, Value *Incoming, AllocaInst *Alloca) {
|
||||
Builder.SetInsertPoint(StoreBlock->getTerminator(), Alloca->getDebugLoc());
|
||||
}
|
||||
|
||||
auto *S = Builder.CreateStore(Incoming, Alloca);
|
||||
auto *S = Builder.createStoreToVariable(Incoming, Alloca);
|
||||
revng_log(Log,
|
||||
"Created StoreInst " << dumpToString(S)
|
||||
<< " in Block: " << StoreBlock->getName());
|
||||
@@ -285,7 +285,9 @@ buildStore(BasicBlock *StoreBlock, Value *Incoming, AllocaInst *Alloca) {
|
||||
for (Use &Operand : NextInBlock.operands()) {
|
||||
if (Operand.get() == IncomingInst) {
|
||||
if (not LoadFromStore) {
|
||||
LoadFromStore = Builder.CreateLoad(IncomingInst->getType(), Alloca);
|
||||
LoadFromStore = Builder
|
||||
.createLoadFromVariable(Alloca,
|
||||
IncomingInst->getType());
|
||||
if (auto *IncomingInst = dyn_cast<Instruction>(Incoming))
|
||||
LoadFromStore->setDebugLoc(IncomingInst->getDebugLoc());
|
||||
}
|
||||
@@ -308,7 +310,7 @@ static void replacePHIEquivalenceClass(const SetVector<PHINode *> &PHIs,
|
||||
const DebugLoc &PHIDebugLoc = (*PHIs.begin())->getDebugLoc();
|
||||
Builder.SetInsertPointPastAllocas(&F, PHIDebugLoc);
|
||||
|
||||
AllocaInst *Alloca = Builder.CreateAlloca((*PHIs.begin())->getType());
|
||||
AllocaInst *Alloca = Builder.createSimpleAlloca((*PHIs.begin())->getType());
|
||||
revng_log(Log, "Created Alloca: " << dumpToString(Alloca));
|
||||
|
||||
{
|
||||
@@ -423,7 +425,7 @@ static void replacePHIEquivalenceClass(const SetVector<PHINode *> &PHIs,
|
||||
LoggerIndent IndentPHI{ Log };
|
||||
|
||||
Builder.SetInsertPoint(PHI->getParent()->getFirstNonPHI());
|
||||
auto *NewLoad = createLoad(Builder, Alloca);
|
||||
auto *NewLoad = Builder.createLoadFromVariable(Alloca, PHI->getType());
|
||||
NewLoad->setDebugLoc(PHIDebugLoc);
|
||||
revng_log(Log, "Create new load: " << dumpToString(NewLoad));
|
||||
|
||||
|
||||
@@ -67,8 +67,10 @@ static std::string rewriteDefaultPointerSize(StringRef Original,
|
||||
|
||||
static void checkAndFixModule(llvm::Module &M, unsigned TargetPointerBits) {
|
||||
for (llvm::GlobalVariable &GV : M.globals()) {
|
||||
// Ignore unused globals
|
||||
if (GV.use_empty())
|
||||
continue;
|
||||
|
||||
revng_assert(not containsPointer(GV.getValueType()),
|
||||
("used global variable's value type transitively contains a "
|
||||
"pointer: "
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
#include "revng/Support/IRBuilder.h"
|
||||
#include "revng/Support/IRHelpers.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@@ -67,12 +68,12 @@ bool SplitExponentialDataflow::runOnFunction(llvm::Function &F) {
|
||||
Changed = true;
|
||||
auto Location = I.getDebugLoc();
|
||||
B.SetInsertPointPastAllocas(&F, Location);
|
||||
auto *Alloca = B.CreateAlloca(I.getType());
|
||||
auto *Alloca = B.createSimpleAlloca(I.getType());
|
||||
B.SetInsertPoint(&*std::next(I.getIterator()), Location);
|
||||
auto *Load = B.CreateLoad(I.getType(), Alloca);
|
||||
auto *Load = B.createLoadFromVariable(Alloca, I.getType());
|
||||
I.replaceAllUsesWith(Load);
|
||||
B.SetInsertPoint(Load, Location);
|
||||
B.CreateStore(&I, Alloca);
|
||||
B.createStoreToVariable(&I, Alloca);
|
||||
}
|
||||
}
|
||||
return Changed;
|
||||
|
||||
@@ -1528,7 +1528,7 @@ private:
|
||||
if constexpr (not IsLegacy) {
|
||||
revng::NonDebugInfoCheckingIRBuilder B(F.getContext());
|
||||
B.SetInsertPointPastAllocas(&F, DL);
|
||||
return B.CreateAlloca(I->getType());
|
||||
return B.createSimpleAlloca(I->getType());
|
||||
} else {
|
||||
revng_assert(I->getType()->isIntOrPtrTy());
|
||||
const model::UpcastableType &VariableType = TheTypeMap.at(I);
|
||||
@@ -1547,6 +1547,8 @@ private:
|
||||
if (auto *I = dyn_cast<Instruction>(ToCopy))
|
||||
DL = I->getDebugLoc();
|
||||
revng::NonDebugInfoCheckingIRBuilder B(InsertBefore, DL);
|
||||
if (auto *Alloca = dyn_cast<AllocaInst>(ToCopy))
|
||||
return B.createLoadFromVariable(Alloca, U->getType());
|
||||
return B.CreateLoad(U->getType(), ToCopy);
|
||||
} else {
|
||||
// TODO: remove when we drop legacy mode.
|
||||
@@ -1580,7 +1582,7 @@ private:
|
||||
if constexpr (not IsLegacy) {
|
||||
revng::NonDebugInfoCheckingIRBuilder B(NextInstruction,
|
||||
ValueToAssign->getDebugLoc());
|
||||
return B.CreateStore(ValueToAssign, LocalVariable);
|
||||
return B.createStoreToVariable(ValueToAssign, LocalVariable);
|
||||
} else {
|
||||
// TODO: drop when we drop legacy mode.
|
||||
return VariableBuilder.createAssignmentBefore(LocalVariable,
|
||||
|
||||
@@ -175,7 +175,7 @@ define i32 @d_argument(ptr %arg) {
|
||||
; The the ret instruction should load from there again.
|
||||
;
|
||||
; CHECK-LABEL: define %s @s
|
||||
; CHECK: [[ALLOCA:%[a-zA-Z0-9_]+]] = alloca %s
|
||||
; CHECK: [[ALLOCA:%[a-zA-Z0-9_]+]] = alloca [8 x i8]
|
||||
; CHECK-NEXT: [[LOADED_VALUE:%[a-zA-Z0-9_]+]] = load %s, ptr %arg
|
||||
; CHECK-NEXT: store %s [[LOADED_VALUE]], ptr [[ALLOCA]]
|
||||
; CHECK-NEXT: store i64 7, ptr @segment
|
||||
@@ -196,7 +196,7 @@ define %s @s(ptr %arg) {
|
||||
; This is the same as the previous test, but with segment and argument swapped.
|
||||
;
|
||||
; CHECK-LABEL: define %s @s_swapped
|
||||
; CHECK: [[ALLOCA:%[a-zA-Z0-9_]+]] = alloca %s
|
||||
; CHECK: [[ALLOCA:%[a-zA-Z0-9_]+]] = alloca [8 x i8]
|
||||
; CHECK-NEXT: [[LOADED_VALUE:%[a-zA-Z0-9_]+]] = load %s, ptr @segment
|
||||
; CHECK-NEXT: store %s [[LOADED_VALUE]], ptr [[ALLOCA]]
|
||||
; CHECK-NEXT: store i64 7, ptr %arg
|
||||
|
||||
Reference in New Issue
Block a user