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