1 | //===--- RuntimeDebugBuilder.cpp - 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 | #include "polly/CodeGen/RuntimeDebugBuilder.h" |
12 | #include "llvm/IR/Module.h" |
13 | #include <string> |
14 | #include <vector> |
15 | |
16 | using namespace llvm; |
17 | using namespace polly; |
18 | |
19 | llvm::Value *RuntimeDebugBuilder::getPrintableString(PollyIRBuilder &Builder, |
20 | llvm::StringRef Str) { |
21 | // FIXME: addressspace(4) is a marker for a string (for the %s conversion |
22 | // specifier) but should be using the default address space. This only works |
23 | // because CPU backends typically ignore the address space. For constant |
24 | // strings as returned by getPrintableString, the format string should instead |
25 | // directly spell out the string. |
26 | return Builder.CreateGlobalStringPtr(Str, Name: "" , AddressSpace: 4); |
27 | } |
28 | |
29 | Function *RuntimeDebugBuilder::getVPrintF(PollyIRBuilder &Builder) { |
30 | Module *M = Builder.GetInsertBlock()->getParent()->getParent(); |
31 | const char *Name = "vprintf" ; |
32 | Function *F = M->getFunction(Name); |
33 | |
34 | if (!F) { |
35 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
36 | FunctionType *Ty = FunctionType::get( |
37 | Result: Builder.getInt32Ty(), Params: {Builder.getPtrTy(), Builder.getPtrTy()}, isVarArg: false); |
38 | F = Function::Create(Ty, Linkage, N: Name, M); |
39 | } |
40 | |
41 | return F; |
42 | } |
43 | |
44 | void RuntimeDebugBuilder::createPrinter(PollyIRBuilder &Builder, |
45 | ArrayRef<Value *> Values) { |
46 | createCPUPrinterT(Builder, Values); |
47 | } |
48 | |
49 | bool RuntimeDebugBuilder::isPrintable(Type *Ty) { |
50 | if (Ty->isFloatingPointTy()) |
51 | return true; |
52 | |
53 | if (Ty->isIntegerTy()) |
54 | return Ty->getIntegerBitWidth() <= 64; |
55 | |
56 | if (isa<PointerType>(Val: Ty)) |
57 | return true; |
58 | |
59 | return false; |
60 | } |
61 | |
62 | static std::tuple<std::string, std::vector<Value *>> |
63 | prepareValuesForPrinting(PollyIRBuilder &Builder, ArrayRef<Value *> Values) { |
64 | std::string FormatString; |
65 | std::vector<Value *> ValuesToPrint; |
66 | |
67 | for (auto Val : Values) { |
68 | Type *Ty = Val->getType(); |
69 | |
70 | if (Ty->isFloatingPointTy()) { |
71 | if (!Ty->isDoubleTy()) |
72 | Val = Builder.CreateFPExt(V: Val, DestTy: Builder.getDoubleTy()); |
73 | } else if (Ty->isIntegerTy()) { |
74 | if (Ty->getIntegerBitWidth() < 64) |
75 | Val = Builder.CreateSExt(V: Val, DestTy: Builder.getInt64Ty()); |
76 | else |
77 | assert(Ty->getIntegerBitWidth() && |
78 | "Integer types larger 64 bit not supported" ); |
79 | } else if (isa<PointerType>(Val: Ty)) { |
80 | if (Ty == Builder.getPtrTy(AddrSpace: 4)) { |
81 | Val = Builder.CreateGEP(Ty: Builder.getInt8Ty(), Ptr: Val, IdxList: Builder.getInt64(C: 0)); |
82 | } else { |
83 | Val = Builder.CreatePtrToInt(V: Val, DestTy: Builder.getInt64Ty()); |
84 | } |
85 | } else { |
86 | llvm_unreachable("Unknown type" ); |
87 | } |
88 | |
89 | Ty = Val->getType(); |
90 | |
91 | if (Ty->isFloatingPointTy()) |
92 | FormatString += "%f" ; |
93 | else if (Ty->isIntegerTy()) |
94 | FormatString += "%ld" ; |
95 | else |
96 | FormatString += "%s" ; |
97 | |
98 | ValuesToPrint.push_back(x: Val); |
99 | } |
100 | |
101 | return std::make_tuple(args&: FormatString, args&: ValuesToPrint); |
102 | } |
103 | |
104 | void RuntimeDebugBuilder::createCPUPrinterT(PollyIRBuilder &Builder, |
105 | ArrayRef<Value *> Values) { |
106 | |
107 | std::string FormatString; |
108 | std::vector<Value *> ValuesToPrint; |
109 | |
110 | std::tie(args&: FormatString, args&: ValuesToPrint) = |
111 | prepareValuesForPrinting(Builder, Values); |
112 | |
113 | createPrintF(Builder, Format: FormatString, Values: ValuesToPrint); |
114 | createFlush(Builder); |
115 | } |
116 | |
117 | Function *RuntimeDebugBuilder::getPrintF(PollyIRBuilder &Builder) { |
118 | Module *M = Builder.GetInsertBlock()->getParent()->getParent(); |
119 | const char *Name = "printf" ; |
120 | Function *F = M->getFunction(Name); |
121 | |
122 | if (!F) { |
123 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
124 | FunctionType *Ty = FunctionType::get(Result: Builder.getInt32Ty(), isVarArg: true); |
125 | F = Function::Create(Ty, Linkage, N: Name, M); |
126 | } |
127 | |
128 | return F; |
129 | } |
130 | |
131 | void RuntimeDebugBuilder::createPrintF(PollyIRBuilder &Builder, |
132 | std::string Format, |
133 | ArrayRef<Value *> Values) { |
134 | Value *FormatString = Builder.CreateGlobalStringPtr(Str: Format); |
135 | std::vector<Value *> Arguments; |
136 | |
137 | Arguments.push_back(x: FormatString); |
138 | Arguments.insert(position: Arguments.end(), first: Values.begin(), last: Values.end()); |
139 | Builder.CreateCall(Callee: getPrintF(Builder), Args: Arguments); |
140 | } |
141 | |
142 | void RuntimeDebugBuilder::createFlush(PollyIRBuilder &Builder) { |
143 | Module *M = Builder.GetInsertBlock()->getParent()->getParent(); |
144 | const char *Name = "fflush" ; |
145 | Function *F = M->getFunction(Name); |
146 | |
147 | if (!F) { |
148 | GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; |
149 | FunctionType *Ty = |
150 | FunctionType::get(Result: Builder.getInt32Ty(), Params: Builder.getPtrTy(), isVarArg: false); |
151 | F = Function::Create(Ty, Linkage, N: Name, M); |
152 | } |
153 | |
154 | // fflush(NULL) flushes _all_ open output streams. |
155 | // |
156 | // fflush is declared as 'int fflush(FILE *stream)'. As we only pass on a NULL |
157 | // pointer, the type we point to does conceptually not matter. However, if |
158 | // fflush is already declared in this translation unit, we use the very same |
159 | // type to ensure that LLVM does not complain about mismatching types. |
160 | Builder.CreateCall(Callee: F, Args: Constant::getNullValue(Ty: F->arg_begin()->getType())); |
161 | } |
162 | |