diff --git a/include/revng/Support/IRBuilder.h b/include/revng/Support/IRBuilder.h index d0d9067f9..242520081 100644 --- a/include/revng/Support/IRBuilder.h +++ b/include/revng/Support/IRBuilder.h @@ -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(Variable)) + return Alloca->getAllocatedType(); + else if (auto *GV = llvm::dyn_cast(Variable)) + return GV->getValueType(); + else + revng_abort("Either GlobalVariable or AllocaInst expected"); +} + namespace revng { class IRBuilder; @@ -44,6 +59,13 @@ using LLVMBuilderBase = llvm::IRBuildergetModule()->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) : diff --git a/include/revng/Support/IRHelpers.h b/include/revng/Support/IRHelpers.h index c00bb0732..03720f8c4 100644 --- a/include/revng/Support/IRHelpers.h +++ b/include/revng/Support/IRHelpers.h @@ -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(Variable)) - return Alloca->getAllocatedType(); - else if (auto *GV = llvm::dyn_cast(Variable)) - return GV->getValueType(); - else - revng_abort("Either GlobalVariable or AllocaInst expected"); -} - void pruneDICompileUnits(llvm::Module &M); llvm::SmallSet findPhiTreeLeaves(llvm::Value *Root); diff --git a/lib/Canonicalize/ExitSSAPass.cpp b/lib/Canonicalize/ExitSSAPass.cpp index 374490ac1..fc1fd842c 100644 --- a/lib/Canonicalize/ExitSSAPass.cpp +++ b/lib/Canonicalize/ExitSSAPass.cpp @@ -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(Incoming)) LoadFromStore->setDebugLoc(IncomingInst->getDebugLoc()); } @@ -308,7 +310,7 @@ static void replacePHIEquivalenceClass(const SetVector &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 &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)); diff --git a/lib/Canonicalize/FixPointerSize.cpp b/lib/Canonicalize/FixPointerSize.cpp index eea9b8af8..b191dc009 100644 --- a/lib/Canonicalize/FixPointerSize.cpp +++ b/lib/Canonicalize/FixPointerSize.cpp @@ -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: " diff --git a/lib/Canonicalize/SplitExponentialDataflow.cpp b/lib/Canonicalize/SplitExponentialDataflow.cpp index 1c67a55fa..20a1bc3d1 100644 --- a/lib/Canonicalize/SplitExponentialDataflow.cpp +++ b/lib/Canonicalize/SplitExponentialDataflow.cpp @@ -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; diff --git a/lib/Canonicalize/SwitchToStatements.cpp b/lib/Canonicalize/SwitchToStatements.cpp index e49d58ba4..34fd000b2 100644 --- a/lib/Canonicalize/SwitchToStatements.cpp +++ b/lib/Canonicalize/SwitchToStatements.cpp @@ -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(ToCopy)) DL = I->getDebugLoc(); revng::NonDebugInfoCheckingIRBuilder B(InsertBefore, DL); + if (auto *Alloca = dyn_cast(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, diff --git a/tests/filecheck/llvm-passes/switch-to-statements.ll b/tests/filecheck/llvm-passes/switch-to-statements.ll index fc1afccb2..e9241b6ee 100644 --- a/tests/filecheck/llvm-passes/switch-to-statements.ll +++ b/tests/filecheck/llvm-passes/switch-to-statements.ll @@ -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