xref: /llvm-project/polly/lib/Support/GICHelper.cpp (revision 2946cd701067404b99c39fb29dc9c74bd7193eb3)
1 //===- GmpConv.cpp - Recreate LLVM IR from the Scop.  ---------------------===//
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 // Functions for converting between gmp objects and llvm::APInt.
10 //
11 //===----------------------------------------------------------------------===//
12 #include "polly/Support/GICHelper.h"
13 #include "llvm/IR/Value.h"
14 #include "isl/aff.h"
15 #include "isl/map.h"
16 #include "isl/schedule.h"
17 #include "isl/set.h"
18 #include "isl/space.h"
19 #include "isl/union_map.h"
20 #include "isl/union_set.h"
21 #include "isl/val.h"
22 
23 #include <climits>
24 
25 using namespace llvm;
26 
27 __isl_give isl_val *polly::isl_valFromAPInt(isl_ctx *Ctx, const APInt Int,
28                                             bool IsSigned) {
29   APInt Abs;
30   isl_val *v;
31 
32   // As isl is interpreting the input always as unsigned value, we need some
33   // additional pre and post processing to import signed values. The approach
34   // we take is to first obtain the absolute value of Int and then negate the
35   // value after it has been imported to isl.
36   //
37   // It should be noted that the smallest integer value represented in two's
38   // complement with a certain amount of bits does not have a corresponding
39   // positive representation in two's complement representation with the same
40   // number of bits. E.g. 110 (-2) does not have a corresponding value for (2).
41   // To ensure that there is always a corresponding value available we first
42   // sign-extend the input by one bit and only then take the absolute value.
43   if (IsSigned)
44     Abs = Int.sext(Int.getBitWidth() + 1).abs();
45   else
46     Abs = Int;
47 
48   const uint64_t *Data = Abs.getRawData();
49   unsigned Words = Abs.getNumWords();
50 
51   v = isl_val_int_from_chunks(Ctx, Words, sizeof(uint64_t), Data);
52 
53   if (IsSigned && Int.isNegative())
54     v = isl_val_neg(v);
55 
56   return v;
57 }
58 
59 APInt polly::APIntFromVal(__isl_take isl_val *Val) {
60   uint64_t *Data;
61   int NumChunks;
62   const static int ChunkSize = sizeof(uint64_t);
63 
64   assert(isl_val_is_int(Val) && "Only integers can be converted to APInt");
65 
66   NumChunks = isl_val_n_abs_num_chunks(Val, ChunkSize);
67   Data = (uint64_t *)malloc(NumChunks * ChunkSize);
68   isl_val_get_abs_num_chunks(Val, ChunkSize, Data);
69   int NumBits = CHAR_BIT * ChunkSize * NumChunks;
70   APInt A(NumBits, NumChunks, Data);
71 
72   // As isl provides only an interface to obtain data that describes the
73   // absolute value of an isl_val, A at this point always contains a positive
74   // number. In case Val was originally negative, we expand the size of A by
75   // one and negate the value (in two's complement representation). As a result,
76   // the new value in A corresponds now with Val.
77   if (isl_val_is_neg(Val)) {
78     A = A.zext(A.getBitWidth() + 1);
79     A = -A;
80   }
81 
82   // isl may represent small numbers with more than the minimal number of bits.
83   // We truncate the APInt to the minimal number of bits needed to represent the
84   // signed value it contains, to ensure that the bitwidth is always minimal.
85   if (A.getMinSignedBits() < A.getBitWidth())
86     A = A.trunc(A.getMinSignedBits());
87 
88   free(Data);
89   isl_val_free(Val);
90   return A;
91 }
92 
93 template <typename ISLTy, typename ISL_CTX_GETTER, typename ISL_PRINTER>
94 static inline std::string stringFromIslObjInternal(__isl_keep ISLTy *isl_obj,
95                                                    ISL_CTX_GETTER ctx_getter_fn,
96                                                    ISL_PRINTER printer_fn) {
97   if (!isl_obj)
98     return "null";
99   isl_ctx *ctx = ctx_getter_fn(isl_obj);
100   isl_printer *p = isl_printer_to_str(ctx);
101   p = printer_fn(p, isl_obj);
102   char *char_str = isl_printer_get_str(p);
103   std::string string;
104   if (char_str)
105     string = char_str;
106   else
107     string = "null";
108   free(char_str);
109   isl_printer_free(p);
110   return string;
111 }
112 
113 std::string polly::stringFromIslObj(__isl_keep isl_map *map) {
114   return stringFromIslObjInternal(map, isl_map_get_ctx, isl_printer_print_map);
115 }
116 
117 std::string polly::stringFromIslObj(__isl_keep isl_set *set) {
118   return stringFromIslObjInternal(set, isl_set_get_ctx, isl_printer_print_set);
119 }
120 
121 std::string polly::stringFromIslObj(__isl_keep isl_union_map *umap) {
122   return stringFromIslObjInternal(umap, isl_union_map_get_ctx,
123                                   isl_printer_print_union_map);
124 }
125 
126 std::string polly::stringFromIslObj(__isl_keep isl_union_set *uset) {
127   return stringFromIslObjInternal(uset, isl_union_set_get_ctx,
128                                   isl_printer_print_union_set);
129 }
130 
131 std::string polly::stringFromIslObj(__isl_keep isl_schedule *schedule) {
132   return stringFromIslObjInternal(schedule, isl_schedule_get_ctx,
133                                   isl_printer_print_schedule);
134 }
135 
136 std::string polly::stringFromIslObj(__isl_keep isl_multi_aff *maff) {
137   return stringFromIslObjInternal(maff, isl_multi_aff_get_ctx,
138                                   isl_printer_print_multi_aff);
139 }
140 
141 std::string polly::stringFromIslObj(__isl_keep isl_pw_multi_aff *pma) {
142   return stringFromIslObjInternal(pma, isl_pw_multi_aff_get_ctx,
143                                   isl_printer_print_pw_multi_aff);
144 }
145 
146 std::string polly::stringFromIslObj(__isl_keep isl_multi_pw_aff *mpa) {
147   return stringFromIslObjInternal(mpa, isl_multi_pw_aff_get_ctx,
148                                   isl_printer_print_multi_pw_aff);
149 }
150 
151 std::string polly::stringFromIslObj(__isl_keep isl_union_pw_multi_aff *upma) {
152   return stringFromIslObjInternal(upma, isl_union_pw_multi_aff_get_ctx,
153                                   isl_printer_print_union_pw_multi_aff);
154 }
155 
156 std::string polly::stringFromIslObj(__isl_keep isl_aff *aff) {
157   return stringFromIslObjInternal(aff, isl_aff_get_ctx, isl_printer_print_aff);
158 }
159 
160 std::string polly::stringFromIslObj(__isl_keep isl_pw_aff *pwaff) {
161   return stringFromIslObjInternal(pwaff, isl_pw_aff_get_ctx,
162                                   isl_printer_print_pw_aff);
163 }
164 
165 std::string polly::stringFromIslObj(__isl_keep isl_space *space) {
166   return stringFromIslObjInternal(space, isl_space_get_ctx,
167                                   isl_printer_print_space);
168 }
169 
170 static void replace(std::string &str, const std::string &find,
171                     const std::string &replace) {
172   size_t pos = 0;
173   while ((pos = str.find(find, pos)) != std::string::npos) {
174     str.replace(pos, find.length(), replace);
175     pos += replace.length();
176   }
177 }
178 
179 static void makeIslCompatible(std::string &str) {
180   replace(str, ".", "_");
181   replace(str, "\"", "_");
182   replace(str, " ", "__");
183   replace(str, "=>", "TO");
184   replace(str, "+", "_");
185 }
186 
187 std::string polly::getIslCompatibleName(const std::string &Prefix,
188                                         const std::string &Middle,
189                                         const std::string &Suffix) {
190   std::string S = Prefix + Middle + Suffix;
191   makeIslCompatible(S);
192   return S;
193 }
194 
195 std::string polly::getIslCompatibleName(const std::string &Prefix,
196                                         const std::string &Name, long Number,
197                                         const std::string &Suffix,
198                                         bool UseInstructionNames) {
199   std::string S = Prefix;
200 
201   if (UseInstructionNames)
202     S += std::string("_") + Name;
203   else
204     S += std::to_string(Number);
205 
206   S += Suffix;
207 
208   makeIslCompatible(S);
209   return S;
210 }
211 
212 std::string polly::getIslCompatibleName(const std::string &Prefix,
213                                         const Value *Val, long Number,
214                                         const std::string &Suffix,
215                                         bool UseInstructionNames) {
216   std::string ValStr;
217 
218   if (UseInstructionNames && Val->hasName())
219     ValStr = std::string("_") + std::string(Val->getName());
220   else
221     ValStr = std::to_string(Number);
222 
223   return getIslCompatibleName(Prefix, ValStr, Suffix);
224 }
225 
226 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
227 /// To call a inline dump() method in a debugger, at it must have been
228 /// instantiated in at least one translation unit. Because isl's dump() method
229 /// are meant to be called from a debugger only, but not from code, no such
230 /// instantiation would exist. We use this method to force an instantiation in
231 /// this translation unit. Because it has non-static linking, the compiler does
232 /// not know that it is never called, and therefore must ensure the existence of
233 /// the dump functions.
234 void neverCalled() {
235   isl::aff().dump();
236   isl::aff_list().dump();
237   isl::ast_expr().dump();
238   isl::ast_expr_list().dump();
239   isl::ast_node().dump();
240   isl::ast_node_list().dump();
241   isl::basic_map().dump();
242   isl::basic_map_list().dump();
243   isl::basic_set().dump();
244   isl::basic_set_list().dump();
245   isl::constraint().dump();
246   isl::constraint_list().dump();
247   isl::id().dump();
248   isl::id_list().dump();
249   isl::id_to_ast_expr().dump();
250   isl::local_space().dump();
251   isl::map().dump();
252   isl::map_list().dump();
253   isl::multi_aff().dump();
254   isl::multi_pw_aff().dump();
255   isl::multi_union_pw_aff().dump();
256   isl::multi_val().dump();
257   isl::point().dump();
258   isl::pw_aff().dump();
259   isl::pw_aff_list().dump();
260   isl::pw_multi_aff().dump();
261   isl::pw_qpolynomial().dump();
262   isl::qpolynomial().dump();
263   isl::schedule().dump();
264   isl::schedule_constraints().dump();
265   isl::schedule_node().dump();
266   isl::set().dump();
267   isl::set_list().dump();
268   isl::space().dump();
269   isl::union_map().dump();
270   isl::union_map_list().dump();
271   isl::union_pw_aff().dump();
272   isl::union_pw_aff_list().dump();
273   isl::union_pw_multi_aff().dump();
274   isl::union_pw_multi_aff_list().dump();
275   isl::union_set().dump();
276   isl::union_set_list().dump();
277   isl::val().dump();
278   isl::val_list().dump();
279 }
280 #endif
281