1 //===- Utils.h --------------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Collector for SandboxIR related convenience functions that don't belong in 10 // other classes. 11 12 #ifndef LLVM_SANDBOXIR_UTILS_H 13 #define LLVM_SANDBOXIR_UTILS_H 14 15 #include "llvm/Analysis/AliasAnalysis.h" 16 #include "llvm/Analysis/LoopAccessAnalysis.h" 17 #include "llvm/Analysis/MemoryLocation.h" 18 #include "llvm/Analysis/ScalarEvolution.h" 19 #include "llvm/Analysis/ValueTracking.h" 20 #include "llvm/IR/Verifier.h" 21 #include "llvm/SandboxIR/Function.h" 22 #include "llvm/SandboxIR/Instruction.h" 23 #include <optional> 24 25 namespace llvm::sandboxir { 26 27 class Utils { 28 public: 29 /// \Returns the expected type of \p Value V. For most Values this is 30 /// equivalent to getType, but for stores returns the stored type, rather 31 /// than void, and for ReturnInsts returns the returned type. getExpectedType(const Value * V)32 static Type *getExpectedType(const Value *V) { 33 if (auto *I = dyn_cast<Instruction>(V)) { 34 // A Return's value operand can be null if it returns void. 35 if (auto *RI = dyn_cast<ReturnInst>(I)) { 36 if (RI->getReturnValue() == nullptr) 37 return RI->getType(); 38 } 39 return getExpectedValue(I)->getType(); 40 } 41 return V->getType(); 42 } 43 44 /// \Returns the expected Value for this instruction. For most instructions, 45 /// this is the instruction itself, but for stores returns the stored 46 /// operand, and for ReturnInstructions returns the returned value. getExpectedValue(const Instruction * I)47 static Value *getExpectedValue(const Instruction *I) { 48 if (auto *SI = dyn_cast<StoreInst>(I)) 49 return SI->getValueOperand(); 50 if (auto *RI = dyn_cast<ReturnInst>(I)) 51 return RI->getReturnValue(); 52 return const_cast<Instruction *>(I); 53 } 54 55 /// \Returns the base Value for load or store instruction \p LSI. 56 template <typename LoadOrStoreT> getMemInstructionBase(const LoadOrStoreT * LSI)57 static Value *getMemInstructionBase(const LoadOrStoreT *LSI) { 58 static_assert(std::is_same_v<LoadOrStoreT, LoadInst> || 59 std::is_same_v<LoadOrStoreT, StoreInst>, 60 "Expected sandboxir::Load or sandboxir::Store!"); 61 return LSI->Ctx.getOrCreateValue( 62 getUnderlyingObject(LSI->getPointerOperand()->Val)); 63 } 64 65 /// \Returns the number of bits of \p Ty. getNumBits(Type * Ty,const DataLayout & DL)66 static unsigned getNumBits(Type *Ty, const DataLayout &DL) { 67 return DL.getTypeSizeInBits(Ty->LLVMTy); 68 } 69 70 /// \Returns the number of bits required to represent the operands or return 71 /// value of \p V in \p DL. getNumBits(Value * V,const DataLayout & DL)72 static unsigned getNumBits(Value *V, const DataLayout &DL) { 73 Type *Ty = getExpectedType(V); 74 return getNumBits(Ty, DL); 75 } 76 77 /// \Returns the number of bits required to represent the operands or 78 /// return value of \p I. getNumBits(Instruction * I)79 static unsigned getNumBits(Instruction *I) { 80 return I->getDataLayout().getTypeSizeInBits(getExpectedType(I)->LLVMTy); 81 } 82 83 /// Equivalent to MemoryLocation::getOrNone(I). 84 static std::optional<llvm::MemoryLocation> memoryLocationGetOrNone(const Instruction * I)85 memoryLocationGetOrNone(const Instruction *I) { 86 return llvm::MemoryLocation::getOrNone(cast<llvm::Instruction>(I->Val)); 87 } 88 89 /// \Returns the gap between the memory locations accessed by \p I0 and 90 /// \p I1 in bytes. 91 template <typename LoadOrStoreT> getPointerDiffInBytes(LoadOrStoreT * I0,LoadOrStoreT * I1,ScalarEvolution & SE)92 static std::optional<int> getPointerDiffInBytes(LoadOrStoreT *I0, 93 LoadOrStoreT *I1, 94 ScalarEvolution &SE) { 95 static_assert(std::is_same_v<LoadOrStoreT, LoadInst> || 96 std::is_same_v<LoadOrStoreT, StoreInst>, 97 "Expected sandboxir::Load or sandboxir::Store!"); 98 llvm::Value *Opnd0 = I0->getPointerOperand()->Val; 99 llvm::Value *Opnd1 = I1->getPointerOperand()->Val; 100 llvm::Value *Ptr0 = getUnderlyingObject(Opnd0); 101 llvm::Value *Ptr1 = getUnderlyingObject(Opnd1); 102 if (Ptr0 != Ptr1) 103 return false; 104 llvm::Type *ElemTy = llvm::Type::getInt8Ty(SE.getContext()); 105 return getPointersDiff(ElemTy, Opnd0, ElemTy, Opnd1, I0->getDataLayout(), 106 SE, /*StrictCheck=*/false, /*CheckType=*/false); 107 } 108 109 /// \Returns true if \p I0 accesses a memory location lower than \p I1. 110 /// Returns false if the difference cannot be determined, if the memory 111 /// locations are equal, or if I1 accesses a memory location greater than I0. 112 template <typename LoadOrStoreT> atLowerAddress(LoadOrStoreT * I0,LoadOrStoreT * I1,ScalarEvolution & SE)113 static bool atLowerAddress(LoadOrStoreT *I0, LoadOrStoreT *I1, 114 ScalarEvolution &SE) { 115 auto Diff = getPointerDiffInBytes(I0, I1, SE); 116 if (!Diff) 117 return false; 118 return *Diff > 0; 119 } 120 121 /// Equivalent to BatchAA::getModRefInfo(). 122 static ModRefInfo aliasAnalysisGetModRefInfo(BatchAAResults & BatchAA,const Instruction * I,const std::optional<MemoryLocation> & OptLoc)123 aliasAnalysisGetModRefInfo(BatchAAResults &BatchAA, const Instruction *I, 124 const std::optional<MemoryLocation> &OptLoc) { 125 return BatchAA.getModRefInfo(cast<llvm::Instruction>(I->Val), OptLoc); 126 } 127 128 /// Equivalent to llvm::verifyFunction(). 129 /// \Returns true if the IR is broken. verifyFunction(const Function * F,raw_ostream & OS)130 static bool verifyFunction(const Function *F, raw_ostream &OS) { 131 const auto &LLVMF = *cast<llvm::Function>(F->Val); 132 return llvm::verifyFunction(LLVMF, &OS); 133 } 134 }; 135 136 } // namespace llvm::sandboxir 137 138 #endif // LLVM_SANDBOXIR_UTILS_H 139