Merge branch 'feature/segretate-aggregates-2'

This commit is contained in:
Alessandro Di Federico
2026-06-19 09:18:32 +02:00
79 changed files with 1116 additions and 306 deletions
@@ -24,6 +24,7 @@
#include "revng/Model/LoadModelPass.h"
#include "revng/Model/ProgramCounterHandler.h"
#include "revng/Support/BlockType.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
// Forward declarations
@@ -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
@@ -10,6 +10,7 @@
#include "revng/EarlyFunctionAnalysis/Outliner.h"
#include "revng/EarlyFunctionAnalysis/TemporaryOpaqueFunction.h"
#include "revng/Model/Binary.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/OpaqueFunctionsPool.h"
#include "revng/Support/OpaqueRegisterUser.h"
@@ -7,6 +7,7 @@
#include <set>
#include "revng/EarlyFunctionAnalysis/AnalyzeRegisterUsage.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/MetaAddress.h"
namespace revng {
@@ -4,6 +4,7 @@
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "revng/Support/IRBuilder.h"
#include "revng/Support/OpaqueFunctionsPool.h"
namespace revng {
+1 -1
View File
@@ -95,7 +95,7 @@ public:
Builder.CreateStore(Undef, V);
}
return createLoadVariable(Builder, V);
return Builder.createLoadVariable(V);
}
/// Get or create the LLVM value associated to a PTC temporary
+6 -9
View File
@@ -9,12 +9,9 @@
#include "revng/Model/Architecture.h"
#include "revng/Support/BlockType.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
namespace revng {
class IRBuilder;
} // namespace revng
inline llvm::IntegerType *getCSVType(llvm::GlobalVariable *CSV) {
using namespace llvm;
return cast<IntegerType>(CSV->getValueType());
@@ -156,7 +153,7 @@ public:
// Load and re-store each CSV affecting the PC and then feed them to
// handleStore
for (GlobalVariable *CSVAffectingPC : CSVsAffectingPC) {
auto *FakeLoad = createLoad(Builder, CSVAffectingPC);
auto *FakeLoad = Builder.createLoad(CSVAffectingPC);
auto *FakeStore = Builder.CreateStore(FakeLoad, CSVAffectingPC);
bool HasInjectedCode = handleStore(Builder, FakeStore);
eraseFromParent(FakeStore);
@@ -183,10 +180,10 @@ public:
llvm::Instruction *composeIntegerPC(revng::IRBuilder &B) const {
return MetaAddress::composeIntegerPC(B,
align(B, createLoad(B, AddressCSV)),
createLoad(B, EpochCSV),
createLoad(B, AddressSpaceCSV),
createLoad(B, TypeCSV));
align(B, B.createLoad(AddressCSV)),
B.createLoad(EpochCSV),
B.createLoad(AddressSpaceCSV),
B.createLoad(TypeCSV));
}
bool isPCSizedType(llvm::Type *T) const {
@@ -97,7 +97,7 @@ public:
TarWriter Writer(OS, TarFormat::Plain);
auto Objects = StorePair.first->objects();
std::vector<const ObjectID> ToSave(Objects.begin(), Objects.end());
std::vector<ObjectID> ToSave(Objects.begin(), Objects.end());
auto Serialized = StorePair.first->serialize(ToSave);
for (auto &[ObjectID, Data] : Serialized) {
@@ -20,7 +20,7 @@ public:
llvm::ArrayRef<char>> &Input) = 0;
virtual std::map<ObjectID, pypeline::Buffer>
serialize(llvm::ArrayRef<const ObjectID> ToSave) const = 0;
serialize(llvm::ArrayRef<ObjectID> ToSave) const = 0;
virtual void *get() = 0;
};
@@ -44,7 +44,7 @@ public:
}
virtual std::map<ObjectID, pypeline::Buffer>
serialize(llvm::ArrayRef<const ObjectID> ToSave) const override {
serialize(llvm::ArrayRef<ObjectID> ToSave) const override {
std::vector<const ObjectID *> Input;
for (const ObjectID &Element : ToSave)
Input.push_back(&Element);
+99
View File
@@ -4,10 +4,20 @@
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.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"
#include "revng/Support/IRHelpers.h"
namespace revng {
@@ -44,6 +54,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 +137,88 @@ 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);
}
llvm::LoadInst *createLoad(llvm::GlobalVariable *GV) {
return this->CreateLoad(GV->getValueType(), GV);
}
llvm::LoadInst *createLoad(llvm::AllocaInst *Alloca) {
return this->CreateLoad(Alloca->getAllocatedType(), Alloca);
}
llvm::LoadInst *createLoadVariable(llvm::Value *Variable) {
if (auto *Alloca = llvm::dyn_cast<llvm::AllocaInst>(Variable))
return createLoad(Alloca);
if (auto *GV = llvm::dyn_cast<llvm::GlobalVariable>(Variable))
return createLoad(GV);
revng_abort("Either GlobalVariable or AllocaInst expected");
}
void setInsertPointToFirstNonAlloca(llvm::Function &F) {
using namespace llvm;
for (Instruction &I : F.getEntryBlock()) {
if (not isa<AllocaInst>(&I)) {
SetInsertPoint(&I);
return;
}
}
revng_abort();
}
llvm::SmallVector<llvm::Value *, 4> unpack(llvm::Value *V) {
using namespace llvm;
Type *T = V->getType();
if (isa<IntegerType>(T))
return { V };
if (auto *ST = dyn_cast<StructType>(T)) {
SmallVector<Value *, 4> Result;
for (unsigned I = 0; I < ST->getNumElements(); ++I)
Result.push_back(this->CreateExtractValue(V, { I }));
return Result;
}
revng_abort("Cannot unpack the given type");
}
protected:
// NOLINTNEXTLINE
explicit IRBuilder(bool EnableDebugInformationChecks, llvm::LLVMContext &C) :
+7 -58
View File
@@ -31,7 +31,6 @@
#include "revng/Support/BasicBlockID.h"
#include "revng/Support/Debug.h"
#include "revng/Support/Generator.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/MetaAddress.h"
class ProgramCounterHandler;
@@ -1443,18 +1442,13 @@ inline void setPointersMetadata(Value *V,
QMD.tuple(PointerOperandsMD) }));
}
inline void setInsertPointToFirstNonAlloca(revng::IRBuilder &Builder,
llvm::Function &F) {
using namespace llvm;
BasicBlock &Entry = F.getEntryBlock();
for (Instruction &I : Entry) {
if (not isa<AllocaInst>(&I)) {
Builder.SetInsertPoint(&I);
return;
}
}
revng_abort();
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");
}
inline llvm::Value *getPointer(llvm::User *U) {
@@ -1495,51 +1489,6 @@ llvm::Function *changeFunctionType(llvm::Function &OldFunction,
llvm::Type *NewReturnType,
llvm::ArrayRef<llvm::Type *> NewArguments);
inline llvm::SmallVector<llvm::Value *, 4> unpack(revng::IRBuilder &Builder,
llvm::Value *V) {
using namespace llvm;
Type *Type = V->getType();
if (isa<IntegerType>(Type)) {
return { V };
} else if (auto *StructType = dyn_cast<llvm::StructType>(Type)) {
llvm::SmallVector<llvm::Value *, 4> Result;
for (unsigned I = 0; I < StructType->getNumElements(); ++I)
Result.push_back(Builder.CreateExtractValue(V, { I }));
return Result;
} else {
revng_abort("Cannot unpack the given type");
}
}
inline llvm::Instruction *createLoad(revng::IRBuilder &Builder,
llvm::GlobalVariable *GV) {
return Builder.CreateLoad(GV->getValueType(), GV);
}
inline llvm::Instruction *createLoad(revng::IRBuilder &Builder,
llvm::AllocaInst *Alloca) {
return Builder.CreateLoad(Alloca->getAllocatedType(), Alloca);
}
inline llvm::Instruction *createLoadVariable(revng::IRBuilder &Builder,
llvm::Value *Variable) {
if (auto *Alloca = llvm::dyn_cast<llvm::AllocaInst>(Variable))
return createLoad(Builder, Alloca);
else if (auto *GV = llvm::dyn_cast<llvm::GlobalVariable>(Variable))
return createLoad(Builder, GV);
else
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);
+1 -4
View File
@@ -11,14 +11,11 @@
#include "revng/ADT/KeyedObjectContainer.h"
#include "revng/Model/Architecture.h"
#include "revng/Runtime/PlainMetaAddress.h"
#include "revng/Support/Debug.h"
#include "revng/Support/IntegerSerialization.h"
#include "revng/Support/OverflowSafeInt.h"
extern "C" {
#include "revng/Runtime/PlainMetaAddress.h"
}
namespace llvm {
class TypeDefinition;
class Constant;
@@ -9,6 +9,7 @@
#include "revng/Model/FunctionTags.h"
#include "revng/Model/Register.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/OpaqueFunctionsPool.h"
namespace revng {
+15 -3
View File
@@ -151,20 +151,32 @@ private:
CUniquePtr<sqlite3_close_v2, SQLITE_OK> Connection;
public:
Database(llvm::StringRef Path) {
enum class OpenMode {
ReadWrite,
ReadOnly
};
Database(llvm::StringRef Path, OpenMode Mode) {
sqlite3 *Ptr = nullptr;
int Result;
if (Path == ":memory:")
if (Path == ":memory:") {
Result = sqlite3_open_v2("",
&Ptr,
SQLITE_OPEN_MEMORY | SQLITE_OPEN_PRIVATECACHE,
NULL);
else
} else if (Mode == OpenMode::ReadOnly) {
std::string URI = ("file:" + Path.str() + "?immutable=1");
Result = sqlite3_open_v2(URI.c_str(),
&Ptr,
SQLITE_OPEN_READONLY | SQLITE_OPEN_URI,
NULL);
} else {
Result = sqlite3_open_v2(Path.str().c_str(),
&Ptr,
SQLITE_OPEN_READWRITE,
NULL);
}
revng_assert(Result == SQLITE_OK);
Connection.reset(Ptr);
+1
View File
@@ -60,6 +60,7 @@
#include "revng/RestructureCFG/RestructureCFG.h"
#include "revng/Support/Assert.h"
#include "revng/Support/DecompilationHelpers.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/YAMLTraits.h"
#include "revng/TypeNames/LLVMTypeNames.h"
+2 -1
View File
@@ -8,6 +8,7 @@
#include "llvm/ADT/SmallVector.h"
#include "revng/BasicAnalyses/RemoveHelperCalls.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/OpaqueRegisterUser.h"
@@ -49,7 +50,7 @@ RemoveHelperCallsPass::run(llvm::Function &F,
// Assumption: helpers do not leave the stack altered, thus we can save the
// stack pointer and restore it back later.
auto *SP = createLoad(Builder, GCBI->spReg());
auto *SP = Builder.createLoad(GCBI->spReg());
auto *RetTy = cast<CallInst>(I)->getFunctionType()->getReturnType();
auto *OriginalHelperMarker = OFPOriginalHelper.get(RetTy,
+1 -1
View File
@@ -1138,7 +1138,7 @@ bool ArithmeticToGEPPass::runOnFunction(llvm::Function &F) {
{
GEPRewriter Rewriter(F);
std::set<const LocalValue<>> Replaced;
std::set<LocalValue<>> Replaced;
for (const LocalValue<> &PointerValue : Pointers) {
// This can happen because a likely pointer may also be an obvious
+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
+7 -4
View File
@@ -28,6 +28,7 @@
#include "revng/ADT/SmallMap.h"
#include "revng/ADT/ZipMapIterator.h"
#include "revng/Support/Debug.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
using namespace llvm;
@@ -273,7 +274,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 +286,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 +311,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 +426,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));
+1
View File
@@ -12,6 +12,7 @@
#include "llvm/Transforms/Utils/Local.h"
#include "revng/Model/FunctionTags.h"
#include "revng/Support/IRBuilder.h"
using namespace llvm;
+129
View File
@@ -0,0 +1,129 @@
//
// 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()) {
// Ignore unused 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
+1
View File
@@ -16,6 +16,7 @@
#include "revng/Model/LoadModelPass.h"
#include "revng/Support/Assert.h"
#include "revng/Support/DecompilationHelpers.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/YAMLTraits.h"
static Logger Log{ "fold-model-gep" };
+1
View File
@@ -15,6 +15,7 @@
#include "revng/Model/FunctionTags.h"
#include "revng/Model/IRHelpers.h"
#include "revng/Model/LoadModelPass.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/OpaqueFunctionsPool.h"
struct MakeLocalVariables : public llvm::FunctionPass {
+1
View File
@@ -19,6 +19,7 @@
#include "revng/Model/IRHelpers.h"
#include "revng/Model/LoadModelPass.h"
#include "revng/Support/Assert.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/YAMLTraits.h"
#include "revng/TypeNames/LLVMTypeNames.h"
+1
View File
@@ -46,6 +46,7 @@
#include "revng/Model/VerifyHelper.h"
#include "revng/Support/BlockType.h"
#include "revng/Support/Debug.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/YAMLTraits.h"
@@ -15,6 +15,7 @@
#include "revng/Model/FunctionTags.h"
#include "revng/Support/Assert.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/OpaqueFunctionsPool.h"
@@ -20,6 +20,7 @@
#include "revng/Model/FunctionTags.h"
#include "revng/Model/IRHelpers.h"
#include "revng/Model/LoadModelPass.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/OpaqueFunctionsPool.h"
+1
View File
@@ -16,6 +16,7 @@
#include "revng/Model/LoadModelPass.h"
#include "revng/Support/Assert.h"
#include "revng/Support/DecompilationHelpers.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/OpaqueFunctionsPool.h"
struct RemoveLoadStore : public llvm::FunctionPass {
+1
View File
@@ -9,6 +9,7 @@
#include "llvm/Pass.h"
#include "revng/Model/FunctionTags.h"
#include "revng/Support/IRBuilder.h"
struct RemovePointerCasts : public llvm::FunctionPass {
public:
@@ -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;
@@ -8,6 +8,7 @@
#include "revng/Model/FunctionTags.h"
#include "revng/Support/Debug.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/OpaqueFunctionsPool.h"
using namespace llvm;
+4 -2
View File
@@ -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,
@@ -13,6 +13,7 @@
#include "llvm/Transforms/Utils/Local.h"
#include "revng/Model/FunctionTags.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/OpaqueFunctionsPool.h"
struct TernaryReductionPass : public llvm::FunctionPass {
@@ -13,6 +13,7 @@
#include "llvm/Transforms/Utils/Local.h"
#include "revng/Model/FunctionTags.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/OpaqueFunctionsPool.h"
struct TwosComplementArithmeticNormalizationPass : public llvm::FunctionPass {
+4 -20
View File
@@ -1633,11 +1633,9 @@ private:
// Alloca instructions get special handling and are emitted as local
// variables in Clift:
if (auto *A = llvm::dyn_cast<llvm::AllocaInst>(&I)) {
const auto *NumElements = A->getArraySize();
// Non-constant alloca is not supported:
revng_assert(not NumElements
or llvm::isa<llvm::ConstantInt>(NumElements));
// Dynamic-size allocas are not supported: callers must encode the
// size in an `ArrayType` instead of using `alloca`'s ArraySize.
revng_assert(not A->isArrayAllocation());
std::optional<std::string> Handle;
@@ -1652,21 +1650,7 @@ private:
revng_assert(*A->getAllocationSizeInBits(*C.DataLayout) % 8 == 0);
llvm::Type *Allocated = A->getAllocatedType();
revng_assert(Allocated->isSized());
if (not Allocated->isArrayTy() and not A->isArrayAllocation()) {
Type = C.importLLVMType(Allocated);
} else {
uint64_t FieldBitSize = C.DataLayout->getTypeSizeInBits(Allocated);
revng_assert(FieldBitSize % 8 == 0);
uint64_t ElementSizeInBytes = FieldBitSize / 8;
const auto
*NumElements = cast<llvm::ConstantInt>(A->getArraySize());
uint64_t NBytes = NumElements->getZExtValue() * ElementSizeInBytes;
auto *ByteType = llvm::IntegerType::get(A->getContext(), 8);
auto *ByteArrayType = llvm::ArrayType::get(ByteType, NBytes);
Type = C.importLLVMType(ByteArrayType);
}
Type = C.importLLVMType(Allocated);
}
mlir::Location Loc = C.getLocation(A);
+5 -4
View File
@@ -37,6 +37,7 @@
#include "revng/Model/FunctionTags.h"
#include "revng/Support/BasicBlockID.h"
#include "revng/Support/Generator.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/MetaAddress.h"
#include "revng/Support/TemporaryLLVMOption.h"
@@ -382,12 +383,12 @@ CFGAnalyzer::State CFGAnalyzer::loadState(revng::IRBuilder &Builder) const {
LLVMContext &Context = M.getContext();
// Load the stack pointer
auto *SP0 = createLoad(Builder, GCBI.spReg());
auto *SP0 = Builder.createLoad(GCBI.spReg());
// Load the return address
Value *ReturnAddress = nullptr;
if (GlobalVariable *Register = GCBI.raReg()) {
ReturnAddress = createLoad(Builder, Register);
ReturnAddress = Builder.createLoad(Register);
} else {
auto *OpaquePointer = PointerType::get(Context, 0);
auto *StackPointerPointer = Builder.CreateIntToPtr(SP0, OpaquePointer);
@@ -409,7 +410,7 @@ CFGAnalyzer::State CFGAnalyzer::loadState(revng::IRBuilder &Builder) const {
SmallVector<Value *, 16> CSVs;
Type *IsRetTy = Type::getInt128Ty(Context);
for (auto *CSR : ABICSVs) {
auto *V = createLoad(Builder, CSR);
auto *V = Builder.createLoad(CSR);
CSVs.emplace_back(V);
}
@@ -1150,7 +1151,7 @@ void CallSummarizer::handleCall(MetaAddress CallerBlock,
// Adjust back the stack pointer
if (not IsTailCall) {
if (MaybeFSO.has_value()) {
auto *StackPointer = createLoad(Builder, SPCSV);
auto *StackPointer = Builder.createLoad(SPCSV);
Value *Offset = ConstantInt::get(StackPointer->getType(), *MaybeFSO);
auto *AdjustedStackPointer = Builder.CreateAdd(StackPointer, Offset);
Builder.CreateStore(AdjustedStackPointer, SPCSV);
+1
View File
@@ -40,6 +40,7 @@
#include "revng/Pipes/ModelGlobal.h"
#include "revng/Support/BasicBlockID.h"
#include "revng/Support/Debug.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/MetaAddress.h"
#include "revng/Support/OpaqueRegisterUser.h"
+2 -1
View File
@@ -16,6 +16,7 @@
#include "revng/EarlyFunctionAnalysis/CallHandler.h"
#include "revng/EarlyFunctionAnalysis/Outliner.h"
#include "revng/Model/IRHelpers.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/MetaAddress.h"
#include "revng/Support/OpaqueRegisterUser.h"
@@ -212,7 +213,7 @@ void Outliner::integrateFunctionCallee(CallHandler *TheCallHandler,
PointeeType = CSV->getValueType();
} else {
PointeeType = GCBI.spReg()->getValueType();
Pointer = Builder.CreateIntToPtr(createLoad(Builder, GCBI.spReg()),
Pointer = Builder.CreateIntToPtr(Builder.createLoad(GCBI.spReg()),
PointeeType->getPointerTo());
}
@@ -8,6 +8,7 @@
#include "revng/EarlyFunctionAnalysis/PromoteGlobalToLocalVars.h"
#include "revng/Model/FunctionTags.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/OpaqueRegisterUser.h"
@@ -48,7 +49,7 @@ PromoteGlobalToLocalPass::run(llvm::Function &F,
// Load all the CSVs and store their value onto the local variables.
for (const auto &[CSV, Alloca] : CSVMap)
Builder.CreateStore(createLoad(Builder, CSV), Alloca);
Builder.CreateStore(Builder.createLoad(CSV), Alloca);
return PreservedAnalyses::none();
}
+2 -1
View File
@@ -39,6 +39,7 @@
#include "revng/Pipes/RootKind.h"
#include "revng/Pipes/TaggedFunctionKind.h"
#include "revng/Support/BlockType.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/MetaAddress.h"
#include "revng/Support/OpaqueFunctionsPool.h"
@@ -292,7 +293,7 @@ static Value *loadCSVOrUndef(revng::IRBuilder &Builder,
auto *Type = IntegerType::get(M->getContext(), Size * 8);
return UndefValue::get(Type);
} else {
return createLoad(Builder, CSV);
return Builder.createLoad(CSV);
}
}
@@ -22,6 +22,7 @@
#include "revng/Pipes/Kinds.h"
#include "revng/Pipes/RootKind.h"
#include "revng/Pipes/TaggedFunctionKind.h"
#include "revng/Support/IRBuilder.h"
using namespace llvm;
using std::tuple;
@@ -167,7 +168,7 @@ public:
auto Name = model::Register::getCSVName(Register);
GlobalVariable *CSV = RootModule.getGlobalVariable(Name, true);
revng_assert(CSV != nullptr);
Arguments.push_back(createLoad(Builder, CSV));
Arguments.push_back(Builder.createLoad(CSV));
}
}
}
@@ -53,6 +53,7 @@
#include "revng/Pipes/StringMap.h"
#include "revng/Pipes/TaggedFunctionKind.h"
#include "revng/Support/Debug.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/MetaAddress.h"
#include "revng/Support/SimplePassManager.h"
+4 -3
View File
@@ -17,6 +17,7 @@
#include "revng/Pipes/Kinds.h"
#include "revng/Pipes/RootKind.h"
#include "revng/Pipes/TaggedFunctionKind.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
using namespace llvm;
@@ -227,7 +228,7 @@ Function *PromoteCSVs::createWrapper(const WrapperKey &Key) {
// Update values of the out arguments
unsigned OutArgument = FirstOutArgument;
for (GlobalVariable *CSV : Written) {
Builder.CreateStore(createLoad(Builder, CSV),
Builder.CreateStore(Builder.createLoad(CSV),
HelperWrapper->getArg(OutArgument));
++OutArgument;
}
@@ -283,7 +284,7 @@ void PromoteCSVs::wrap(CallInst *Call,
// Add arguments read
for (GlobalVariable *CSV : Read)
NewArguments.push_back(createLoad(Builder, CSV));
NewArguments.push_back(Builder.createLoad(CSV));
SmallVector<AllocaInst *, 16> WrittenCSVAllocas;
for (GlobalVariable *CSV : Written) {
@@ -300,7 +301,7 @@ void PromoteCSVs::wrap(CallInst *Call,
// Restore into CSV the written registers
for (const auto &[CSV, Alloca] : zip(Written, WrittenCSVAllocas))
Builder.CreateStore(createLoad(Builder, Alloca), CSV);
Builder.CreateStore(Builder.createLoad(Alloca), CSV);
// Erase the old call
eraseFromParent(Call);
@@ -4,6 +4,7 @@
#include "revng/FunctionIsolation/StructInitializers.h"
#include "revng/Model/FunctionTags.h"
#include "revng/Support/IRBuilder.h"
using namespace llvm;
+2 -1
View File
@@ -333,7 +333,8 @@ AccessFixer::decomposeMemcpy(llvm::Instruction &I) {
BasicBlock &Entry = I.getFunction()->getEntryBlock();
Builder.SetInsertPoint(&Entry, Entry.begin());
auto *UInt8Type = IntegerType::getInt8Ty(Abort.getContext());
auto *Storage = Builder.CreateAlloca(UInt8Type, 0, Size);
auto *StorageType = ArrayType::get(UInt8Type, Size->getZExtValue());
auto *Storage = Builder.CreateAlloca(StorageType);
uint64_t Alignment = Storage->getAlign().value();
auto &Read = Call;
auto &Write = *cast<CallInst>(Call.clone());
+1
View File
@@ -54,6 +54,7 @@
#include "revng/Model/RawBinaryView.h"
#include "revng/Support/CommandLine.h"
#include "revng/Support/Debug.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/SimplePassManager.h"
+2 -1
View File
@@ -11,6 +11,7 @@
#include "llvm/IR/PassManager.h"
#include "revng/Model/FunctionTags.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
using CSVToAllocaMap = llvm::DenseMap<llvm::GlobalVariable *,
@@ -42,7 +43,7 @@ public:
std::back_inserter(Arguments));
for (GlobalVariable *CSV : ReadCSVs)
Arguments.push_back(createLoadVariable(Builder, csvToAlloca(CSV)));
Arguments.push_back(Builder.createLoadVariable(csvToAlloca(CSV)));
CallInst *Result = Builder.CreateCall(getRandom(M, ReturnType), Arguments);
+2 -1
View File
@@ -20,6 +20,7 @@
#include "revng/BasicAnalyses/GeneratedCodeBasicInfo.h"
#include "revng/Model/ProgramCounterHandler.h"
#include "revng/Support/Debug.h"
#include "revng/Support/IRBuilder.h"
#include "ExternalJumpsHandler.h"
@@ -47,7 +48,7 @@ BasicBlock *ExternalJumpsHandler::createReturnFromExternal() {
// Identify the global variables to be serialized
GlobalVariable *SavedRegistersPtr = TheModule.getGlobalVariable("saved_"
"registers");
Instruction *SavedRegisters = createLoad(Builder, SavedRegistersPtr);
Instruction *SavedRegisters = Builder.createLoad(SavedRegistersPtr);
// TODO: if we do not support this architecture, here things will be
// completely broken
+1
View File
@@ -26,6 +26,7 @@
#include "revng/Lift/VariableManager.h"
#include "revng/Model/FunctionTags.h"
#include "revng/Support/Assert.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/RandomAccessIterator.h"
#include "revng/Support/Range.h"
+1
View File
@@ -13,6 +13,7 @@
#include "revng/Lift/LibTcg.h"
#include "revng/Model/ProgramCounterHandler.h"
#include "revng/Support/IRBuilder.h"
#include "JumpTargetManager.h"
+1
View File
@@ -16,6 +16,7 @@
#include "revng/Lift/Lift.h"
#include "revng/Model/FunctionTags.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/MetaAddress.h"
#include "revng/Support/SimplePassManager.h"
#include "revng/Support/Statistics.h"
+2 -1
View File
@@ -28,6 +28,7 @@
#include "revng/ABI/FunctionType/Layout.h"
#include "revng/BasicAnalyses/ShrinkInstructionOperandsPass.h"
#include "revng/FunctionCallIdentification/FunctionCallIdentification.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/OpaqueRegisterUser.h"
#include "revng/Support/Statistics.h"
@@ -546,7 +547,7 @@ RootAnalyzer::promoteCSVsToAlloca(Function *OptimizedFunction) {
replaceAllUsesInFunctionWith(OptimizedFunction, CSV, Alloca);
// Initialize the alloca
InitBuilder.CreateStore(createLoad(InitBuilder, CSV), Alloca);
InitBuilder.CreateStore(InitBuilder.createLoad(CSV), Alloca);
}
return CSVMap;
+1
View File
@@ -11,6 +11,7 @@
#include "llvm/Transforms/Utils/ValueMapper.h"
#include "revng/Model/Binary.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/MetaAddress.h"
#include "DropHelperCallsPass.h"
+4 -3
View File
@@ -32,6 +32,7 @@
#include "revng/Support/Assert.h"
#include "revng/Support/CommandLine.h"
#include "revng/Support/Debug.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
// This name corresponds to a function in `early-linked`.
@@ -243,7 +244,7 @@ VariableManager::storeToCPUStateOffset(revng::IRBuilder &Builder,
if (BitMask != 0 and StoreSize != FieldSize) {
// Load the value
auto *LoadEnvField = createLoad(Builder, Target);
auto *LoadEnvField = Builder.createLoad(Target);
auto *Blanked = Builder.CreateAnd(LoadEnvField, BitMask);
@@ -268,7 +269,7 @@ Value *VariableManager::loadFromCPUStateOffset(revng::IRBuilder &Builder,
return nullptr;
// Load the whole field
auto *LoadEnvField = createLoad(Builder, Target);
auto *LoadEnvField = Builder.createLoad(Target);
// Extract the desired part
// Shift right of the desired amount
@@ -351,7 +352,7 @@ void VariableManager::memOpAtEnvOffset(revng::IRBuilder &Builder,
StoreInst *New = nullptr;
if (EnvIsSrc) {
revng_assert(not IsMemset);
New = Builder.CreateStore(createLoad(Builder, EnvVar), OtherPtr);
New = Builder.CreateStore(Builder.createLoad(EnvVar), OtherPtr);
} else {
Type *CSVType = EnvVar->getValueType();
Value *ToStore = nullptr;
+5 -5
View File
@@ -150,7 +150,7 @@ LegacyVB::createLocalVariable(const model::Type &VariableType) {
// Here we should definitely use the builder that checks the debug info,
// but since this going to go away soon, let it stay as is.
revng::NonDebugInfoCheckingIRBuilder B(F->getContext());
setInsertPointToFirstNonAlloca(B, *F);
B.setInsertPointToFirstNonAlloca(*F);
Constant *ReferenceString = toLLVMString(VariableType, *F->getParent());
return B.CreateCall(LocalVarFunction, { ReferenceString });
}
@@ -189,7 +189,7 @@ LegacyVB::createCallStackArgumentVariable(const model::Type &VariableType) {
llvm::Constant *VarTypeString = toLLVMString(VariableType, *F->getParent());
revng::NonDebugInfoCheckingIRBuilder B(F->getContext());
setInsertPointToFirstNonAlloca(B, *F);
B.setInsertPointToFirstNonAlloca(*F);
Value *Size = ConstantInt::get(Types.InputPointerSizedInteger, VariableSize);
Instruction *Reference = B.CreateCall(getCallStackArgumentsAllocator(),
@@ -214,7 +214,7 @@ LegacyVB::createStackFrameVariable(model::UpcastableType FrameType) {
revng_assert(StackSize);
revng::NonDebugInfoCheckingIRBuilder B(F->getContext());
setInsertPointToFirstNonAlloca(B, *F);
B.setInsertPointToFirstNonAlloca(*F);
Instruction
*Reference = B.CreateCall(getStackFrameAllocator(),
@@ -301,7 +301,7 @@ VB::LocalVarType *VB::createLocalVariable(const model::Type &VariableType) {
revng_assert(VariableSize);
revng::NonDebugInfoCheckingIRBuilder B(F->getContext());
setInsertPointToFirstNonAlloca(B, *F);
B.setInsertPointToFirstNonAlloca(*F);
return B.CreateAlloca(llvm::ArrayType::get(Types.Int8Ty, VariableSize));
}
@@ -310,7 +310,7 @@ template<>
std::pair<VB::LocalVarType *, llvm::Instruction *>
VB::createLocalVariableAndTakeIntAddress(const model::Type &VariableType) {
revng::NonDebugInfoCheckingIRBuilder B(F->getContext());
setInsertPointToFirstNonAlloca(B, *F);
B.setInsertPointToFirstNonAlloca(*F);
auto *Variable = createLocalVariable(VariableType);
return {
Variable,
+1
View File
@@ -4,6 +4,7 @@
#include "revng/Model/FunctionTags.h"
#include "revng/Model/ProgramCounterHandler.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
namespace FunctionTags {
@@ -84,7 +84,8 @@ private:
sqlite::Database Database;
public:
PrototypeDatabase(llvm::StringRef Path) : Database(Path) {}
PrototypeDatabase(llvm::StringRef Path) :
Database(Path, sqlite::Database::OpenMode::ReadOnly) {}
/// Find a platform by its exact name.
/// Returns -1 if no platform with that name exists.
+17 -16
View File
@@ -10,6 +10,7 @@
#include "revng/Model/FunctionTags.h"
#include "revng/Model/ProgramCounterHandler.h"
#include "revng/Support/Assert.h"
#include "revng/Support/IRBuilder.h"
// This name corresponds to a function in `early-linked`.
RegisterIRHelper SetMetaAddressHelper("set_PlainMetaAddress");
@@ -62,7 +63,7 @@ public:
}
Value *loadJumpablePC(revng::IRBuilder &Builder) const final {
return createLoad(Builder, AddressCSV);
return Builder.createLoad(AddressCSV);
}
std::array<Value *, 4>
@@ -156,10 +157,10 @@ private:
}
Value *loadJumpablePC(revng::IRBuilder &Builder) const final {
auto *Address = createLoad(Builder, AddressCSV);
auto *Address = Builder.createLoad(AddressCSV);
auto *AddressType = Address->getType();
return Builder.CreateOr(Address,
Builder.CreateZExt(createLoad(Builder, IsThumb),
Builder.CreateZExt(Builder.createLoad(IsThumb),
AddressType));
}
@@ -411,10 +412,10 @@ static void setPlainMetaAddressImpl(revng::IRBuilder &Builder,
void PCH::setCurrentPCPlainMetaAddress(revng::IRBuilder &Builder) const {
setPlainMetaAddressImpl(Builder,
"current_pc",
createLoad(Builder, EpochCSV),
createLoad(Builder, AddressSpaceCSV),
createLoad(Builder, TypeCSV),
createLoad(Builder, AddressCSV));
Builder.createLoad(EpochCSV),
Builder.createLoad(AddressSpaceCSV),
Builder.createLoad(TypeCSV),
Builder.createLoad(AddressCSV));
}
void PCH::setLastPCPlainMetaAddress(revng::IRBuilder &Builder,
@@ -618,10 +619,10 @@ public:
bool Empty = Root->case_begin() == Root->case_end();
if (Empty) {
revng::NonDebugInfoCheckingIRBuilder Builder(Root);
CurrentEpoch = createLoad(Builder, EpochCSV);
CurrentAddressSpace = createLoad(Builder, AddressSpaceCSV);
CurrentType = createLoad(Builder, TypeCSV);
CurrentAddress = createLoad(Builder, AddressCSV);
CurrentEpoch = Builder.createLoad(EpochCSV);
CurrentAddressSpace = Builder.createLoad(AddressSpaceCSV);
CurrentType = Builder.createLoad(TypeCSV);
CurrentAddress = Builder.createLoad(AddressCSV);
} else {
// Get the switches of the the first MA. This is just in order to get a
// reference to their conditions
@@ -819,10 +820,10 @@ PCH::buildDispatcher(DispatcherTargets &Targets,
});
// First of all, create code to load the components of the MetaAddress
Value *CurrentEpoch = createLoad(Builder, EpochCSV);
Value *CurrentAddressSpace = createLoad(Builder, AddressSpaceCSV);
Value *CurrentType = createLoad(Builder, TypeCSV);
Value *CurrentAddress = createLoad(Builder, AddressCSV);
Value *CurrentEpoch = Builder.createLoad(EpochCSV);
Value *CurrentAddressSpace = Builder.createLoad(AddressSpaceCSV);
Value *CurrentType = Builder.createLoad(TypeCSV);
Value *CurrentAddress = Builder.createLoad(AddressCSV);
SwitchManager SM(Default,
CurrentEpoch,
@@ -952,7 +953,7 @@ void PCH::buildHotPath(revng::IRBuilder &B,
auto &[Address, BB] = CandidateTarget;
auto CreateCmp = [&B](GlobalVariable *CSV, uint64_t Value) {
Instruction *Load = createLoad(B, CSV);
Instruction *Load = B.createLoad(CSV);
Type *LoadType = Load->getType();
return B.CreateICmpEQ(Load, ConstantInt::get(LoadType, Value));
};
+2
View File
@@ -23,6 +23,8 @@ model::TypeDefinition::trySize(VerifyHelper &VH) const {
Result = rc_recur E->UnderlyingType()->trySize(VH);
} else if (auto *T = llvm::dyn_cast<model::TypedefDefinition>(this)) {
// TODO: in case of a recursive type (not via a pointer), we'll get an
// assertion, instead of a clean failure
Result = rc_recur T->UnderlyingType()->trySize(VH);
} else if (auto *S = llvm::dyn_cast<model::StructDefinition>(this)) {
+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);
@@ -6,6 +6,7 @@
#include "revng/Model/FunctionTags.h"
#include "revng/PromoteStackPointer/InjectStackSizeProbesAtCallSites.h"
#include "revng/PromoteStackPointer/InjectStackSizeProbesAtCallSitesPass.h"
#include "revng/Support/IRBuilder.h"
// This name is not present after `CleanupStackSizeMarkers`.
RegisterIRHelper StackSizeAtCallSite("stack_size_at_call_site");
@@ -33,9 +34,9 @@ static bool injectStackSizeProbesAtCallSites(llvm::Module &M,
for (Function &F : FunctionTags::Isolated.functions(&M)) {
if (F.isDeclaration())
continue;
setInsertPointToFirstNonAlloca(B, F);
B.setInsertPointToFirstNonAlloca(F);
auto *SP0 = createLoad(B, SP);
auto *SP0 = B.createLoad(SP);
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
@@ -45,7 +46,7 @@ static bool injectStackSizeProbesAtCallSites(llvm::Module &M,
B.SetInsertPoint(&I);
// Inject a call to the marker. First argument is sp - sp0
auto *Call = B.CreateCall(SSACS, B.CreateSub(SP0, createLoad(B, SP)));
auto *Call = B.CreateCall(SSACS, B.CreateSub(SP0, B.createLoad(SP)));
Call->copyMetadata(I);
}
}
@@ -8,6 +8,7 @@
#include "revng/Model/FunctionTags.h"
#include "revng/Model/IRHelpers.h"
#include "revng/PromoteStackPointer/InstrumentStackAccessesPass.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/OpaqueFunctionsPool.h"
@@ -32,6 +32,7 @@
#include "revng/PromoteStackPointer/PromoteStackPointerPass.h"
#include "revng/Support/Assert.h"
#include "revng/Support/Debug.h"
#include "revng/Support/IRBuilder.h"
// This name is not present after `promote-stack-pointer`.
RegisterIRHelper UndefinedLocalSPMarker("revng_undefined_local_sp");
@@ -77,7 +78,7 @@ static bool adjustStackAfterCalls(const model::Binary &Binary,
Changed = true;
B.SetInsertPoint(I.getNextNode());
B.CreateStore(B.CreateAdd(createLoad(B, GlobalSP), FSO), GlobalSP);
B.CreateStore(B.CreateAdd(B.createLoad(GlobalSP), FSO), GlobalSP);
}
}
}
@@ -169,7 +170,7 @@ static bool promoteStackPointer(const model::Binary &Binary,
AllocaInst *LocalSP = Builder.CreateAlloca(SPType, nullptr, "local_sp");
// Call InitLocalSP, to initialize the value of the local stack pointer.
setInsertPointToFirstNonAlloca(Builder, F);
Builder.setInsertPointToFirstNonAlloca(F);
auto *SPVal = Builder.CreateCall(InitLocalSP);
// Store the initial SP value in the new alloca.
@@ -1230,7 +1230,7 @@ void SegregateFunctionStack<Legacy>::upgrade() {
// TODO: the checks should be enabled conditionally based on the user.
revng::NonDebugInfoCheckingIRBuilder B(NewFunction->getContext());
setInsertPointToFirstNonAlloca(B, *NewFunction);
B.setInsertPointToFirstNonAlloca(*NewFunction);
lowerArguments(B);
@@ -7,6 +7,7 @@
#include "revng/Model/FunctionTags.h"
#include "revng/RemoveExtractValues/RemoveExtractValuesPass.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/OpaqueFunctionsPool.h"
using namespace llvm;
+8 -7
View File
@@ -3,6 +3,7 @@
//
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
@@ -14,6 +15,7 @@
#include "revng/Model/FunctionTags.h"
#include "revng/Model/LoadModelPass.h"
#include "revng/RemoveLiftingArtifacts/CleanupIR.h"
#include "revng/Support/IRBuilder.h"
using namespace llvm;
@@ -83,20 +85,19 @@ bool CleanupIRPass::Impl::replaceInstructions(Function &F) {
FunctionTags::AllocatesLocalVariable)) {
revng::IRBuilder Builder(Context);
Builder.SetInsertPointPastAllocas(Call->getFunction());
Value *AllocatedSize = nullptr;
uint64_t AllocatedBytes = 0;
if (auto *Callee = getCalledFunction(Call);
Callee and Callee->getName().startswith("revng_stack_frame")) {
AllocatedSize = Call->getArgOperand(0);
auto *Size = cast<ConstantInt>(Call->getArgOperand(0));
AllocatedBytes = Size->getZExtValue();
} else {
model::UpcastableType
AllocatedType = fromLLVMString(Call->getArgOperand(0), Model);
AllocatedSize = ConstantInt::get(Context,
APInt(/*NumBits*/ 64,
AllocatedType->size().value()));
AllocatedBytes = AllocatedType->size().value();
}
auto *Int8Type = IntegerType::getInt8Ty(Context);
auto *Alloca = Builder.CreateAlloca(Int8Type,
/* ArraySize */ AllocatedSize);
auto *Alloca = Builder.CreateAlloca(ArrayType::get(Int8Type,
AllocatedBytes));
// Some uses of the Call can be replaced directly with GEPs in the Alloca.
for (Use &U : Call->uses()) {
@@ -34,6 +34,7 @@
#include "revng/Pipes/Kinds.h"
#include "revng/RemoveLiftingArtifacts/MakeSegmentRef.h"
#include "revng/Support/Debug.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/MetaAddress.h"
#include "revng/Support/OpaqueFunctionsPool.h"
@@ -11,6 +11,7 @@
#include "revng/RestructureCFG/ScopeGraphGraphTraits.h"
#include "revng/RestructureCFG/ScopeGraphUtils.h"
#include "revng/Support/GraphAlgorithms.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
using namespace llvm;
+1
View File
@@ -10,6 +10,7 @@
#include "revng/Model/FunctionTags.h"
#include "revng/RestructureCFG/ScopeGraphUtils.h"
#include "revng/Support/IRBuilder.h"
#include "revng/Support/IRHelpers.h"
using namespace llvm;
+1
View File
@@ -15,6 +15,7 @@
#include "revng/RestructureCFG/ASTTree.h"
#include "revng/RestructureCFG/ExprNode.h"
#include "revng/Support/Assert.h"
#include "revng/Support/IRBuilder.h"
#include "SimplifyHybridNot.h"
+1
View File
@@ -14,6 +14,7 @@ revng_add_library_internal(
CommonOptions.cpp
CustomizedLLVMPasses.cpp
Debug.cpp
DropRedundantPtrIntCasts.cpp
ExplicitSpecializations.cpp
FileSystem.cpp
InitRevng.cpp
+84
View File
@@ -0,0 +1,84 @@
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/Pass.h"
using namespace llvm;
namespace {
/// `inttoptr` already does an implicit zero-extension when its operand is
/// narrower than the target pointer, and `ptrtoint` already truncates when the
/// target integer is narrower than the pointer.
/// This pass exploits this fact turning:
///
/// %w = zext iN %x to iM
/// %p = inttoptr iM %w to ptr
/// %w = ptrtoint ptr %p to iM
/// %t = trunc iM %w to iN
///
/// into:
///
/// %p = inttoptr iN %x to ptr
/// %t = ptrtoint ptr %p to iN
///
/// \note instcombine reverts these changes, so you might want to run this
// close to the leaves of your pipeline.
struct DropRedundantPtrIntCasts : public FunctionPass {
static char ID;
DropRedundantPtrIntCasts() : FunctionPass(ID) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
}
bool runOnFunction(Function &F) override {
bool Changed = false;
SmallVector<Instruction *, 16> ToErase;
for (auto &I : llvm::instructions(F)) {
if (auto *IntToPtr = dyn_cast<IntToPtrInst>(&I)) {
if (auto *ZeroExtend = dyn_cast<ZExtInst>(IntToPtr->getOperand(0))) {
IRBuilder<> B(IntToPtr);
auto *New = B.CreateIntToPtr(ZeroExtend->getOperand(0),
IntToPtr->getType());
if (auto *NewI = dyn_cast<Instruction>(New))
NewI->copyMetadata(*IntToPtr);
IntToPtr->replaceAllUsesWith(New);
ToErase.push_back(IntToPtr);
Changed = true;
}
} else if (auto *TR = dyn_cast<TruncInst>(&I)) {
if (auto *PtrToInt = dyn_cast<PtrToIntInst>(TR->getOperand(0))) {
IRBuilder<> B(TR);
auto *New = B.CreatePtrToInt(PtrToInt->getPointerOperand(),
TR->getType());
if (auto *NewI = dyn_cast<Instruction>(New))
NewI->copyMetadata(*TR);
TR->replaceAllUsesWith(New);
ToErase.push_back(TR);
Changed = true;
}
}
}
for (auto *I : ToErase)
I->eraseFromParent();
return Changed;
}
};
} // namespace
char DropRedundantPtrIntCasts::ID = 0;
using Register = RegisterPass<DropRedundantPtrIntCasts>;
static Register X("drop-redundant-ptrint-casts", "", false, false);
+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:
@@ -17,5 +17,5 @@ commands:
- type: source
filter: db-invariants
command: |-
sqlite3 "$SOURCES_ROOT/share/revng/prototypes.sqlite" < "$INPUT"
sqlite3 -cmd ".open \"file:$SOURCES_ROOT/share/revng/prototypes.sqlite?immutable=1\"" < "$INPUT"
| FileCheck "$INPUT"
@@ -16,7 +16,7 @@ commands:
revng model override-by-name
"$OUTPUT/context/model.yml"
${SOURCE}.override.yml
${SOURCE}.override.$QEMU_NAME.yml
> "$OUTPUT/context/model-tmp.yml";
mv "$OUTPUT/context/model-tmp.yml" "$OUTPUT/context/model.yml";
@@ -25,6 +25,7 @@ commands:
revng analyze --resume "$OUTPUT" detect-stack-size "$INPUT" -o /dev/null;
revng artifact --resume "$OUTPUT" segregate-stack-accesses "$INPUT" |
revng opt -S | FileCheck ${SOURCE}.filecheck.ll;
revng opt -remove-llvmassume-calls -instcombine-noarrays -sroa-noarrays -drop-redundant-ptrint-casts -dce -type-shrinking -dce -drop-redundant-ptrint-casts -early-cse -instsimplify -dce -S |
FileCheck --check-prefix=CHECK-$QEMU_NAME ${SOURCE}.filecheck.ll;
revng artifact --resume "$OUTPUT" emit-c "$INPUT" -o /dev/null;
@@ -2,163 +2,332 @@
; This file is distributed under the MIT License. See LICENSE.md for details.
;
CHECK: define i64 @local_raw_primitives_on_registers(i64 %[[ARG1:.*]], i64 %[[ARG2:.*]]) [[IGN:.*]] {
CHECK-DAG: add i64 [[IGN:.*]]%[[ARG1]]
CHECK-DAG: add i64 [[IGN:.*]]%[[ARG2]]
CHECK: }
; This file mixes checks for what we expect to happen on a x86-64 binarya and an
; i386 binary. In this case, the i386 binary is interesting due to SystemV ABI
; making heavy use of stack arguments.
CHECK: define i64 @local_call_raw_primitives_on_registers() [[IGN:.*]] {
CHECK-DAG: = call i64 @local_raw_primitives_on_registers(i64 2, i64 1)
CHECK: }
; raw_primitives_on_registers
CHECK: define i64 @local_raw_pointers_on_registers(i64 %[[ARG1:.*]], i64 %[[ARG2:.*]]) [[IGN:.*]] {
CHECK-DAG: %[[ARG1_PTR:.*]] = inttoptr i64 %[[ARG1]] to ptr
CHECK-DAG: load i64, ptr %[[ARG1_PTR:.*]]
CHECK-DAG: %[[ARG2_PTR:.*]] = inttoptr i64 %[[ARG2]] to ptr
CHECK-DAG: load i64, ptr %[[ARG2_PTR]]
CHECK: }
CHECK-x86_64: define i64 @local_raw_primitives_on_registers(i64 %[[ARG1:.*]], i64 %[[ARG2:.*]]) [[IGN:.*]] {
CHECK-x86_64-DAG: add i64 [[IGN:.*]]%[[ARG1]]
CHECK-x86_64-DAG: add i64 [[IGN:.*]]%[[ARG2]]
CHECK-x86_64: }
CHECK: define i64 @local_call_raw_pointers_on_registers() [[IGN:.*]] {
CHECK-DAG: = call i64 @local_raw_pointers_on_registers(i64 [[ARG:.*]], i64 [[ARG]])
CHECK: }
CHECK-x86_64: define i64 @local_call_raw_primitives_on_registers() [[IGN:.*]] {
CHECK-x86_64-DAG: = call i64 @local_raw_primitives_on_registers(i64 2, i64 1)
CHECK-x86_64: }
CHECK: define i64 @local_raw_primitives_on_stack(i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[STACK_ARG:.*]]) [[IGN:.*]] {
CHECK-DAG: %[[STACK_ARG8:.*]] = add i64 %[[STACK_ARG]], 8
CHECK-DAG: %[[STACK_ARG8_PTR:.*]] = inttoptr i64 %[[STACK_ARG8]] to ptr
CHECK-DAG: load i64, ptr %[[STACK_ARG8_PTR:.*]]
CHECK-DAG: %[[STACK_ARG_PTR:.*]] = inttoptr i64 %[[STACK_ARG]] to ptr
CHECK-DAG: load i64, ptr %[[STACK_ARG_PTR]]
CHECK: }
; raw_pointers_on_registers
CHECK: define i64 @local_call_raw_primitives_on_stack() [[IGN:.*]] {
CHECK-DAG: %[[STACK:.*]] = alloca [16 x i8]
CHECK-DAG: %[[STACK_INT:.*]] = ptrtoint ptr %[[STACK]] to i64
CHECK-DAG: %[[STACK_INT_8:.*]] = add i64 %[[STACK_INT]], 8
CHECK-DAG: %[[STACK_8:.*]] = inttoptr i64 %[[STACK_INT_8]] to ptr
CHECK-DAG: store i64 8, ptr %[[STACK_8]]
CHECK-DAG: store i64 7, ptr %[[STACK]]
CHECK-DAG: = call i64 @local_raw_primitives_on_stack(i64 4, i64 3, i64 2, i64 1, i64 5, i64 6, i64 %[[STACK_INT]])
CHECK: }
CHECK-x86_64: define i64 @local_raw_pointers_on_registers(i64 %[[ARG1:.*]], i64 %[[ARG2:.*]]) [[IGN:.*]] {
CHECK-x86_64-DAG: %[[ARG1_PTR:.*]] = inttoptr i64 %[[ARG1]] to ptr
CHECK-x86_64-DAG: load i64, ptr %[[ARG1_PTR]]
CHECK-x86_64-DAG: %[[ARG2_PTR:.*]] = inttoptr i64 %[[ARG2]] to ptr
CHECK-x86_64-DAG: load i64, ptr %[[ARG2_PTR]]
CHECK-x86_64: }
CHECK: define i64 @local_cabi_primitives_on_registers(i64 %[[ARG1:.*]], i64 %[[ARG2:.*]]) [[IGN:.*]] {
CHECK-DAG: add i64 [[IGN:.*]]%[[ARG1]]
CHECK-DAG: add i64 [[IGN:.*]]%[[ARG2]]
CHECK: }
CHECK-x86_64: define i64 @local_call_raw_pointers_on_registers() [[IGN:.*]] {
CHECK-x86_64-DAG: = call i64 @local_raw_pointers_on_registers(i64 [[ARG:.*]], i64 [[ARG]])
CHECK-x86_64: }
CHECK: define i64 @local_call_cabi_primitives_on_registers() [[IGN:.*]] {
CHECK-DAG: = call i64 @local_cabi_primitives_on_registers(i64 1, i64 2)
CHECK: }
; raw_primitives_on_stack
CHECK: define i64 @local_cabi_primitives_on_stack(i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[STACK_ARG1:.*]], i64 %[[STACK_ARG2:.*]]) [[IGN:.*]] {
CHECK-DAG: %[[IGN:.*]] = add i64 %[[IGN:.*]]%[[STACK_ARG1]]
CHECK-DAG: %[[IGN:.*]] = add i64 %[[IGN:.*]]%[[STACK_ARG2]]
CHECK: }
CHECK-x86_64: define i64 @local_raw_primitives_on_stack(i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[STACK_ARG:.*]]) [[IGN:.*]] {
CHECK-x86_64-DAG: %[[STACK_ARG8:.*]] = add i64 %[[STACK_ARG]], 8
CHECK-x86_64-DAG: %[[STACK_ARG8_PTR:.*]] = inttoptr i64 %[[STACK_ARG8]] to ptr
CHECK-x86_64-DAG: load i64, ptr %[[STACK_ARG8_PTR]]
CHECK-x86_64-DAG: %[[STACK_ARG_PTR:.*]] = inttoptr i64 %[[STACK_ARG]] to ptr
CHECK-x86_64-DAG: load i64, ptr %[[STACK_ARG_PTR]]
CHECK-x86_64: }
CHECK: define i64 @local_call_cabi_primitives_on_stack() [[IGN:.*]] {
CHECK-DAG: = call i64 @local_cabi_primitives_on_stack(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 [[SCALAR1:.*]], i64 [[SCALAR2:.*]])
CHECK: }
CHECK-x86_64: define i64 @local_call_raw_primitives_on_stack() [[IGN:.*]] {
CHECK-x86_64-DAG: %[[STACK:.*]] = alloca [16 x i8]
CHECK-x86_64-DAG: %[[STACK_INT:.*]] = ptrtoint ptr %[[STACK]] to i64
CHECK-x86_64-DAG: %[[STACK_INT_8:.*]] = add i64 %[[STACK_INT]], 8
CHECK-x86_64-DAG: %[[STACK_8:.*]] = inttoptr i64 %[[STACK_INT_8]] to ptr
CHECK-x86_64-DAG: store i64 8, ptr %[[STACK_8]]
CHECK-x86_64-DAG: store i64 7, ptr %[[STACK]]
CHECK-x86_64-DAG: = call i64 @local_raw_primitives_on_stack(i64 4, i64 3, i64 2, i64 1, i64 5, i64 6, i64 %[[STACK_INT]])
CHECK-x86_64: }
CHECK: define i64 @local_cabi_aggregate_on_registers(i64 %[[ARG1:.*]]) [[IGN:.*]] {
CHECK-DAG: %[[FIELD1_PTR:.*]] = inttoptr i64 %[[ARG1]] to ptr
CHECK-DAG: load i64, ptr %[[FIELD1_PTR]]
CHECK-DAG: %[[FIELD2_ADDR:.*]] = add i64 %[[ARG1]], 8
CHECK-DAG: %[[FIELD2_PTR:.*]] = inttoptr i64 %[[FIELD2_ADDR]] to ptr
CHECK-DAG: load i64, ptr %[[FIELD2_PTR]], align 8
CHECK: }
; cabi_primitives_on_registers
CHECK: define i64 @local_call_cabi_aggregate_on_registers() [[IGN:.*]] {
CHECK-DAG: %[[STACK:.*]] = alloca [16 x i8]
CHECK-DAG: %[[STACK_INT:.*]] = ptrtoint ptr %[[STACK]] to i64
CHECK-DAG: store i64 1, ptr %[[STACK]]
CHECK-DAG: %[[STACK_INT_8:.*]] = add i64 %[[STACK_INT]], 8
CHECK-DAG: %[[STACK_8:.*]] = inttoptr i64 %[[STACK_INT_8]] to ptr
CHECK-DAG: store i64 2, ptr %[[STACK_8]]
CHECK-DAG: = call i64 @local_cabi_aggregate_on_registers(i64 %[[STACK_INT]])
CHECK: }
CHECK-x86_64: define i64 @local_cabi_primitives_on_registers(i64 %[[ARG1:.*]], i64 %[[ARG2:.*]]) [[IGN:.*]] {
CHECK-x86_64-DAG: add i64 [[IGN:.*]]%[[ARG1]]
CHECK-x86_64-DAG: add i64 [[IGN:.*]]%[[ARG2]]
CHECK-x86_64: }
CHECK: define i64 @local_cabi_aggregate_on_stack(i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[STACK_ARG:.*]]) [[IGN:.*]] {
CHECK-DAG: %[[FIELD1_PTR:.*]] = inttoptr i64 %[[STACK_ARG]] to ptr
CHECK-DAG: load i64, ptr %[[FIELD1_PTR]]
CHECK-DAG: %[[FIELD2_ADDR:.*]] = add i64 %[[STACK_ARG]], 8
CHECK-DAG: %[[FIELD2_PTR:.*]] = inttoptr i64 %[[FIELD2_ADDR]] to ptr
CHECK-DAG: load i64, ptr %[[FIELD2_PTR]]
CHECK: }
CHECK-x86_64: define i64 @local_call_cabi_primitives_on_registers() [[IGN:.*]] {
CHECK-x86_64-DAG: = call i64 @local_cabi_primitives_on_registers(i64 1, i64 2)
CHECK-x86_64: }
CHECK: define i64 @local_call_cabi_aggregate_on_stack() [[IGN:.*]] {
CHECK-DAG: %[[STACK:.*]] = alloca [16 x i8]
CHECK-DAG: %[[STACK_INT:.*]] = ptrtoint ptr %[[STACK]] to i64
CHECK-DAG: store i64 1, ptr %[[STACK]]
CHECK-DAG: %[[STACK_INT_8:.*]] = add i64 %[[STACK_INT]], 8
CHECK-DAG: %[[STACK_8:.*]] = inttoptr i64 %[[STACK_INT_8]] to ptr
CHECK-DAG: store i64 2, ptr %[[STACK_8]]
CHECK-DAG: = call i64 @local_cabi_aggregate_on_stack(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 %[[STACK_INT]])
CHECK: }
CHECK-i386: define i32 @local_cabi_primitives_on_registers(i32 %[[A:.*]], i32 %[[B:.*]]) [[IGN:.*]] {
CHECK-i386-DAG: %[[T1:.*]] = add i32 {{.*}}, %[[A]]
CHECK-i386-DAG: %[[T2:.*]] = add i32 %[[T1]], %[[B]]
CHECK-i386: ret i32 %[[T2]]
CHECK-i386: }
CHECK: define i64 @local_cabi_aggregate_on_stack_and_registers(i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[STACK_ARG:.*]]) [[IGN:.*]] {
CHECK-DAG: %[[FIELD1_PTR:.*]] = inttoptr i64 %[[STACK_ARG]] to ptr
CHECK-DAG: load i64, ptr %[[FIELD1_PTR]]
CHECK-DAG: %[[FIELD2_ADDR:.*]] = add i64 %[[STACK_ARG]], 8
CHECK-DAG: %[[FIELD2_PTR:.*]] = inttoptr i64 %[[FIELD2_ADDR]] to ptr
CHECK-DAG: load i64, ptr %[[FIELD2_PTR]]
CHECK: }
CHECK-i386: define i32 @local_call_cabi_primitives_on_registers() [[IGN:.*]] {
CHECK-i386: %[[CALL:.*]] = call i32 @local_cabi_primitives_on_registers(i32 1, i32 2)
CHECK-i386: %[[RET:.*]] = add i32 %[[CALL]], {{.*}}
CHECK-i386: ret i32 %[[RET]]
CHECK-i386: }
CHECK: define i64 @local_call_cabi_aggregate_on_stack_and_registers() [[IGN:.*]] {
CHECK-DAG: %[[STACK:.*]] = alloca [16 x i8]
CHECK-DAG: %[[STACK_INT:.*]] = ptrtoint ptr %[[STACK]] to i64
CHECK-DAG: store i64 1, ptr %[[STACK]]
CHECK-DAG: %[[STACK_INT_8:.*]] = add i64 %[[STACK_INT]], 8
CHECK-DAG: %[[STACK_8:.*]] = inttoptr i64 %[[STACK_INT_8]] to ptr
CHECK-DAG: store i64 2, ptr %[[STACK_8]]
CHECK-DAG: = call i64 @local_cabi_aggregate_on_stack_and_registers(i64 1, i64 2, i64 3, i64 4, i64 5, i64 %[[STACK_INT]])
CHECK: }
; cabi_primitives_on_stack
CHECK: define <{ i64, i64 }> @local_raw_return_small_aggregate() [[IGN:.*]] {
CHECK-DAG: %[[RESULT:.*]] = call <{ i64, i64 }> @struct_initializer(i64 124, i64 123)
CHECK-DAG: ret <{ i64, i64 }> %[[RESULT]]
CHECK: }
CHECK-x86_64: define i64 @local_cabi_primitives_on_stack(i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[STACK_ARG1:.*]], i64 %[[STACK_ARG2:.*]]) [[IGN:.*]] {
CHECK-x86_64-DAG: %[[IGN:.*]] = add i64 %[[IGN:.*]]%[[STACK_ARG1]]
CHECK-x86_64-DAG: %[[IGN:.*]] = add i64 %[[IGN:.*]]%[[STACK_ARG2]]
CHECK-x86_64: }
CHECK: define i64 @local_call_raw_return_small_aggregate() [[IGN:.*]] {
CHECK: %[[RESULT:.*]] = call <{ i64, i64 }> @local_raw_return_small_aggregate()
CHECK-DAG: call i64 @OpaqueExtractvalue(<{ i64, i64 }> %[[RESULT]], i64 1)
CHECK: }
CHECK-x86_64: define i64 @local_call_cabi_primitives_on_stack() [[IGN:.*]] {
CHECK-x86_64-DAG: = call i64 @local_cabi_primitives_on_stack(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 [[SCALAR1:.*]], i64 [[SCALAR2:.*]])
CHECK-x86_64: }
CHECK: define [16 x i8] @local_cabi_return_small_aggregate() [[IGN:.*]] {
CHECK-DAG: %[[RETURN_ALLOCA:.*]] = alloca [16 x i8]
CHECK-DAG: %[[RETURN_ALLOCA_INT:.*]] = ptrtoint ptr %[[RETURN_ALLOCA]] to i64
CHECK-DAG: %[[RETURN_ALLOCA_INT_8:.*]] = add i64 %[[RETURN_ALLOCA_INT]], 8
CHECK-DAG: %[[RETURN_ALLOCA_8:.*]] = inttoptr i64 %[[RETURN_ALLOCA_INT_8]] to ptr
CHECK-DAG: store i64 124, ptr %[[RETURN_ALLOCA]]
CHECK-DAG: store i64 123, ptr %[[RETURN_ALLOCA_8]]
CHECK-DAG: %[[TO_RETURN:.*]] = load [16 x i8], ptr %[[RETURN_ALLOCA]]
CHECK-DAG: ret [16 x i8] %[[TO_RETURN]]
CHECK: }
CHECK-i386: define i32 @local_cabi_primitives_on_stack(i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[G:.*]], i32 %[[H:.*]]) [[IGN:.*]] {
CHECK-i386: %[[T1:.*]] = add i32 {{.*}}, %[[G]]
CHECK-i386: %[[T2:.*]] = add i32 %[[T1]], %[[H]]
CHECK-i386: ret i32 %[[T2]]
CHECK-i386: }
CHECK: define i64 @local_call_cabi_return_small_aggregate() [[IGN:.*]] {
CHECK-DAG: %[[RETURN_ALLOCA:.*]] = alloca [16 x i8]
CHECK-DAG: %[[RETURN_ALLOCA_INT:.*]] = ptrtoint ptr %[[RETURN_ALLOCA]] to i64
CHECK-DAG: %[[RETURN_VALUE:.*]] = call [16 x i8] @local_cabi_return_small_aggregate()
CHECK-DAG: store [16 x i8] %[[RETURN_VALUE]], ptr %[[RETURN_ALLOCA]]
CHECK-DAG: %[[RETURN_ALLOCA_INT_8:.*]] = add i64 %[[RETURN_ALLOCA_INT]], 8
CHECK-DAG: %[[RETURN_ALLOCA_8:.*]] = inttoptr i64 %[[RETURN_ALLOCA_INT_8]] to ptr
CHECK-DAG: %[[TO_RETURN:.*]] = load i64, ptr %[[RETURN_ALLOCA_8]]
CHECK: }
CHECK-i386: define i32 @local_call_cabi_primitives_on_stack() [[IGN:.*]] {
CHECK-i386: %[[CALL:.*]] = call i32 @local_cabi_primitives_on_stack(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8)
CHECK-i386: %[[RET:.*]] = add i32 %[[CALL]], {{.*}}
CHECK-i386: ret i32 %[[RET]]
CHECK-i386: }
CHECK: define [64 x i8] @local_cabi_return_big_aggregate() [[IGN:.*]] {
CHECK-DAG: %[[RETURN_ALLOCA:.*]] = alloca [64 x i8]
CHECK-DAG: %[[RETURN_ALLOCA_INT:.*]] = ptrtoint ptr %[[RETURN_ALLOCA]] to i64
CHECK-DAG: %[[RETURN_ALLOCA_INT_16:.*]] = add i64 %[[RETURN_ALLOCA_INT]], 16
CHECK-DAG: %[[RETURN_ALLOCA_16:.*]] = inttoptr i64 %[[RETURN_ALLOCA_INT_16]] to ptr
CHECK-DAG: store i64 123, ptr %[[RETURN_ALLOCA_16]]
CHECK-DAG: %[[TO_RETURN:.*]] = load [64 x i8], ptr %[[RETURN_ALLOCA]]
CHECK-DAG: ret [64 x i8] %[[TO_RETURN]]
CHECK: }
; cabi_aggregate_on_registers
CHECK: define i64 @local_call_cabi_return_big_aggregate() [[IGN:.*]] {
CHECK-DAG: %[[RETURN_ALLOCA:.*]] = alloca [64 x i8]
CHECK-DAG: %[[RETURN_ALLOCA_INT:.*]] = ptrtoint ptr %[[RETURN_ALLOCA]] to i64
CHECK-DAG: %[[RETURN_VALUE:.*]] = call [64 x i8] @local_cabi_return_big_aggregate()
CHECK-DAG: store [64 x i8] %[[RETURN_VALUE]], ptr %[[RETURN_ALLOCA]]
CHECK-DAG: %[[RETURN_ALLOCA_INT_16:.*]] = add i64 %[[RETURN_ALLOCA_INT]], 16
CHECK-DAG: %[[RETURN_ALLOCA_16:.*]] = inttoptr i64 %[[RETURN_ALLOCA_INT_16]] to ptr
CHECK-DAG: %[[TO_RETURN:.*]] = load i64, ptr %[[RETURN_ALLOCA_16]]
CHECK: }
CHECK-x86_64: define i64 @local_cabi_aggregate_on_registers(i64 %[[ARG1:.*]]) [[IGN:.*]] {
CHECK-x86_64-DAG: %[[FIELD1_PTR:.*]] = inttoptr i64 %[[ARG1]] to ptr
CHECK-x86_64-DAG: load i64, ptr %[[FIELD1_PTR]]
CHECK-x86_64-DAG: %[[FIELD2_ADDR:.*]] = add i64 %[[ARG1]], 8
CHECK-x86_64-DAG: %[[FIELD2_PTR:.*]] = inttoptr i64 %[[FIELD2_ADDR]] to ptr
CHECK-x86_64-DAG: load i64, ptr %[[FIELD2_PTR]], align 8
CHECK-x86_64: }
CHECK-x86_64: define i64 @local_call_cabi_aggregate_on_registers() [[IGN:.*]] {
CHECK-x86_64-DAG: %[[STACK:.*]] = alloca [16 x i8]
CHECK-x86_64-DAG: %[[STACK_INT:.*]] = ptrtoint ptr %[[STACK]] to i64
CHECK-x86_64-DAG: store i64 1, ptr %[[STACK]]
CHECK-x86_64-DAG: %[[STACK_INT_8:.*]] = add i64 %[[STACK_INT]], 8
CHECK-x86_64-DAG: %[[STACK_8:.*]] = inttoptr i64 %[[STACK_INT_8]] to ptr
CHECK-x86_64-DAG: store i64 2, ptr %[[STACK_8]]
CHECK-x86_64-DAG: = call i64 @local_cabi_aggregate_on_registers(i64 %[[STACK_INT]])
CHECK-x86_64: }
CHECK-i386: define i32 @local_cabi_aggregate_on_registers(i32 %[[PTR:.*]]) [[IGN:.*]] {
CHECK-i386: %[[A_PTR:.*]] = inttoptr i32 %[[PTR]] to ptr
CHECK-i386: %[[A:.*]] = load i32, ptr %[[A_PTR]]
CHECK-i386: %[[T1:.*]] = add i32 {{.*}}, %[[A]]
CHECK-i386: %[[B_OFF:.*]] = add i32 %[[PTR]], 4
CHECK-i386: %[[B_PTR:.*]] = inttoptr i32 %[[B_OFF]] to ptr
CHECK-i386: %[[B:.*]] = load i32, ptr %[[B_PTR]]
CHECK-i386: %[[T2:.*]] = add i32 %[[T1]], %[[B]]
CHECK-i386: ret i32 %[[T2]]
CHECK-i386: }
CHECK-i386: define i32 @local_call_cabi_aggregate_on_registers() [[IGN:.*]] {
CHECK-i386: %[[SLOT:.*]] = alloca [8 x i8]
CHECK-i386: %[[SLOT_INT:.*]] = ptrtoint ptr %[[SLOT]] to i32
CHECK-i386: %[[B_OFF:.*]] = add i32 %[[SLOT_INT]], 4
CHECK-i386: %[[B_PTR:.*]] = inttoptr i32 %[[B_OFF]] to ptr
CHECK-i386: store i32 2, ptr %[[B_PTR]]
CHECK-i386: %[[A_PTR:.*]] = inttoptr i32 %[[SLOT_INT]] to ptr
CHECK-i386: store i32 1, ptr %[[A_PTR]]
CHECK-i386: %[[CALL:.*]] = call i32 @local_cabi_aggregate_on_registers(i32 %[[SLOT_INT]])
CHECK-i386: %[[RET:.*]] = add i32 %[[CALL]], {{.*}}
CHECK-i386: ret i32 %[[RET]]
CHECK-i386: }
; cabi_aggregate_on_stack
CHECK-x86_64: define i64 @local_cabi_aggregate_on_stack(i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[STACK_ARG:.*]]) [[IGN:.*]] {
CHECK-x86_64-DAG: %[[FIELD1_PTR:.*]] = inttoptr i64 %[[STACK_ARG]] to ptr
CHECK-x86_64-DAG: load i64, ptr %[[FIELD1_PTR]]
CHECK-x86_64-DAG: %[[FIELD2_ADDR:.*]] = add i64 %[[STACK_ARG]], 8
CHECK-x86_64-DAG: %[[FIELD2_PTR:.*]] = inttoptr i64 %[[FIELD2_ADDR]] to ptr
CHECK-x86_64-DAG: load i64, ptr %[[FIELD2_PTR]]
CHECK-x86_64: }
CHECK-x86_64: define i64 @local_call_cabi_aggregate_on_stack() [[IGN:.*]] {
CHECK-x86_64-DAG: %[[STACK:.*]] = alloca [16 x i8]
CHECK-x86_64-DAG: %[[STACK_INT:.*]] = ptrtoint ptr %[[STACK]] to i64
CHECK-x86_64-DAG: store i64 1, ptr %[[STACK]]
CHECK-x86_64-DAG: %[[STACK_INT_8:.*]] = add i64 %[[STACK_INT]], 8
CHECK-x86_64-DAG: %[[STACK_8:.*]] = inttoptr i64 %[[STACK_INT_8]] to ptr
CHECK-x86_64-DAG: store i64 2, ptr %[[STACK_8]]
CHECK-x86_64-DAG: = call i64 @local_cabi_aggregate_on_stack(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 %[[STACK_INT]])
CHECK-x86_64: }
CHECK-i386: define i32 @local_cabi_aggregate_on_stack(i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[PTR:.*]]) [[IGN:.*]] {
CHECK-i386: %[[A_PTR:.*]] = inttoptr i32 %[[PTR]] to ptr
CHECK-i386: %[[A:.*]] = load i32, ptr %[[A_PTR]]
CHECK-i386: %[[T1:.*]] = add i32 {{.*}}, %[[A]]
CHECK-i386: %[[B_OFF:.*]] = add i32 %[[PTR]], 4
CHECK-i386: %[[B_PTR:.*]] = inttoptr i32 %[[B_OFF]] to ptr
CHECK-i386: %[[B:.*]] = load i32, ptr %[[B_PTR]]
CHECK-i386: %[[T2:.*]] = add i32 %[[T1]], %[[B]]
CHECK-i386: ret i32 %[[T2]]
CHECK-i386: }
CHECK-i386: define i32 @local_call_cabi_aggregate_on_stack() [[IGN:.*]] {
CHECK-i386: %[[SLOT:.*]] = alloca [8 x i8]
CHECK-i386: %[[SLOT_INT:.*]] = ptrtoint ptr %[[SLOT]] to i32
CHECK-i386: %[[B_OFF:.*]] = add i32 %[[SLOT_INT]], 4
CHECK-i386: %[[B_PTR:.*]] = inttoptr i32 %[[B_OFF]] to ptr
CHECK-i386: store i32 2, ptr %[[B_PTR]]
CHECK-i386: %[[A_PTR:.*]] = inttoptr i32 %[[SLOT_INT]] to ptr
CHECK-i386: store i32 1, ptr %[[A_PTR]]
CHECK-i386: %[[CALL:.*]] = call i32 @local_cabi_aggregate_on_stack(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 %[[SLOT_INT]])
CHECK-i386: %[[RET:.*]] = add i32 %[[CALL]], {{.*}}
CHECK-i386: ret i32 %[[RET]]
CHECK-i386: }
; cabi_aggregate_on_stack_and_registers
CHECK-x86_64: define i64 @local_cabi_aggregate_on_stack_and_registers(i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[IGN:.*]], i64 %[[STACK_ARG:.*]]) [[IGN:.*]] {
CHECK-x86_64-DAG: %[[FIELD1_PTR:.*]] = inttoptr i64 %[[STACK_ARG]] to ptr
CHECK-x86_64-DAG: load i64, ptr %[[FIELD1_PTR]]
CHECK-x86_64-DAG: %[[FIELD2_ADDR:.*]] = add i64 %[[STACK_ARG]], 8
CHECK-x86_64-DAG: %[[FIELD2_PTR:.*]] = inttoptr i64 %[[FIELD2_ADDR]] to ptr
CHECK-x86_64-DAG: load i64, ptr %[[FIELD2_PTR]]
CHECK-x86_64: }
CHECK-x86_64: define i64 @local_call_cabi_aggregate_on_stack_and_registers() [[IGN:.*]] {
CHECK-x86_64-DAG: %[[STACK:.*]] = alloca [16 x i8]
CHECK-x86_64-DAG: %[[STACK_INT:.*]] = ptrtoint ptr %[[STACK]] to i64
CHECK-x86_64-DAG: store i64 1, ptr %[[STACK]]
CHECK-x86_64-DAG: %[[STACK_INT_8:.*]] = add i64 %[[STACK_INT]], 8
CHECK-x86_64-DAG: %[[STACK_8:.*]] = inttoptr i64 %[[STACK_INT_8]] to ptr
CHECK-x86_64-DAG: store i64 2, ptr %[[STACK_8]]
CHECK-x86_64-DAG: = call i64 @local_cabi_aggregate_on_stack_and_registers(i64 1, i64 2, i64 3, i64 4, i64 5, i64 %[[STACK_INT]])
CHECK-x86_64: }
CHECK-i386: define i32 @local_cabi_aggregate_on_stack_and_registers(i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[IGN:.*]], i32 %[[PTR:.*]]) [[IGN:.*]] {
CHECK-i386: %[[A_PTR:.*]] = inttoptr i32 %[[PTR]] to ptr
CHECK-i386: %[[A:.*]] = load i32, ptr %[[A_PTR]]
CHECK-i386: %[[T1:.*]] = add i32 {{.*}}, %[[A]]
CHECK-i386: %[[B_OFF:.*]] = add i32 %[[PTR]], 4
CHECK-i386: %[[B_PTR:.*]] = inttoptr i32 %[[B_OFF]] to ptr
CHECK-i386: %[[B:.*]] = load i32, ptr %[[B_PTR]]
CHECK-i386: %[[T2:.*]] = add i32 %[[T1]], %[[B]]
CHECK-i386: ret i32 %[[T2]]
CHECK-i386: }
CHECK-i386: define i32 @local_call_cabi_aggregate_on_stack_and_registers() [[IGN:.*]] {
CHECK-i386: %[[SLOT:.*]] = alloca [8 x i8]
CHECK-i386: %[[SLOT_INT:.*]] = ptrtoint ptr %[[SLOT]] to i32
CHECK-i386: %[[B_OFF:.*]] = add i32 %[[SLOT_INT]], 4
CHECK-i386: %[[B_PTR:.*]] = inttoptr i32 %[[B_OFF]] to ptr
CHECK-i386: store i32 2, ptr %[[B_PTR]]
CHECK-i386: %[[A_PTR:.*]] = inttoptr i32 %[[SLOT_INT]] to ptr
CHECK-i386: store i32 1, ptr %[[A_PTR]]
CHECK-i386: %[[CALL:.*]] = call i32 @local_cabi_aggregate_on_stack_and_registers(i32 1, i32 2, i32 3, i32 4, i32 5, i32 %[[SLOT_INT]])
CHECK-i386: %[[RET:.*]] = add i32 %[[CALL]], {{.*}}
CHECK-i386: ret i32 %[[RET]]
CHECK-i386: }
; raw_return_small_aggregate
CHECK-x86_64: define <{ i64, i64 }> @local_raw_return_small_aggregate() [[IGN:.*]] {
CHECK-x86_64-DAG: %[[RESULT:.*]] = call <{ i64, i64 }> @struct_initializer(i64 124, i64 123)
CHECK-x86_64-DAG: ret <{ i64, i64 }> %[[RESULT]]
CHECK-x86_64: }
CHECK-x86_64: define i64 @local_call_raw_return_small_aggregate() [[IGN:.*]] {
CHECK-x86_64: %[[RESULT:.*]] = call <{ i64, i64 }> @local_raw_return_small_aggregate()
CHECK-x86_64-DAG: call i64 @OpaqueExtractvalue(<{ i64, i64 }> %[[RESULT]], i64 1)
CHECK-x86_64: }
; cabi_return_small_aggregate
CHECK-x86_64: define [16 x i8] @local_cabi_return_small_aggregate() [[IGN:.*]] {
CHECK-x86_64-DAG: %[[RETURN_ALLOCA:.*]] = alloca [16 x i8]
CHECK-x86_64-DAG: %[[RETURN_ALLOCA_INT:.*]] = ptrtoint ptr %[[RETURN_ALLOCA]] to i64
CHECK-x86_64-DAG: %[[RETURN_ALLOCA_INT_8:.*]] = add i64 %[[RETURN_ALLOCA_INT]], 8
CHECK-x86_64-DAG: %[[RETURN_ALLOCA_8:.*]] = inttoptr i64 %[[RETURN_ALLOCA_INT_8]] to ptr
CHECK-x86_64-DAG: store i64 124, ptr %[[RETURN_ALLOCA]]
CHECK-x86_64-DAG: store i64 123, ptr %[[RETURN_ALLOCA_8]]
CHECK-x86_64-DAG: %[[TO_RETURN:.*]] = load [16 x i8], ptr %[[RETURN_ALLOCA]]
CHECK-x86_64-DAG: ret [16 x i8] %[[TO_RETURN]]
CHECK-x86_64: }
CHECK-x86_64: define i64 @local_call_cabi_return_small_aggregate() [[IGN:.*]] {
CHECK-x86_64-DAG: %[[RETURN_ALLOCA:.*]] = alloca [16 x i8]
CHECK-x86_64-DAG: %[[RETURN_ALLOCA_INT:.*]] = ptrtoint ptr %[[RETURN_ALLOCA]] to i64
CHECK-x86_64-DAG: %[[RETURN_VALUE:.*]] = call [16 x i8] @local_cabi_return_small_aggregate()
CHECK-x86_64-DAG: store [16 x i8] %[[RETURN_VALUE]], ptr %[[RETURN_ALLOCA]]
CHECK-x86_64-DAG: %[[RETURN_ALLOCA_INT_8:.*]] = add i64 %[[RETURN_ALLOCA_INT]], 8
CHECK-x86_64-DAG: %[[RETURN_ALLOCA_8:.*]] = inttoptr i64 %[[RETURN_ALLOCA_INT_8]] to ptr
CHECK-x86_64-DAG: %[[TO_RETURN:.*]] = load i64, ptr %[[RETURN_ALLOCA_8]]
CHECK-x86_64: }
CHECK-i386: define [8 x i8] @local_cabi_return_small_aggregate() [[IGN:.*]] {
CHECK-i386: %[[SLOT:.*]] = alloca [8 x i8]
CHECK-i386: %[[SLOT_INT:.*]] = ptrtoint ptr %[[SLOT]] to i32
CHECK-i386: %[[SLOT_PTR:.*]] = inttoptr i32 %[[SLOT_INT]] to ptr
CHECK-i386: %[[BASE:.*]] = load i32, ptr %[[SLOT_PTR]]
CHECK-i386-DAG: store i32 124, ptr {{.*}}
CHECK-i386-DAG: %[[OFF:.*]] = add i32 %[[BASE]], 4
CHECK-i386-DAG: store i32 123, ptr {{.*}}
CHECK-i386: %[[RV:.*]] = load [8 x i8], ptr %[[SLOT]]
CHECK-i386: ret [8 x i8] %[[RV]]
CHECK-i386: }
CHECK-i386: define i32 @local_call_cabi_return_small_aggregate() [[IGN:.*]] {
CHECK-i386: %[[SLOT:.*]] = alloca [8 x i8]
CHECK-i386: %[[RV:.*]] = call [8 x i8] @local_cabi_return_small_aggregate()
CHECK-i386: store [8 x i8] %[[RV]], ptr %[[SLOT]]
CHECK-i386: %[[SLOT_INT:.*]] = ptrtoint ptr %[[SLOT]] to i32
CHECK-i386: %[[SLOT_PTR:.*]] = inttoptr i32 %[[SLOT_INT]] to ptr
CHECK-i386: %[[B:.*]] = load i32, ptr %[[SLOT_PTR]]
CHECK-i386: %[[RET:.*]] = add i32 {{.*}}%[[B]]
CHECK-i386: ret i32 %[[RET]]
CHECK-i386: }
; cabi_return_big_aggregate
CHECK-x86_64: define [64 x i8] @local_cabi_return_big_aggregate() [[IGN:.*]] {
CHECK-x86_64-DAG: %[[RETURN_ALLOCA:.*]] = alloca [64 x i8]
CHECK-x86_64-DAG: %[[RETURN_ALLOCA_INT:.*]] = ptrtoint ptr %[[RETURN_ALLOCA]] to i64
CHECK-x86_64-DAG: %[[RETURN_ALLOCA_INT_16:.*]] = add i64 %[[RETURN_ALLOCA_INT]], 16
CHECK-x86_64-DAG: %[[RETURN_ALLOCA_16:.*]] = inttoptr i64 %[[RETURN_ALLOCA_INT_16]] to ptr
CHECK-x86_64-DAG: store i64 123, ptr %[[RETURN_ALLOCA_16]]
CHECK-x86_64-DAG: %[[TO_RETURN:.*]] = load [64 x i8], ptr %[[RETURN_ALLOCA]]
CHECK-x86_64-DAG: ret [64 x i8] %[[TO_RETURN]]
CHECK-x86_64: }
CHECK-x86_64: define i64 @local_call_cabi_return_big_aggregate() [[IGN:.*]] {
CHECK-x86_64-DAG: %[[RETURN_ALLOCA:.*]] = alloca [64 x i8]
CHECK-x86_64-DAG: %[[RETURN_ALLOCA_INT:.*]] = ptrtoint ptr %[[RETURN_ALLOCA]] to i64
CHECK-x86_64-DAG: %[[RETURN_VALUE:.*]] = call [64 x i8] @local_cabi_return_big_aggregate()
CHECK-x86_64-DAG: store [64 x i8] %[[RETURN_VALUE]], ptr %[[RETURN_ALLOCA]]
CHECK-x86_64-DAG: %[[RETURN_ALLOCA_INT_16:.*]] = add i64 %[[RETURN_ALLOCA_INT]], 16
CHECK-x86_64-DAG: %[[RETURN_ALLOCA_16:.*]] = inttoptr i64 %[[RETURN_ALLOCA_INT_16]] to ptr
CHECK-x86_64-DAG: %[[TO_RETURN:.*]] = load i64, ptr %[[RETURN_ALLOCA_16]]
CHECK-x86_64: }
CHECK-i386: define [28 x i8] @local_cabi_return_big_aggregate() [[IGN:.*]] {
CHECK-i386: %[[SLOT:.*]] = alloca [28 x i8]
CHECK-i386: %[[SLOT_INT:.*]] = ptrtoint ptr %[[SLOT]] to i32
CHECK-i386: %[[SLOT_PTR:.*]] = inttoptr i32 %[[SLOT_INT]] to ptr
CHECK-i386: %[[BASE:.*]] = load i32, ptr %[[SLOT_PTR]]
CHECK-i386: %[[OFF:.*]] = add i32 %[[BASE]], 8
CHECK-i386: store i32 123, ptr {{.*}}
CHECK-i386: %[[RV:.*]] = load [28 x i8], ptr %[[SLOT]]
CHECK-i386: ret [28 x i8] %[[RV]]
CHECK-i386: }
CHECK-i386: define i32 @local_call_cabi_return_big_aggregate() [[IGN:.*]] {
CHECK-i386: %[[SLOT:.*]] = alloca [28 x i8]
CHECK-i386: %[[RV:.*]] = call [28 x i8] @local_cabi_return_big_aggregate()
CHECK-i386: store [28 x i8] %[[RV]], ptr %[[SLOT]]
CHECK-i386: %[[SLOT_INT:.*]] = ptrtoint ptr %[[SLOT]] to i32
CHECK-i386: %[[OFF:.*]] = add i32 %[[SLOT_INT]], 4
CHECK-i386: %[[SLOT_PTR:.*]] = inttoptr i32 %[[OFF]] to ptr
CHECK-i386: %[[D:.*]] = load i32, ptr %[[SLOT_PTR]]
CHECK-i386: %[[RET:.*]] = add i32 {{.*}}%[[D]]
CHECK-i386: ret i32 %[[RET]]
CHECK-i386: }
@@ -0,0 +1,274 @@
#
# This file is distributed under the MIT License. See LICENSE.md for details.
#
---
Architecture: x86
Functions:
- Name: cabi_primitives_on_registers
Prototype:
Kind: DefinedType
Definition: "/TypeDefinitions/100004-CABIFunctionDefinition"
- Name: cabi_primitives_on_stack
Prototype:
Kind: DefinedType
Definition: "/TypeDefinitions/100005-CABIFunctionDefinition"
- Name: cabi_aggregate_on_registers
Prototype:
Kind: DefinedType
Definition: "/TypeDefinitions/100006-CABIFunctionDefinition"
- Name: cabi_aggregate_on_stack
Prototype:
Kind: DefinedType
Definition: "/TypeDefinitions/100007-CABIFunctionDefinition"
- Name: cabi_aggregate_on_stack_and_registers
Prototype:
Kind: DefinedType
Definition: "/TypeDefinitions/100008-CABIFunctionDefinition"
- Name: cabi_return_small_aggregate
Prototype:
Kind: DefinedType
Definition: "/TypeDefinitions/100010-CABIFunctionDefinition"
- Name: cabi_return_big_aggregate
Prototype:
Kind: DefinedType
Definition: "/TypeDefinitions/100012-CABIFunctionDefinition"
TypeDefinitions:
- Kind: StructDefinition
ID: 100003
Size: 8
Fields:
- Offset: 0
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Offset: 4
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Kind: CABIFunctionDefinition
ID: 100004
ABI: SystemV_x86
ReturnType:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
Arguments:
- Index: 0
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 1
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Kind: CABIFunctionDefinition
ID: 100005
ABI: SystemV_x86
ReturnType:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
Arguments:
- Index: 0
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 1
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 2
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 3
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 4
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 5
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 6
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 7
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Kind: CABIFunctionDefinition
ID: 100006
ABI: SystemV_x86
ReturnType:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
Arguments:
- Index: 0
Type:
Kind: DefinedType
Definition: "/TypeDefinitions/100003-StructDefinition"
- Kind: CABIFunctionDefinition
ID: 100007
ABI: SystemV_x86
ReturnType:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
Arguments:
- Index: 0
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 1
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 2
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 3
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 4
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 5
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 6
Type:
Kind: DefinedType
Definition: "/TypeDefinitions/100003-StructDefinition"
- Kind: CABIFunctionDefinition
ID: 100008
ABI: SystemV_x86
ReturnType:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
Arguments:
- Index: 0
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 1
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 2
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 3
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 4
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Index: 5
Type:
Kind: DefinedType
Definition: "/TypeDefinitions/100003-StructDefinition"
- Kind: StructDefinition
ID: 100009
Size: 8
Fields:
- Offset: 0
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Offset: 4
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Kind: CABIFunctionDefinition
ID: 100010
ABI: SystemV_x86
ReturnType:
Kind: DefinedType
Definition: "/TypeDefinitions/100009-StructDefinition"
Arguments: []
- Kind: StructDefinition
ID: 100011
Size: 28
Fields:
- Offset: 0
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Offset: 4
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Offset: 8
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Offset: 12
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Offset: 16
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Offset: 20
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Offset: 24
Type:
Kind: PrimitiveType
PrimitiveKind: Generic
Size: 4
- Kind: CABIFunctionDefinition
ID: 100012
ABI: SystemV_x86
ReturnType:
Kind: DefinedType
Definition: "/TypeDefinitions/100011-StructDefinition"
Arguments: []
@@ -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