xref: /freebsd/contrib/llvm-project/llvm/include/llvm/SandboxIR/Utils.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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