Introduce FixPointerSize

This commit introduces `FixPointerSize`, a pipe changing the
`DataLayout` of module in order to have a pointer size identical to the
one of `targetABI()`.

The pipe also performs safety checks to ensure this does not corrupt
semantics.
This commit is contained in:
Alessandro Di Federico
2026-06-16 14:33:59 +02:00
parent 1ff0eedc5f
commit 3e31edf817
5 changed files with 183 additions and 0 deletions
@@ -0,0 +1,51 @@
#pragma once
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "revng/PipeboxCommon/Common.h"
#include "revng/PipeboxCommon/LLVMContainer.h"
#include "revng/PipeboxCommon/Model.h"
namespace revng::pypeline::pipes {
// For target binaries with 32-bit pointers, rewrite the LLVM module's
// DataLayout so the default-address-space pointer is 32 bits wide before the
// IR is handed off to `clifter`.
//
// Two preconditions must hold for the rewrite to be valid:
//
// 1. No scalar `alloca`'s allocated type transitively contains an
// `llvm::PointerType`. Pointer-typed allocas would silently shrink
// from 8 to 4 bytes when the DataLayout changes; pointer values must
// instead live in integer-typed allocas and be bitcast (via
// `ptrtoint`/`inttoptr`) at load/store boundaries.
//
// 2. No `getelementptr` has a source type that transitively contains an
// `llvm::PointerType`. Otherwise the GEP's byte offsets would shift
// under the new DataLayout.
//
// Both preconditions are checked with hard assertions; the pipe aborts if
// either fails. The DataLayout rewrite is a no-op for targets whose pointer
// is not 32 bits wide.
class FixPointerSize {
public:
static constexpr llvm::StringRef Name = "fix-pointer-size";
using Arguments = TypeList<PipeArgument<"Module",
"LLVM Modules whose pointer size "
"needs to match the "
"target architecture">>;
const std::string StaticConfiguration;
FixPointerSize(llvm::StringRef StaticConfiguration) :
StaticConfiguration(StaticConfiguration) {}
PipeOutput run(const Model &TheModel,
const revng::pypeline::Request &Incoming,
const revng::pypeline::Request &Outgoing,
llvm::StringRef Configuration,
LLVMFunctionContainer &Container);
};
} // namespace revng::pypeline::pipes
+1
View File
@@ -10,6 +10,7 @@ revng_add_analyses_library_internal(
EmbedStatementComments.cpp
ExitSSAPass.cpp
ExtractValueToGEP.cpp
FixPointerSize.cpp
FoldModelGEP.cpp
SplitStructPhis.cpp
ImplicitModelCastPass.cpp
+127
View File
@@ -0,0 +1,127 @@
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "revng/ADT/Queue.h"
#include "revng/Canonicalize/FixPointerSize.h"
#include "revng/Model/Architecture.h"
#include "revng/PipeboxCommon/ObjectID.h"
#include "revng/Support/Assert.h"
#include "revng/Support/IRHelpers.h"
using namespace llvm;
static bool containsPointer(Type *T) {
OnceQueue<Type *> Queue;
Queue.insert(T);
while (not Queue.empty()) {
Type *Current = Queue.pop();
if (Current->isPointerTy())
return true;
auto ContainedTypesCount = Current->getNumContainedTypes();
for (unsigned I = 0; I < ContainedTypesCount; ++I)
Queue.insert(Current->getContainedType(I));
}
return false;
}
// Rewrite the default-address-space pointer specification in a DataLayout
// string to the given pointer size in bits.
static std::string rewriteDefaultPointerSize(StringRef Original,
unsigned Bits) {
std::string Width = std::to_string(Bits);
std::string NewSpec = "p:" + Width + ":" + Width;
SmallVector<StringRef, 16> Parts;
Original.split(Parts, '-');
std::string Result;
bool Replaced = false;
for (StringRef Part : Parts) {
if (not Result.empty())
Result += '-';
if (Part.starts_with("p:") or Part.starts_with("p0:")) {
Result += NewSpec;
Replaced = true;
} else {
Result += Part.str();
}
}
if (not Replaced) {
if (not Result.empty())
Result += '-';
Result += NewSpec;
}
return Result;
}
static void checkAndFixModule(llvm::Module &M, unsigned TargetPointerBits) {
for (llvm::GlobalVariable &GV : M.globals()) {
if (GV.use_empty())
continue;
revng_assert(not containsPointer(GV.getValueType()),
("used global variable's value type transitively contains a "
"pointer: "
+ dumpToString(&GV))
.c_str());
}
for (llvm::Function &F : M) {
if (F.isDeclaration())
continue;
for (llvm::Instruction &I : llvm::instructions(F)) {
if (auto *Alloca = dyn_cast<llvm::AllocaInst>(&I)) {
Type *AllocatedTy = Alloca->getAllocatedType();
revng_assert(not containsPointer(AllocatedTy),
("scalar alloca containing a pointer in @" + F.getName()
+ ": " + dumpToString(Alloca))
.str()
.c_str());
} else if (auto *GEP = dyn_cast<llvm::GetElementPtrInst>(&I)) {
revng_assert(not containsPointer(GEP->getSourceElementType()),
("GEP source type transitively contains a pointer in @"
+ F.getName() + ": " + dumpToString(GEP))
.str()
.c_str());
}
}
}
auto &DL = M.getDataLayout();
if (DL.getPointerSizeInBits(0) == TargetPointerBits)
return;
auto Original = DL.getStringRepresentation();
M.setDataLayout(rewriteDefaultPointerSize(Original, TargetPointerBits));
}
namespace revng::pypeline::pipes {
PipeOutput FixPointerSize::run(const Model &TheModel,
const revng::pypeline::Request &Incoming,
const revng::pypeline::Request &Outgoing,
llvm::StringRef Configuration,
LLVMFunctionContainer &Container) {
using namespace model::ABI;
auto TargetPointerBits = getPointerSize(TheModel.get()->targetABI()) * 8;
for (const ObjectID *Object : Outgoing.at(0)) {
revng_assert(Object->kind() == Kinds::Function);
checkAndFixModule(Container.getModule(*Object), TargetPointerBits);
}
return { {}, {} };
}
} // namespace revng::pypeline::pipes
+2
View File
@@ -4,6 +4,7 @@
#include "revng/ABI/Analyses/ConvertFunctionsToCABI.h"
#include "revng/ABI/Analyses/ConvertFunctionsToRaw.h"
#include "revng/Canonicalize/FixPointerSize.h"
#include "revng/Canonicalize/SimplifySwitch.h"
#include "revng/Canonicalize/SwitchToStatements.h"
#include "revng/CliftPipes/Clifter.h"
@@ -93,6 +94,7 @@ REGISTER(Container, TranslatedContainer);
using namespace revng::pypeline::pipes;
REGISTER(Pipe, FixPointerSize);
REGISTER(Pipe, PureLLVMPassesPipe);
REGISTER(Pipe, PureLLVMPassesRootPipe);
REGISTER(Pipe, PureMLIRPassesPipe);
+2
View File
@@ -396,6 +396,8 @@ branches:
container: llvm-functions
category: debug
filename: clifter_input.bc
- pipe: fix-pointer-size
arguments: [llvm-functions]
- pipe: clifter
arguments: [llvm-functions, clift-functions]
artifacts: