139 lines
5.3 KiB
C++
139 lines
5.3 KiB
C++
//===- Utils.h --------------------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Collector for SandboxIR related convenience functions that don't belong in
|
|
// other classes.
|
|
|
|
#ifndef LLVM_SANDBOXIR_UTILS_H
|
|
#define LLVM_SANDBOXIR_UTILS_H
|
|
|
|
#include "llvm/Analysis/AliasAnalysis.h"
|
|
#include "llvm/Analysis/LoopAccessAnalysis.h"
|
|
#include "llvm/Analysis/MemoryLocation.h"
|
|
#include "llvm/Analysis/ScalarEvolution.h"
|
|
#include "llvm/Analysis/ValueTracking.h"
|
|
#include "llvm/IR/Verifier.h"
|
|
#include "llvm/SandboxIR/Function.h"
|
|
#include "llvm/SandboxIR/Instruction.h"
|
|
#include <optional>
|
|
|
|
namespace llvm::sandboxir {
|
|
|
|
class Utils {
|
|
public:
|
|
/// \Returns the expected type of \p Value V. For most Values this is
|
|
/// equivalent to getType, but for stores returns the stored type, rather
|
|
/// than void, and for ReturnInsts returns the returned type.
|
|
static Type *getExpectedType(const Value *V) {
|
|
if (auto *I = dyn_cast<Instruction>(V)) {
|
|
// A Return's value operand can be null if it returns void.
|
|
if (auto *RI = dyn_cast<ReturnInst>(I)) {
|
|
if (RI->getReturnValue() == nullptr)
|
|
return RI->getType();
|
|
}
|
|
return getExpectedValue(I)->getType();
|
|
}
|
|
return V->getType();
|
|
}
|
|
|
|
/// \Returns the expected Value for this instruction. For most instructions,
|
|
/// this is the instruction itself, but for stores returns the stored
|
|
/// operand, and for ReturnInstructions returns the returned value.
|
|
static Value *getExpectedValue(const Instruction *I) {
|
|
if (auto *SI = dyn_cast<StoreInst>(I))
|
|
return SI->getValueOperand();
|
|
if (auto *RI = dyn_cast<ReturnInst>(I))
|
|
return RI->getReturnValue();
|
|
return const_cast<Instruction *>(I);
|
|
}
|
|
|
|
/// \Returns the base Value for load or store instruction \p LSI.
|
|
template <typename LoadOrStoreT>
|
|
static Value *getMemInstructionBase(const LoadOrStoreT *LSI) {
|
|
static_assert(std::is_same_v<LoadOrStoreT, LoadInst> ||
|
|
std::is_same_v<LoadOrStoreT, StoreInst>,
|
|
"Expected sandboxir::Load or sandboxir::Store!");
|
|
return LSI->Ctx.getOrCreateValue(
|
|
getUnderlyingObject(LSI->getPointerOperand()->Val));
|
|
}
|
|
|
|
/// \Returns the number of bits of \p Ty.
|
|
static unsigned getNumBits(Type *Ty, const DataLayout &DL) {
|
|
return DL.getTypeSizeInBits(Ty->LLVMTy);
|
|
}
|
|
|
|
/// \Returns the number of bits required to represent the operands or return
|
|
/// value of \p V in \p DL.
|
|
static unsigned getNumBits(Value *V, const DataLayout &DL) {
|
|
Type *Ty = getExpectedType(V);
|
|
return getNumBits(Ty, DL);
|
|
}
|
|
|
|
/// \Returns the number of bits required to represent the operands or
|
|
/// return value of \p I.
|
|
static unsigned getNumBits(Instruction *I) {
|
|
return I->getDataLayout().getTypeSizeInBits(getExpectedType(I)->LLVMTy);
|
|
}
|
|
|
|
/// Equivalent to MemoryLocation::getOrNone(I).
|
|
static std::optional<llvm::MemoryLocation>
|
|
memoryLocationGetOrNone(const Instruction *I) {
|
|
return llvm::MemoryLocation::getOrNone(cast<llvm::Instruction>(I->Val));
|
|
}
|
|
|
|
/// \Returns the gap between the memory locations accessed by \p I0 and
|
|
/// \p I1 in bytes.
|
|
template <typename LoadOrStoreT>
|
|
static std::optional<int> getPointerDiffInBytes(LoadOrStoreT *I0,
|
|
LoadOrStoreT *I1,
|
|
ScalarEvolution &SE) {
|
|
static_assert(std::is_same_v<LoadOrStoreT, LoadInst> ||
|
|
std::is_same_v<LoadOrStoreT, StoreInst>,
|
|
"Expected sandboxir::Load or sandboxir::Store!");
|
|
llvm::Value *Opnd0 = I0->getPointerOperand()->Val;
|
|
llvm::Value *Opnd1 = I1->getPointerOperand()->Val;
|
|
llvm::Value *Ptr0 = getUnderlyingObject(Opnd0);
|
|
llvm::Value *Ptr1 = getUnderlyingObject(Opnd1);
|
|
if (Ptr0 != Ptr1)
|
|
return false;
|
|
llvm::Type *ElemTy = llvm::Type::getInt8Ty(SE.getContext());
|
|
return getPointersDiff(ElemTy, Opnd0, ElemTy, Opnd1, I0->getDataLayout(),
|
|
SE, /*StrictCheck=*/false, /*CheckType=*/false);
|
|
}
|
|
|
|
/// \Returns true if \p I0 accesses a memory location lower than \p I1.
|
|
/// Returns false if the difference cannot be determined, if the memory
|
|
/// locations are equal, or if I1 accesses a memory location greater than I0.
|
|
template <typename LoadOrStoreT>
|
|
static bool atLowerAddress(LoadOrStoreT *I0, LoadOrStoreT *I1,
|
|
ScalarEvolution &SE) {
|
|
auto Diff = getPointerDiffInBytes(I0, I1, SE);
|
|
if (!Diff)
|
|
return false;
|
|
return *Diff > 0;
|
|
}
|
|
|
|
/// Equivalent to BatchAA::getModRefInfo().
|
|
static ModRefInfo
|
|
aliasAnalysisGetModRefInfo(BatchAAResults &BatchAA, const Instruction *I,
|
|
const std::optional<MemoryLocation> &OptLoc) {
|
|
return BatchAA.getModRefInfo(cast<llvm::Instruction>(I->Val), OptLoc);
|
|
}
|
|
|
|
/// Equivalent to llvm::verifyFunction().
|
|
/// \Returns true if the IR is broken.
|
|
static bool verifyFunction(const Function *F, raw_ostream &OS) {
|
|
const auto &LLVMF = *cast<llvm::Function>(F->Val);
|
|
return llvm::verifyFunction(LLVMF, &OS);
|
|
}
|
|
};
|
|
|
|
} // namespace llvm::sandboxir
|
|
|
|
#endif // LLVM_SANDBOXIR_UTILS_H
|