1 //===--- RuntimeDebugBuilder.h --- Helper to insert prints into LLVM-IR ---===// 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 //===----------------------------------------------------------------------===// 10 11 #ifndef RUNTIME_DEBUG_BUILDER_H 12 #define RUNTIME_DEBUG_BUILDER_H 13 14 #include "polly/CodeGen/IRBuilder.h" 15 #include "llvm/ADT/ArrayRef.h" 16 #include "llvm/ADT/StringRef.h" 17 #include <vector> 18 19 namespace llvm { 20 class Value; 21 class Function; 22 } // namespace llvm 23 24 namespace polly { 25 26 /// Insert function calls that print certain LLVM values at run time. 27 /// 28 /// This class inserts libc function calls to print certain LLVM values at 29 /// run time. 30 struct RuntimeDebugBuilder { 31 32 /// Generate a constant string into the builder's llvm::Module which can be 33 /// passed to createGPUPrinter() or createGPUPrinter(). 34 /// 35 /// @param Builder The builder used to emit the printer calls. 36 /// @param Str The string to be printed. 37 38 /// @return A global containing @p Str. getPrintableStringRuntimeDebugBuilder39 static llvm::Value *getPrintableString(PollyIRBuilder &Builder, 40 llvm::StringRef Str) { 41 // TODO: Get rid of magic number 4. It it NVPTX's constant address space and 42 // works on X86 (CPU) only because its backend ignores the address space. 43 return Builder.CreateGlobalStringPtr(Str, "", 4); 44 } 45 46 /// Return whether an llvm::Value of the type @p Ty is printable for 47 /// debugging. 48 /// 49 /// That is, whether such a value can be passed to createGPUPrinter() or 50 /// createGPUPrinter() to be dumped as runtime. If false is returned, those 51 /// functions will fail. 52 static bool isPrintable(llvm::Type *Ty); 53 54 /// Print a set of LLVM-IR Values or StringRefs via printf 55 /// 56 /// This function emits a call to printf that will print the given arguments. 57 /// It is useful for debugging CPU programs. All arguments given in this list 58 /// will be automatically concatenated and the resulting string will be 59 /// printed atomically. We also support ArrayRef arguments, which can be used 60 /// to provide of id values. 61 /// 62 /// @param Builder The builder used to emit the printer calls. 63 /// @param Args The list of values to print. 64 template <typename... Args> createCPUPrinterRuntimeDebugBuilder65 static void createCPUPrinter(PollyIRBuilder &Builder, Args... args) { 66 std::vector<llvm::Value *> Vector; 67 createPrinter(Builder, /* CPU */ false, Vector, args...); 68 } 69 70 /// Print a set of LLVM-IR Values or StringRefs on an NVIDIA GPU. 71 /// 72 /// This function emits a call to vprintf that will print the given 73 /// arguments from within a kernel thread. It is useful for debugging 74 /// CUDA program kernels. All arguments given in this list will be 75 /// automatically concatenated and the resulting string will be printed 76 /// atomically. We also support ArrayRef arguments, which can be used to 77 /// provide for example a list of thread-id values. 78 /// 79 /// @param Builder The builder used to emit the printer calls. 80 /// @param Args The list of values to print. 81 template <typename... Args> createGPUPrinterRuntimeDebugBuilder82 static void createGPUPrinter(PollyIRBuilder &Builder, Args... args) { 83 std::vector<llvm::Value *> Vector; 84 createPrinter(Builder, /* GPU */ true, Vector, args...); 85 } 86 87 private: 88 /// Handle Values. 89 template <typename... Args> createPrinterRuntimeDebugBuilder90 static void createPrinter(PollyIRBuilder &Builder, bool UseGPU, 91 std::vector<llvm::Value *> &Values, 92 llvm::Value *Value, Args... args) { 93 Values.push_back(Value); 94 createPrinter(Builder, UseGPU, Values, args...); 95 } 96 97 /// Handle StringRefs. 98 template <typename... Args> createPrinterRuntimeDebugBuilder99 static void createPrinter(PollyIRBuilder &Builder, bool UseGPU, 100 std::vector<llvm::Value *> &Values, 101 llvm::StringRef String, Args... args) { 102 Values.push_back(getPrintableString(Builder, String)); 103 createPrinter(Builder, UseGPU, Values, args...); 104 } 105 106 /// Handle ArrayRefs. 107 template <typename... Args> createPrinterRuntimeDebugBuilder108 static void createPrinter(PollyIRBuilder &Builder, bool UseGPU, 109 std::vector<llvm::Value *> &Values, 110 llvm::ArrayRef<llvm::Value *> Array, Args... args) { 111 Values.insert(Values.end(), Array.begin(), Array.end()); 112 createPrinter(Builder, UseGPU, Values, args...); 113 } 114 115 /// Print a list of Values. 116 static void createPrinter(PollyIRBuilder &Builder, bool UseGPU, 117 llvm::ArrayRef<llvm::Value *> Values); 118 119 /// Print a list of Values on a GPU. 120 static void createGPUPrinterT(PollyIRBuilder &Builder, 121 llvm::ArrayRef<llvm::Value *> Values); 122 123 /// Print a list of Values on a CPU. 124 static void createCPUPrinterT(PollyIRBuilder &Builder, 125 llvm::ArrayRef<llvm::Value *> Values); 126 127 /// Get a reference to the 'printf' function. 128 /// 129 /// If the current module does not yet contain a reference to printf, we 130 /// insert a reference to it. Otherwise the existing reference is returned. 131 static llvm::Function *getPrintF(PollyIRBuilder &Builder); 132 133 /// Call printf 134 /// 135 /// @param Builder The builder used to insert the code. 136 /// @param Format The format string. 137 /// @param Values The set of values to print. 138 static void createPrintF(PollyIRBuilder &Builder, std::string Format, 139 llvm::ArrayRef<llvm::Value *> Values); 140 141 /// Get (and possibly insert) a vprintf declaration into the module. 142 static llvm::Function *getVPrintF(PollyIRBuilder &Builder); 143 144 /// Call fflush 145 /// 146 /// @parma Builder The builder used to insert the code. 147 static void createFlush(PollyIRBuilder &Builder); 148 149 /// Get (and possibly insert) a NVIDIA address space cast call. 150 static llvm::Function *getAddressSpaceCast(PollyIRBuilder &Builder, 151 unsigned Src, unsigned Dst, 152 unsigned SrcBits = 8, 153 unsigned DstBits = 8); 154 155 /// Get identifiers that describe the currently executed GPU thread. 156 /// 157 /// The result will be a vector that if passed to the GPU printer will result 158 /// into a string (initialized to values corresponding to the printing 159 /// thread): 160 /// 161 /// "> block-id: bidx bid1y bidz | thread-id: tidx tidy tidz " 162 static std::vector<llvm::Value *> 163 getGPUThreadIdentifiers(PollyIRBuilder &Builder); 164 }; 165 } // namespace polly 166 167 extern bool PollyDebugPrinting; 168 169 #endif 170