//===- 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 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(V)) { // A Return's value operand can be null if it returns void. if (auto *RI = dyn_cast(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(I)) return SI->getValueOperand(); if (auto *RI = dyn_cast(I)) return RI->getReturnValue(); return const_cast(I); } /// \Returns the base Value for load or store instruction \p LSI. template static Value *getMemInstructionBase(const LoadOrStoreT *LSI) { static_assert(std::is_same_v || std::is_same_v, "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 memoryLocationGetOrNone(const Instruction *I) { return llvm::MemoryLocation::getOrNone(cast(I->Val)); } /// \Returns the gap between the memory locations accessed by \p I0 and /// \p I1 in bytes. template static std::optional getPointerDiffInBytes(LoadOrStoreT *I0, LoadOrStoreT *I1, ScalarEvolution &SE) { static_assert(std::is_same_v || std::is_same_v, "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 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 &OptLoc) { return BatchAA.getModRefInfo(cast(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(F->Val); return llvm::verifyFunction(LLVMF, &OS); } }; } // namespace llvm::sandboxir #endif // LLVM_SANDBOXIR_UTILS_H