Enzyme main
Loading...
Searching...
No Matches
TypeAnalysis.cpp
Go to the documentation of this file.
1//===- TypeAnalysis.cpp - Implementation of Type Analysis ------------===//
2//
3// Enzyme Project
4//
5// Part of the Enzyme Project, under the Apache License v2.0 with LLVM
6// Exceptions. See https://llvm.org/LICENSE.txt for license information.
7// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8//
9// If using this code in an academic setting, please cite the following:
10// @incollection{enzymeNeurips,
11// title = {Instead of Rewriting Foreign Code for Machine Learning,
12// Automatically Synthesize Fast Gradients},
13// author = {Moses, William S. and Churavy, Valentin},
14// booktitle = {Advances in Neural Information Processing Systems 33},
15// year = {2020},
16// note = {To appear in},
17// }
18//
19//===----------------------------------------------------------------------===//
20//
21// This file contains the implementation of Type Analysis, a utility for
22// computing the underlying data type of LLVM values.
23//
24//===----------------------------------------------------------------------===//
25#include <cstdint>
26#include <deque>
27
28#include <llvm/Config/llvm-config.h>
29
30#include "llvm/Demangle/Demangle.h"
31#include "llvm/Demangle/ItaniumDemangle.h"
32
33#include "llvm/IR/Constants.h"
34#include "llvm/IR/Function.h"
35#include "llvm/IR/InstrTypes.h"
36#include "llvm/IR/Instructions.h"
37#include "llvm/IR/IntrinsicInst.h"
38#include "llvm/IR/ModuleSlotTracker.h"
39#include "llvm/IR/Type.h"
40#include "llvm/IR/Value.h"
41
42#include "llvm/ProfileData/InstrProf.h"
43
44#include "llvm/IR/InstIterator.h"
45
46#include "llvm/Support/CommandLine.h"
47#include "llvm/Support/TimeProfiler.h"
48#include "llvm/Support/raw_ostream.h"
49
50#include "llvm/ADT/SmallSet.h"
51#include "llvm/ADT/StringMap.h"
52#include "llvm/ADT/StringSet.h"
53
54#include "llvm/IR/InlineAsm.h"
55
56#include "../EnzymeLogic.h"
57#include "../Utils.h"
58#include "TypeAnalysis.h"
59
60#include "../FunctionUtils.h"
61#include "../LibraryFuncs.h"
62
63#include "TBAA.h"
64
65#include <math.h>
66
67#if LLVM_VERSION_MAJOR >= 14
68#define getAttribute getAttributeAtIndex
69#define hasAttribute hasAttributeAtIndex
70#define addAttribute addAttributeAtIndex
71#endif
72
73using namespace llvm;
74
75extern "C" {
76/// Maximum offset for type trees to keep
77llvm::cl::opt<int> MaxIntOffset("enzyme-max-int-offset", cl::init(100),
78 cl::Hidden,
79 cl::desc("Maximum type tree offset"));
80
81llvm::cl::opt<unsigned> EnzymeMaxTypeDepth("enzyme-max-type-depth", cl::init(6),
82 cl::Hidden,
83 cl::desc("Maximum type tree depth"));
84
85llvm::cl::opt<bool> EnzymePrintType("enzyme-print-type", cl::init(false),
86 cl::Hidden,
87 cl::desc("Print type analysis algorithm"));
88
89llvm::cl::opt<bool> RustTypeRules("enzyme-rust-type", cl::init(false),
90 cl::Hidden,
91 cl::desc("Enable rust-specific type rules"));
92
93llvm::cl::opt<bool> EnzymeStrictAliasing(
94 "enzyme-strict-aliasing", cl::init(true), cl::Hidden,
95 cl::desc("Assume strict aliasing of types / type stability"));
96}
97
98const llvm::StringMap<llvm::Intrinsic::ID> LIBM_FUNCTIONS = {
99 {"sinc", Intrinsic::not_intrinsic},
100 {"sincn", Intrinsic::not_intrinsic},
101 {"cos", Intrinsic::cos},
102 {"sin", Intrinsic::sin},
103#if LLVM_VERSION_MAJOR >= 19
104 {"tan", Intrinsic::tan},
105 {"acos", Intrinsic::acos},
106#else
107 {"tan", Intrinsic::not_intrinsic},
108 {"acos", Intrinsic::not_intrinsic},
109#endif
110 {"__nv_frcp_rd", Intrinsic::not_intrinsic},
111 {"__nv_frcp_rn", Intrinsic::not_intrinsic},
112 {"__nv_frcp_ru", Intrinsic::not_intrinsic},
113 {"__nv_frcp_rz", Intrinsic::not_intrinsic},
114 {"__nv_drcp_rd", Intrinsic::not_intrinsic},
115 {"__nv_drcp_rn", Intrinsic::not_intrinsic},
116 {"__nv_drcp_ru", Intrinsic::not_intrinsic},
117 {"__nv_drcp_rz", Intrinsic::not_intrinsic},
118#if LLVM_VERSION_MAJOR >= 19
119 {"asin", Intrinsic::asin},
120#else
121 {"asin", Intrinsic::not_intrinsic},
122#endif
123 {"__nv_asin", Intrinsic::not_intrinsic},
124#if LLVM_VERSION_MAJOR >= 19
125 {"atan", Intrinsic::atan},
126#else
127 {"atan", Intrinsic::not_intrinsic},
128#endif
129 {"atan2", Intrinsic::not_intrinsic},
130 {"__nv_atan2", Intrinsic::not_intrinsic},
131#if LLVM_VERSION_MAJOR >= 19
132 {"cosh", Intrinsic::cosh},
133 {"sinh", Intrinsic::sinh},
134 {"tanh", Intrinsic::tanh},
135#else
136 {"cosh", Intrinsic::not_intrinsic},
137 {"sinh", Intrinsic::not_intrinsic},
138 {"tanh", Intrinsic::not_intrinsic},
139#endif
140 {"acosh", Intrinsic::not_intrinsic},
141 {"asinh", Intrinsic::not_intrinsic},
142 {"atanh", Intrinsic::not_intrinsic},
143 {"exp", Intrinsic::exp},
144 {"exp2", Intrinsic::exp2},
145#if LLVM_VERSION_MAJOR >= 18
146 {"exp10", Intrinsic::exp10},
147#else
148 {"exp10", Intrinsic::not_intrinsic},
149#endif
150 {"log", Intrinsic::log},
151 {"log10", Intrinsic::log10},
152 {"expm1", Intrinsic::not_intrinsic},
153 {"log1p", Intrinsic::not_intrinsic},
154 {"log2", Intrinsic::log2},
155 {"logb", Intrinsic::not_intrinsic},
156 {"pow", Intrinsic::pow},
157 {"sqrt", Intrinsic::sqrt},
158 {"cbrt", Intrinsic::not_intrinsic},
159 {"hypot", Intrinsic::not_intrinsic},
160
161 {"__mulsc3", Intrinsic::not_intrinsic},
162 {"__muldc3", Intrinsic::not_intrinsic},
163 {"__multc3", Intrinsic::not_intrinsic},
164 {"__mulxc3", Intrinsic::not_intrinsic},
165
166 {"__divsc3", Intrinsic::not_intrinsic},
167 {"__divdc3", Intrinsic::not_intrinsic},
168 {"__divtc3", Intrinsic::not_intrinsic},
169 {"__divxc3", Intrinsic::not_intrinsic},
170
171 {"Faddeeva_erf", Intrinsic::not_intrinsic},
172 {"Faddeeva_erfc", Intrinsic::not_intrinsic},
173 {"Faddeeva_erfcx", Intrinsic::not_intrinsic},
174 {"Faddeeva_erfi", Intrinsic::not_intrinsic},
175 {"Faddeeva_dawson", Intrinsic::not_intrinsic},
176 {"Faddeeva_erf_re", Intrinsic::not_intrinsic},
177 {"Faddeeva_erfc_re", Intrinsic::not_intrinsic},
178 {"Faddeeva_erfcx_re", Intrinsic::not_intrinsic},
179 {"Faddeeva_erfi_re", Intrinsic::not_intrinsic},
180 {"Faddeeva_dawson_re", Intrinsic::not_intrinsic},
181 {"erf", Intrinsic::not_intrinsic},
182 {"erfi", Intrinsic::not_intrinsic},
183 {"erfc", Intrinsic::not_intrinsic},
184 {"erfinv", Intrinsic::not_intrinsic},
185
186 {"__fd_sincos_1", Intrinsic::not_intrinsic},
187 {"sincospi", Intrinsic::not_intrinsic},
188 {"cmplx_inv", Intrinsic::not_intrinsic},
189
190 // bessel functions
191 {"j0", Intrinsic::not_intrinsic},
192 {"j1", Intrinsic::not_intrinsic},
193 {"jn", Intrinsic::not_intrinsic},
194 {"y0", Intrinsic::not_intrinsic},
195 {"y1", Intrinsic::not_intrinsic},
196 {"yn", Intrinsic::not_intrinsic},
197 {"tgamma", Intrinsic::not_intrinsic},
198 {"lgamma", Intrinsic::not_intrinsic},
199 {"logabsgamma", Intrinsic::not_intrinsic},
200 {"ceil", Intrinsic::ceil},
201 {"__nv_ceil", Intrinsic::ceil},
202 {"floor", Intrinsic::floor},
203 {"fmod", Intrinsic::not_intrinsic},
204 {"trunc", Intrinsic::trunc},
205 {"round", Intrinsic::round},
206 {"rint", Intrinsic::rint},
207 {"nearbyint", Intrinsic::nearbyint},
208 {"remainder", Intrinsic::not_intrinsic},
209 {"copysign", Intrinsic::copysign},
210 {"nextafter", Intrinsic::not_intrinsic},
211 {"nexttoward", Intrinsic::not_intrinsic},
212 {"fdim", Intrinsic::not_intrinsic},
213 {"fmax", Intrinsic::maxnum},
214 {"fmin", Intrinsic::minnum},
215 {"fabs", Intrinsic::fabs},
216 {"fma", Intrinsic::fma},
217 {"ilogb", Intrinsic::not_intrinsic},
218 {"scalbn", Intrinsic::not_intrinsic},
219 {"scalbln", Intrinsic::not_intrinsic},
220 {"powi", Intrinsic::powi},
221 {"cabs", Intrinsic::not_intrinsic},
222 {"ldexp", Intrinsic::not_intrinsic},
223 {"fmod", Intrinsic::not_intrinsic},
224 {"finite", Intrinsic::not_intrinsic},
225 {"isinf", Intrinsic::not_intrinsic},
226 {"isnan", Intrinsic::not_intrinsic},
227 {"lround", Intrinsic::lround},
228 {"llround", Intrinsic::llround},
229 {"lrint", Intrinsic::lrint},
230 {"llrint", Intrinsic::llrint}};
231
232static bool isItaniumEncoding(StringRef S) {
233 // Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'.
234 return startsWith(S, "_Z") || startsWith(S, "___Z");
235}
236
237bool dontAnalyze(StringRef str) {
238 if (isItaniumEncoding(str)) {
239 if (str.empty())
240 return false;
241
242 ItaniumPartialDemangler Parser;
243 char *data = (char *)malloc(str.size() + 1);
244 memcpy(data, str.data(), str.size());
245 data[str.size()] = 0;
246 bool hasError = Parser.partialDemangle(data);
247 if (hasError) {
248 free(data);
249 return false;
250 }
251
252 // auto basename = Parser.getFunctionBaseName(0, 0);
253 // auto base = Parser.getFunctionDeclContextName(0, 0);
254 // auto fn = Parser.getFunctionName(0, 0);
255 // llvm::errs() << " err: " << base << " - " << basename << " fn - " << fn
256 // << "\n";
257 free(data);
258 }
259 return false;
260}
261
263 uint8_t direction)
264 : MST(EnzymePrintType ? new ModuleSlotTracker(fn.Function->getParent())
265 : nullptr),
266 notForAnalysis(getGuaranteedUnreachable(fn.Function)), intseen(),
267 fntypeinfo(fn), interprocedural(TA), direction(direction), Invalid(false),
268 PHIRecur(false),
269 TLI(TA.Logic.PPC.FAM.getResult<TargetLibraryAnalysis>(*fn.Function)),
270 DT(TA.Logic.PPC.FAM.getResult<DominatorTreeAnalysis>(*fn.Function)),
271 PDT(TA.Logic.PPC.FAM.getResult<PostDominatorTreeAnalysis>(*fn.Function)),
272 LI(TA.Logic.PPC.FAM.getResult<LoopAnalysis>(*fn.Function)),
273 SE(TA.Logic.PPC.FAM.getResult<ScalarEvolutionAnalysis>(*fn.Function)) {
274
275 assert(fntypeinfo.KnownValues.size() ==
276 fntypeinfo.Function->getFunctionType()->getNumParams());
277
278 // Add all instructions in the function
279 for (BasicBlock &BB : *fntypeinfo.Function) {
280 if (notForAnalysis.count(&BB))
281 continue;
282 for (Instruction &I : BB) {
283 workList.insert(&I);
284 }
285 }
286 // Add all operands referenced in the function
287 // This is done to investigate any referenced globals/etc
288 for (BasicBlock &BB : *fntypeinfo.Function) {
289 for (Instruction &I : BB) {
290 for (auto &Op : I.operands()) {
291 addToWorkList(Op);
292 }
293 }
294 }
295}
296
298 const FnTypeInfo &fn, TypeAnalysis &TA,
299 const llvm::SmallPtrSetImpl<llvm::BasicBlock *> &notForAnalysis,
300 const TypeAnalyzer &Prev, uint8_t direction, bool PHIRecur)
301 : MST(Prev.MST),
302 notForAnalysis(notForAnalysis.begin(), notForAnalysis.end()), intseen(),
303 fntypeinfo(fn), interprocedural(TA), direction(direction), Invalid(false),
304 PHIRecur(PHIRecur), TLI(Prev.TLI), DT(Prev.DT), PDT(Prev.PDT),
305 LI(Prev.LI), SE(Prev.SE) {
306 assert(fntypeinfo.KnownValues.size() ==
307 fntypeinfo.Function->getFunctionType()->getNumParams());
308}
309
310static SmallPtrSet<BasicBlock *, 1>
311findLoopIndices(llvm::Value *val, LoopInfo &LI, DominatorTree &DT,
312 SmallPtrSet<PHINode *, 1> &seen) {
313 if (isa<Constant>(val))
314 return {};
315 if (auto CI = dyn_cast<CastInst>(val))
316 return findLoopIndices(CI->getOperand(0), LI, DT, seen);
317 if (auto CI = dyn_cast<UnaryOperator>(val))
318 return findLoopIndices(CI->getOperand(0), LI, DT, seen);
319 if (auto bo = dyn_cast<BinaryOperator>(val)) {
320 auto inset0 = findLoopIndices(bo->getOperand(0), LI, DT, seen);
321 auto inset1 = findLoopIndices(bo->getOperand(1), LI, DT, seen);
322 inset0.insert(inset1.begin(), inset1.end());
323 return inset0;
324 }
325 if (auto LDI = dyn_cast<LoadInst>(val)) {
326 if (auto AI = dyn_cast<AllocaInst>(LDI->getPointerOperand())) {
327 StoreInst *SI = nullptr;
328 bool failed = false;
329 for (auto u : AI->users()) {
330 if (auto SIu = dyn_cast<StoreInst>(u)) {
331 if (SI && SIu->getValueOperand() == AI) {
332 failed = true;
333 break;
334 }
335 SI = SIu;
336 } else if (!isa<LoadInst>(u)) {
337 if (!cast<Instruction>(u)->mayReadOrWriteMemory() &&
338 cast<Instruction>(u)->use_empty())
339 continue;
340 if (auto CI = dyn_cast<CallBase>(u)) {
341 if (auto F = CI->getCalledFunction()) {
342 auto funcName = F->getName();
343 if (funcName == "__kmpc_for_static_init_4" ||
344 funcName == "__kmpc_for_static_init_4u" ||
345 funcName == "__kmpc_for_static_init_8" ||
346 funcName == "__kmpc_for_static_init_8u") {
347 continue;
348 }
349 }
350 }
351 failed = true;
352 break;
353 }
354 }
355 if (SI && !failed && DT.dominates(SI, LDI)) {
356 return findLoopIndices(SI->getValueOperand(), LI, DT, seen);
357 }
358 }
359 }
360 if (auto pn = dyn_cast<PHINode>(val)) {
361 auto L = LI.getLoopFor(pn->getParent());
362 if (L && L->getHeader() == pn->getParent())
363 return {pn->getParent()};
364 if (seen.contains(pn))
365 return {};
366 SmallPtrSet<BasicBlock *, 1> ops;
367 seen.insert(pn);
368 for (unsigned i = 0; i < pn->getNumIncomingValues(); ++i) {
369 auto a = pn->getIncomingValue(i);
370 auto seti = findLoopIndices(a, LI, DT, seen);
371 ops.insert(seti.begin(), seti.end());
372 }
373 return ops;
374 }
375 return {};
376}
377
378std::set<int64_t>
379FnTypeInfo::knownIntegralValues(llvm::Value *val, const DominatorTree &DT,
380 std::map<Value *, std::set<int64_t>> &intseen,
381 ScalarEvolution &SE) const {
382 if (auto constant = dyn_cast<ConstantInt>(val)) {
383#if LLVM_VERSION_MAJOR > 14
384 if (constant->getValue().getSignificantBits() > 64)
385 return {};
386#else
387 if (constant->getValue().getMinSignedBits() > 64)
388 return {};
389#endif
390 return {constant->getSExtValue()};
391 }
392
393 if (isa<ConstantPointerNull>(val)) {
394 return {0};
395 }
396
397 assert(KnownValues.size() == Function->getFunctionType()->getNumParams());
398
399 if (auto arg = dyn_cast<llvm::Argument>(val)) {
400 auto found = KnownValues.find(arg);
401 if (found == KnownValues.end()) {
402 for (const auto &pair : KnownValues) {
403 llvm::errs() << " KnownValues[" << *pair.first << "] - "
404 << pair.first->getParent()->getName() << "\n";
405 }
406 llvm::errs() << " arg: " << *arg << " - " << arg->getParent()->getName()
407 << "\n";
408 }
409 assert(found != KnownValues.end());
410 return found->second;
411 }
412
413 if (intseen.find(val) != intseen.end())
414 return intseen[val];
415 intseen[val] = {};
416
417 if (auto ci = dyn_cast<CastInst>(val)) {
418 intseen[val] = knownIntegralValues(ci->getOperand(0), DT, intseen, SE);
419 }
420
421 auto insert = [&](int64_t v) {
422 if (intseen[val].size() == 0) {
423 intseen[val].insert(v);
424 } else {
425 if (intseen[val].size() == 1) {
426 if (abs(*intseen[val].begin()) > MaxIntOffset) {
427 if (abs(*intseen[val].begin()) > abs(v)) {
428 intseen[val].clear();
429 intseen[val].insert(v);
430 } else {
431 return;
432 }
433 } else {
434 if (abs(v) > MaxIntOffset) {
435 return;
436 } else {
437 intseen[val].insert(v);
438 }
439 }
440 } else {
441 if (abs(v) > MaxIntOffset) {
442 return;
443 } else {
444 intseen[val].insert(v);
445 }
446 }
447 }
448 };
449 if (auto II = dyn_cast<IntrinsicInst>(val)) {
450 switch (II->getIntrinsicID()) {
451#if LLVM_VERSION_MAJOR >= 12
452 case Intrinsic::abs:
453 for (auto val :
454 knownIntegralValues(II->getArgOperand(0), DT, intseen, SE))
455 insert(abs(val));
456 break;
457#endif
458 case Intrinsic::nvvm_read_ptx_sreg_tid_x:
459 case Intrinsic::nvvm_read_ptx_sreg_tid_y:
460 case Intrinsic::nvvm_read_ptx_sreg_tid_z:
461 case Intrinsic::nvvm_read_ptx_sreg_ctaid_x:
462 case Intrinsic::nvvm_read_ptx_sreg_ctaid_y:
463 case Intrinsic::nvvm_read_ptx_sreg_ctaid_z:
464 case Intrinsic::amdgcn_workitem_id_x:
465 case Intrinsic::amdgcn_workitem_id_y:
466 case Intrinsic::amdgcn_workitem_id_z:
467 insert(0);
468 break;
469 default:
470 break;
471 }
472 }
473 if (auto LI = dyn_cast<LoadInst>(val)) {
474 if (auto AI = dyn_cast<AllocaInst>(LI->getPointerOperand())) {
475 StoreInst *SI = nullptr;
476 bool failed = false;
477 for (auto u : AI->users()) {
478 if (auto SIu = dyn_cast<StoreInst>(u)) {
479 if (SI && SIu->getValueOperand() == AI) {
480 failed = true;
481 break;
482 }
483 SI = SIu;
484 } else if (!isa<LoadInst>(u)) {
485 if (!cast<Instruction>(u)->mayReadOrWriteMemory() &&
486 cast<Instruction>(u)->use_empty())
487 continue;
488 if (auto CI = dyn_cast<CallBase>(u)) {
489 if (auto F = CI->getCalledFunction()) {
490 auto funcName = F->getName();
491 if (funcName == "__kmpc_for_static_init_4" ||
492 funcName == "__kmpc_for_static_init_4u" ||
493 funcName == "__kmpc_for_static_init_8" ||
494 funcName == "__kmpc_for_static_init_8u") {
495 continue;
496 }
497 }
498 }
499 failed = true;
500 break;
501 }
502 }
503 if (SI && !failed && DT.dominates(SI, LI)) {
504 for (auto val :
505 knownIntegralValues(SI->getValueOperand(), DT, intseen, SE)) {
506 insert(val);
507 }
508 }
509 }
510 }
511 if (auto pn = dyn_cast<PHINode>(val)) {
512 if (SE.isSCEVable(pn->getType()))
513 if (auto S = dyn_cast<SCEVAddRecExpr>(SE.getSCEV(pn))) {
514 if (auto StartC = dyn_cast<SCEVConstant>(S->getStart())) {
515 auto L = S->getLoop();
516 auto BE = SE.getBackedgeTakenCount(L);
517 if (BE != SE.getCouldNotCompute()) {
518 if (auto Iters = dyn_cast<SCEVConstant>(BE)) {
519 uint64_t ival = Iters->getAPInt().getZExtValue();
520 // If strict aliasing and the loop header does not dominate all
521 // blocks at low optimization levels the last "iteration" will
522 // actually exit leading to one extra backedge that would be wise
523 // to ignore.
525 bool rotated = false;
526 BasicBlock *Latch = L->getLoopLatch();
527 rotated = Latch && L->isLoopExiting(Latch);
528 if (!rotated) {
529 if (ival > 0)
530 ival--;
531 }
532 }
533
534 uint64_t istart = 0;
535
536 if (S->isAffine()) {
537 if (auto StepC = dyn_cast<SCEVConstant>(S->getOperand(1))) {
538 APInt StartI = StartC->getAPInt();
539 APInt A = StepC->getAPInt();
540
541 if (A.sle(-1)) {
542 A = -A;
543 StartI = -StartI;
544 }
545
546 if (A.sge(1)) {
547 if (StartI.sge(MaxIntOffset)) {
548 ival = std::min(ival, (uint64_t)0);
549 } else {
550 ival = std::min(
551 ival,
552 (MaxIntOffset - StartI + A).udiv(A).getZExtValue());
553 }
554
555 if (StartI.slt(-MaxIntOffset)) {
556 istart = std::max(
557 istart,
558 (-MaxIntOffset - StartI).udiv(A).getZExtValue());
559 }
560
561 } else {
562 ival = std::min(ival, (uint64_t)0);
563 }
564 } else {
565 ival = std::min(ival, (uint64_t)0);
566 }
567 }
568
569 for (uint64_t i = istart; i <= ival; i++) {
570 if (auto Val = dyn_cast<SCEVConstant>(S->evaluateAtIteration(
571 SE.getConstant(Iters->getType(), i, /*signed*/ false),
572 SE))) {
573 if (Val->getAPInt().getSignificantBits() <= 64)
574 insert(Val->getAPInt().getSExtValue());
575 }
576 }
577 return intseen[val];
578 }
579 }
580 }
581 }
582
583 for (unsigned i = 0; i < pn->getNumIncomingValues(); ++i) {
584 auto a = pn->getIncomingValue(i);
585 auto b = pn->getIncomingBlock(i);
586
587 // do not consider loop incoming edges
588 if (pn->getParent() == b || DT.dominates(pn, b)) {
589 continue;
590 }
591
592 auto inset = knownIntegralValues(a, DT, intseen, SE);
593
594 // TODO this here is not fully justified yet
595 for (auto pval : inset) {
596 if (pval < 20 && pval > -20) {
597 insert(pval);
598 }
599 }
600
601 // if we are an iteration variable, suppose that it could be zero in that
602 // range
603 // TODO: could actually check the range intercepts 0
604 if (auto bo = dyn_cast<BinaryOperator>(a)) {
605 if (bo->getOperand(0) == pn || bo->getOperand(1) == pn) {
606 if (bo->getOpcode() == BinaryOperator::Add ||
607 bo->getOpcode() == BinaryOperator::Sub) {
608 insert(0);
609 }
610 }
611 }
612 }
613 return intseen[val];
614 }
615
616 if (auto bo = dyn_cast<BinaryOperator>(val)) {
617 auto inset0 = knownIntegralValues(bo->getOperand(0), DT, intseen, SE);
618 auto inset1 = knownIntegralValues(bo->getOperand(1), DT, intseen, SE);
619 if (bo->getOpcode() == BinaryOperator::Mul) {
620
621 if (inset0.size() == 1 || inset1.size() == 1) {
622 for (auto val0 : inset0) {
623 for (auto val1 : inset1) {
624
625 insert(val0 * val1);
626 }
627 }
628 }
629 if (inset0.count(0) || inset1.count(0)) {
630 intseen[val].insert(0);
631 }
632 }
633
634 if (bo->getOpcode() == BinaryOperator::Add) {
635 if (inset0.size() == 1 || inset1.size() == 1) {
636 for (auto val0 : inset0) {
637 for (auto val1 : inset1) {
638 insert(val0 + val1);
639 }
640 }
641 }
642 }
643 if (bo->getOpcode() == BinaryOperator::Sub) {
644 if (inset0.size() == 1 || inset1.size() == 1) {
645 for (auto val0 : inset0) {
646 for (auto val1 : inset1) {
647 insert(val0 - val1);
648 }
649 }
650 }
651 }
652
653 if (bo->getOpcode() == BinaryOperator::SDiv) {
654 if (inset0.size() == 1 || inset1.size() == 1) {
655 for (auto val0 : inset0) {
656 for (auto val1 : inset1) {
657 insert(val0 / val1);
658 }
659 }
660 }
661 }
662
663 if (bo->getOpcode() == BinaryOperator::Shl) {
664 if (inset0.size() == 1 || inset1.size() == 1) {
665 for (auto val0 : inset0) {
666 for (auto val1 : inset1) {
667 insert(val0 << val1);
668 }
669 }
670 }
671 }
672
673 // TODO note C++ doesnt guarantee behavior of >> being arithmetic or logical
674 // and should replace with llvm apint internal
675 if (bo->getOpcode() == BinaryOperator::AShr ||
676 bo->getOpcode() == BinaryOperator::LShr) {
677 if (inset0.size() == 1 || inset1.size() == 1) {
678 for (auto val0 : inset0) {
679 for (auto val1 : inset1) {
680 insert(val0 >> val1);
681 }
682 }
683 }
684 }
685 }
686
687 return intseen[val];
688}
689
690/// Given a constant value, deduce any type information applicable
691void getConstantAnalysis(Constant *Val, TypeAnalyzer &TA,
692 std::map<llvm::Value *, TypeTree> &analysis) {
693 auto found = analysis.find(Val);
694 if (found != analysis.end())
695 return;
696
697 auto &DL = TA.fntypeinfo.Function->getParent()->getDataLayout();
698
699 // Undefined value is an anything everywhere
700 if (isa<UndefValue>(Val) || isa<ConstantAggregateZero>(Val)) {
701 analysis[Val].insert({-1}, BaseType::Anything);
702 return;
703 }
704
705 // Null pointer is a pointer to anything, everywhere
706 if (isa<ConstantPointerNull>(Val)) {
707 TypeTree &Result = analysis[Val];
708 Result.insert({-1}, BaseType::Pointer);
709 Result.insert({-1, -1}, BaseType::Anything);
710 return;
711 }
712
713 // Known pointers are pointers at offset 0
714 if (isa<Function>(Val) || isa<BlockAddress>(Val)) {
715 analysis[Val].insert({-1}, BaseType::Pointer);
716 return;
717 }
718
719 // Any constants == 0 are considered Anything
720 // other floats are assumed to be that type
721 if (auto FP = dyn_cast<ConstantFP>(Val)) {
722 if (FP->isExactlyValue(0.0)) {
723 analysis[Val].insert({-1}, BaseType::Anything);
724 return;
725 }
726 analysis[Val].insert({-1}, ConcreteType(FP->getType()->getScalarType()));
727 return;
728 }
729
730 if (auto ci = dyn_cast<ConstantInt>(Val)) {
731 // Constants in range [1, 4096] are assumed to be integral since
732 // any float or pointers they may represent are ill-formed
733 if (!ci->isNegative() && ci->getLimitedValue() >= 1 &&
734 ci->getLimitedValue() <= 4096) {
735 analysis[Val].insert({-1}, BaseType::Integer);
736 return;
737 }
738
739 // Constants explicitly marked as negative that aren't -1 are considered
740 // integral if >= -4096
741 if (ci->isNegative() && !ci->isMinusOne() && ci->getValue().sge(-4096)) {
742 analysis[Val].insert({-1}, BaseType::Integer);
743 return;
744 }
745
746 // Values of size < 16 (half size) are considered integral
747 // since they cannot possibly represent a float or pointer
748 if (cast<IntegerType>(ci->getType())->getBitWidth() < 16) {
749 analysis[Val].insert({-1}, BaseType::Integer);
750 return;
751 }
752 // All other constant-ints could be any type
753 analysis[Val].insert({-1}, BaseType::Anything);
754 return;
755 }
756
757 // Type of an aggregate is the aggregation of
758 // the subtypes
759 if (auto CA = dyn_cast<ConstantAggregate>(Val)) {
760 TypeTree &Result = analysis[Val];
761 for (unsigned i = 0, size = CA->getNumOperands(); i < size; ++i) {
762 assert(TA.fntypeinfo.Function);
763 auto Op = CA->getOperand(i);
764 // TODO check this for i1 constant aggregates packing/etc
765 auto ObjSize = (TA.fntypeinfo.Function->getParent()
766 ->getDataLayout()
767 .getTypeSizeInBits(Op->getType()) +
768 7) /
769 8;
770
771 int Off = (int)getAggregateElementOffset(DL, Val->getType(), i);
772 if (auto VT = dyn_cast<VectorType>(Val->getType()))
773 if (VT->getElementType()->isIntegerTy(1))
774 Off = i / 8;
775
776 getConstantAnalysis(Op, TA, analysis);
777 auto mid = analysis[Op];
778 if (TA.fntypeinfo.Function->getParent()
779 ->getDataLayout()
780 .getTypeSizeInBits(CA->getType()) >= 16) {
781 mid.ReplaceIntWithAnything();
782 }
783
784 Result |= mid.ShiftIndices(DL, /*init offset*/ 0,
785 /*maxSize*/ ObjSize,
786 /*addOffset*/ Off);
787 }
788 Result.CanonicalizeInPlace(
789 (TA.fntypeinfo.Function->getParent()->getDataLayout().getTypeSizeInBits(
790 CA->getType()) +
791 7) /
792 8,
793 DL);
794 return;
795 }
796
797 // Type of an sequence is the aggregation of
798 // the subtypes
799 if (auto CD = dyn_cast<ConstantDataSequential>(Val)) {
800 TypeTree &Result = analysis[Val];
801 for (unsigned i = 0, size = CD->getNumElements(); i < size; ++i) {
802 assert(TA.fntypeinfo.Function);
803 auto Op = CD->getElementAsConstant(i);
804 // TODO check this for i1 constant aggregates packing/etc
805 auto ObjSize = (TA.fntypeinfo.Function->getParent()
806 ->getDataLayout()
807 .getTypeSizeInBits(Op->getType()) +
808 7) /
809 8;
810
811 int Off = (int)getAggregateElementOffset(DL, Val->getType(), i);
812
813 getConstantAnalysis(Op, TA, analysis);
814 auto mid = analysis[Op];
815 if (TA.fntypeinfo.Function->getParent()
816 ->getDataLayout()
817 .getTypeSizeInBits(CD->getType()) >= 16) {
818 mid.ReplaceIntWithAnything();
819 }
820 Result |= mid.ShiftIndices(DL, /*init offset*/ 0,
821 /*maxSize*/ ObjSize,
822 /*addOffset*/ Off);
823 }
824 Result.CanonicalizeInPlace(
825 (TA.fntypeinfo.Function->getParent()->getDataLayout().getTypeSizeInBits(
826 CD->getType()) +
827 7) /
828 8,
829 DL);
830 return;
831 }
832
833 // ConstantExprs are handled by considering the
834 // equivalent instruction
835 if (auto CE = dyn_cast<ConstantExpr>(Val)) {
836 if (CE->isCast()) {
837 if (CE->getType()->isPointerTy() && isa<ConstantInt>(CE->getOperand(0))) {
838 analysis[Val] = TypeTree(BaseType::Anything).Only(-1, nullptr);
839 return;
840 }
841 getConstantAnalysis(CE->getOperand(0), TA, analysis);
842 analysis[Val] = analysis[CE->getOperand(0)];
843 return;
844 }
845 if (CE->getOpcode() == Instruction::GetElementPtr) {
846 TA.visitGEPOperator(*cast<GEPOperator>(CE));
847 return;
848 }
849
850 auto I = CE->getAsInstruction();
852 TA.fntypeinfo.Function->getEntryBlock().getTerminator());
853
854 // Just analyze this new "instruction" and none of the others
855 {
856 TypeAnalyzer tmpAnalysis(TA.fntypeinfo, TA.interprocedural,
857 TA.notForAnalysis, TA);
858 tmpAnalysis.visit(*I);
859 analysis[Val] = tmpAnalysis.getAnalysis(I);
860
861 if (tmpAnalysis.workList.remove(I)) {
862 TA.workList.insert(CE);
863 }
864 }
865
866 I->eraseFromParent();
867 return;
868 }
869
870 if (auto GV = dyn_cast<GlobalVariable>(Val)) {
871 if (auto MD = GV->getMetadata("enzyme_type")) {
872 analysis[Val] |= TypeTree::fromMD(MD);
873 return;
874 }
875
876 if (GV->getName() == "__cxa_thread_atexit_impl") {
877 analysis[Val] = TypeTree(BaseType::Pointer).Only(-1, nullptr);
878 return;
879 }
880
881 // from julia code
882 if (GV->getName() == "small_typeof" || GV->getName() == "jl_small_typeof") {
883 TypeTree T;
884 T.insert({-1}, BaseType::Pointer);
885 T.insert({-1, -1}, BaseType::Pointer);
886 analysis[Val] = T;
887 return;
888 }
889
890 // from julia code, the world age counter is an integer
891 if (GV->getName() == "jl_world_counter" ||
892 GV->getName() == "ijl_world_counter") {
893 TypeTree T;
894 T.insert({-1}, BaseType::Pointer);
895 T.insert({-1, -1}, BaseType::Integer);
896 analysis[Val] = T;
897 return;
898 }
899
900 if (startsWith(GV->getName(), getInstrProfCountersVarPrefix())) {
901 TypeTree T;
902 T.insert({-1}, BaseType::Pointer);
903 T.insert({-1, -1}, BaseType::Integer);
904 analysis[Val] = T;
905 return;
906 }
907 // A fixed constant global is a pointer to its initializer
908 if (GV->isConstant() && GV->hasInitializer()) {
909 // Record that this global is a pointer before analyzing its initializer.
910 // An initializer which refers back to its own global (such as a relative
911 // pointer jump table) would otherwise recurse forever, as the type of a
912 // global is only recorded once its initializer has been fully analyzed.
913 // Seeding with the fact that a global is a pointer is always correct, so
914 // any type deduced from it remains sound, and the seed is refined into
915 // the full type below once the initializer has been analyzed.
916 TypeTree seed;
918 GV->setMetadata("enzyme_type", seed.toMD(GV->getContext()));
919
920 getConstantAnalysis(GV->getInitializer(), TA, analysis);
921 TypeTree constTT = analysis[GV->getInitializer()].Only(-1, nullptr);
922 constTT.insert({-1}, ConcreteType(BaseType::Pointer));
923 GV->setMetadata("enzyme_type", constTT.toMD(GV->getContext()));
924 analysis[Val] |= constTT;
925 return;
926 }
927
928 TypeTree &Result = analysis[Val];
930
931 if (!isa<StructType>(GV->getValueType()) ||
932 !cast<StructType>(GV->getValueType())->isOpaque()) {
933 auto globalSize = (DL.getTypeSizeInBits(GV->getValueType()) + 7) / 8;
934 // Since halfs are 16bit (2 byte) and pointers are >=32bit (4 byte) any
935 // Single byte object must be integral
936 if (globalSize == 1) {
937 Result.insert({-1, -1}, ConcreteType(BaseType::Integer));
938 return;
939 }
940 }
941
942 // Otherwise, we simply know that this is a pointer, and
943 // not what it is a pointer to
944 return;
945 }
946
947 // No other information can be ascertained
948 analysis[Val] = TypeTree();
949 return;
950}
951
952static bool AllJuliaTypes(Type *T) {
953 if (auto PT = dyn_cast<PointerType>(T)) {
954 unsigned AS = PT->getPointerAddressSpace();
955 if (AS == 10 || AS == 11 || AS == 13) {
956 return true;
957 }
958 }
959 if (auto AT = dyn_cast<ArrayType>(T)) {
960 return AllJuliaTypes(AT->getElementType());
961 }
962 if (auto ST = dyn_cast<StructType>(T)) {
963 auto len = ST->getNumElements();
964 if (len != 0) {
965 for (size_t i = 0; i < len; i++) {
966 if (!AllJuliaTypes(ST->getElementType(i)))
967 return false;
968 }
969 return true;
970 }
971 }
972 return false;
973}
974
975/// Type of a pointer to an LLVM flang descriptor (CFI_cdesc_t). All fields
976/// but base_addr are integral; dims are included only when the rank is known
977/// from the allocation type, as a pointer may follow them.
978static TypeTree fortranDescriptorTree(Value *desc, const DataLayout &DL) {
979 TypeTree TT;
980 TT.insert({-1}, BaseType::Pointer);
981 TT.insert({-1, 0}, BaseType::Pointer);
982 const int HeaderSize = 24;
983 int end = HeaderSize;
984
985 Type *T = nullptr;
986 auto base = getBaseObject(desc);
987 if (auto AI = dyn_cast<AllocaInst>(base))
988 T = AI->getAllocatedType();
989 else if (auto GV = dyn_cast<GlobalVariable>(base))
990 T = GV->getValueType();
991 if (auto ST = dyn_cast_or_null<StructType>(T))
992 if (ST->getNumElements() >= 8 &&
993 DL.getStructLayout(ST)->getElementOffset(7) == HeaderSize)
994 if (auto dims = dyn_cast<ArrayType>(ST->getElementType(7)))
995 end += DL.getTypeAllocSize(dims);
996
997 for (int i = DL.getPointerSize(); i < end; i++)
998 TT.insert({-1, i}, BaseType::Integer);
999 return TT;
1000}
1001
1002static bool AnyJuliaTypes(Type *T) {
1003 if (auto PT = dyn_cast<PointerType>(T)) {
1004 unsigned AS = PT->getPointerAddressSpace();
1005 if (AS == 10 || AS == 11 || AS == 13) {
1006 return true;
1007 }
1008 }
1009 if (auto AT = dyn_cast<ArrayType>(T)) {
1010 return AnyJuliaTypes(AT->getElementType());
1011 }
1012 if (auto ST = dyn_cast<StructType>(T)) {
1013 auto len = ST->getNumElements();
1014 for (size_t i = 0; i < len; i++) {
1015 if (AnyJuliaTypes(ST->getElementType(i)))
1016 return true;
1017 }
1018 }
1019 return false;
1020}
1021
1022static void AugmentWithJuliaObjectType(TypeTree &TT, Type *T,
1023 const DataLayout &DL) {
1024 if (AllJuliaTypes(T)) {
1025 TT.remove({-1});
1026 TT.remove({0});
1027 TT.insert({-1}, BaseType::Pointer);
1028 return;
1029 }
1030 if (!AnyJuliaTypes(T))
1031 return;
1032 auto outAll = TT[{-1}];
1033 if (outAll != BaseType::Unknown)
1034 return;
1035
1036 std::vector<std::pair<Type *, size_t>> todo;
1037 todo.emplace_back(T, 0);
1038 while (!todo.empty()) {
1039 auto cur = todo.back();
1040 todo.pop_back();
1041 T = cur.first;
1042 auto offset = cur.second;
1043 if (!AnyJuliaTypes(T))
1044 continue;
1045 if (isa<PointerType>(T)) {
1046 TT.remove(std::vector<int>{(int)offset});
1047 TT.insert(std::vector<int>{(int)offset}, BaseType::Pointer);
1048 continue;
1049 }
1050 if (auto AT = dyn_cast<ArrayType>(T)) {
1051 // Array elements are laid out at successive multiples of the element's
1052 // alloc size, which is what a gep [0, 1] into the array would compute.
1053 size_t stride = DL.getTypeAllocSize(AT->getElementType());
1054 for (size_t i = 0; i < AT->getNumElements(); i++) {
1055 todo.emplace_back(AT->getElementType(), offset + i * stride);
1056 }
1057
1058 continue;
1059 }
1060 if (auto ST = dyn_cast<StructType>(T)) {
1061 // The struct layout already records each field's offset, which is what a
1062 // gep [0, i] into the struct would compute.
1063 auto SL = DL.getStructLayout(ST);
1064 for (size_t i = 0; i < ST->getNumElements(); i++) {
1065 todo.emplace_back(ST->getElementType(i),
1066 offset + (size_t)SL->getElementOffset(i));
1067 }
1068
1069 continue;
1070 }
1071 }
1072}
1073
1075 // Integers with fewer than 16 bits (size of half)
1076 // must be integral, since it cannot possibly represent a float or pointer
1077 if (!isa<UndefValue>(Val) && Val->getType()->isIntegerTy() &&
1078 cast<IntegerType>(Val->getType())->getBitWidth() < 16) {
1079 static const TypeTree SmallInt =
1080 TypeTree(BaseType::Integer).Only(-1, nullptr);
1081 return SmallInt;
1082 }
1083 if (auto C = dyn_cast<Constant>(Val)) {
1084 getConstantAnalysis(C, *this, analysis);
1087 analysis[Val], Val->getType(),
1088 fntypeinfo.Function->getParent()->getDataLayout());
1089 return analysis[Val];
1090 }
1091
1092 // Check that this value is from the function being analyzed
1093 if (auto I = dyn_cast<Instruction>(Val)) {
1094 if (I->getParent()->getParent() != fntypeinfo.Function) {
1095 llvm::errs() << " function: " << *fntypeinfo.Function << "\n";
1096 llvm::errs() << " instParent: " << *I->getParent()->getParent() << "\n";
1097 llvm::errs() << " inst: " << *I << "\n";
1098 }
1099 assert(I->getParent()->getParent() == fntypeinfo.Function);
1100 }
1101 if (auto Arg = dyn_cast<Argument>(Val)) {
1102 if (Arg->getParent() != fntypeinfo.Function) {
1103 llvm::errs() << " function: " << *fntypeinfo.Function << "\n";
1104 llvm::errs() << " argParent: " << *Arg->getParent() << "\n";
1105 llvm::errs() << " arg: " << *Arg << "\n";
1106 }
1107 assert(Arg->getParent() == fntypeinfo.Function);
1108 }
1109
1112 analysis[Val], Val->getType(),
1113 fntypeinfo.Function->getParent()->getDataLayout());
1114
1115 // Return current results
1116 if (isa<Argument>(Val) || isa<Instruction>(Val))
1117 return analysis[Val];
1118
1119 // Unhandled/unknown Value
1120 llvm::errs() << "Error Unknown Value: " << *Val << "\n";
1121 assert(0 && "Error Unknown Value: ");
1122 llvm_unreachable("Error Unknown Value: ");
1123 // return TypeTree();
1124}
1125
1126void TypeAnalyzer::updateAnalysis(Value *Val, ConcreteType Data,
1127 Value *Origin) {
1128 updateAnalysis(Val, TypeTree(Data), Origin);
1129}
1130
1131void TypeAnalyzer::updateAnalysis(Value *Val, BaseType Data, Value *Origin) {
1132 updateAnalysis(Val, TypeTree(ConcreteType(Data)), Origin);
1133}
1134
1135void TypeAnalyzer::addToWorkList(Value *Val) {
1136 // Only consider instructions/arguments
1137 if (!isa<Instruction>(Val) && !isa<Argument>(Val) &&
1138 !isa<ConstantExpr>(Val) && !isa<GlobalVariable>(Val))
1139 return;
1140
1141 // Verify this value comes from the function being analyzed
1142 if (auto I = dyn_cast<Instruction>(Val)) {
1143 if (fntypeinfo.Function != I->getParent()->getParent())
1144 return;
1145 if (notForAnalysis.count(I->getParent()))
1146 return;
1147 if (fntypeinfo.Function != I->getParent()->getParent()) {
1148 llvm::errs() << "function: " << *fntypeinfo.Function << "\n";
1149 llvm::errs() << "instf: " << *I->getParent()->getParent() << "\n";
1150 llvm::errs() << "inst: " << *I << "\n";
1151 }
1152 assert(fntypeinfo.Function == I->getParent()->getParent());
1153 } else if (auto Arg = dyn_cast<Argument>(Val)) {
1154 if (fntypeinfo.Function != Arg->getParent()) {
1155 llvm::errs() << "fn: " << *fntypeinfo.Function << "\n";
1156 llvm::errs() << "argparen: " << *Arg->getParent() << "\n";
1157 llvm::errs() << "val: " << *Arg << "\n";
1158 }
1159 assert(fntypeinfo.Function == Arg->getParent());
1160 }
1161
1162 // Add to workList
1163 workList.insert(Val);
1164}
1165
1166void TypeAnalyzer::updateAnalysis(Value *Val, TypeTree Data, Value *Origin) {
1167 if (Val->getType()->isVoidTy())
1168 return;
1169 // ConstantData's and Functions don't have analysis updated
1170 // We don't do "Constant" as globals are "Constant" types
1171 if (isa<ConstantData>(Val) || isa<Function>(Val)) {
1172 return;
1173 }
1174
1175 if (auto GV = dyn_cast<GlobalVariable>(Val)) {
1176 if (hasMetadata(GV, "enzyme_ta_norecur")) {
1177 if (EnzymePrintType)
1178 llvm::errs() << "Skipping updateAnalysis " << GV->getName() << "\n";
1179 return;
1180 }
1181 }
1182
1183 if (auto CE = dyn_cast<ConstantExpr>(Val)) {
1184 if (CE->isCast() && isa<ConstantInt>(CE->getOperand(0))) {
1185 return;
1186 }
1187 if (CE->getOpcode() == Instruction::GetElementPtr &&
1188 isa<ConstantPointerNull>(CE->getOperand(0)))
1189 return;
1190 }
1191
1192 if (auto I = dyn_cast<Instruction>(Val)) {
1193 if (fntypeinfo.Function != I->getParent()->getParent()) {
1194 llvm::errs() << "function: " << *fntypeinfo.Function << "\n";
1195 llvm::errs() << "instf: " << *I->getParent()->getParent() << "\n";
1196 llvm::errs() << "inst: " << *I << "\n";
1197 }
1198 assert(fntypeinfo.Function == I->getParent()->getParent());
1199 assert(Origin);
1200 if (!EnzymeStrictAliasing) {
1201 if (auto OI = dyn_cast<Instruction>(Origin)) {
1202 if (OI->getParent() != I->getParent() &&
1203 !PDT.dominates(OI->getParent(), I->getParent())) {
1204 bool allocationWithAllUsersInBlock = false;
1205 if (auto AI = dyn_cast<AllocaInst>(I)) {
1206 allocationWithAllUsersInBlock = true;
1207 for (auto U : AI->users()) {
1208 auto P = cast<Instruction>(U)->getParent();
1209 if (P == OI->getParent())
1210 continue;
1211 if (PDT.dominates(OI->getParent(), P))
1212 continue;
1213 allocationWithAllUsersInBlock = false;
1214 break;
1215 }
1216 }
1217 if (!allocationWithAllUsersInBlock) {
1218 if (EnzymePrintType) {
1219 llvm::errs() << " skipping update into ";
1220 I->print(llvm::errs(), *MST);
1221 llvm::errs() << " of " << Data.str() << " from ";
1222 OI->print(llvm::errs(), *MST);
1223 llvm::errs() << "\n";
1224 }
1225 return;
1226 }
1227 }
1228 }
1229 }
1230 } else if (auto Arg = dyn_cast<Argument>(Val)) {
1231 assert(fntypeinfo.Function == Arg->getParent());
1233 if (auto OI = dyn_cast<Instruction>(Origin)) {
1234 auto I = &*fntypeinfo.Function->getEntryBlock().begin();
1235 if (OI->getParent() != I->getParent() &&
1236 !PDT.dominates(OI->getParent(), I->getParent())) {
1237 if (EnzymePrintType) {
1238 llvm::errs() << " skipping update into ";
1239 Arg->print(llvm::errs(), *MST);
1240 llvm::errs() << " of " << Data.str() << " from ";
1241 OI->print(llvm::errs(), *MST);
1242 llvm::errs() << "\n";
1243 }
1244 return;
1245 }
1246 }
1247 }
1248
1249 // Attempt to update the underlying analysis
1250 bool LegalOr = true;
1251 if (analysis.find(Val) == analysis.end() && isa<Constant>(Val)) {
1252 if (!isa<ConstantExpr>(Val) ||
1253 cast<ConstantExpr>(Val)->getOpcode() != Instruction::GetElementPtr)
1254 getConstantAnalysis(cast<Constant>(Val), *this, analysis);
1255 }
1256
1257 TypeTree prev = analysis[Val];
1258
1259 auto &DL = fntypeinfo.Function->getParent()->getDataLayout();
1260 auto RegSize = (DL.getTypeSizeInBits(Val->getType()) + 7) / 8;
1261 Data.CanonicalizeInPlace(RegSize, DL);
1262
1263 if (auto GV = dyn_cast<GlobalVariable>(Val)) {
1264 if (!isa<StructType>(GV->getValueType()) ||
1265 !cast<StructType>(GV->getValueType())->isOpaque()) {
1266 auto allocSize = (DL.getTypeSizeInBits(GV->getValueType()) + 7) / 8;
1267 if (EnzymePrintType) {
1268 llvm::errs() << " pre global update input " << Data.str()
1269 << " for global of size " << allocSize << "\n";
1270 }
1271 Data = Data.Lookup(allocSize, DL)
1272 .Only(-1, dyn_cast_or_null<Instruction>(Origin));
1273 if (EnzymePrintType) {
1274 llvm::errs() << " post global update input " << Data.str()
1275 << " for global of size " << allocSize << "\n";
1276 }
1277 }
1278 }
1279
1280 bool Changed =
1281 analysis[Val].checkedOrIn(Data, /*PointerIntSame*/ false, LegalOr);
1282
1283 // Print the update being made, if requested
1284 if (EnzymePrintType) {
1285 llvm::errs() << "updating analysis of val: ";
1286 Val->print(llvm::errs(), *MST);
1287 llvm::errs() << " current: " << prev.str() << " new " << Data.str();
1288 if (Origin) {
1289 llvm::errs() << " from ";
1290 Origin->print(llvm::errs(), *MST);
1291 }
1292 llvm::errs() << " Changed=" << Changed << " legal=" << LegalOr << "\n";
1293 }
1294
1295 if (!LegalOr) {
1296 if (direction != BOTH) {
1297 Invalid = true;
1298 return;
1299 }
1300 std::string str;
1301 raw_string_ostream ss(str);
1302 if (!CustomErrorHandler) {
1303 llvm::errs() << *fntypeinfo.Function->getParent() << "\n";
1304 llvm::errs() << *fntypeinfo.Function << "\n";
1305 dump(ss);
1306 }
1307 ss << "Illegal updateAnalysis prev:" << prev.str() << " new: " << Data.str()
1308 << "\n";
1309 ss << "val: " << *Val;
1310 if (Origin)
1311 ss << " origin=" << *Origin;
1312
1313 if (CustomErrorHandler) {
1315 (void *)this, wrap(Origin), nullptr);
1316 }
1317 if (auto I = dyn_cast<Instruction>(Val)) {
1318 EmitFailure("IllegalUpdateAnalysis", I->getDebugLoc(), I, ss.str());
1319 exit(1);
1320 } else if (auto I = dyn_cast_or_null<Instruction>(Origin)) {
1321 EmitFailure("IllegalUpdateAnalysis", I->getDebugLoc(), I, ss.str());
1322 exit(1);
1323 } else {
1324 EmitFailure("IllegalUpdateAnalysis", DiagnosticLocation(),
1325 fntypeinfo.Function, ss.str());
1326 exit(1);
1327 }
1328 }
1329
1330 if (Changed) {
1331
1332 if (auto GV = dyn_cast<GlobalVariable>(Val)) {
1333 if (GV->getValueType()->isSized()) {
1334 auto Size = (DL.getTypeSizeInBits(GV->getValueType()) + 7) / 8;
1335 Data = analysis[Val].Lookup(Size, DL).Only(-1, nullptr);
1336 Data.insert({-1}, BaseType::Pointer);
1337 analysis[Val] = Data;
1338 Origin = Val;
1339 }
1340 }
1341 // Add val so it can explicitly propagate this new info, if able to
1342 if (Val != Origin)
1343 addToWorkList(Val);
1344
1345 // Add users and operands of the value so they can update from the new
1346 // operand/use
1347 for (User *U : Val->users()) {
1348 if (U != Origin) {
1349
1350 if (auto I = dyn_cast<Instruction>(U)) {
1351 if (fntypeinfo.Function != I->getParent()->getParent()) {
1352 continue;
1353 }
1354 }
1355
1356 addToWorkList(U);
1357
1358 // per the handling of phi's
1359 if (auto BO = dyn_cast<BinaryOperator>(U)) {
1360 for (User *U2 : BO->users()) {
1361 if (isa<PHINode>(U2) && U2 != Origin) {
1362 addToWorkList(U2);
1363 }
1364 }
1365 }
1366 }
1367 }
1368
1369 if (User *US = dyn_cast<User>(Val)) {
1370 for (Value *Op : US->operands()) {
1371 if (Op != Origin) {
1372 addToWorkList(Op);
1373 }
1374 }
1375 }
1376 }
1377}
1378
1379/// Analyze type info given by the arguments, possibly adding to work queue
1381 // Propagate input type information for arguments
1382 for (auto &pair : fntypeinfo.Arguments) {
1383 assert(pair.first->getParent() == fntypeinfo.Function);
1384 updateAnalysis(pair.first, pair.second, pair.first);
1385 }
1386
1387 // Get type and other information about argument
1388 // getAnalysis may add more information so this
1389 // is necessary/useful
1390 for (Argument &Arg : fntypeinfo.Function->args()) {
1391 updateAnalysis(&Arg, getAnalysis(&Arg), &Arg);
1392 }
1393
1394 // Propagate return value type information
1395 for (BasicBlock &BB : *fntypeinfo.Function) {
1396 for (Instruction &I : BB) {
1397 if (ReturnInst *RI = dyn_cast<ReturnInst>(&I)) {
1398 if (Value *RV = RI->getReturnValue()) {
1400 updateAnalysis(RV, getAnalysis(RV), RV);
1401 }
1402 }
1403 }
1404 }
1405}
1406
1407// An enzyme_type annotation may only name offsets within the value it
1408// annotates. A violation is reported through the error handler when one is
1409// installed, so that the frontend can turn it into a catchable error, and
1410// otherwise stops the analysis with a diagnostic.
1412 size_t RegSize, Instruction &I, Value *Val) {
1413 for (const auto &pair : TT.getMapping()) {
1414 if (pair.first[0] == -1 || (size_t)pair.first[0] < RegSize)
1415 continue;
1416 std::string str;
1417 raw_string_ostream ss(str);
1418 ss << "enzyme_type " << TT.str() << " names offset " << pair.first[0]
1419 << " beyond the " << RegSize << " bytes of " << *Val << " in " << I;
1422 (void *)TA, wrap(Val), nullptr);
1423 EmitFailure("BadEnzymeType", I.getDebugLoc(), &I, ss.str());
1424 llvm::report_fatal_error("Canonicalization failed");
1425 }
1426}
1427
1428/// Analyze type info given by the TBAA, possibly adding to work queue
1430 auto &DL = fntypeinfo.Function->getParent()->getDataLayout();
1431
1432 for (BasicBlock &BB : *fntypeinfo.Function) {
1433 if (notForAnalysis.count(&BB))
1434 continue;
1435 for (Instruction &I : BB) {
1436 if (auto MD = I.getMetadata("enzyme_type")) {
1437 auto TT = TypeTree::fromMD(MD);
1438
1439 auto RegSize = (DL.getTypeSizeInBits(I.getType()) + 7) / 8;
1440 checkEnzymeTypeExtent(this, TT, RegSize, I, &I);
1441 updateAnalysis(&I, TT, &I);
1442 }
1443
1444 if (CallBase *call = dyn_cast<CallBase>(&I)) {
1445#if LLVM_VERSION_MAJOR >= 14
1446 size_t num_args = call->arg_size();
1447#else
1448 size_t num_args = call->getNumArgOperands();
1449#endif
1450
1451 if (call->getAttributes().hasAttribute(AttributeList::ReturnIndex,
1452 "enzyme_type")) {
1453 auto attr = call->getAttributes().getAttribute(
1454 AttributeList::ReturnIndex, "enzyme_type");
1455 auto TT =
1456 TypeTree::parse(attr.getValueAsString(), call->getContext());
1457
1458 auto RegSize = I.getType()->isVoidTy()
1459 ? 0
1460 : (DL.getTypeSizeInBits(I.getType()) + 7) / 8;
1461 checkEnzymeTypeExtent(this, TT, RegSize, I, call);
1462 updateAnalysis(call, TT, call);
1463 }
1464 for (size_t i = 0; i < num_args; i++) {
1465 if (call->getAttributes().hasParamAttr(i, "enzyme_type")) {
1466 auto attr = call->getAttributes().getParamAttr(i, "enzyme_type");
1467 auto TT =
1468 TypeTree::parse(attr.getValueAsString(), call->getContext());
1469 auto argTy = call->getArgOperand(i)->getType();
1470 auto RegSize = (DL.getTypeSizeInBits(argTy) + 7) / 8;
1471 checkEnzymeTypeExtent(this, TT, RegSize, I, call->getArgOperand(i));
1472 updateAnalysis(call->getArgOperand(i), TT, call);
1473 }
1474 }
1475
1476 Function *F = call->getCalledFunction();
1477
1478 if (F) {
1479 if (F->getAttributes().hasAttribute(AttributeList::ReturnIndex,
1480 "enzyme_type")) {
1481 auto attr = F->getAttributes().getAttribute(
1482 AttributeList::ReturnIndex, "enzyme_type");
1483 auto TT =
1484 TypeTree::parse(attr.getValueAsString(), call->getContext());
1485 auto RegSize = I.getType()->isVoidTy()
1486 ? 0
1487 : (DL.getTypeSizeInBits(I.getType()) + 7) / 8;
1488 checkEnzymeTypeExtent(this, TT, RegSize, I, call);
1489 updateAnalysis(call, TT, call);
1490 }
1491 size_t f_num_args = F->arg_size();
1492 for (size_t i = 0; i < f_num_args; i++) {
1493 if (F->getAttributes().hasParamAttr(i, "enzyme_type")) {
1494 auto attr = F->getAttributes().getParamAttr(i, "enzyme_type");
1495 auto TT =
1496 TypeTree::parse(attr.getValueAsString(), call->getContext());
1497 auto argTy = call->getArgOperand(i)->getType();
1498 auto RegSize = (DL.getTypeSizeInBits(argTy) + 7) / 8;
1499 checkEnzymeTypeExtent(this, TT, RegSize, I,
1500 call->getArgOperand(i));
1501 updateAnalysis(call->getArgOperand(i), TT, call);
1502 }
1503 }
1504 }
1505
1506 if (auto castinst = dyn_cast<ConstantExpr>(call->getCalledOperand())) {
1507 if (castinst->isCast())
1508 if (auto fn = dyn_cast<Function>(castinst->getOperand(0))) {
1509 F = fn;
1510 }
1511 }
1512 if (F && F->getName().contains("__enzyme_float")) {
1513 assert(num_args == 1 || num_args == 2);
1514 assert(call->getArgOperand(0)->getType()->isPointerTy());
1515 TypeTree TT;
1516 ssize_t num = 1;
1517 if (num_args == 2) {
1518 assert(isa<ConstantInt>(call->getArgOperand(1)));
1519 auto CI = cast<ConstantInt>(call->getArgOperand(1));
1520 if (CI->isNegative())
1521 num = -1;
1522 else
1523 num = CI->getLimitedValue();
1524 }
1525 if (num == -1)
1526 TT.insert({(int)num}, Type::getFloatTy(call->getContext()));
1527 else
1528 for (size_t i = 0; i < (size_t)num; i += 4)
1529 TT.insert({(int)i}, Type::getFloatTy(call->getContext()));
1530 TT.insert({}, BaseType::Pointer);
1531 updateAnalysis(call->getOperand(0), TT.Only(-1, call), call);
1532 }
1533 if (F && F->getName().contains("__enzyme_double")) {
1534 assert(num_args == 1 || num_args == 2);
1535 assert(call->getArgOperand(0)->getType()->isPointerTy());
1536 TypeTree TT;
1537 size_t num = 1;
1538 if (num_args == 2) {
1539 assert(isa<ConstantInt>(call->getArgOperand(1)));
1540 num = cast<ConstantInt>(call->getArgOperand(1))->getLimitedValue();
1541 }
1542 for (size_t i = 0; i < num; i += 8)
1543 TT.insert({(int)i}, Type::getDoubleTy(call->getContext()));
1544 TT.insert({}, BaseType::Pointer);
1545 updateAnalysis(call->getOperand(0), TT.Only(-1, call), call);
1546 }
1547 if (F && F->getName().contains("__enzyme_integer")) {
1548 assert(num_args == 1 || num_args == 2);
1549 assert(call->getArgOperand(0)->getType()->isPointerTy());
1550 size_t num = 1;
1551 if (num_args == 2) {
1552 assert(isa<ConstantInt>(call->getArgOperand(1)));
1553 num = cast<ConstantInt>(call->getArgOperand(1))->getLimitedValue();
1554 }
1555 TypeTree TT;
1556 for (size_t i = 0; i < num; i++)
1557 TT.insert({(int)i}, BaseType::Integer);
1558 TT.insert({}, BaseType::Pointer);
1559 updateAnalysis(call->getOperand(0), TT.Only(-1, call), call);
1560 }
1561 if (F && F->getName().contains("__enzyme_pointer")) {
1562 assert(num_args == 1 || num_args == 2);
1563 assert(call->getArgOperand(0)->getType()->isPointerTy());
1564 TypeTree TT;
1565 size_t num = 1;
1566 if (num_args == 2) {
1567 assert(isa<ConstantInt>(call->getArgOperand(1)));
1568 num = cast<ConstantInt>(call->getArgOperand(1))->getLimitedValue();
1569 }
1570 for (size_t i = 0; i < num;
1571 i += ((DL.getPointerSizeInBits() + 7) / 8))
1572 TT.insert({(int)i}, BaseType::Pointer);
1573 TT.insert({}, BaseType::Pointer);
1574 updateAnalysis(call->getOperand(0), TT.Only(-1, call), call);
1575 }
1576 if (F) {
1577 static const StringSet<> JuliaKnownTypes = {
1578 "julia.gc_alloc_obj",
1579 "jl_alloc_array_1d",
1580 "jl_alloc_array_2d",
1581 "jl_alloc_array_3d",
1582 "ijl_alloc_array_1d",
1583 "ijl_alloc_array_2d",
1584 "ijl_alloc_array_3d",
1585 "jl_gc_alloc_typed",
1586 "ijl_gc_alloc_typed",
1587 "jl_alloc_genericmemory",
1588 "ijl_alloc_genericmemory",
1589 "jl_alloc_genericmemory_unchecked",
1590 "ijl_alloc_genericmemory_unchecked",
1591 "jl_new_array",
1592 "ijl_new_array"};
1593 if (JuliaKnownTypes.count(F->getName())) {
1594 visitCallBase(*call);
1595 continue;
1596 }
1597 }
1598 }
1599
1600 TypeTree vdptr = parseTBAA(I, DL, MST);
1601
1602 // If we don't have any useful information,
1603 // don't bother updating
1604 if (!vdptr.isKnownPastPointer())
1605 continue;
1606
1607 if (CallBase *call = dyn_cast<CallBase>(&I)) {
1608 if (call->getCalledFunction() &&
1609 (call->getCalledFunction()->getIntrinsicID() == Intrinsic::memcpy ||
1610 call->getCalledFunction()->getIntrinsicID() ==
1611 Intrinsic::memmove)) {
1612 int64_t copySize = 1;
1613 for (auto val : fntypeinfo.knownIntegralValues(call->getOperand(2),
1614 DT, intseen, SE)) {
1615 copySize = max(copySize, val);
1616 }
1617 TypeTree update =
1618 vdptr
1619 .ShiftIndices(DL, /*init offset*/ 0,
1620 /*max size*/ copySize, /*new offset*/ 0)
1621 .Only(-1, call);
1622
1623 updateAnalysis(call->getOperand(0), update, call);
1624 updateAnalysis(call->getOperand(1), update, call);
1625 continue;
1626 } else if (call->getCalledFunction() &&
1627 (call->getCalledFunction()->getIntrinsicID() ==
1628 Intrinsic::memset ||
1629 call->getCalledFunction()->getName() ==
1630 "memset_pattern16")) {
1631 int64_t copySize = 1;
1632 for (auto val : fntypeinfo.knownIntegralValues(call->getOperand(2),
1633 DT, intseen, SE)) {
1634 copySize = max(copySize, val);
1635 }
1636 TypeTree update =
1637 vdptr
1638 .ShiftIndices(DL, /*init offset*/ 0,
1639 /*max size*/ copySize, /*new offset*/ 0)
1640 .Only(-1, call);
1641
1642 updateAnalysis(call->getOperand(0), update, call);
1643 continue;
1644#if LLVM_VERSION_MAJOR >= 20
1645 } else if (call->getCalledFunction() &&
1646 (call->getCalledFunction()->getIntrinsicID() ==
1647 Intrinsic::experimental_memset_pattern)) {
1648 int64_t copySize = 1;
1649 for (auto val : fntypeinfo.knownIntegralValues(call->getOperand(2),
1650 DT, intseen, SE)) {
1651 copySize = max(copySize, val);
1652 }
1653 TypeTree update =
1654 vdptr
1655 .ShiftIndices(DL, /*init offset*/ 0,
1656 /*max size*/ copySize, /*new offset*/ 0)
1657 .Only(-1, call);
1658
1659 updateAnalysis(call->getOperand(0), update, call);
1660 continue;
1661#endif
1662 } else if (call->getCalledFunction() &&
1663 call->getCalledFunction()->getIntrinsicID() ==
1664 Intrinsic::masked_gather) {
1665 auto VT = cast<VectorType>(call->getType());
1666 auto LoadSize = (DL.getTypeSizeInBits(VT) + 7) / 8;
1667 TypeTree req = vdptr.Only(-1, call);
1668 updateAnalysis(call, req.Lookup(LoadSize, DL), call);
1669 // TODO use mask to propagate up to relevant pointer
1670 } else if (call->getCalledFunction() &&
1671 call->getCalledFunction()->getIntrinsicID() ==
1672 Intrinsic::masked_scatter) {
1673 // TODO use mask to propagate up to relevant pointer
1674 } else if (call->getCalledFunction() &&
1675 call->getCalledFunction()->getIntrinsicID() ==
1676 Intrinsic::masked_load) {
1677 auto VT = cast<VectorType>(call->getType());
1678 auto LoadSize = (DL.getTypeSizeInBits(VT) + 7) / 8;
1679 TypeTree req = vdptr.Only(-1, call);
1680 updateAnalysis(call, req.Lookup(LoadSize, DL), call);
1681 // TODO use mask to propagate up to relevant pointer
1682 } else if (call->getCalledFunction() &&
1683 call->getCalledFunction()->getIntrinsicID() ==
1684 Intrinsic::masked_store) {
1685 // TODO use mask to propagate up to relevant pointer
1686 } else if (call->getType()->isPointerTy()) {
1687 updateAnalysis(call, vdptr.Only(-1, call), call);
1688 } else {
1689 llvm::errs() << " unknown tbaa call instruction user inst: " << I
1690 << " vdptr: " << vdptr.str() << "\n";
1691 }
1692 } else if (auto SI = dyn_cast<StoreInst>(&I)) {
1693 auto StoreSize =
1694 (DL.getTypeSizeInBits(SI->getValueOperand()->getType()) + 7) / 8;
1695 updateAnalysis(SI->getPointerOperand(),
1696 vdptr
1697 // Don't propagate "Anything" into ptr
1698 .PurgeAnything()
1699 // Cut off any values outside of store
1700 .ShiftIndices(DL, /*init offset*/ 0,
1701 /*max size*/ StoreSize,
1702 /*new offset*/ 0)
1703 .Only(-1, SI),
1704 SI);
1705 TypeTree req = vdptr.Only(-1, SI);
1706 updateAnalysis(SI->getValueOperand(), req.Lookup(StoreSize, DL), SI);
1707 } else if (auto LI = dyn_cast<LoadInst>(&I)) {
1708 auto LoadSize = (DL.getTypeSizeInBits(LI->getType()) + 7) / 8;
1709 updateAnalysis(LI->getPointerOperand(),
1710 vdptr
1711 // Don't propagate "Anything" into ptr
1712 .PurgeAnything()
1713 // Cut off any values outside of load
1714 .ShiftIndices(DL, /*init offset*/ 0,
1715 /*max size*/ LoadSize,
1716 /*new offset*/ 0)
1717 .Only(-1, LI),
1718 LI);
1719 TypeTree req = vdptr.Only(-1, LI);
1720 updateAnalysis(LI, req.Lookup(LoadSize, DL), LI);
1721 } else {
1722 llvm::errs() << " inst: " << I << " vdptr: " << vdptr.str() << "\n";
1723 assert(0 && "unknown tbaa instruction user");
1724 llvm_unreachable("unknown tbaa instruction user");
1725 }
1726 }
1727 }
1728}
1729
1731 if (PHIRecur)
1732 return;
1733 bool Changed;
1734 do {
1735 Changed = false;
1736 for (BasicBlock &BB : *fntypeinfo.Function) {
1737 for (Instruction &inst : BB) {
1738 if (PHINode *phi = dyn_cast<PHINode>(&inst)) {
1739 if (direction & DOWN && phi->getType()->isIntOrIntVectorTy() &&
1740 !getAnalysis(phi).isKnown()) {
1741 // Assume that this is an integer, does that mean we can prove that
1742 // the incoming operands are integral
1743
1745 notForAnalysis, *this, DOWN,
1746 /*PHIRecur*/ true);
1747 tmpAnalysis.intseen = intseen;
1748 tmpAnalysis.analysis = analysis;
1749 tmpAnalysis.analysis[phi] =
1751 for (auto U : phi->users()) {
1752 if (auto I = dyn_cast<Instruction>(U)) {
1753 tmpAnalysis.visit(*I);
1754 }
1755 }
1756 tmpAnalysis.run();
1757 if (!tmpAnalysis.Invalid) {
1758 TypeTree Result = tmpAnalysis.getAnalysis(phi);
1759 for (auto &op : phi->incoming_values()) {
1760 Result &= tmpAnalysis.getAnalysis(op);
1761 }
1762 if (Result == TypeTree(BaseType::Integer).Only(-1, phi) ||
1763 Result == TypeTree(BaseType::Anything).Only(-1, phi)) {
1764 updateAnalysis(phi, Result, phi);
1765 for (auto &pair : tmpAnalysis.analysis) {
1766 updateAnalysis(pair.first, pair.second, phi);
1767 }
1768 Changed = true;
1769 }
1770 }
1771 }
1772
1773 if (direction & DOWN && phi->getType()->isFPOrFPVectorTy() &&
1774 !getAnalysis(phi).isKnown()) {
1775 // Assume that this is an integer, does that mean we can prove that
1776 // the incoming operands are integral
1778 notForAnalysis, *this, DOWN,
1779 /*PHIRecur*/ true);
1780 tmpAnalysis.intseen = intseen;
1781 tmpAnalysis.analysis = analysis;
1782 tmpAnalysis.analysis[phi] =
1783 TypeTree(phi->getType()->getScalarType()).Only(-1, phi);
1784 for (auto U : phi->users()) {
1785 if (auto I = dyn_cast<Instruction>(U)) {
1786 tmpAnalysis.visit(*I);
1787 }
1788 }
1789 tmpAnalysis.run();
1790 if (!tmpAnalysis.Invalid) {
1791 TypeTree Result = tmpAnalysis.getAnalysis(phi);
1792 for (auto &op : phi->incoming_values()) {
1793 Result &= tmpAnalysis.getAnalysis(op);
1794 }
1795 if (Result ==
1796 TypeTree(phi->getType()->getScalarType()).Only(-1, phi) ||
1797 Result == TypeTree(BaseType::Anything).Only(-1, phi)) {
1798 updateAnalysis(phi, Result, phi);
1799 for (auto &pair : tmpAnalysis.analysis) {
1800 updateAnalysis(pair.first, pair.second, phi);
1801 }
1802 Changed = true;
1803 }
1804 }
1805 }
1806 }
1807 }
1808 }
1809 } while (Changed);
1810 return;
1811}
1812
1814
1815 TimeTraceScope timeScope("Type Analysis", fntypeinfo.Function->getName());
1816
1817 // This function runs a full round of type analysis.
1818 // This works by doing two stages of analysis,
1819 // with a "deduced integer types for unused" values
1820 // sandwiched in-between. This is done because we only
1821 // perform that check for values without types.
1822 //
1823 // For performance reasons in each round of type analysis
1824 // only analyze any call instances after all other potential
1825 // updates have been done. This is to minimize the number
1826 // of expensive interprocedural analyses
1827 std::deque<CallBase *> pendingCalls;
1828
1829 do {
1830 while (!Invalid && workList.size()) {
1831 auto todo = *workList.begin();
1832 workList.erase(workList.begin());
1833 if (auto call = dyn_cast<CallBase>(todo)) {
1834 StringRef funcName = getFuncNameFromCall(call);
1835 auto ci = getFunctionFromCall(call);
1836 if (ci && !ci->empty()) {
1837 if (interprocedural.CustomRules.find(funcName) ==
1839 pendingCalls.push_back(call);
1840 continue;
1841 }
1842 }
1843 }
1844 visitValue(*todo);
1845 }
1846
1847 if (pendingCalls.size() > 0) {
1848 auto todo = pendingCalls.front();
1849 pendingCalls.pop_front();
1850 visitValue(*todo);
1851 continue;
1852 } else
1853 break;
1854
1855 } while (1);
1856
1858
1859 do {
1860
1861 while (!Invalid && workList.size()) {
1862 auto todo = *workList.begin();
1863 workList.erase(workList.begin());
1864 if (auto ci = dyn_cast<CallBase>(todo)) {
1865 pendingCalls.push_back(ci);
1866 continue;
1867 }
1868 visitValue(*todo);
1869 }
1870
1871 if (pendingCalls.size() > 0) {
1872 auto todo = pendingCalls.front();
1873 pendingCalls.pop_front();
1874 visitValue(*todo);
1875 continue;
1876 } else
1877 break;
1878
1879 } while (1);
1880}
1881
1883 if (auto CE = dyn_cast<ConstantExpr>(&val)) {
1884 visitConstantExpr(*CE);
1885 }
1886
1887 if (isa<Constant>(&val)) {
1888 return;
1889 }
1890
1891 if (!isa<Argument>(&val) && !isa<Instruction>(&val))
1892 return;
1893
1894 if (auto *FPMO = dyn_cast<FPMathOperator>(&val)) {
1895 if (FPMO->getOpcode() == Instruction::FNeg) {
1896 Value *op = FPMO->getOperand(0);
1897 auto ty = op->getType()->getScalarType();
1898 assert(ty->isFloatingPointTy());
1899 ConcreteType dt(ty);
1900 updateAnalysis(op, TypeTree(ty).Only(-1, nullptr),
1901 cast<Instruction>(&val));
1902 updateAnalysis(FPMO, TypeTree(ty).Only(-1, nullptr),
1903 cast<Instruction>(&val));
1904 return;
1905 }
1906 }
1907
1908 if (auto inst = dyn_cast<Instruction>(&val)) {
1909 visit(*inst);
1910 }
1911}
1912
1913void TypeAnalyzer::visitConstantExpr(ConstantExpr &CE) {
1914 if (CE.isCast()) {
1915 if (direction & DOWN)
1916 updateAnalysis(&CE, getAnalysis(CE.getOperand(0)), &CE);
1917 if (direction & UP)
1918 updateAnalysis(CE.getOperand(0), getAnalysis(&CE), &CE);
1919 return;
1920 }
1921 if (CE.getOpcode() == Instruction::GetElementPtr) {
1922 visitGEPOperator(*cast<GEPOperator>(&CE));
1923 return;
1924 }
1925 auto I = CE.getAsInstruction();
1926 insertBeforeInst(I, fntypeinfo.Function->getEntryBlock().getTerminator());
1927 analysis[I] = analysis[&CE];
1928 visit(*I);
1929 updateAnalysis(&CE, analysis[I], &CE);
1930 analysis.erase(I);
1931 if (workList.remove(I)) {
1932 workList.insert(&CE);
1933 }
1934 I->eraseFromParent();
1935}
1936
1937void TypeAnalyzer::visitCmpInst(CmpInst &cmp) {
1938 // No directionality check needed as always true
1939 updateAnalysis(&cmp, TypeTree(BaseType::Integer).Only(-1, &cmp), &cmp);
1940 if (direction & UP) {
1942 cmp.getOperand(0),
1943 TypeTree(getAnalysis(cmp.getOperand(1)).Inner0().PurgeAnything())
1944 .Only(-1, &cmp),
1945 &cmp);
1947 cmp.getOperand(1),
1948 TypeTree(getAnalysis(cmp.getOperand(0)).Inner0().PurgeAnything())
1949 .Only(-1, &cmp),
1950 &cmp);
1951 }
1952}
1953
1955 // No directionality check needed as always true
1956 updateAnalysis(I.getArraySize(), TypeTree(BaseType::Integer).Only(-1, &I),
1957 &I);
1958
1959 auto ptr = TypeTree(BaseType::Pointer);
1960
1961 if (auto CI = dyn_cast<ConstantInt>(I.getArraySize())) {
1962 auto &DL = I.getParent()->getParent()->getParent()->getDataLayout();
1963 auto LoadSize = CI->getZExtValue() *
1964 (DL.getTypeSizeInBits(I.getAllocatedType()) + 7) / 8;
1965 // Only propagate mappings in range that aren't "Anything" into the pointer
1966 ptr |= getAnalysis(&I).Lookup(LoadSize, DL);
1967 }
1968 updateAnalysis(&I, ptr.Only(-1, &I), &I);
1969}
1970
1972 auto &DL = I.getParent()->getParent()->getParent()->getDataLayout();
1973 auto LoadSize = (DL.getTypeSizeInBits(I.getType()) + 7) / 8;
1974
1975 if (direction & UP) {
1976 // Only propagate mappings in range that aren't "Anything" into the pointer
1977 auto ptr = getAnalysis(&I).PurgeAnything().ShiftIndices(
1978 DL, /*start*/ 0, LoadSize, /*addOffset*/ 0);
1980 updateAnalysis(I.getOperand(0), ptr.Only(-1, &I), &I);
1981 }
1982 if (direction & DOWN)
1983 updateAnalysis(&I, getAnalysis(I.getOperand(0)).Lookup(LoadSize, DL), &I);
1984}
1985
1987 auto &DL = I.getParent()->getParent()->getParent()->getDataLayout();
1988 auto StoreSize =
1989 (DL.getTypeSizeInBits(I.getValueOperand()->getType()) + 7) / 8;
1990
1991 // Rust specific rule, if storing an integer equal to the alignment
1992 // of a store, assuming nothing (or assume it is a pointer)
1993 // https://doc.rust-lang.org/src/core/ptr/non_null.rs.html#70-78
1994 if (RustTypeRules)
1995 if (auto CI = dyn_cast<ConstantInt>(I.getValueOperand())) {
1996 auto alignment = I.getAlign().value();
1997
1998 if (CI->getLimitedValue() == alignment) {
1999 return;
2000 }
2001 }
2002
2003 // Only propagate mappings in range that aren't "Anything" into the pointer
2004 auto ptr = TypeTree(BaseType::Pointer);
2005 auto purged = getAnalysis(I.getValueOperand())
2006 .PurgeAnything()
2007 .ShiftIndices(DL, /*start*/ 0, StoreSize, /*addOffset*/ 0)
2008 .ReplaceMinus();
2009 ptr |= purged;
2010
2011 if (direction & UP) {
2012 updateAnalysis(I.getPointerOperand(), ptr.Only(-1, &I), &I);
2013
2014 // Note that we also must purge anything from ptr => value in case we store
2015 // to a nullptr which has type [-1, -1]: Anything. While storing to a
2016 // nullptr is obviously bad, this doesn't mean the value we're storing is an
2017 // Anything
2018 updateAnalysis(I.getValueOperand(),
2019 getAnalysis(I.getPointerOperand())
2020 .PurgeAnything()
2021 .Lookup(StoreSize, DL),
2022 &I);
2023 }
2024}
2025
2026// Give a list of sets representing the legal set of values at a given index
2027// return a set of all possible combinations of those values
2028template <typename T>
2029std::set<SmallVector<T, 4>> getSet(ArrayRef<std::set<T>> todo, size_t idx) {
2030 assert(idx < todo.size());
2031 std::set<SmallVector<T, 4>> out;
2032 if (idx == 0) {
2033 for (auto val : todo[0]) {
2034 out.insert({val});
2035 }
2036 return out;
2037 }
2038
2039 auto old = getSet(todo, idx - 1);
2040 for (const auto &oldv : old) {
2041 for (auto val : todo[idx]) {
2042 auto nex = oldv;
2043 nex.push_back(val);
2044 out.insert(nex);
2045 }
2046 }
2047 return out;
2048}
2049
2050void TypeAnalyzer::visitGetElementPtrInst(GetElementPtrInst &gep) {
2051 visitGEPOperator(*cast<GEPOperator>(&gep));
2052}
2053
2054void TypeAnalyzer::visitGEPOperator(GEPOperator &gep) {
2055 auto inst = dyn_cast<Instruction>(&gep);
2056 if (isa<UndefValue>(gep.getPointerOperand())) {
2057 updateAnalysis(&gep, TypeTree(BaseType::Anything).Only(-1, inst), &gep);
2058 return;
2059 }
2060 if (isa<ConstantPointerNull>(gep.getPointerOperand())) {
2061 bool nonZero = false;
2062 bool legal = true;
2063 for (auto I = gep.idx_begin(), E = gep.idx_end(); I != E; I++) {
2064 auto ind = I->get();
2065 if (auto CI = dyn_cast<ConstantInt>(ind)) {
2066 if (!CI->isZero()) {
2067 nonZero = true;
2068 continue;
2069 }
2070 }
2071 auto CT = getAnalysis(ind).Inner0();
2072 if (CT == BaseType::Integer) {
2073 continue;
2074 }
2075 legal = false;
2076 break;
2077 }
2078 if (legal && nonZero) {
2079 updateAnalysis(&gep, TypeTree(BaseType::Integer).Only(-1, inst), &gep);
2080 return;
2081 }
2082 }
2083 if (auto GV = dyn_cast<GlobalVariable>(gep.getPointerOperand())) {
2084 // from julia code, do not propagate int to operands
2085 if (GV->getName() == "small_typeof" || GV->getName() == "jl_small_typeof") {
2086 TypeTree T;
2087 T.insert({-1}, BaseType::Pointer);
2088 T.insert({-1, -1}, BaseType::Pointer);
2089 updateAnalysis(&gep, T, &gep);
2090 return;
2091 }
2092 }
2093
2094 if (gep.idx_begin() == gep.idx_end()) {
2095 if (direction & DOWN)
2096 updateAnalysis(&gep, getAnalysis(gep.getPointerOperand()), &gep);
2097 if (direction & UP)
2098 updateAnalysis(gep.getPointerOperand(), getAnalysis(&gep), &gep);
2099 return;
2100 }
2101
2102 auto &DL = fntypeinfo.Function->getParent()->getDataLayout();
2103
2104 auto pointerAnalysis = getAnalysis(gep.getPointerOperand());
2105
2106 // If we know that the pointer operand is indeed a pointer, then the indicies
2107 // must be integers Note that we can't do this if we don't know the pointer
2108 // operand is a pointer since doing 1[pointer] is legal
2109 // sadly this still may not work since (nullptr)[fn] => fn where fn is
2110 // pointer and not int (whereas nullptr is a pointer) However if we are
2111 // inbounds you are only allowed to have nullptr[0] or nullptr[nullptr],
2112 // making this valid
2113 // Assuming nullptr[nullptr] doesn't occur in practice, the following
2114 // is valid. We could make it always valid by checking the pointer
2115 // operand explicitly is a pointer.
2116 if (direction & UP) {
2117 bool has_non_const_idx = false;
2118 for (auto I = gep.idx_begin(), E = gep.idx_end(); I != E; I++) {
2119 auto ind = I->get();
2120 if (!isa<ConstantInt>(ind)) {
2121 has_non_const_idx = true;
2122 break;
2123 }
2124 }
2125
2126 if (has_non_const_idx &&
2127 (gep.isInBounds() ||
2129 pointerAnalysis.Inner0() == BaseType::Pointer &&
2130 getAnalysis(&gep).Inner0() == BaseType::Pointer))) {
2131 for (auto I = gep.idx_begin(), E = gep.idx_end(); I != E; I++) {
2132 auto ind = I->get();
2133 updateAnalysis(ind, TypeTree(BaseType::Integer).Only(-1, inst), &gep);
2134 }
2135 }
2136 }
2137
2138 // If one of these is known to be a pointer, propagate it if either in bounds
2139 // or all operands are integral/unknown
2140 bool pointerPropagate = gep.isInBounds();
2141 if (!pointerPropagate) {
2142 bool allIntegral = true;
2143 for (auto I = gep.idx_begin(), E = gep.idx_end(); I != E; I++) {
2144 auto ind = I->get();
2145 auto CT = getAnalysis(ind).Inner0();
2146 if (CT != BaseType::Integer && CT != BaseType::Anything) {
2147 allIntegral = false;
2148 break;
2149 }
2150 }
2151 if (allIntegral)
2152 pointerPropagate = true;
2153 }
2154
2155 if (!pointerPropagate)
2156 return;
2157
2158 if (direction & DOWN) {
2159 bool legal = true;
2160 auto keepMinus = pointerAnalysis.KeepMinusOne(legal);
2161 if (!legal) {
2163 CustomErrorHandler("Could not keep minus one", wrap(&gep),
2164 ErrorType::IllegalTypeAnalysis, this, nullptr,
2165 nullptr);
2166 else {
2167 dump();
2168 llvm::errs() << " could not perform minus one for gep'd: " << gep
2169 << "\n";
2170 }
2171 }
2172 updateAnalysis(&gep, keepMinus, &gep);
2173 // Don't propagate pointer type when the input pointer is null
2174 if (!isa<ConstantPointerNull>(gep.getPointerOperand())) {
2175 updateAnalysis(&gep, TypeTree(pointerAnalysis.Inner0()).Only(-1, inst),
2176 &gep);
2177 }
2178 }
2179 if (direction & UP)
2180 updateAnalysis(gep.getPointerOperand(),
2181 TypeTree(getAnalysis(&gep).Inner0()).Only(-1, inst), &gep);
2182
2183 TypeTree upTree;
2184 TypeTree downTree;
2185
2186 TypeTree gepData0;
2187 TypeTree pointerData0;
2188 if (direction & UP)
2189 gepData0 = getAnalysis(&gep).Data0();
2190 if (direction & DOWN)
2191 pointerData0 = pointerAnalysis.Data0();
2192
2193 auto BitWidth = DL.getIndexSizeInBits(gep.getPointerAddressSpace());
2194
2195 APInt constOffset(BitWidth, 0);
2196
2197#if LLVM_VERSION_MAJOR >= 20
2198 SmallMapVector<Value *, APInt, 4> VariableOffsets;
2199#else
2200 MapVector<Value *, APInt> VariableOffsets;
2201#endif
2202 bool legalOffset =
2203 collectOffset(&gep, DL, BitWidth, VariableOffsets, constOffset);
2204 (void)legalOffset;
2205 assert(legalOffset);
2206
2207 SmallVector<std::set<int>, 4> idnext;
2208
2209 SmallPtrSet<BasicBlock *, 1> previousLoopInductionHeaders;
2210 {
2211 Value *ptr = gep.getPointerOperand();
2212 while (true) {
2213 if (auto gepop = dyn_cast<GEPOperator>(ptr)) {
2214 for (auto I = gepop->idx_begin(), E = gepop->idx_end(); I != E; I++) {
2215 SmallPtrSet<PHINode *, 1> seen;
2216 for (auto loopInd : findLoopIndices(*I, LI, DT, seen)) {
2217 previousLoopInductionHeaders.insert(loopInd);
2218 }
2219 }
2220 ptr = gepop->getPointerOperand();
2221 continue;
2222 }
2223 if (auto CI = dyn_cast<CastInst>(ptr)) {
2224 ptr = CI->getOperand(0);
2225 continue;
2226 }
2227 break;
2228 }
2229 }
2230
2231 for (auto &pair : VariableOffsets) {
2232 auto a = pair.first;
2233 auto iset = fntypeinfo.knownIntegralValues(a, DT, intseen, SE);
2234 std::set<int> vset;
2235 for (auto i : iset) {
2236 // Don't consider negative indices of gep
2237 if (i < 0)
2238 continue;
2239 vset.insert(i);
2240 }
2241 if (vset.size() == 0)
2242 return;
2243
2244 // If seen the same variable before with > 1 option, we will accidentally
2245 // do an offset for [option1, option2] * oldOffset + [option1, option2] *
2246 // newOffset
2247 // instead of [option1, option2] * (oldOffset + newOffset).
2248 // In this case abort
2249 // TODO, in the future, mutually compute the offset together.
2250 if (vset.size() != 1) {
2251 SmallPtrSet<PHINode *, 1> seen;
2252 for (auto loopInd : findLoopIndices(pair.first, LI, DT, seen))
2253 if (previousLoopInductionHeaders.count(loopInd))
2254 return;
2255 }
2256 idnext.push_back(vset);
2257 }
2258
2259 // Stores pair ([whether first offset is zero], offset)
2260 std::vector<std::pair<bool, int>> offsets;
2261 Value *firstIdx = *gep.idx_begin();
2262 if (VariableOffsets.size() == 0) {
2263 bool firstIsZero = cast<ConstantInt>(firstIdx)->getLimitedValue() == 0;
2264 offsets.emplace_back(firstIsZero, (int)constOffset.getLimitedValue());
2265 } else {
2266 bool firstIsZero = false;
2267 if (auto CI = dyn_cast<ConstantInt>(firstIdx))
2268 firstIsZero = CI->getLimitedValue() == 0;
2269 for (auto vec : getSet<int>(idnext, idnext.size() - 1)) {
2270 APInt nextOffset = constOffset;
2271 for (auto [varpair, const_value] : llvm::zip(VariableOffsets, vec)) {
2272 nextOffset += varpair.second * const_value;
2273 if (varpair.first == firstIdx)
2274 firstIsZero = const_value == 0;
2275 }
2276 offsets.emplace_back(firstIsZero, (int)nextOffset.getLimitedValue());
2277 }
2278 }
2279
2280 bool seenIdx = false;
2281
2282 for (auto [firstIsZero, off] : offsets) {
2283 // TODO also allow negative offsets
2284 if (off < 0)
2285 continue;
2286
2287 int maxSize = -1;
2288 if (firstIsZero) {
2289 maxSize = DL.getTypeAllocSizeInBits(gep.getResultElementType()) / 8;
2290 }
2291
2292 if (direction & DOWN) {
2293 auto shft =
2294 pointerData0.ShiftIndices(DL, /*init offset*/ off,
2295 /*max size*/ maxSize, /*newoffset*/ 0);
2296 if (seenIdx)
2297 downTree &= shft;
2298 else
2299 downTree = shft;
2300 }
2301
2302 if (direction & UP) {
2303 auto shft = gepData0.ShiftIndices(DL, /*init offset*/ 0, /*max size*/ -1,
2304 /*new offset*/ off);
2305 if (seenIdx)
2306 upTree |= shft;
2307 else
2308 upTree = shft;
2309 }
2310 seenIdx = true;
2311 }
2312 if (direction & DOWN)
2313 updateAnalysis(&gep, downTree.Only(-1, inst), &gep);
2314 if (direction & UP)
2315 updateAnalysis(gep.getPointerOperand(), upTree.Only(-1, inst), &gep);
2316}
2317
2318void TypeAnalyzer::visitPHINode(PHINode &phi) {
2319 if (direction & UP) {
2320 TypeTree upVal = getAnalysis(&phi);
2321 // only propagate anything's up if there is one
2322 // incoming value
2323 Value *seen = phi.getIncomingValue(0);
2324 for (size_t i = 0, end = phi.getNumIncomingValues(); i < end; ++i) {
2325 if (seen != phi.getIncomingValue(i)) {
2326 seen = nullptr;
2327 break;
2328 }
2329 }
2330
2331 if (!seen) {
2332 upVal = upVal.PurgeAnything();
2333 }
2334
2335 if (EnzymeStrictAliasing || seen) {
2336 auto L = LI.getLoopFor(phi.getParent());
2337 bool isHeader = L && L->getHeader() == phi.getParent();
2338 for (size_t i = 0, end = phi.getNumIncomingValues(); i < end; ++i) {
2339 if (!isHeader || !L->contains(phi.getIncomingBlock(i))) {
2340 updateAnalysis(phi.getIncomingValue(i), upVal, &phi);
2341 }
2342 }
2343 } else {
2344 if (EnzymePrintType) {
2345 for (size_t i = 0, end = phi.getNumIncomingValues(); i < end; ++i) {
2346 llvm::errs() << " skipping update into ";
2347 phi.getIncomingValue(i)->print(llvm::errs(), *MST);
2348 llvm::errs() << " of " << upVal.str() << " from ";
2349 phi.print(llvm::errs(), *MST);
2350 llvm::errs() << "\n";
2351 }
2352 }
2353 }
2354 }
2355
2356 assert(phi.getNumIncomingValues() > 0);
2357
2358 // TODO generalize this (and for recursive, etc)
2359
2360 for (int i = 0; i < 2; i++) {
2361
2362 std::deque<Value *> vals;
2363 std::set<Value *> seen{&phi};
2364 for (auto &op : phi.incoming_values()) {
2365 vals.push_back(op);
2366 }
2367 SmallVector<BinaryOperator *, 4> bos;
2368
2369 // Unique values that propagate into this phi
2370 SmallVector<Value *, 4> UniqueValues;
2371
2372 while (vals.size()) {
2373 Value *todo = vals.front();
2374 vals.pop_front();
2375
2376 if (auto bo = dyn_cast<BinaryOperator>(todo)) {
2377 if (bo->getOpcode() == BinaryOperator::Add) {
2378 if (isa<Constant>(bo->getOperand(0))) {
2379 bos.push_back(bo);
2380 todo = bo->getOperand(1);
2381 }
2382 if (isa<Constant>(bo->getOperand(1))) {
2383 bos.push_back(bo);
2384 todo = bo->getOperand(0);
2385 }
2386 }
2387 }
2388
2389 if (seen.count(todo))
2390 continue;
2391 seen.insert(todo);
2392
2393 if (auto nphi = dyn_cast<PHINode>(todo)) {
2394 if (i == 0) {
2395 for (auto &op : nphi->incoming_values()) {
2396 vals.push_back(op);
2397 }
2398 continue;
2399 }
2400 }
2401 if (auto sel = dyn_cast<SelectInst>(todo)) {
2402 vals.push_back(sel->getOperand(1));
2403 vals.push_back(sel->getOperand(2));
2404 continue;
2405 }
2406 UniqueValues.push_back(todo);
2407 }
2408
2409 TypeTree PhiTypes;
2410 bool set = false;
2411
2412 for (size_t i = 0, size = UniqueValues.size(); i < size; ++i) {
2413 TypeTree newData = getAnalysis(UniqueValues[i]);
2414 if (UniqueValues.size() == 2) {
2415 if (auto BO = dyn_cast<BinaryOperator>(UniqueValues[i])) {
2416 if (BO->getOpcode() == BinaryOperator::Add ||
2417 BO->getOpcode() == BinaryOperator::Mul) {
2418 TypeTree otherData = getAnalysis(UniqueValues[1 - i]);
2419 // If we are adding/muling to a constant to derive this, we can
2420 // assume it to be an integer rather than Anything
2421 if (isa<Constant>(UniqueValues[1 - i])) {
2422 otherData = TypeTree(BaseType::Integer).Only(-1, &phi);
2423 }
2424 if (BO->getOperand(0) == &phi) {
2425 set = true;
2426 PhiTypes = otherData;
2427 bool Legal = true;
2428 PhiTypes.binopIn(Legal, getAnalysis(BO->getOperand(1)),
2429 BO->getOpcode());
2430 if (!Legal) {
2431 std::string str;
2432 raw_string_ostream ss(str);
2433 if (!CustomErrorHandler) {
2434 llvm::errs() << *fntypeinfo.Function->getParent() << "\n";
2435 llvm::errs() << *fntypeinfo.Function << "\n";
2436 dump(ss);
2437 }
2438 ss << "Illegal updateBinop Analysis " << *BO << "\n";
2439 ss << "Illegal binopIn(0): " << *BO
2440 << " lhs: " << PhiTypes.str()
2441 << " rhs: " << getAnalysis(BO->getOperand(0)).str() << "\n";
2442 if (CustomErrorHandler) {
2443 CustomErrorHandler(str.c_str(), wrap(BO),
2445 (void *)this, wrap(BO), nullptr);
2446 }
2447 EmitFailure("IllegalUpdateAnalysis", BO->getDebugLoc(), BO,
2448 ss.str());
2449 report_fatal_error("Performed illegal updateAnalysis");
2450 }
2451 break;
2452 } else if (BO->getOperand(1) == &phi) {
2453 set = true;
2454 PhiTypes = getAnalysis(BO->getOperand(0));
2455 bool Legal = true;
2456 PhiTypes.binopIn(Legal, otherData, BO->getOpcode());
2457 if (!Legal) {
2458 std::string str;
2459 raw_string_ostream ss(str);
2460 if (!CustomErrorHandler) {
2461 llvm::errs() << *fntypeinfo.Function->getParent() << "\n";
2462 llvm::errs() << *fntypeinfo.Function << "\n";
2463 dump(ss);
2464 }
2465 ss << "Illegal updateBinop Analysis " << *BO << "\n";
2466 ss << "Illegal binopIn(1): " << *BO
2467 << " lhs: " << PhiTypes.str() << " rhs: " << otherData.str()
2468 << "\n";
2469 if (CustomErrorHandler) {
2470 CustomErrorHandler(str.c_str(), wrap(BO),
2472 (void *)this, wrap(BO), nullptr);
2473 }
2474 EmitFailure("IllegalUpdateAnalysis", BO->getDebugLoc(), BO,
2475 ss.str());
2476 report_fatal_error("Performed illegal updateAnalysis");
2477 }
2478 break;
2479 }
2480 } else if (BO->getOpcode() == BinaryOperator::Sub) {
2481 // Repeated subtraction from a type X yields the type X back
2482 TypeTree otherData = getAnalysis(UniqueValues[1 - i]);
2483 // If we are subtracting from a constant to derive this, we can
2484 // assume it to be an integer rather than Anything
2485 if (isa<Constant>(UniqueValues[1 - i])) {
2486 otherData = TypeTree(BaseType::Integer).Only(-1, &phi);
2487 }
2488 if (BO->getOperand(0) == &phi) {
2489 set = true;
2490 PhiTypes = otherData;
2491 break;
2492 }
2493 }
2494 }
2495 }
2496 if (set) {
2497 PhiTypes &= newData;
2498 // TODO consider the or of anything (see selectinst)
2499 // however, this cannot be done yet for risk of turning
2500 // phi's that add floats into anything
2501 // PhiTypes |= newData.JustAnything();
2502 } else {
2503 set = true;
2504 PhiTypes = newData;
2505 }
2506 }
2507
2508 assert(set);
2509 // If we are only add / sub / etc to derive a value based off 0
2510 // we can start by assuming the type of 0 is integer rather
2511 // than assuming it could be anything (per null)
2512 if (bos.size() > 0 && UniqueValues.size() == 1 &&
2513 isa<ConstantInt>(UniqueValues[0]) &&
2514 (cast<ConstantInt>(UniqueValues[0])->isZero() ||
2515 cast<ConstantInt>(UniqueValues[0])->isOne())) {
2516 PhiTypes = TypeTree(BaseType::Integer).Only(-1, &phi);
2517 }
2518 for (BinaryOperator *bo : bos) {
2519 TypeTree vd1 = isa<Constant>(bo->getOperand(0))
2520 ? getAnalysis(bo->getOperand(0)).Data0()
2521 : PhiTypes.Data0();
2522 TypeTree vd2 = isa<Constant>(bo->getOperand(1))
2523 ? getAnalysis(bo->getOperand(1)).Data0()
2524 : PhiTypes.Data0();
2525 bool Legal = true;
2526 vd1.binopIn(Legal, vd2, bo->getOpcode());
2527 if (!Legal) {
2528 std::string str;
2529 raw_string_ostream ss(str);
2530 if (!CustomErrorHandler) {
2531 llvm::errs() << *fntypeinfo.Function->getParent() << "\n";
2532 llvm::errs() << *fntypeinfo.Function << "\n";
2533 dump(ss);
2534 }
2535 ss << "Illegal updateBinop Analysis " << *bo << "\n";
2536 ss << "Illegal binopIn(consts): " << *bo << " lhs: " << vd1.str()
2537 << " rhs: " << vd2.str() << "\n";
2538 if (CustomErrorHandler) {
2539 CustomErrorHandler(str.c_str(), wrap(bo),
2540 ErrorType::IllegalTypeAnalysis, (void *)this,
2541 wrap(bo), nullptr);
2542 }
2543 EmitFailure("IllegalUpdateAnalysis", bo->getDebugLoc(), bo, ss.str());
2544 report_fatal_error("Performed illegal updateAnalysis");
2545 }
2546 PhiTypes &= vd1.Only(bo->getType()->isIntegerTy() ? -1 : 0, &phi);
2547 }
2548
2549 if (direction & DOWN) {
2550 if (phi.getType()->isIntOrIntVectorTy() &&
2551 PhiTypes.Inner0() == BaseType::Anything) {
2552 if (mustRemainInteger(&phi)) {
2553 PhiTypes = TypeTree(BaseType::Integer).Only(-1, &phi);
2554 }
2555 }
2556 updateAnalysis(&phi, PhiTypes, &phi);
2557 }
2558 }
2559}
2560
2562 auto &DL = fntypeinfo.Function->getParent()->getDataLayout();
2563 size_t inSize = (DL.getTypeSizeInBits(I.getOperand(0)->getType()) + 7) / 8;
2564 size_t outSize = (DL.getTypeSizeInBits(I.getType()) + 7) / 8;
2565 if (direction & DOWN)
2566 if (outSize != 1)
2567 updateAnalysis(&I,
2568 getAnalysis(I.getOperand(0))
2569 .ShiftIndices(DL, /*off*/ 0, inSize, /*addOffset*/ 0)
2570 .ShiftIndices(DL, /*off*/ 0, outSize, /*addOffset*/ 0),
2571 &I);
2572 // Don't propagate up a trunc float -> i8
2573 if (direction & UP)
2574 if (outSize != 1 || inSize == 1)
2576 I.getOperand(0),
2577 getAnalysis(&I).ShiftIndices(DL, /*off*/ 0, outSize, /*addOffset*/ 0),
2578 &I);
2579}
2580
2582 if (direction & DOWN) {
2583 TypeTree Result;
2584 if (cast<IntegerType>(I.getOperand(0)->getType()->getScalarType())
2585 ->getBitWidth() == 1) {
2586 Result = TypeTree(BaseType::Anything).Only(-1, &I);
2587 } else {
2588 Result = getAnalysis(I.getOperand(0));
2589 }
2590
2591 if (I.getType()->isIntOrIntVectorTy() &&
2592 Result.Inner0() == BaseType::Anything) {
2593 if (mustRemainInteger(&I)) {
2594 Result = TypeTree(BaseType::Integer).Only(-1, &I);
2595 }
2596 }
2597 updateAnalysis(&I, Result, &I);
2598 }
2599 if (direction & UP) {
2600 updateAnalysis(I.getOperand(0), getAnalysis(&I), &I);
2601 }
2602}
2603
2605 // This is only legal on integer types [not pointers per sign]
2606 // nor floatings points. Likewise, there's no direction check
2607 // necessary since this is always valid.
2608 updateAnalysis(&I, TypeTree(BaseType::Integer).Only(-1, &I), &I);
2609 updateAnalysis(I.getOperand(0), TypeTree(BaseType::Integer).Only(-1, &I), &I);
2610}
2611
2612void TypeAnalyzer::visitAddrSpaceCastInst(AddrSpaceCastInst &I) {
2613 if (direction & DOWN)
2614 updateAnalysis(&I, getAnalysis(I.getOperand(0)), &I);
2615 if (direction & UP)
2616 updateAnalysis(I.getOperand(0), getAnalysis(&I), &I);
2617}
2618
2620 // No direction check as always true
2622 &I, TypeTree(ConcreteType(I.getType()->getScalarType())).Only(-1, &I),
2623 &I);
2625 I.getOperand(0),
2626 TypeTree(ConcreteType(I.getOperand(0)->getType()->getScalarType()))
2627 .Only(-1, &I),
2628 &I);
2629}
2630
2632 // No direction check as always true
2634 &I, TypeTree(ConcreteType(I.getType()->getScalarType())).Only(-1, &I),
2635 &I);
2637 I.getOperand(0),
2638 TypeTree(ConcreteType(I.getOperand(0)->getType()->getScalarType()))
2639 .Only(-1, &I),
2640 &I);
2641}
2642
2644 // No direction check as always true
2645 updateAnalysis(&I, TypeTree(BaseType::Integer).Only(-1, &I), &I);
2647 I.getOperand(0),
2648 TypeTree(ConcreteType(I.getOperand(0)->getType()->getScalarType()))
2649 .Only(-1, &I),
2650 &I);
2651}
2652
2654 // No direction check as always true
2655 updateAnalysis(&I, TypeTree(BaseType::Integer).Only(-1, &I), &I);
2657 I.getOperand(0),
2658 TypeTree(ConcreteType(I.getOperand(0)->getType()->getScalarType()))
2659 .Only(-1, &I),
2660 &I);
2661}
2662
2664 // No direction check as always true
2665 updateAnalysis(I.getOperand(0), TypeTree(BaseType::Integer).Only(-1, &I), &I);
2667 &I, TypeTree(ConcreteType(I.getType()->getScalarType())).Only(-1, &I),
2668 &I);
2669}
2670
2672 // No direction check as always true
2673 updateAnalysis(I.getOperand(0), TypeTree(BaseType::Integer).Only(-1, &I), &I);
2675 &I, TypeTree(ConcreteType(I.getType()->getScalarType())).Only(-1, &I),
2676 &I);
2677}
2678
2679void TypeAnalyzer::visitPtrToIntInst(PtrToIntInst &I) {
2680 // Note it is illegal to assume here that either is a pointer or an int
2681 if (direction & DOWN)
2682 updateAnalysis(&I, getAnalysis(I.getOperand(0)), &I);
2683 if (direction & UP)
2684 updateAnalysis(I.getOperand(0), getAnalysis(&I), &I);
2685}
2686
2687void TypeAnalyzer::visitIntToPtrInst(IntToPtrInst &I) {
2688 // Note it is illegal to assume here that either is a pointer or an int
2689 if (direction & DOWN) {
2690 if (isa<ConstantInt>(I.getOperand(0))) {
2691 updateAnalysis(&I, TypeTree(BaseType::Anything).Only(-1, &I), &I);
2692 } else {
2693 updateAnalysis(&I, getAnalysis(I.getOperand(0)), &I);
2694 }
2695 }
2696 if (direction & UP)
2697 updateAnalysis(I.getOperand(0), getAnalysis(&I), &I);
2698}
2699
2700void TypeAnalyzer::visitFreezeInst(FreezeInst &I) {
2701 if (direction & DOWN)
2702 updateAnalysis(&I, getAnalysis(I.getOperand(0)), &I);
2703 if (direction & UP)
2704 updateAnalysis(I.getOperand(0), getAnalysis(&I), &I);
2705}
2706
2708 if (direction & DOWN)
2709 updateAnalysis(&I, getAnalysis(I.getOperand(0)), &I);
2710 if (direction & UP)
2711 updateAnalysis(I.getOperand(0), getAnalysis(&I), &I);
2712}
2713
2715 if (direction & UP) {
2716 auto Data = getAnalysis(&I).PurgeAnything();
2717 if (EnzymeStrictAliasing || (I.getTrueValue() == I.getFalseValue())) {
2718 updateAnalysis(I.getTrueValue(), Data, &I);
2719 updateAnalysis(I.getFalseValue(), Data, &I);
2720 } else {
2721 if (EnzymePrintType) {
2722 llvm::errs() << " skipping update into ";
2723 I.getTrueValue()->print(llvm::errs(), *MST);
2724 llvm::errs() << " of " << Data.str() << " from ";
2725 I.print(llvm::errs(), *MST);
2726 llvm::errs() << "\n";
2727 llvm::errs() << " skipping update into ";
2728 I.getFalseValue()->print(llvm::errs(), *MST);
2729 llvm::errs() << " of " << Data.str() << " from ";
2730 I.print(llvm::errs(), *MST);
2731 llvm::errs() << "\n";
2732 }
2733 }
2734 }
2735 if (direction & DOWN) {
2736 // special case for min/max result is still that operand [even if something
2737 // is 0]
2738 if (auto cmpI = dyn_cast<CmpInst>(I.getCondition())) {
2739 // is relational equiv to not is equality
2740 if (!cmpI->isEquality())
2741 if ((cmpI->getOperand(0) == I.getTrueValue() &&
2742 cmpI->getOperand(1) == I.getFalseValue()) ||
2743 (cmpI->getOperand(1) == I.getTrueValue() &&
2744 cmpI->getOperand(0) == I.getFalseValue())) {
2745 auto vd = getAnalysis(I.getTrueValue()).Inner0();
2746 vd &= getAnalysis(I.getFalseValue()).Inner0();
2747 if (vd.isKnown()) {
2748 updateAnalysis(&I, TypeTree(vd).Only(-1, &I), &I);
2749 return;
2750 }
2751 }
2752 }
2753 // If getTrueValue and getFalseValue are the same type (per the and)
2754 // it is safe to assume the result is as well
2755 TypeTree vd = getAnalysis(I.getTrueValue()).PurgeAnything();
2756 vd &= getAnalysis(I.getFalseValue()).PurgeAnything();
2757
2758 // A regular and operation, however is not sufficient. One of the operands
2759 // could be anything whereas the other is concrete, resulting in the
2760 // concrete type (e.g. select true, anything(0), integer(i64)) This is not
2761 // correct as the result of the select could always be anything (e.g. if it
2762 // is a pointer). As a result, explicitly or in any anything values
2763 // TODO this should be propagated elsewhere as well (specifically returns,
2764 // phi)
2765 TypeTree any = getAnalysis(I.getTrueValue()).JustAnything();
2766 any &= getAnalysis(I.getFalseValue()).JustAnything();
2767 vd |= any;
2768 updateAnalysis(&I, vd, &I);
2769 }
2770}
2771
2772void TypeAnalyzer::visitExtractElementInst(ExtractElementInst &I) {
2773 updateAnalysis(I.getIndexOperand(), BaseType::Integer, &I);
2774
2775 auto &dl = fntypeinfo.Function->getParent()->getDataLayout();
2776 VectorType *vecType = cast<VectorType>(I.getVectorOperand()->getType());
2777
2778 size_t bitsize = dl.getTypeSizeInBits(vecType->getElementType());
2779 size_t size = (bitsize + 7) / 8;
2780
2781 if (auto CI = dyn_cast<ConstantInt>(I.getIndexOperand())) {
2782 size_t off = (CI->getZExtValue() * bitsize) / 8;
2783
2784 if (direction & DOWN)
2785 updateAnalysis(&I,
2786 getAnalysis(I.getVectorOperand())
2787 .ShiftIndices(dl, off, size, /*addOffset*/ 0),
2788 &I);
2789
2790 if (direction & UP)
2791 updateAnalysis(I.getVectorOperand(),
2792 getAnalysis(&I).ShiftIndices(dl, 0, size, off), &I);
2793
2794 } else {
2795 if (direction & DOWN) {
2796 const TypeTree &vecAnalysis = getAnalysis(I.getVectorOperand());
2797 // TODO merge of anythings (see selectinst)
2798 TypeTree res = vecAnalysis.Lookup(size, dl);
2799 updateAnalysis(&I, res.Only(-1, &I), &I);
2800 }
2801 if (direction & UP) {
2802 // propagated upward to unknown location, no analysis
2803 // can be updated
2804 }
2805 }
2806}
2807
2808void TypeAnalyzer::visitInsertElementInst(InsertElementInst &I) {
2809 updateAnalysis(I.getOperand(2), TypeTree(BaseType::Integer).Only(-1, &I), &I);
2810
2811 auto &dl = fntypeinfo.Function->getParent()->getDataLayout();
2812 VectorType *vecType = cast<VectorType>(I.getOperand(0)->getType());
2813 if (vecType->getElementType()->isIntegerTy(1)) {
2814 if (direction & UP) {
2815 updateAnalysis(I.getOperand(0), TypeTree(BaseType::Integer).Only(-1, &I),
2816 &I);
2817 updateAnalysis(I.getOperand(1), TypeTree(BaseType::Integer).Only(-1, &I),
2818 &I);
2819 }
2820 if (direction & DOWN) {
2821 updateAnalysis(&I, TypeTree(BaseType::Integer).Only(-1, &I), &I);
2822 }
2823 return;
2824 }
2825#if LLVM_VERSION_MAJOR >= 12
2826 assert(!vecType->getElementCount().isScalable());
2827 size_t numElems = vecType->getElementCount().getKnownMinValue();
2828#else
2829 size_t numElems = vecType->getNumElements();
2830#endif
2831 size_t size = (dl.getTypeSizeInBits(vecType->getElementType()) + 7) / 8;
2832 size_t vecSize = (dl.getTypeSizeInBits(vecType) + 7) / 8;
2833
2834 if (auto CI = dyn_cast<ConstantInt>(I.getOperand(2))) {
2835 size_t off = CI->getZExtValue() * size;
2836
2837 if (direction & UP)
2838 updateAnalysis(I.getOperand(0),
2839 getAnalysis(&I).Clear(off, off + size, vecSize), &I);
2840
2841 if (direction & UP)
2842 updateAnalysis(I.getOperand(1),
2843 getAnalysis(&I).ShiftIndices(dl, off, size, 0), &I);
2844
2845 if (direction & DOWN) {
2846 auto new_res =
2847 getAnalysis(I.getOperand(0)).Clear(off, off + size, vecSize);
2848 auto shifted =
2849 getAnalysis(I.getOperand(1)).ShiftIndices(dl, 0, size, off);
2850 new_res |= shifted;
2851 updateAnalysis(&I, new_res, &I);
2852 }
2853 } else {
2854 if (direction & DOWN) {
2855 auto new_res = getAnalysis(I.getOperand(0));
2856 auto inserted = getAnalysis(I.getOperand(1));
2857 // TODO merge of anythings (see selectinst)
2858 for (size_t i = 0; i < numElems; ++i)
2859 new_res &= inserted.ShiftIndices(dl, 0, size, size * i);
2860 updateAnalysis(&I, new_res, &I);
2861 }
2862 }
2863}
2864
2865void TypeAnalyzer::visitShuffleVectorInst(ShuffleVectorInst &I) {
2866 // See selectinst type propagation rule for a description
2867 // of the ncessity and correctness of this rule.
2868 VectorType *resType = cast<VectorType>(I.getType());
2869
2870 auto &dl = fntypeinfo.Function->getParent()->getDataLayout();
2871
2872 const size_t lhs = 0;
2873 const size_t rhs = 1;
2874
2875#if LLVM_VERSION_MAJOR >= 12
2876 assert(!cast<VectorType>(I.getOperand(lhs)->getType())
2877 ->getElementCount()
2878 .isScalable());
2879 size_t numFirst = cast<VectorType>(I.getOperand(lhs)->getType())
2880 ->getElementCount()
2881 .getKnownMinValue();
2882#else
2883 size_t numFirst =
2884 cast<VectorType>(I.getOperand(lhs)->getType())->getNumElements();
2885#endif
2886 size_t size = (dl.getTypeSizeInBits(resType->getElementType()) + 7) / 8;
2887
2888 auto mask = I.getShuffleMask();
2889
2890 TypeTree result; // = getAnalysis(&I);
2891 for (size_t i = 0; i < mask.size(); ++i) {
2892 int newOff;
2893 {
2894 newOff =
2895 (int)getAggregateElementOffset(dl, I.getOperand(0)->getType(), i);
2896 // there is a bug in LLVM, this is the correct offset
2897 if (cast<VectorType>(I.getOperand(lhs)->getType())
2898 ->getElementType()
2899 ->isIntegerTy(1)) {
2900 newOff = i / 8;
2901 }
2902 }
2903#if LLVM_VERSION_MAJOR > 16
2904 if (mask[i] == PoisonMaskElem)
2905#elif LLVM_VERSION_MAJOR >= 12
2906 if (mask[i] == UndefMaskElem)
2907#else
2908 if (mask[i] == -1)
2909#endif
2910 {
2911 if (direction & DOWN) {
2912 result |= TypeTree(BaseType::Anything)
2913 .Only(-1, &I)
2914 .ShiftIndices(dl, 0, size, newOff);
2915 }
2916 } else {
2917 if ((size_t)mask[i] < numFirst) {
2918 int oldOff = (int)getAggregateElementOffset(
2919 dl, I.getOperand(0)->getType(), mask[i]);
2920 // there is a bug in LLVM, this is the correct offset
2921 if (cast<VectorType>(I.getOperand(lhs)->getType())
2922 ->getElementType()
2923 ->isIntegerTy(1)) {
2924 oldOff = mask[i] / 8;
2925 }
2926 if (direction & UP) {
2927 updateAnalysis(I.getOperand(lhs),
2928 getAnalysis(&I).ShiftIndices(dl, newOff, size, oldOff),
2929 &I);
2930 }
2931 if (direction & DOWN) {
2932 result |= getAnalysis(I.getOperand(lhs))
2933 .ShiftIndices(dl, oldOff, size, newOff);
2934 }
2935 } else {
2936 int oldOff = (int)getAggregateElementOffset(
2937 dl, I.getOperand(0)->getType(), mask[i] - numFirst);
2938 // there is a bug in LLVM, this is the correct offset
2939 if (cast<VectorType>(I.getOperand(lhs)->getType())
2940 ->getElementType()
2941 ->isIntegerTy(1)) {
2942 oldOff = (mask[i] - numFirst) / 8;
2943 }
2944 if (direction & UP) {
2945 updateAnalysis(I.getOperand(rhs),
2946 getAnalysis(&I).ShiftIndices(dl, newOff, size, oldOff),
2947 &I);
2948 }
2949 if (direction & DOWN) {
2950 result |= getAnalysis(I.getOperand(rhs))
2951 .ShiftIndices(dl, oldOff, size, newOff);
2952 }
2953 }
2954 }
2955 }
2956
2957 if (direction & DOWN) {
2958 updateAnalysis(&I, result, &I);
2959 }
2960}
2961
2962void TypeAnalyzer::visitExtractValueInst(ExtractValueInst &I) {
2963 auto &dl = fntypeinfo.Function->getParent()->getDataLayout();
2964
2965 int off = (int)getAggregateElementOffset(dl, I.getOperand(0)->getType(),
2966 I.getIndices());
2967 int size = dl.getTypeSizeInBits(I.getType()) / 8;
2968
2969 if (direction & DOWN)
2970 updateAnalysis(&I,
2971 getAnalysis(I.getOperand(0))
2972 .ShiftIndices(dl, off, size, /*addOffset*/ 0),
2973 &I);
2974
2975 if (direction & UP)
2976 updateAnalysis(I.getOperand(0),
2977 getAnalysis(&I).ShiftIndices(dl, 0, size, off), &I);
2978}
2979
2980void TypeAnalyzer::visitInsertValueInst(InsertValueInst &I) {
2981 auto &dl = fntypeinfo.Function->getParent()->getDataLayout();
2982 auto AggTy = I.getOperand(0)->getType();
2983
2984 int off = (int)getAggregateElementOffset(dl, AggTy, I.getIndices());
2985
2986 // Compute the offset at the next logical element [e.g. adding 1 to the last
2987 // index, carrying the value on overflow]. Carrying past the outermost index
2988 // lands one past the aggregate itself.
2989 SmallVector<unsigned, 4> next(I.getIndices().begin(), I.getIndices().end());
2990 size_t endOff = dl.getTypeAllocSize(AggTy);
2991 for (ssize_t i = next.size() - 1; i >= 0; i--) {
2992 auto subTy = ExtractValueInst::getIndexedType(
2993 AggTy, ArrayRef<unsigned>(next).slice(0, i));
2994 unsigned numElements = isa<StructType>(subTy)
2995 ? cast<StructType>(subTy)->getNumElements()
2996 : cast<ArrayType>(subTy)->getNumElements();
2997 if (next[i] + 1 == numElements) {
2998 next.truncate(i);
2999 continue;
3000 }
3001 next[i]++;
3002 endOff = getAggregateElementOffset(dl, AggTy, next);
3003 break;
3004 }
3005
3006 int agg_size = (dl.getTypeSizeInBits(I.getType()) + 7) / 8;
3007 int ins_size = (int)(endOff - off);
3008 int ins2_size =
3009 (dl.getTypeSizeInBits(I.getInsertedValueOperand()->getType()) + 7) / 8;
3010
3011 if (direction & UP)
3012 updateAnalysis(I.getAggregateOperand(),
3013 getAnalysis(&I).Clear(off, off + ins_size, agg_size), &I);
3014 if (direction & UP)
3015 updateAnalysis(I.getInsertedValueOperand(),
3016 getAnalysis(&I).ShiftIndices(dl, off, ins2_size, 0), &I);
3017 auto new_res =
3018 getAnalysis(I.getAggregateOperand()).Clear(off, off + ins_size, agg_size);
3019 auto shifted = getAnalysis(I.getInsertedValueOperand())
3020 .ShiftIndices(dl, 0, ins_size, off);
3021 new_res |= shifted;
3022 if (direction & DOWN)
3023 updateAnalysis(&I, new_res, &I);
3024}
3025
3026void TypeAnalyzer::dump(llvm::raw_ostream &ss) {
3027 ss << "<analysis>\n";
3028 // We don't care about correct MD node numbering here.
3029#if LLVM_VERSION_MAJOR >= 24
3030 ModuleSlotTracker MST(fntypeinfo.Function->getParent());
3031#else
3032 ModuleSlotTracker MST(fntypeinfo.Function->getParent(),
3033 /*ShouldInitializeAllMetadata*/ false);
3034#endif
3035 for (auto &pair : analysis) {
3036 if (auto F = dyn_cast<Function>(pair.first))
3037 ss << "@" << F->getName();
3038 else
3039 pair.first->print(ss, MST);
3040 ss << ": " << pair.second.str()
3041 << ", intvals: " << to_string(knownIntegralValues(pair.first)) << "\n";
3042 }
3043 ss << "</analysis>\n";
3044}
3045
3046void TypeAnalyzer::visitAtomicRMWInst(llvm::AtomicRMWInst &I) {
3047 Value *Args[2] = {nullptr, I.getOperand(1)};
3048 TypeTree Ret = getAnalysis(&I);
3049 auto &DL = I.getParent()->getParent()->getParent()->getDataLayout();
3050 auto LoadSize = (DL.getTypeSizeInBits(I.getType()) + 7) / 8;
3051 TypeTree LHS = getAnalysis(I.getOperand(0)).Lookup(LoadSize, DL);
3052 TypeTree RHS = getAnalysis(I.getOperand(1));
3053
3054 switch (I.getOperation()) {
3055 case AtomicRMWInst::Xchg: {
3056 auto tmp = LHS;
3057 LHS = RHS;
3058 RHS = tmp;
3059 bool Legal = true;
3060 LHS.checkedOrIn(Ret, /*PointerIntSame*/ false, Legal);
3061 if (!Legal) {
3062 dump();
3063 llvm::errs() << I << "\n";
3064 llvm::errs() << "Illegal orIn: " << LHS.str() << " right: " << Ret.str()
3065 << "\n";
3066 llvm::errs() << *I.getOperand(0) << " "
3067 << getAnalysis(I.getOperand(0)).str() << "\n";
3068 llvm::errs() << *I.getOperand(1) << " "
3069 << getAnalysis(I.getOperand(1)).str() << "\n";
3070 assert(0 && "Performed illegal visitAtomicRMWInst::orIn");
3071 llvm_unreachable("Performed illegal visitAtomicRMWInst::orIn");
3072 }
3073 Ret = tmp;
3074 break;
3075 }
3076 case AtomicRMWInst::Add:
3077 visitBinaryOperation(DL, I.getType(), BinaryOperator::Add, Args, Ret, LHS,
3078 RHS, &I);
3079 break;
3080 case AtomicRMWInst::Sub:
3081 visitBinaryOperation(DL, I.getType(), BinaryOperator::Sub, Args, Ret, LHS,
3082 RHS, &I);
3083 break;
3084 case AtomicRMWInst::And:
3085 visitBinaryOperation(DL, I.getType(), BinaryOperator::And, Args, Ret, LHS,
3086 RHS, &I);
3087 break;
3088 case AtomicRMWInst::Or:
3089 visitBinaryOperation(DL, I.getType(), BinaryOperator::Or, Args, Ret, LHS,
3090 RHS, &I);
3091 break;
3092 case AtomicRMWInst::Xor:
3093 visitBinaryOperation(DL, I.getType(), BinaryOperator::Xor, Args, Ret, LHS,
3094 RHS, &I);
3095 break;
3096 case AtomicRMWInst::FAdd:
3097 visitBinaryOperation(DL, I.getType(), BinaryOperator::FAdd, Args, Ret, LHS,
3098 RHS, &I);
3099 break;
3100 case AtomicRMWInst::FSub:
3101 visitBinaryOperation(DL, I.getType(), BinaryOperator::FSub, Args, Ret, LHS,
3102 RHS, &I);
3103 break;
3104 case AtomicRMWInst::Max:
3105 case AtomicRMWInst::Min:
3106 case AtomicRMWInst::UMax:
3107 case AtomicRMWInst::UMin:
3108 case AtomicRMWInst::Nand:
3109 default:
3110 break;
3111 }
3112
3113 if (direction & UP) {
3114 TypeTree ptr = LHS.PurgeAnything()
3115 .ShiftIndices(DL, /*start*/ 0, LoadSize, /*addOffset*/ 0)
3116 .Only(-1, &I);
3117 ptr.insert({-1}, BaseType::Pointer);
3118 updateAnalysis(I.getOperand(0), ptr, &I);
3119 updateAnalysis(I.getOperand(1), RHS, &I);
3120 }
3121
3122 if (direction & DOWN) {
3123 if (Ret[{-1}] == BaseType::Anything && LHS[{-1}] != BaseType::Anything)
3124 Ret = LHS;
3125 if (I.getType()->isIntOrIntVectorTy() && Ret[{-1}] == BaseType::Anything) {
3126 if (mustRemainInteger(&I)) {
3127 Ret = TypeTree(BaseType::Integer).Only(-1, &I);
3128 }
3129 }
3130 updateAnalysis(&I, Ret, &I);
3131 }
3132}
3133
3134void TypeAnalyzer::visitBinaryOperation(const DataLayout &dl, llvm::Type *T,
3135 llvm::Instruction::BinaryOps Opcode,
3136 Value *Args[2], TypeTree &Ret,
3137 TypeTree &LHS, TypeTree &RHS,
3138 Instruction *origin) {
3139 if (Opcode == BinaryOperator::FAdd || Opcode == BinaryOperator::FSub ||
3140 Opcode == BinaryOperator::FMul || Opcode == BinaryOperator::FDiv ||
3141 Opcode == BinaryOperator::FRem) {
3142 auto ty = T->getScalarType();
3143 assert(ty->isFloatingPointTy());
3144 ConcreteType dt(ty);
3145 if (direction & UP) {
3146 bool LegalOr = true;
3147 auto Data = TypeTree(dt).Only(-1, nullptr);
3148 LHS.checkedOrIn(Data, /*PointerIntSame*/ false, LegalOr);
3149 if (CustomErrorHandler && !LegalOr) {
3150 std::string str;
3151 raw_string_ostream ss(str);
3152 ss << "Illegal updateAnalysis prev:" << LHS.str()
3153 << " new: " << Data.str() << "\n";
3154 ss << "val: " << *Args[0];
3155 ss << "origin: " << *origin;
3156 CustomErrorHandler(str.c_str(), wrap(Args[0]),
3157 ErrorType::IllegalTypeAnalysis, (void *)this,
3158 wrap(origin), nullptr);
3159 }
3160 RHS.checkedOrIn(Data, /*PointerIntSame*/ false, LegalOr);
3161 if (CustomErrorHandler && !LegalOr) {
3162 std::string str;
3163 raw_string_ostream ss(str);
3164 ss << "Illegal updateAnalysis prev:" << RHS.str()
3165 << " new: " << Data.str() << "\n";
3166 ss << "val: " << *Args[1];
3167 ss << "origin: " << *origin;
3168 CustomErrorHandler(str.c_str(), wrap(Args[1]),
3169 ErrorType::IllegalTypeAnalysis, (void *)this,
3170 wrap(origin), nullptr);
3171 }
3172 }
3173 if (direction & DOWN)
3174 Ret |= TypeTree(dt).Only(-1, nullptr);
3175 } else {
3176 auto AnalysisLHS = LHS.Data0();
3177 auto AnalysisRHS = RHS.Data0();
3178 auto AnalysisRet = Ret.Data0();
3179
3180 switch (Opcode) {
3181 case BinaryOperator::Sub:
3182 // ptr - ptr => int and int - int => int; thus int = a - b says only that
3183 // these are equal ptr - int => ptr and int - ptr => ptr; thus
3184 // howerver we do not want to propagate underlying ptr types since it's
3185 // legal to subtract unrelated pointer
3186 if (direction & UP) {
3187 if (AnalysisRet[{}] == BaseType::Integer) {
3188 LHS |= TypeTree(AnalysisRHS[{}]).PurgeAnything().Only(-1, nullptr);
3189 RHS |= TypeTree(AnalysisLHS[{}]).PurgeAnything().Only(-1, nullptr);
3190 }
3191 if (AnalysisRet[{}] == BaseType::Pointer) {
3192 if (AnalysisLHS[{}] == BaseType::Pointer) {
3193 RHS |= TypeTree(BaseType::Integer).Only(-1, nullptr);
3194 }
3195 if (AnalysisRHS[{}] == BaseType::Integer) {
3196 LHS |= TypeTree(BaseType::Pointer).Only(-1, nullptr);
3197 }
3198 }
3199 }
3200 break;
3201
3202 case BinaryOperator::Add:
3203 case BinaryOperator::Mul:
3204 // if a + b or a * b == int, then a and b must be ints
3205 if (direction & UP) {
3206 if (AnalysisRet[{}] == BaseType::Integer) {
3207 LHS.orIn({-1}, BaseType::Integer);
3208 RHS.orIn({-1}, BaseType::Integer);
3209 }
3210 }
3211 break;
3212
3213 case BinaryOperator::Xor:
3214 if (direction & UP)
3215 for (int i = 0; i < 2; ++i) {
3216 Type *FT = nullptr;
3217 if (!(FT = Ret.allFloat(origin, dl)))
3218 continue;
3219 // If ^ against 0b10000000000, the result is a float
3220 bool validXor = containsOnlyAtMostTopBit(Args[i], FT, dl);
3221 if (validXor) {
3222 bool Legal = true;
3223 ((i == 0) ? RHS : LHS)
3224 .checkedOrIn(TypeTree(FT).Only(-1, nullptr),
3225 /*pointerintsame*/ false, Legal);
3226
3227 if (!Legal) {
3228 std::string str;
3229 raw_string_ostream ss(str);
3230 if (!CustomErrorHandler) {
3231 llvm::errs() << *fntypeinfo.Function->getParent() << "\n";
3232 llvm::errs() << *fntypeinfo.Function << "\n";
3233 dump(ss);
3234 }
3235 ss << "Illegal updateBinop (xor up) Analysis " << *origin << "\n";
3236 ss << " (i=" << i << ") " << (i == 0 ? "RHS" : "LHS") << " "
3237 << ((i == 0) ? RHS : LHS).str() << " FT from ret: " << *FT
3238 << "\n";
3239 if (CustomErrorHandler) {
3240 CustomErrorHandler(str.c_str(), wrap(origin),
3241 ErrorType::IllegalTypeAnalysis, (void *)this,
3242 wrap(origin), nullptr);
3243 }
3244 EmitFailure("IllegalUpdateAnalysis", origin->getDebugLoc(),
3245 origin, ss.str());
3246 report_fatal_error("Performed illegal updateAnalysis");
3247 }
3248 }
3249 }
3250 break;
3251 case BinaryOperator::Or:
3252 for (int i = 0; i < 2; ++i) {
3253 Type *FT = nullptr;
3254 if (!(FT = Ret.allFloat(origin, dl)))
3255 continue;
3256 // If | against a number only or'ing the exponent, the result is a float
3257 bool validXor = false;
3258 if (auto CIT = dyn_cast_or_null<ConstantInt>(Args[i])) {
3259 if (dl.getTypeSizeInBits(FT) != dl.getTypeSizeInBits(CIT->getType()))
3260 continue;
3261 auto CI = CIT->getValue();
3262#if LLVM_VERSION_MAJOR > 16
3263 if (CI.isZero())
3264#else
3265 if (CI.isNullValue())
3266#endif
3267 {
3268 validXor = true;
3269 } else if (
3270 !CI.isNegative() &&
3271 ((FT->isFloatTy()
3272#if LLVM_VERSION_MAJOR > 16
3273 && (CI & ~0b01111111100000000000000000000000ULL).isZero()
3274#else
3275 && (CI & ~0b01111111100000000000000000000000ULL).isNullValue()
3276#endif
3277 ) ||
3278 (FT->isDoubleTy()
3279#if LLVM_VERSION_MAJOR > 16
3280 &&
3281 (CI &
3282 ~0b0111111111110000000000000000000000000000000000000000000000000000ULL)
3283 .isZero()
3284#else
3285 &&
3286 (CI &
3287 ~0b0111111111110000000000000000000000000000000000000000000000000000ULL)
3288 .isNullValue()
3289#endif
3290 ))) {
3291 validXor = true;
3292 }
3293 } else if (auto CV = dyn_cast_or_null<ConstantVector>(Args[i])) {
3294 validXor = true;
3295 if (dl.getTypeSizeInBits(FT) !=
3296 dl.getTypeSizeInBits(CV->getOperand(i)->getType()))
3297 continue;
3298 for (size_t i = 0, end = CV->getNumOperands(); i < end; ++i) {
3299 auto CI = dyn_cast<ConstantInt>(CV->getOperand(i))->getValue();
3300
3301#if LLVM_VERSION_MAJOR > 16
3302 if (CI.isZero())
3303#else
3304 if (CI.isNullValue())
3305#endif
3306 {
3307 } else if (
3308 !CI.isNegative() &&
3309 ((FT->isFloatTy()
3310#if LLVM_VERSION_MAJOR > 16
3311 && (CI & ~0b01111111100000000000000000000000ULL).isZero()
3312#else
3313 && (CI & ~0b01111111100000000000000000000000ULL).isNullValue()
3314#endif
3315 ) ||
3316 (FT->isDoubleTy()
3317#if LLVM_VERSION_MAJOR > 16
3318 &&
3319 (CI &
3320 ~0b0111111111110000000000000000000000000000000000000000000000000000ULL)
3321 .isZero()
3322#else
3323 &&
3324 (CI &
3325 ~0b0111111111110000000000000000000000000000000000000000000000000000ULL)
3326 .isNullValue()
3327#endif
3328 ))) {
3329 } else
3330 validXor = false;
3331 }
3332 } else if (auto CV = dyn_cast_or_null<ConstantDataVector>(Args[i])) {
3333 validXor = true;
3334 if (dl.getTypeSizeInBits(FT) !=
3335 dl.getTypeSizeInBits(CV->getElementType()))
3336 continue;
3337 for (size_t i = 0, end = CV->getNumElements(); i < end; ++i) {
3338 auto CI = CV->getElementAsAPInt(i);
3339#if LLVM_VERSION_MAJOR > 16
3340 if (CI.isZero())
3341#else
3342 if (CI.isNullValue())
3343#endif
3344 {
3345 } else if (
3346 !CI.isNegative() &&
3347 ((FT->isFloatTy()
3348#if LLVM_VERSION_MAJOR > 16
3349 && (CI & ~0b01111111100000000000000000000000ULL).isZero()
3350#else
3351 && (CI & ~0b01111111100000000000000000000000ULL).isNullValue()
3352#endif
3353 ) ||
3354 (FT->isDoubleTy()
3355#if LLVM_VERSION_MAJOR > 16
3356 &&
3357 (CI &
3358 ~0b0111111111110000000000000000000000000000000000000000000000000000ULL)
3359 .isZero()
3360#else
3361 &&
3362 (CI &
3363 ~0b0111111111110000000000000000000000000000000000000000000000000000ULL)
3364 .isNullValue()
3365#endif
3366 ))) {
3367 } else
3368 validXor = false;
3369 }
3370 }
3371 if (validXor) {
3372 ((i == 0) ? RHS : LHS) |= TypeTree(FT).Only(-1, nullptr);
3373 }
3374 }
3375 break;
3376 default:
3377 break;
3378 }
3379
3380 if (direction & DOWN) {
3381 TypeTree Result = AnalysisLHS;
3382 bool Legal = true;
3383 Result.binopIn(Legal, AnalysisRHS, Opcode);
3384 if (!Legal) {
3385 std::string str;
3386 raw_string_ostream ss(str);
3387 if (!CustomErrorHandler) {
3388 llvm::errs() << *fntypeinfo.Function->getParent() << "\n";
3389 llvm::errs() << *fntypeinfo.Function << "\n";
3390 dump(ss);
3391 }
3392 ss << "Illegal updateBinop Analysis " << *origin << "\n";
3393 ss << "Illegal binopIn(down): " << Opcode << " lhs: " << Result.str()
3394 << " rhs: " << AnalysisRHS.str() << "\n";
3395 if (CustomErrorHandler) {
3396 CustomErrorHandler(str.c_str(), wrap(origin),
3397 ErrorType::IllegalTypeAnalysis, (void *)this,
3398 wrap(origin), nullptr);
3399 }
3400 EmitFailure("IllegalUpdateAnalysis", origin->getDebugLoc(), origin,
3401 ss.str());
3402 report_fatal_error("Performed illegal updateAnalysis");
3403 }
3404 if (Opcode == BinaryOperator::And) {
3405 for (int i = 0; i < 2; ++i) {
3406 bool isNegMask = false;
3407 if (Args[i]) {
3408 if (auto CI = dyn_cast<ConstantInt>(Args[i])) {
3409 // Masks wider than 64 bits (e.g. on i128) cannot be a small
3410 // negative number, and getSExtValue would assert on them.
3411 if (CI->getValue().getSignificantBits() <= 64) {
3412 int64_t andval = CI->getSExtValue();
3413 if (andval < 0 && andval >= -64) {
3414 Result = (i == 0 ? AnalysisRHS : AnalysisLHS);
3415 isNegMask = true;
3416 }
3417 }
3418 }
3419 if (!isNegMask) {
3420 for (auto andval :
3421 fntypeinfo.knownIntegralValues(Args[i], DT, intseen, SE)) {
3422 if (andval <= 16 && andval >= 0) {
3423 Result = TypeTree(BaseType::Integer);
3424 } else if (andval < 0 && andval >= -64) {
3425 // If a small negative number, this just masks off the lower
3426 // bits in this case we can say that this is the same as the
3427 // other operand
3428 Result = (i == 0 ? AnalysisRHS : AnalysisLHS);
3429 isNegMask = true;
3430 }
3431 }
3432 }
3433 }
3434 // If we and a constant against an integer, the result remains an
3435 // integer
3436 if (!isNegMask && Args[i] && isa<ConstantInt>(Args[i]) &&
3437 (i == 0 ? AnalysisRHS : AnalysisLHS).Inner0() ==
3439 Result = TypeTree(BaseType::Integer);
3440 }
3441 }
3442 } else if (Opcode == BinaryOperator::Add ||
3443 Opcode == BinaryOperator::Sub) {
3444 for (int i = 0; i < 2; ++i) {
3445 if (i == 1 || Opcode == BinaryOperator::Add)
3446 if (auto CI = dyn_cast_or_null<ConstantInt>(Args[i])) {
3447 if (CI->isNegative() || CI->isZero() ||
3448 CI->getLimitedValue() <= 4096) {
3449 // If add/sub with zero, small, or negative number, the result
3450 // is equal to the type of the other operand (and we don't need
3451 // to assume this was an "anything")
3452 Result = (i == 0 ? AnalysisRHS : AnalysisLHS);
3453 }
3454 }
3455 }
3456 } else if (Opcode == BinaryOperator::Mul) {
3457 for (int i = 0; i < 2; ++i) {
3458 // If we mul a constant against an integer, the result remains an
3459 // integer
3460 if (Args[i] && isa<ConstantInt>(Args[i]) &&
3461 (i == 0 ? AnalysisRHS : AnalysisLHS)[{}] == BaseType::Integer) {
3462 Result = TypeTree(BaseType::Integer);
3463 }
3464 }
3465 } else if (Opcode == BinaryOperator::URem) {
3466 if (auto CI = dyn_cast_or_null<ConstantInt>(Args[1])) {
3467 // If rem with a small integer, the result is also a small integer
3468 if (CI->getLimitedValue() <= 4096) {
3469 Result = TypeTree(BaseType::Integer);
3470 }
3471 }
3472 } else if (Opcode == BinaryOperator::Xor) {
3473 for (int i = 0; i < 2; ++i) {
3474 Type *FT;
3475 if (!(FT = (i == 0 ? RHS : LHS).allFloat(Args[1 - i], dl)))
3476 continue;
3477 // If ^ against 0b10000000000, the result is a float
3478 bool validXor = containsOnlyAtMostTopBit(Args[i], FT, dl);
3479 if (validXor) {
3480 Result = ConcreteType(FT);
3481 }
3482 }
3483 } else if (Opcode == BinaryOperator::Or) {
3484 for (int i = 0; i < 2; ++i) {
3485 Type *FT;
3486 if (!(FT = (i == 0 ? RHS : LHS).allFloat(Args[1 - i], dl)))
3487 continue;
3488 // If & against 0b10000000000, the result is a float
3489 bool validXor = false;
3490 if (auto CIT = dyn_cast_or_null<ConstantInt>(Args[i])) {
3491 if (dl.getTypeSizeInBits(FT) !=
3492 dl.getTypeSizeInBits(CIT->getType()))
3493 continue;
3494 auto CI = CIT->getValue();
3495#if LLVM_VERSION_MAJOR > 16
3496 if (CI.isZero())
3497#else
3498 if (CI.isNullValue())
3499#endif
3500 {
3501 validXor = true;
3502 } else if (
3503 !CI.isNegative() &&
3504 ((FT->isFloatTy()
3505#if LLVM_VERSION_MAJOR > 16
3506 && (CI & ~0b01111111100000000000000000000000ULL).isZero()
3507#else
3508 && (CI & ~0b01111111100000000000000000000000ULL).isNullValue()
3509#endif
3510 ) ||
3511 (FT->isDoubleTy()
3512#if LLVM_VERSION_MAJOR > 16
3513 &&
3514 (CI &
3515 ~0b0111111111110000000000000000000000000000000000000000000000000000ULL)
3516 .isZero()
3517#else
3518 &&
3519 (CI &
3520 ~0b0111111111110000000000000000000000000000000000000000000000000000ULL)
3521 .isNullValue()
3522#endif
3523 ))) {
3524 validXor = true;
3525 }
3526 } else if (auto CV = dyn_cast_or_null<ConstantVector>(Args[i])) {
3527 validXor = true;
3528 if (dl.getTypeSizeInBits(FT) !=
3529 dl.getTypeSizeInBits(CV->getOperand(i)->getType()))
3530 continue;
3531 for (size_t i = 0, end = CV->getNumOperands(); i < end; ++i) {
3532 auto CI = dyn_cast<ConstantInt>(CV->getOperand(i))->getValue();
3533#if LLVM_VERSION_MAJOR > 16
3534 if (CI.isZero())
3535#else
3536 if (CI.isNullValue())
3537#endif
3538 {
3539 } else if (
3540 !CI.isNegative() &&
3541 ((FT->isFloatTy()
3542#if LLVM_VERSION_MAJOR > 16
3543 && (CI & ~0b01111111100000000000000000000000ULL).isZero()
3544#else
3545 &&
3546 (CI & ~0b01111111100000000000000000000000ULL).isNullValue()
3547#endif
3548 ) ||
3549 (FT->isDoubleTy()
3550#if LLVM_VERSION_MAJOR > 16
3551 &&
3552 (CI &
3553 ~0b0111111111110000000000000000000000000000000000000000000000000000ULL)
3554 .isZero()
3555#else
3556 &&
3557 (CI &
3558 ~0b0111111111110000000000000000000000000000000000000000000000000000ULL)
3559 .isNullValue()
3560#endif
3561 ))) {
3562 } else
3563 validXor = false;
3564 }
3565 } else if (auto CV = dyn_cast_or_null<ConstantDataVector>(Args[i])) {
3566 validXor = true;
3567 if (dl.getTypeSizeInBits(FT) !=
3568 dl.getTypeSizeInBits(CV->getElementType()))
3569 continue;
3570 for (size_t i = 0, end = CV->getNumElements(); i < end; ++i) {
3571 auto CI = CV->getElementAsAPInt(i);
3572#if LLVM_VERSION_MAJOR > 16
3573 if (CI.isZero())
3574#else
3575 if (CI.isNullValue())
3576#endif
3577 {
3578 } else if (
3579 !CI.isNegative() &&
3580 ((FT->isFloatTy()
3581#if LLVM_VERSION_MAJOR > 16
3582 && (CI & ~0b01111111100000000000000000000000ULL).isZero()
3583#else
3584 &&
3585 (CI & ~0b01111111100000000000000000000000ULL).isNullValue()
3586#endif
3587 ) ||
3588 (FT->isDoubleTy()
3589#if LLVM_VERSION_MAJOR > 16
3590 &&
3591 (CI &
3592 ~0b0111111111110000000000000000000000000000000000000000000000000000ULL)
3593 .isZero()
3594#else
3595 &&
3596 (CI &
3597 ~0b0111111111110000000000000000000000000000000000000000000000000000ULL)
3598 .isNullValue()
3599#endif
3600 ))) {
3601 } else
3602 validXor = false;
3603 }
3604 }
3605 if (validXor) {
3606 Result = ConcreteType(FT);
3607 }
3608 }
3609 }
3610
3611 Ret = Result.Only(-1, nullptr);
3612 }
3613 }
3614}
3615void TypeAnalyzer::visitBinaryOperator(BinaryOperator &I) {
3616 Value *Args[2] = {I.getOperand(0), I.getOperand(1)};
3617 TypeTree Ret = getAnalysis(&I);
3618 TypeTree LHS = getAnalysis(I.getOperand(0));
3619 TypeTree RHS = getAnalysis(I.getOperand(1));
3620 auto &DL = I.getParent()->getParent()->getParent()->getDataLayout();
3621 visitBinaryOperation(DL, I.getType(), I.getOpcode(), Args, Ret, LHS, RHS, &I);
3622
3623 if (direction & UP) {
3624 updateAnalysis(I.getOperand(0), LHS, &I);
3625 updateAnalysis(I.getOperand(1), RHS, &I);
3626 }
3627
3628 if (direction & DOWN) {
3629 if (I.getType()->isIntOrIntVectorTy() && Ret[{-1}] == BaseType::Anything) {
3630 if (mustRemainInteger(&I)) {
3631 Ret = TypeTree(BaseType::Integer).Only(-1, &I);
3632 }
3633 }
3634 updateAnalysis(&I, Ret, &I);
3635 }
3636}
3637
3638void TypeAnalyzer::visitMemTransferInst(llvm::MemTransferInst &MTI) {
3640}
3641
3642void TypeAnalyzer::visitMemTransferCommon(llvm::CallBase &MTI) {
3643 if (MTI.getType()->isIntegerTy()) {
3644 updateAnalysis(&MTI, TypeTree(BaseType::Integer).Only(-1, &MTI), &MTI);
3645 }
3646
3647 if (!(direction & UP))
3648 return;
3649
3650 // If memcpy / memmove of pointer, we can propagate type information from src
3651 // to dst up to the length and vice versa
3652 size_t sz = 1;
3653 for (auto val :
3654 fntypeinfo.knownIntegralValues(MTI.getArgOperand(2), DT, intseen, SE)) {
3655 if (val >= 0) {
3656 sz = max(sz, (size_t)val);
3657 }
3658 }
3659
3660 auto &dl = MTI.getParent()->getParent()->getParent()->getDataLayout();
3661 TypeTree res = getAnalysis(MTI.getArgOperand(0))
3662 .PurgeAnything()
3663 .Data0()
3664 .ShiftIndices(dl, 0, sz, 0);
3665 TypeTree res2 = getAnalysis(MTI.getArgOperand(1))
3666 .PurgeAnything()
3667 .Data0()
3668 .ShiftIndices(dl, 0, sz, 0);
3669
3670 bool Legal = true;
3671 res.checkedOrIn(res2, /*PointerIntSame*/ false, Legal);
3672 if (!Legal) {
3673 std::string str;
3674 raw_string_ostream ss(str);
3675 if (!CustomErrorHandler) {
3676 llvm::errs() << *fntypeinfo.Function->getParent() << "\n";
3677 llvm::errs() << *fntypeinfo.Function << "\n";
3678 dump(ss);
3679 }
3680 ss << "Illegal updateMemTransfer Analysis " << MTI << "\n";
3681 ss << "Illegal orIn: " << res.str() << " right: " << res2.str() << "\n";
3682 ss << *MTI.getArgOperand(0) << " "
3683 << getAnalysis(MTI.getArgOperand(0)).str() << "\n";
3684 ss << *MTI.getArgOperand(1) << " "
3685 << getAnalysis(MTI.getArgOperand(1)).str() << "\n";
3686
3687 if (CustomErrorHandler) {
3688 CustomErrorHandler(str.c_str(), wrap(&MTI),
3689 ErrorType::IllegalTypeAnalysis, (void *)this,
3690 wrap(&MTI), nullptr);
3691 }
3692 EmitFailure("IllegalUpdateAnalysis", MTI.getDebugLoc(), &MTI, ss.str());
3693 report_fatal_error("Performed illegal updateAnalysis");
3694 }
3695 res.insert({}, BaseType::Pointer);
3696 res = res.Only(-1, &MTI);
3697 updateAnalysis(MTI.getArgOperand(0), res, &MTI);
3698 updateAnalysis(MTI.getArgOperand(1), res, &MTI);
3699#if LLVM_VERSION_MAJOR >= 14
3700 for (unsigned i = 2; i < MTI.arg_size(); ++i)
3701#else
3702 for (unsigned i = 2; i < MTI.getNumArgOperands(); ++i)
3703#endif
3704 {
3705 updateAnalysis(MTI.getArgOperand(i),
3706 TypeTree(BaseType::Integer).Only(-1, &MTI), &MTI);
3707 }
3708}
3709
3710void TypeAnalyzer::visitIntrinsicInst(llvm::IntrinsicInst &I) {
3711 switch (I.getIntrinsicID()) {
3712 case Intrinsic::ctpop:
3713 case Intrinsic::ctlz:
3714 case Intrinsic::cttz:
3715 case Intrinsic::nvvm_read_ptx_sreg_tid_x:
3716 case Intrinsic::nvvm_read_ptx_sreg_tid_y:
3717 case Intrinsic::nvvm_read_ptx_sreg_tid_z:
3718 case Intrinsic::nvvm_read_ptx_sreg_ntid_x:
3719 case Intrinsic::nvvm_read_ptx_sreg_ntid_y:
3720 case Intrinsic::nvvm_read_ptx_sreg_ntid_z:
3721 case Intrinsic::nvvm_read_ptx_sreg_ctaid_x:
3722 case Intrinsic::nvvm_read_ptx_sreg_ctaid_y:
3723 case Intrinsic::nvvm_read_ptx_sreg_ctaid_z:
3724 case Intrinsic::nvvm_read_ptx_sreg_nctaid_x:
3725 case Intrinsic::nvvm_read_ptx_sreg_nctaid_y:
3726 case Intrinsic::nvvm_read_ptx_sreg_nctaid_z:
3727 case Intrinsic::nvvm_read_ptx_sreg_warpsize:
3728 case Intrinsic::amdgcn_workitem_id_x:
3729 case Intrinsic::amdgcn_workitem_id_y:
3730 case Intrinsic::amdgcn_workitem_id_z:
3731 // No direction check as always valid
3732 updateAnalysis(&I, TypeTree(BaseType::Integer).Only(-1, &I), &I);
3733 return;
3734
3735#if LLVM_VERSION_MAJOR < 22
3736 case Intrinsic::nvvm_barrier0_popc:
3737 case Intrinsic::nvvm_barrier0_and:
3738 case Intrinsic::nvvm_barrier0_or:
3739#else
3740 case Intrinsic::nvvm_barrier_cta_red_and_aligned_all:
3741 case Intrinsic::nvvm_barrier_cta_red_and_aligned_count:
3742 case Intrinsic::nvvm_barrier_cta_red_or_aligned_all:
3743 case Intrinsic::nvvm_barrier_cta_red_or_aligned_count:
3744 case Intrinsic::nvvm_barrier_cta_red_popc_aligned_all:
3745 case Intrinsic::nvvm_barrier_cta_red_popc_aligned_count:
3746#endif
3747 // No direction check as always valid
3748 updateAnalysis(&I, TypeTree(BaseType::Integer).Only(-1, &I), &I);
3749 updateAnalysis(I.getOperand(0), TypeTree(BaseType::Integer).Only(-1, &I),
3750 &I);
3751 return;
3752
3753 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f32_col:
3754 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f32_col_stride:
3755 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f32_row:
3756 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f32_row_stride:
3757 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f32_col:
3758 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f32_col_stride:
3759 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f32_row:
3760 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f32_row_stride:
3761 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f32_col:
3762 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f32_col_stride:
3763 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f32_row:
3764 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f32_row_stride: {
3765 TypeTree TT;
3766 TT.insert({-1}, BaseType::Pointer);
3767 TT.insert({-1, 0}, Type::getFloatTy(I.getContext()));
3768 updateAnalysis(I.getOperand(0), TT, &I);
3769 for (int i = 1; i <= 9; i++)
3771 I.getOperand(i),
3772 TypeTree(ConcreteType(Type::getFloatTy(I.getContext()))).Only(-1, &I),
3773 &I);
3774 return;
3775 }
3776
3777 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f16_col:
3778 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f16_col_stride:
3779 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f16_row:
3780 case Intrinsic::nvvm_wmma_m16n16k16_store_d_f16_row_stride:
3781 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f16_col:
3782 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f16_col_stride:
3783 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f16_row:
3784 case Intrinsic::nvvm_wmma_m32n8k16_store_d_f16_row_stride:
3785 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f16_col:
3786 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f16_col_stride:
3787 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f16_row:
3788 case Intrinsic::nvvm_wmma_m8n32k16_store_d_f16_row_stride: {
3789 TypeTree TT;
3790 TT.insert({-1}, BaseType::Pointer);
3791 TT.insert({-1, 0}, Type::getHalfTy(I.getContext()));
3792 updateAnalysis(I.getOperand(0), TT, &I);
3793 for (int i = 1; i <= 9; i++)
3795 I.getOperand(i),
3796 TypeTree(ConcreteType(Type::getHalfTy(I.getContext()))).Only(-1, &I),
3797 &I);
3798 return;
3799 }
3800
3801 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f32_col:
3802 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f32_col_stride:
3803 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f32_row:
3804 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f32_row_stride:
3805 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f32_col:
3806 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f32_col_stride:
3807 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f32_row:
3808 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f32_row_stride:
3809 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f32_col:
3810 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f32_col_stride:
3811 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f32_row:
3812 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f32_row_stride: {
3813 TypeTree TT;
3814 TT.insert({-1}, BaseType::Pointer);
3815 TT.insert({-1, 0}, Type::getFloatTy(I.getContext()));
3816 updateAnalysis(I.getOperand(0), TT, &I);
3818 &I,
3819 TypeTree(ConcreteType(Type::getFloatTy(I.getContext()))).Only(-1, &I),
3820 &I);
3821 return;
3822 }
3823
3824 case Intrinsic::nvvm_wmma_m16n16k16_load_a_f16_col:
3825 case Intrinsic::nvvm_wmma_m16n16k16_load_a_f16_col_stride:
3826 case Intrinsic::nvvm_wmma_m16n16k16_load_a_f16_row:
3827 case Intrinsic::nvvm_wmma_m16n16k16_load_a_f16_row_stride:
3828 case Intrinsic::nvvm_wmma_m16n16k16_load_b_f16_col:
3829 case Intrinsic::nvvm_wmma_m16n16k16_load_b_f16_col_stride:
3830 case Intrinsic::nvvm_wmma_m16n16k16_load_b_f16_row:
3831 case Intrinsic::nvvm_wmma_m16n16k16_load_b_f16_row_stride:
3832 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f16_col:
3833 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f16_col_stride:
3834 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f16_row:
3835 case Intrinsic::nvvm_wmma_m16n16k16_load_c_f16_row_stride:
3836 case Intrinsic::nvvm_wmma_m32n8k16_load_a_f16_col:
3837 case Intrinsic::nvvm_wmma_m32n8k16_load_a_f16_col_stride:
3838 case Intrinsic::nvvm_wmma_m32n8k16_load_a_f16_row:
3839 case Intrinsic::nvvm_wmma_m32n8k16_load_a_f16_row_stride:
3840 case Intrinsic::nvvm_wmma_m32n8k16_load_b_f16_col:
3841 case Intrinsic::nvvm_wmma_m32n8k16_load_b_f16_col_stride:
3842 case Intrinsic::nvvm_wmma_m32n8k16_load_b_f16_row:
3843 case Intrinsic::nvvm_wmma_m32n8k16_load_b_f16_row_stride:
3844 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f16_col:
3845 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f16_col_stride:
3846 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f16_row:
3847 case Intrinsic::nvvm_wmma_m32n8k16_load_c_f16_row_stride:
3848 case Intrinsic::nvvm_wmma_m8n32k16_load_a_f16_col:
3849 case Intrinsic::nvvm_wmma_m8n32k16_load_a_f16_col_stride:
3850 case Intrinsic::nvvm_wmma_m8n32k16_load_a_f16_row:
3851 case Intrinsic::nvvm_wmma_m8n32k16_load_a_f16_row_stride:
3852 case Intrinsic::nvvm_wmma_m8n32k16_load_b_f16_col:
3853 case Intrinsic::nvvm_wmma_m8n32k16_load_b_f16_col_stride:
3854 case Intrinsic::nvvm_wmma_m8n32k16_load_b_f16_row:
3855 case Intrinsic::nvvm_wmma_m8n32k16_load_b_f16_row_stride:
3856 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f16_col:
3857 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f16_col_stride:
3858 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f16_row:
3859 case Intrinsic::nvvm_wmma_m8n32k16_load_c_f16_row_stride: {
3860 TypeTree TT;
3861 TT.insert({-1}, BaseType::Pointer);
3862 TT.insert({-1, 0}, Type::getHalfTy(I.getContext()));
3863 updateAnalysis(I.getOperand(0), TT, &I);
3865 &I,
3866 TypeTree(ConcreteType(Type::getHalfTy(I.getContext()))).Only(-1, &I),
3867 &I);
3868 return;
3869 }
3870
3871 case Intrinsic::nvvm_wmma_m16n16k16_load_c_s32_col:
3872 case Intrinsic::nvvm_wmma_m16n16k16_load_c_s32_col_stride:
3873 case Intrinsic::nvvm_wmma_m16n16k16_load_a_s8_col:
3874 case Intrinsic::nvvm_wmma_m16n16k16_load_a_s8_col_stride:
3875 case Intrinsic::nvvm_wmma_m16n16k16_load_a_u8_col_stride:
3876 case Intrinsic::nvvm_wmma_m16n16k16_load_a_u8_col:
3877 case Intrinsic::nvvm_wmma_m16n16k16_load_a_s8_row:
3878 case Intrinsic::nvvm_wmma_m16n16k16_load_a_s8_row_stride:
3879 case Intrinsic::nvvm_wmma_m16n16k16_load_a_u8_row_stride:
3880 case Intrinsic::nvvm_wmma_m16n16k16_load_a_u8_row:
3881 case Intrinsic::nvvm_wmma_m16n16k16_load_b_s8_col:
3882 case Intrinsic::nvvm_wmma_m16n16k16_load_b_s8_col_stride:
3883 case Intrinsic::nvvm_wmma_m16n16k16_load_b_u8_col_stride:
3884 case Intrinsic::nvvm_wmma_m16n16k16_load_b_u8_col:
3885 case Intrinsic::nvvm_wmma_m16n16k16_load_b_s8_row:
3886 case Intrinsic::nvvm_wmma_m16n16k16_load_b_s8_row_stride:
3887 case Intrinsic::nvvm_wmma_m16n16k16_load_b_u8_row_stride:
3888 case Intrinsic::nvvm_wmma_m16n16k16_load_b_u8_row:
3889 case Intrinsic::nvvm_wmma_m16n16k16_load_c_s32_row:
3890 case Intrinsic::nvvm_wmma_m16n16k16_load_c_s32_row_stride:
3891 case Intrinsic::nvvm_wmma_m32n8k16_load_a_s8_col:
3892 case Intrinsic::nvvm_wmma_m32n8k16_load_a_s8_col_stride:
3893 case Intrinsic::nvvm_wmma_m32n8k16_load_a_u8_col_stride:
3894 case Intrinsic::nvvm_wmma_m32n8k16_load_a_u8_col:
3895 case Intrinsic::nvvm_wmma_m32n8k16_load_a_s8_row:
3896 case Intrinsic::nvvm_wmma_m32n8k16_load_a_s8_row_stride:
3897 case Intrinsic::nvvm_wmma_m32n8k16_load_a_u8_row_stride:
3898 case Intrinsic::nvvm_wmma_m32n8k16_load_a_u8_row:
3899 case Intrinsic::nvvm_wmma_m32n8k16_load_b_s8_col:
3900 case Intrinsic::nvvm_wmma_m32n8k16_load_b_s8_col_stride:
3901 case Intrinsic::nvvm_wmma_m32n8k16_load_b_u8_col_stride:
3902 case Intrinsic::nvvm_wmma_m32n8k16_load_b_u8_col:
3903 case Intrinsic::nvvm_wmma_m32n8k16_load_b_s8_row:
3904 case Intrinsic::nvvm_wmma_m32n8k16_load_b_s8_row_stride:
3905 case Intrinsic::nvvm_wmma_m32n8k16_load_b_u8_row_stride:
3906 case Intrinsic::nvvm_wmma_m32n8k16_load_b_u8_row:
3907 case Intrinsic::nvvm_wmma_m32n8k16_load_c_s32_col:
3908 case Intrinsic::nvvm_wmma_m32n8k16_load_c_s32_col_stride:
3909 case Intrinsic::nvvm_wmma_m32n8k16_load_c_s32_row:
3910 case Intrinsic::nvvm_wmma_m32n8k16_load_c_s32_row_stride:
3911 case Intrinsic::nvvm_wmma_m8n32k16_load_a_s8_col:
3912 case Intrinsic::nvvm_wmma_m8n32k16_load_a_s8_col_stride:
3913 case Intrinsic::nvvm_wmma_m8n32k16_load_a_u8_col_stride:
3914 case Intrinsic::nvvm_wmma_m8n32k16_load_a_u8_col:
3915 case Intrinsic::nvvm_wmma_m8n32k16_load_a_s8_row:
3916 case Intrinsic::nvvm_wmma_m8n32k16_load_a_s8_row_stride:
3917 case Intrinsic::nvvm_wmma_m8n32k16_load_a_u8_row_stride:
3918 case Intrinsic::nvvm_wmma_m8n32k16_load_a_u8_row:
3919 case Intrinsic::nvvm_wmma_m8n32k16_load_b_s8_col:
3920 case Intrinsic::nvvm_wmma_m8n32k16_load_b_s8_col_stride:
3921 case Intrinsic::nvvm_wmma_m8n32k16_load_b_u8_col_stride:
3922 case Intrinsic::nvvm_wmma_m8n32k16_load_b_u8_col:
3923 case Intrinsic::nvvm_wmma_m8n32k16_load_b_s8_row:
3924 case Intrinsic::nvvm_wmma_m8n32k16_load_b_s8_row_stride:
3925 case Intrinsic::nvvm_wmma_m8n32k16_load_b_u8_row_stride:
3926 case Intrinsic::nvvm_wmma_m8n32k16_load_b_u8_row:
3927 case Intrinsic::nvvm_wmma_m8n32k16_load_c_s32_col:
3928 case Intrinsic::nvvm_wmma_m8n32k16_load_c_s32_col_stride:
3929 case Intrinsic::nvvm_wmma_m8n32k16_load_c_s32_row:
3930 case Intrinsic::nvvm_wmma_m8n32k16_load_c_s32_row_stride:
3931 case Intrinsic::nvvm_wmma_m8n8k128_load_a_b1_row:
3932 case Intrinsic::nvvm_wmma_m8n8k128_load_a_b1_row_stride:
3933 case Intrinsic::nvvm_wmma_m8n8k128_load_b_b1_col:
3934 case Intrinsic::nvvm_wmma_m8n8k128_load_b_b1_col_stride:
3935 case Intrinsic::nvvm_wmma_m8n8k128_load_c_s32_col:
3936 case Intrinsic::nvvm_wmma_m8n8k128_load_c_s32_col_stride:
3937 case Intrinsic::nvvm_wmma_m8n8k128_load_c_s32_row:
3938 case Intrinsic::nvvm_wmma_m8n8k128_load_c_s32_row_stride:
3939 case Intrinsic::nvvm_wmma_m8n8k32_load_a_s4_row:
3940 case Intrinsic::nvvm_wmma_m8n8k32_load_a_s4_row_stride:
3941 case Intrinsic::nvvm_wmma_m8n8k32_load_a_u4_row_stride:
3942 case Intrinsic::nvvm_wmma_m8n8k32_load_a_u4_row:
3943 case Intrinsic::nvvm_wmma_m8n8k32_load_b_s4_col:
3944 case Intrinsic::nvvm_wmma_m8n8k32_load_b_s4_col_stride:
3945 case Intrinsic::nvvm_wmma_m8n8k32_load_b_u4_col_stride:
3946 case Intrinsic::nvvm_wmma_m8n8k32_load_b_u4_col:
3947 case Intrinsic::nvvm_wmma_m8n8k32_load_c_s32_col:
3948 case Intrinsic::nvvm_wmma_m8n8k32_load_c_s32_col_stride:
3949 case Intrinsic::nvvm_wmma_m8n8k32_load_c_s32_row:
3950 case Intrinsic::nvvm_wmma_m8n8k32_load_c_s32_row_stride: {
3951 // TODO
3952 return;
3953 }
3954
3955 case Intrinsic::nvvm_wmma_m16n16k16_mma_col_col_f16_f16:
3956 case Intrinsic::nvvm_wmma_m16n16k16_mma_col_row_f16_f16:
3957 case Intrinsic::nvvm_wmma_m16n16k16_mma_row_col_f16_f16:
3958 case Intrinsic::nvvm_wmma_m16n16k16_mma_row_row_f16_f16:
3959 case Intrinsic::nvvm_wmma_m32n8k16_mma_col_col_f16_f16:
3960 case Intrinsic::nvvm_wmma_m32n8k16_mma_col_row_f16_f16:
3961 case Intrinsic::nvvm_wmma_m32n8k16_mma_row_col_f16_f16:
3962 case Intrinsic::nvvm_wmma_m32n8k16_mma_row_row_f16_f16:
3963 case Intrinsic::nvvm_wmma_m8n32k16_mma_col_col_f16_f16:
3964 case Intrinsic::nvvm_wmma_m8n32k16_mma_col_row_f16_f16:
3965 case Intrinsic::nvvm_wmma_m8n32k16_mma_row_col_f16_f16:
3966 case Intrinsic::nvvm_wmma_m8n32k16_mma_row_row_f16_f16: {
3967 for (int i = 0; i < 16; i++)
3969 I.getOperand(i),
3970 TypeTree(ConcreteType(Type::getHalfTy(I.getContext()))).Only(-1, &I),
3971 &I);
3972 for (int i = 16; i < 16 + 8; i++)
3974 I.getOperand(i),
3975 TypeTree(ConcreteType(Type::getHalfTy(I.getContext()))).Only(-1, &I),
3976 &I);
3978 &I,
3979 TypeTree(ConcreteType(Type::getHalfTy(I.getContext()))).Only(-1, &I),
3980 &I);
3981 return;
3982 }
3983
3984 case Intrinsic::nvvm_wmma_m16n16k16_mma_col_col_f16_f32:
3985 case Intrinsic::nvvm_wmma_m16n16k16_mma_col_row_f16_f32:
3986 case Intrinsic::nvvm_wmma_m16n16k16_mma_row_col_f16_f32:
3987 case Intrinsic::nvvm_wmma_m16n16k16_mma_row_row_f16_f32:
3988 case Intrinsic::nvvm_wmma_m32n8k16_mma_col_col_f16_f32:
3989 case Intrinsic::nvvm_wmma_m32n8k16_mma_col_row_f16_f32:
3990 case Intrinsic::nvvm_wmma_m32n8k16_mma_row_col_f16_f32:
3991 case Intrinsic::nvvm_wmma_m32n8k16_mma_row_row_f16_f32:
3992 case Intrinsic::nvvm_wmma_m8n32k16_mma_col_col_f16_f32:
3993 case Intrinsic::nvvm_wmma_m8n32k16_mma_col_row_f16_f32:
3994 case Intrinsic::nvvm_wmma_m8n32k16_mma_row_col_f16_f32:
3995 case Intrinsic::nvvm_wmma_m8n32k16_mma_row_row_f16_f32: {
3996 for (int i = 0; i < 16; i++)
3998 I.getOperand(i),
3999 TypeTree(ConcreteType(Type::getHalfTy(I.getContext()))).Only(-1, &I),
4000 &I);
4001 for (int i = 16; i < 16 + 8; i++)
4003 I.getOperand(i),
4004 TypeTree(ConcreteType(Type::getFloatTy(I.getContext()))).Only(-1, &I),
4005 &I);
4007 &I,
4008 TypeTree(ConcreteType(Type::getHalfTy(I.getContext()))).Only(-1, &I),
4009 &I);
4010 return;
4011 }
4012
4013 case Intrinsic::nvvm_wmma_m16n16k16_mma_col_col_f32_f16:
4014 case Intrinsic::nvvm_wmma_m16n16k16_mma_col_row_f32_f16:
4015 case Intrinsic::nvvm_wmma_m16n16k16_mma_row_col_f32_f16:
4016 case Intrinsic::nvvm_wmma_m16n16k16_mma_row_row_f32_f16:
4017 case Intrinsic::nvvm_wmma_m32n8k16_mma_col_col_f32_f16:
4018 case Intrinsic::nvvm_wmma_m32n8k16_mma_col_row_f32_f16:
4019 case Intrinsic::nvvm_wmma_m32n8k16_mma_row_col_f32_f16:
4020 case Intrinsic::nvvm_wmma_m32n8k16_mma_row_row_f32_f16:
4021 case Intrinsic::nvvm_wmma_m8n32k16_mma_col_col_f32_f16:
4022 case Intrinsic::nvvm_wmma_m8n32k16_mma_col_row_f32_f16:
4023 case Intrinsic::nvvm_wmma_m8n32k16_mma_row_col_f32_f16:
4024 case Intrinsic::nvvm_wmma_m8n32k16_mma_row_row_f32_f16: {
4025 for (int i = 0; i < 16; i++)
4027 I.getOperand(i),
4028 TypeTree(ConcreteType(Type::getHalfTy(I.getContext()))).Only(-1, &I),
4029 &I);
4030 for (int i = 16; i < 16 + 8; i++)
4032 I.getOperand(i),
4033 TypeTree(ConcreteType(Type::getHalfTy(I.getContext()))).Only(-1, &I),
4034 &I);
4036 &I,
4037 TypeTree(ConcreteType(Type::getFloatTy(I.getContext()))).Only(-1, &I),
4038 &I);
4039 return;
4040 }
4041
4042 case Intrinsic::nvvm_wmma_m16n16k16_mma_col_col_f32_f32:
4043 case Intrinsic::nvvm_wmma_m16n16k16_mma_col_row_f32_f32:
4044 case Intrinsic::nvvm_wmma_m16n16k16_mma_row_col_f32_f32:
4045 case Intrinsic::nvvm_wmma_m16n16k16_mma_row_row_f32_f32:
4046 case Intrinsic::nvvm_wmma_m32n8k16_mma_col_col_f32_f32:
4047 case Intrinsic::nvvm_wmma_m32n8k16_mma_col_row_f32_f32:
4048 case Intrinsic::nvvm_wmma_m32n8k16_mma_row_col_f32_f32:
4049 case Intrinsic::nvvm_wmma_m32n8k16_mma_row_row_f32_f32:
4050 case Intrinsic::nvvm_wmma_m8n32k16_mma_col_col_f32_f32:
4051 case Intrinsic::nvvm_wmma_m8n32k16_mma_col_row_f32_f32:
4052 case Intrinsic::nvvm_wmma_m8n32k16_mma_row_col_f32_f32:
4053 case Intrinsic::nvvm_wmma_m8n32k16_mma_row_row_f32_f32: {
4054 for (int i = 0; i < 16; i++)
4056 I.getOperand(i),
4057 TypeTree(ConcreteType(Type::getHalfTy(I.getContext()))).Only(-1, &I),
4058 &I);
4059 for (int i = 16; i < 16 + 8; i++)
4061 I.getOperand(i),
4062 TypeTree(ConcreteType(Type::getFloatTy(I.getContext()))).Only(-1, &I),
4063 &I);
4065 &I,
4066 TypeTree(ConcreteType(Type::getFloatTy(I.getContext()))).Only(-1, &I),
4067 &I);
4068 return;
4069 }
4070
4071#if LLVM_VERSION_MAJOR < 20
4072 case Intrinsic::nvvm_ldg_global_i:
4073 case Intrinsic::nvvm_ldg_global_p:
4074 case Intrinsic::nvvm_ldg_global_f:
4075#endif
4076 case Intrinsic::nvvm_ldu_global_i:
4077 case Intrinsic::nvvm_ldu_global_p:
4078 case Intrinsic::nvvm_ldu_global_f: {
4079 auto &DL = I.getParent()->getParent()->getParent()->getDataLayout();
4080 auto LoadSize = (DL.getTypeSizeInBits(I.getType()) + 7) / 8;
4081
4082 if (direction & UP) {
4085 DL, /*start*/ 0, LoadSize, /*addOffset*/ 0);
4086 updateAnalysis(I.getOperand(0), ptr.Only(-1, &I), &I);
4087 }
4088 if (direction & DOWN)
4089 updateAnalysis(&I, getAnalysis(I.getOperand(0)).Lookup(LoadSize, DL), &I);
4090 return;
4091 }
4092
4093 case Intrinsic::log:
4094 case Intrinsic::log2:
4095 case Intrinsic::log10:
4096 case Intrinsic::exp:
4097 case Intrinsic::exp2:
4098 case Intrinsic::sin:
4099 case Intrinsic::cos:
4100#if LLVM_VERSION_MAJOR >= 18
4101 case Intrinsic::exp10:
4102#endif
4103#if LLVM_VERSION_MAJOR >= 19
4104 case Intrinsic::sinh:
4105 case Intrinsic::cosh:
4106 case Intrinsic::tanh:
4107 case Intrinsic::tan:
4108 case Intrinsic::asin:
4109 case Intrinsic::acos:
4110 case Intrinsic::atan:
4111#endif
4112 case Intrinsic::floor:
4113 case Intrinsic::ceil:
4114 case Intrinsic::trunc:
4115 case Intrinsic::rint:
4116 case Intrinsic::nearbyint:
4117 case Intrinsic::round:
4118 case Intrinsic::sqrt:
4119#if LLVM_VERSION_MAJOR >= 21
4120 case Intrinsic::nvvm_fabs:
4121 case Intrinsic::nvvm_fabs_ftz:
4122#else
4123 case Intrinsic::nvvm_fabs_f:
4124 case Intrinsic::nvvm_fabs_d:
4125 case Intrinsic::nvvm_fabs_ftz_f:
4126#endif
4127 case Intrinsic::fabs:
4128 // No direction check as always valid
4130 &I, TypeTree(ConcreteType(I.getType()->getScalarType())).Only(-1, &I),
4131 &I);
4132 // No direction check as always valid
4134 I.getOperand(0),
4135 TypeTree(ConcreteType(I.getOperand(0)->getType()->getScalarType()))
4136 .Only(-1, &I),
4137 &I);
4138 return;
4139
4140#if LLVM_VERSION_MAJOR >= 20
4141 case Intrinsic::sincos: {
4142 // {sin(x), cos(x)}: two values of the type of x.
4143 // No direction check as always valid
4144 Type *T = I.getOperand(0)->getType()->getScalarType();
4145 updateAnalysis(I.getOperand(0), TypeTree(ConcreteType(T)).Only(-1, &I), &I);
4146 if (!I.getOperand(0)->getType()->isVectorTy()) {
4147 auto &DL = I.getParent()->getParent()->getParent()->getDataLayout();
4148 auto *ST = cast<StructType>(I.getType());
4149 auto *SL = DL.getStructLayout(ST);
4150 TypeTree res;
4151 for (unsigned i = 0; i < 2; i++)
4152 res |= TypeTree(ConcreteType(T))
4153 .Only((int)(size_t)SL->getElementOffset(i), &I);
4154 updateAnalysis(&I, res, &I);
4155 }
4156 return;
4157 }
4158#endif
4159
4160 case Intrinsic::lround:
4161 case Intrinsic::llround:
4162 case Intrinsic::lrint:
4163 case Intrinsic::llrint:
4164#if LLVM_VERSION_MAJOR >= 12
4165 case Intrinsic::fptosi_sat:
4166 case Intrinsic::fptoui_sat:
4167#endif
4168 // A floating point value converted to an integer, as with fptosi.
4169 // No direction check as always valid
4170 updateAnalysis(&I, TypeTree(BaseType::Integer).Only(-1, &I), &I);
4171 // No direction check as always valid
4173 I.getOperand(0),
4174 TypeTree(ConcreteType(I.getOperand(0)->getType()->getScalarType()))
4175 .Only(-1, &I),
4176 &I);
4177 return;
4178
4179 case Intrinsic::fmuladd:
4180 case Intrinsic::fma:
4181 // No direction check as always valid
4183 &I, TypeTree(ConcreteType(I.getType()->getScalarType())).Only(-1, &I),
4184 &I);
4185 // No direction check as always valid
4187 I.getOperand(0),
4188 TypeTree(ConcreteType(I.getOperand(0)->getType()->getScalarType()))
4189 .Only(-1, &I),
4190 &I);
4191 // No direction check as always valid
4193 I.getOperand(1),
4194 TypeTree(ConcreteType(I.getOperand(1)->getType()->getScalarType()))
4195 .Only(-1, &I),
4196 &I);
4197 // No direction check as always valid
4199 I.getOperand(2),
4200 TypeTree(ConcreteType(I.getOperand(2)->getType()->getScalarType()))
4201 .Only(-1, &I),
4202 &I);
4203 return;
4204
4205 case Intrinsic::powi:
4206 // No direction check as always valid
4208 &I, TypeTree(ConcreteType(I.getType()->getScalarType())).Only(-1, &I),
4209 &I);
4210 // No direction check as always valid
4212 I.getOperand(0),
4213 TypeTree(ConcreteType(I.getOperand(0)->getType()->getScalarType()))
4214 .Only(-1, &I),
4215 &I);
4216 // No direction check as always valid
4217 updateAnalysis(I.getOperand(1), TypeTree(BaseType::Integer).Only(-1, &I),
4218 &I);
4219 return;
4220
4221#if LLVM_VERSION_MAJOR >= 12
4222 case Intrinsic::vector_reduce_fadd:
4223 case Intrinsic::vector_reduce_fmul:
4224#else
4225 case Intrinsic::experimental_vector_reduce_v2_fadd:
4226 case Intrinsic::experimental_vector_reduce_v2_fmul:
4227#endif
4228 case Intrinsic::copysign:
4229 case Intrinsic::maxnum:
4230 case Intrinsic::minnum:
4231#if LLVM_VERSION_MAJOR >= 15
4232 case Intrinsic::maximum:
4233 case Intrinsic::minimum:
4234#endif
4235#if LLVM_VERSION_MAJOR >= 20
4236 case Intrinsic::maximumnum:
4237 case Intrinsic::minimumnum:
4238#endif
4239 case Intrinsic::nvvm_fmax_f:
4240 case Intrinsic::nvvm_fmax_d:
4241 case Intrinsic::nvvm_fmax_ftz_f:
4242 case Intrinsic::nvvm_fmin_f:
4243 case Intrinsic::nvvm_fmin_d:
4244 case Intrinsic::nvvm_fmin_ftz_f:
4245 case Intrinsic::pow:
4246#if LLVM_VERSION_MAJOR >= 20
4247 case Intrinsic::atan2:
4248#endif
4249 // No direction check as always valid
4251 &I, TypeTree(ConcreteType(I.getType()->getScalarType())).Only(-1, &I),
4252 &I);
4253 // No direction check as always valid
4255 I.getOperand(0),
4256 TypeTree(ConcreteType(I.getOperand(0)->getType()->getScalarType()))
4257 .Only(-1, &I),
4258 &I);
4259 // No direction check as always valid
4261 I.getOperand(1),
4262 TypeTree(ConcreteType(I.getOperand(1)->getType()->getScalarType()))
4263 .Only(-1, &I),
4264 &I);
4265 return;
4266#if LLVM_VERSION_MAJOR >= 12
4267 case Intrinsic::smax:
4268 case Intrinsic::smin:
4269 case Intrinsic::umax:
4270 case Intrinsic::umin:
4271 if (direction & UP) {
4272 auto returnType = getAnalysis(&I)[{-1}];
4273 if (returnType == BaseType::Integer || returnType == BaseType::Pointer) {
4274 updateAnalysis(I.getOperand(0), TypeTree(returnType).Only(-1, &I), &I);
4275 updateAnalysis(I.getOperand(1), TypeTree(returnType).Only(-1, &I), &I);
4276 }
4277 }
4278 if (direction & DOWN) {
4279 auto opType0 = getAnalysis(I.getOperand(0))[{-1}];
4280 auto opType1 = getAnalysis(I.getOperand(1))[{-1}];
4281 if (opType0 == opType1 &&
4282 (opType0 == BaseType::Integer || opType0 == BaseType::Pointer)) {
4283 updateAnalysis(&I, TypeTree(opType0).Only(-1, &I), &I);
4284 } else if (opType0 == BaseType::Integer &&
4285 opType1 == BaseType::Anything) {
4286 updateAnalysis(&I, TypeTree(BaseType::Integer).Only(-1, &I), &I);
4287 } else if (opType1 == BaseType::Integer &&
4288 opType0 == BaseType::Anything) {
4289 updateAnalysis(&I, TypeTree(BaseType::Integer).Only(-1, &I), &I);
4290 }
4291 }
4292 return;
4293#endif
4294 case Intrinsic::umul_with_overflow:
4295 case Intrinsic::smul_with_overflow:
4296 case Intrinsic::ssub_with_overflow:
4297 case Intrinsic::usub_with_overflow:
4298 case Intrinsic::sadd_with_overflow:
4299 case Intrinsic::uadd_with_overflow: {
4300 // val, bool
4301 auto analysis = getAnalysis(&I).Data0();
4302
4303 BinaryOperator::BinaryOps opcode;
4304 // TODO update to use better rules in regular binop
4305 switch (I.getIntrinsicID()) {
4306 case Intrinsic::ssub_with_overflow:
4307 case Intrinsic::usub_with_overflow: {
4308 // TODO propagate this info
4309 // ptr - ptr => int and int - int => int; thus int = a - b says only that
4310 // these are equal ptr - int => ptr and int - ptr => ptr; thus
4312 opcode = BinaryOperator::Sub;
4313 break;
4314 }
4315
4316 case Intrinsic::smul_with_overflow:
4317 case Intrinsic::umul_with_overflow: {
4318 opcode = BinaryOperator::Mul;
4319 // if a + b or a * b == int, then a and b must be ints
4320 analysis = analysis.JustInt();
4321 break;
4322 }
4323 case Intrinsic::sadd_with_overflow:
4324 case Intrinsic::uadd_with_overflow: {
4325 opcode = BinaryOperator::Add;
4326 // if a + b or a * b == int, then a and b must be ints
4327 analysis = analysis.JustInt();
4328 break;
4329 }
4330 default:
4331 llvm_unreachable("unknown binary operator");
4332 }
4333
4334 // TODO update with newer binop protocol (see binop)
4335 if (direction & UP)
4336 updateAnalysis(I.getOperand(0), analysis.Only(-1, &I), &I);
4337 if (direction & UP)
4338 updateAnalysis(I.getOperand(1), analysis.Only(-1, &I), &I);
4339
4340 TypeTree vd = getAnalysis(I.getOperand(0)).Data0();
4341 bool Legal = true;
4342 vd.binopIn(Legal, getAnalysis(I.getOperand(1)).Data0(), opcode);
4343 if (!Legal) {
4344 std::string str;
4345 raw_string_ostream ss(str);
4346 if (!CustomErrorHandler) {
4347 llvm::errs() << *fntypeinfo.Function->getParent() << "\n";
4348 llvm::errs() << *fntypeinfo.Function << "\n";
4349 dump(ss);
4350 }
4351 ss << "Illegal updateBinopIntr Analysis " << I << "\n";
4352 ss << "Illegal binopIn(intr): " << I << " lhs: " << vd.str()
4353 << " rhs: " << getAnalysis(I.getOperand(1)).str() << "\n";
4354 if (CustomErrorHandler) {
4355 CustomErrorHandler(str.c_str(), wrap(&I),
4356 ErrorType::IllegalTypeAnalysis, (void *)this,
4357 wrap(&I), nullptr);
4358 }
4359 EmitFailure("IllegalUpdateAnalysis", I.getDebugLoc(), &I, ss.str());
4360 report_fatal_error("Performed illegal updateAnalysis");
4361 }
4362 auto &dl = I.getParent()->getParent()->getParent()->getDataLayout();
4363 int sz = (dl.getTypeSizeInBits(I.getOperand(0)->getType()) + 7) / 8;
4364 TypeTree overall = vd.Only(-1, &I).ShiftIndices(dl, 0, sz, 0);
4365
4366 int sz2 = (dl.getTypeSizeInBits(I.getType()) + 7) / 8;
4367 auto btree = TypeTree(BaseType::Integer)
4368 .Only(-1, &I)
4369 .ShiftIndices(dl, 0, sz2 - sz, sz);
4370 overall |= btree;
4371
4372 if (direction & DOWN)
4373 updateAnalysis(&I, overall, &I);
4374 return;
4375 }
4376 default:
4377 return;
4378 }
4379}
4380
4381/// This template class is defined to take the templated type T
4382/// update the analysis of the first argument (val) to be type T
4383/// As such, below we have several template specializations
4384/// to convert various c/c++ to TypeAnalysis types
4385template <typename T> struct TypeHandler {};
4386
4387template <> struct TypeHandler<double> {
4388 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4389 TA.updateAnalysis(
4390 val,
4391 TypeTree(ConcreteType(Type::getDoubleTy(call.getContext())))
4392 .Only(-1, &call),
4393 &call);
4394 }
4395};
4396
4397template <> struct TypeHandler<float> {
4398 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4399 TA.updateAnalysis(
4400 val,
4401 TypeTree(ConcreteType(Type::getFloatTy(call.getContext())))
4402 .Only(-1, &call),
4403 &call);
4404 }
4405};
4406
4407template <> struct TypeHandler<long double> {
4408 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4409 TA.updateAnalysis(
4410 val,
4411 TypeTree(ConcreteType(Type::getX86_FP80Ty(call.getContext())))
4412 .Only(-1, &call),
4413 &call);
4414 }
4415};
4416
4417#if defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__)
4418template <> struct TypeHandler<__float128> {
4419 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4420 TA.updateAnalysis(
4421 val,
4422 TypeTree(ConcreteType(Type::getFP128Ty(call.getContext())))
4423 .Only(-1, &call),
4424 &call);
4425 }
4426};
4427#endif
4428
4429template <> struct TypeHandler<double *> {
4430 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4431 TypeTree vd = TypeTree(Type::getDoubleTy(call.getContext())).Only(0, &call);
4433 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4434 }
4435};
4436
4437template <> struct TypeHandler<float *> {
4438 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4439 TypeTree vd = TypeTree(Type::getFloatTy(call.getContext())).Only(0, &call);
4441 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4442 }
4443};
4444
4445template <> struct TypeHandler<long double *> {
4446 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4447 TypeTree vd =
4448 TypeTree(Type::getX86_FP80Ty(call.getContext())).Only(0, &call);
4450 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4451 }
4452};
4453
4454#if defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__)
4455template <> struct TypeHandler<__float128 *> {
4456 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4457 TypeTree vd = TypeTree(Type::getFP128Ty(call.getContext())).Only(0, &call);
4459 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4460 }
4461};
4462#endif
4463
4464template <> struct TypeHandler<void> {
4465 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {}
4466};
4467
4468template <> struct TypeHandler<void *> {
4469 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4471 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4472 }
4473};
4474
4475template <> struct TypeHandler<int> {
4476 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4478 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4479 }
4480};
4481
4482template <> struct TypeHandler<int *> {
4483 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4484 TypeTree vd = TypeTree(BaseType::Integer).Only(0, &call);
4486 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4487 }
4488};
4489
4490template <> struct TypeHandler<unsigned int> {
4491 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4493 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4494 }
4495};
4496
4497template <> struct TypeHandler<unsigned int *> {
4498 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4499 TypeTree vd = TypeTree(BaseType::Integer).Only(0, &call);
4501 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4502 }
4503};
4504
4505template <> struct TypeHandler<long int> {
4506 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4508 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4509 }
4510};
4511
4512template <> struct TypeHandler<long int *> {
4513 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4514 TypeTree vd = TypeTree(BaseType::Integer).Only(0, &call);
4516 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4517 }
4518};
4519
4520template <> struct TypeHandler<long unsigned int> {
4521 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4523 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4524 }
4525};
4526
4527template <> struct TypeHandler<long unsigned int *> {
4528 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4529 TypeTree vd = TypeTree(BaseType::Integer).Only(0, &call);
4531 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4532 }
4533};
4534
4535template <> struct TypeHandler<long long int> {
4536 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4538 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4539 }
4540};
4541
4542template <> struct TypeHandler<long long int *> {
4543 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4544 TypeTree vd = TypeTree(BaseType::Integer).Only(0, &call);
4546 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4547 }
4548};
4549
4550template <> struct TypeHandler<long long unsigned int> {
4551 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4553 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4554 }
4555};
4556
4557template <> struct TypeHandler<long long unsigned int *> {
4558 static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA) {
4559 TypeTree vd = TypeTree(BaseType::Integer).Only(0, &call);
4561 TA.updateAnalysis(val, vd.Only(-1, &call), &call);
4562 }
4563};
4564
4565template <typename... Arg0> struct FunctionArgumentIterator {
4566 static void analyzeFuncTypesHelper(unsigned idx, CallBase &call,
4567 TypeAnalyzer &TA) {}
4568};
4569
4570template <typename Arg0, typename... Args>
4572 static void analyzeFuncTypesHelper(unsigned idx, CallBase &call,
4573 TypeAnalyzer &TA) {
4574 TypeHandler<Arg0>::analyzeType(call.getOperand(idx), call, TA);
4576 TA);
4577 }
4578};
4579
4580template <typename RT, typename... Args>
4585
4586template <typename RT, typename... Args>
4587void analyzeFuncTypes(RT (*fn)(Args...), CallBase &call, TypeAnalyzer &TA) {
4588 analyzeFuncTypesNoFn<RT, Args...>(call, TA);
4589}
4590
4591void analyzeIntelSubscriptIntrinsic(IntrinsicInst &II, TypeAnalyzer &TA) {
4592 assert(isIntelSubscriptIntrinsic(II));
4593#if LLVM_VERSION_MAJOR >= 14
4594 assert(II.arg_size() == 5);
4595#else
4596 assert(II.getNumArgOperands() == 5);
4597#endif
4598
4599 constexpr size_t idxArgsIndices[4] = {0, 1, 2, 4};
4600 constexpr size_t ptrArgIndex = 3;
4601
4602 // Update analysis of index parameters
4603
4604 if (TA.direction & TypeAnalyzer::UP) {
4605 for (auto i : idxArgsIndices) {
4606 auto idx = II.getOperand(i);
4607 TA.updateAnalysis(idx, TypeTree(BaseType::Integer).Only(-1, &II), &II);
4608 }
4609 }
4610
4611 // Update analysis of ptr parameter
4612
4613 auto &DL = TA.fntypeinfo.Function->getParent()->getDataLayout();
4614 auto pointerAnalysis = TA.getAnalysis(II.getOperand(ptrArgIndex));
4615
4616 if (TA.direction & TypeAnalyzer::DOWN) {
4617 bool legal = true;
4618 auto keepMinus = pointerAnalysis.KeepMinusOne(legal);
4619 if (!legal) {
4621 CustomErrorHandler("Could not keep minus one", wrap(&II),
4622 ErrorType::IllegalTypeAnalysis, &TA, nullptr,
4623 nullptr);
4624 else {
4625 TA.dump();
4626 llvm::errs()
4627 << " could not perform minus one for llvm.intel.subscript'd: " << II
4628 << "\n";
4629 }
4630 }
4631 TA.updateAnalysis(&II, keepMinus, &II);
4632 TA.updateAnalysis(&II, TypeTree(pointerAnalysis.Inner0()).Only(-1, &II),
4633 &II);
4634 }
4635
4636 if (TA.direction & TypeAnalyzer::UP) {
4637 TA.updateAnalysis(II.getOperand(ptrArgIndex),
4638 TypeTree(TA.getAnalysis(&II).Inner0()).Only(-1, &II),
4639 &II);
4640 }
4641
4642 SmallVector<std::set<int64_t>, 4> idnext;
4643 // The first operand is used to denote the axis of a multidimensional array,
4644 // but it is not used for address calculation, and so we skip it here.
4645 constexpr size_t offsetCalculationIndices[3] = {1, 2, 4};
4646 for (auto i : offsetCalculationIndices) {
4647 auto idx = II.getOperand(i);
4648 auto iset = TA.knownIntegralValues(idx);
4649 std::set<int64_t> vset;
4650 for (auto i : iset) {
4651 // Don't consider negative indices of llvm.intel.subscript
4652 if (i < 0)
4653 continue;
4654 vset.insert(i);
4655 }
4656 idnext.push_back(vset);
4657 if (idnext.back().size() == 0)
4658 return;
4659 }
4660 assert(idnext.size() != 0);
4661
4662 TypeTree upTree;
4663 TypeTree downTree;
4664
4665 TypeTree intrinsicData0;
4666 TypeTree pointerData0;
4667 if (TA.direction & TypeAnalyzer::UP)
4668 intrinsicData0 = TA.getAnalysis(&II).Data0();
4670 pointerData0 = pointerAnalysis.Data0();
4671
4672 bool firstLoop = true;
4673
4674 for (auto vec : getSet<int64_t>(idnext, idnext.size() - 1)) {
4675 auto baseIndex = vec[0];
4676 auto stride = vec[1];
4677 auto index = vec[2];
4678
4679 int offset = static_cast<int>(stride * (index - baseIndex));
4680 if (offset < 0) {
4681 continue; // The intrinsic doesn't handle negative offsets
4682 }
4683
4684 if (TA.direction & TypeAnalyzer::DOWN) {
4685 auto shft = pointerData0.ShiftIndices(DL, /*init offset*/ offset,
4686 /*max size*/ -1, /*newoffset*/ 0);
4687 if (firstLoop)
4688 downTree = shft;
4689 else
4690 downTree &= shft;
4691 }
4692
4693 if (TA.direction & TypeAnalyzer::UP) {
4694 auto shft =
4695 intrinsicData0.ShiftIndices(DL, /*init offset*/ 0, /*max size*/ -1,
4696 /*new offset*/ offset);
4697 if (firstLoop)
4698 upTree = shft;
4699 else
4700 upTree |= shft;
4701 }
4702 firstLoop = false;
4703 }
4705 TA.updateAnalysis(&II, downTree.Only(-1, &II), &II);
4706 if (TA.direction & TypeAnalyzer::UP)
4707 TA.updateAnalysis(II.getOperand(ptrArgIndex), upTree.Only(-1, &II), &II);
4708}
4709
4710void TypeAnalyzer::visitCallBase(CallBase &call) {
4711 assert(fntypeinfo.KnownValues.size() ==
4712 fntypeinfo.Function->getFunctionType()->getNumParams());
4713
4714 if (auto iasm = dyn_cast<InlineAsm>(call.getCalledOperand())) {
4715 // NO direction check as always valid
4716 if (StringRef(iasm->getAsmString()).contains("cpuid")) {
4717 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
4718#if LLVM_VERSION_MAJOR >= 14
4719 for (auto &arg : call.args())
4720#else
4721 for (auto &arg : call.arg_operands())
4722#endif
4723 {
4724 updateAnalysis(arg, TypeTree(BaseType::Integer).Only(-1, &call), &call);
4725 }
4726 }
4727 }
4728
4729 if (call.hasFnAttr("enzyme_ta_norecur"))
4730 return;
4731
4732 Function *ci = getFunctionFromCall(&call);
4733
4734 if (ci) {
4735 if (ci->getAttributes().hasAttribute(AttributeList::FunctionIndex,
4736 "enzyme_ta_norecur"))
4737 return;
4738
4739 StringRef funcName = getFuncNameFromCall(&call);
4740
4741 auto blasMetaData = extractBLAS(funcName);
4742 if (blasMetaData) {
4743 BlasInfo blas = *blasMetaData;
4744#include "BlasTA.inc"
4745 }
4746
4747 // clang-format off
4748 const char* NoTARecurStartsWith[] = {
4749 "std::__u::basic_ostream<wchar_t, std::__u::char_traits<wchar_t>>& std::__u::operator<<",
4750 };
4751 // clang-format on
4752 {
4753 std::string demangledName = llvm::demangle(funcName.str());
4754 // replace all '> >' with '>>'
4755 size_t start = 0;
4756 while ((start = demangledName.find("> >", start)) != std::string::npos) {
4757 demangledName.replace(start, 3, ">>");
4758 }
4759 for (auto Name : NoTARecurStartsWith)
4760 if (startsWith(demangledName, Name))
4761 return;
4762 }
4763
4764 // Manual TT specification is non-interprocedural and already handled once
4765 // at the start.
4766
4767 // When compiling Enzyme against standard LLVM, and not Intel's
4768 // modified version of LLVM, the intrinsic `llvm.intel.subscript` is
4769 // not fully understood by LLVM. One of the results of this is that the
4770 // visitor dispatches to visitCallBase, rather than visitIntrinsicInst, when
4771 // presented with the intrinsic - hence why we are handling it here.
4772 if (startsWith(funcName, "llvm.intel.subscript")) {
4773 assert(isa<IntrinsicInst>(call));
4774 analyzeIntelSubscriptIntrinsic(cast<IntrinsicInst>(call), *this);
4775 return;
4776 }
4777
4778 // Julia's atomic modify pseudo-intrinsic (introduced in Julia 1.13):
4779 // {old, new} = julia.atomicmodify.iN.pAS(ptr, op, ordering, syncscope,
4780 // args...)
4781 // which atomically performs old = *ptr; new = op(old, args...);
4782 // *ptr = new. Both result elements and the return of op have the type of
4783 // the pointee of ptr, and op is analyzed interprocedurally to relate the
4784 // forwarded arguments with the modified memory.
4785 if (startsWith(funcName, "julia.atomicmodify.")) {
4786 auto &DL = fntypeinfo.Function->getParent()->getDataLayout();
4787 auto *RT = cast<StructType>(call.getType());
4788 auto *SL = DL.getStructLayout(RT);
4789 auto LoadSize = (DL.getTypeSizeInBits(RT->getElementType(0)) + 7) / 8;
4790 int Off[2] = {(int)SL->getElementOffset(0), (int)SL->getElementOffset(1)};
4791 Value *ptr = call.getArgOperand(0);
4792
4793 // What is known about the modified location from the pointer. Anything
4794 // else known about it (both result elements, the return of op) is
4795 // merged into the pointee of ptr through updateAnalysis, which reports
4796 // conflicting (float/integer) information instead of asserting, and
4797 // reaches the other users of the location on a later iteration.
4798 TypeTree Pointee = getAnalysis(ptr).Lookup(LoadSize, DL).PurgeAnything();
4799 auto updateLocation = [&](const TypeTree &Loc) {
4800 if (!(direction & UP))
4801 return;
4802 TypeTree Ptr = Loc.ShiftIndices(DL, /*start*/ 0, LoadSize,
4803 /*addOffset*/ 0)
4804 .Only(-1, &call);
4805 Ptr.insert({-1}, BaseType::Pointer);
4806 updateAnalysis(ptr, Ptr, &call);
4807 };
4808 auto updateResult = [&](const TypeTree &Loc) {
4809 if (!(direction & DOWN))
4810 return;
4811 for (int i = 0; i < 2; i++)
4812 updateAnalysis(&call, Loc.ShiftIndices(DL, 0, LoadSize, Off[i]),
4813 &call);
4814 };
4815
4816 TypeTree Ret = getAnalysis(&call);
4817 for (int i = 0; i < 2; i++)
4818 updateLocation(
4819 Ret.ShiftIndices(DL, Off[i], LoadSize, 0).PurgeAnything());
4820 updateResult(Pointee);
4821
4822 Function *op = dyn_cast<Function>(call.getArgOperand(1));
4823 if (op && !op->empty() && !op->isVarArg() &&
4824 call.arg_size() - 3 == op->getFunctionType()->getNumParams()) {
4825 // As for visitIPOCall, skip the interprocedural analysis of op once
4826 // everything it could tell about the location and the forwarded
4827 // arguments has been derived.
4828 bool unknown = false;
4829 for (size_t i = 0; i < LoadSize;) {
4830 auto CT = Pointee[{(int)i}];
4831 if (auto flt = CT.isFloat()) {
4832 i += (DL.getTypeSizeInBits(flt) + 7) / 8;
4833 } else if (CT == BaseType::Pointer) {
4834 i += DL.getPointerSize(0);
4835 } else if (CT == BaseType::Integer) {
4836 i++;
4837 } else {
4838 unknown = true;
4839 break;
4840 }
4841 }
4842 for (size_t i = 4; !unknown && i < call.arg_size(); i++) {
4843 Value *arg = call.getArgOperand(i);
4844 if (!isa<ConstantData>(arg) && !getAnalysis(arg).IsFullyDetermined())
4845 unknown = true;
4846 }
4847
4848 if (unknown) {
4849 // The same call information visitIPOCall derives through
4850 // getCallInfo, with op's first parameter fed from the location
4851 // rather than from a call operand.
4852 FnTypeInfo typeInfo(op);
4853 size_t argnum = 0;
4854 for (auto &arg : op->args()) {
4855 Value *src = argnum == 0 ? nullptr : call.getArgOperand(argnum + 3);
4856 TypeTree dt = src ? getAnalysis(src) : Pointee;
4857 if (arg.getType()->isIntOrIntVectorTy() &&
4858 dt.Inner0() == BaseType::Anything && mustRemainInteger(&arg))
4859 dt = TypeTree(BaseType::Integer).Only(-1, &call);
4860 typeInfo.Arguments.insert(
4861 std::pair<Argument *, TypeTree>(&arg, dt));
4862 std::set<int64_t> bounded;
4863 if (src)
4864 for (auto v :
4865 fntypeinfo.knownIntegralValues(src, DT, intseen, SE)) {
4866 if (abs(v) > MaxIntOffset)
4867 continue;
4868 bounded.insert(v);
4869 }
4870 typeInfo.KnownValues.insert(
4871 std::pair<Argument *, std::set<int64_t>>(&arg, bounded));
4872 ++argnum;
4873 }
4874 // The new value stored to the location is op's return.
4875 typeInfo.Return = Pointee;
4876 typeInfo = preventTypeAnalysisLoops(typeInfo, fntypeinfo.Function);
4877
4878 if (EnzymePrintType) {
4879 llvm::errs() << " starting IPO of ";
4880 call.print(llvm::errs(), *MST);
4881 llvm::errs() << "\n";
4882 }
4883
4885
4886 if (EnzymePrintType) {
4887 llvm::errs() << " ending IPO of ";
4888 call.print(llvm::errs(), *MST);
4889 llvm::errs() << "\n";
4890 }
4891
4893 updateLocation(OpRet);
4894 updateResult(OpRet);
4895 if (direction & UP) {
4896 argnum = 0;
4897 for (auto &arg : op->args()) {
4898 if (argnum != 0)
4899 updateAnalysis(call.getArgOperand(argnum + 3), STR.query(&arg),
4900 &call);
4901 ++argnum;
4902 }
4903 }
4904 }
4905 }
4906 return;
4907 }
4908
4909#define CONSIDER(fn) \
4910 if (funcName == #fn) { \
4911 analyzeFuncTypes(::fn, call, *this); \
4912 return; \
4913 }
4914
4915#define CONSIDER2(fn, ...) \
4916 if (funcName == #fn) { \
4917 analyzeFuncTypesNoFn<__VA_ARGS__>(call, *this); \
4918 return; \
4919 }
4920
4921 auto customrule = interprocedural.CustomRules.find(funcName);
4922 if (customrule != interprocedural.CustomRules.end()) {
4923 auto returnAnalysis = getAnalysis(&call);
4924 SmallVector<TypeTree, 4> args;
4925 SmallVector<std::set<int64_t>, 4> knownValues;
4926#if LLVM_VERSION_MAJOR >= 14
4927 for (auto &arg : call.args())
4928#else
4929 for (auto &arg : call.arg_operands())
4930#endif
4931 {
4932 args.push_back(getAnalysis(arg));
4933 knownValues.push_back(
4934 fntypeinfo.knownIntegralValues((Value *)arg, DT, intseen, SE));
4935 }
4936
4937 bool err = customrule->second(direction, returnAnalysis, args,
4938 knownValues, &call, this);
4939 if (err) {
4940 Invalid = true;
4941 return;
4942 }
4943 updateAnalysis(&call, returnAnalysis, &call);
4944 size_t argnum = 0;
4945#if LLVM_VERSION_MAJOR >= 14
4946 for (auto &arg : call.args())
4947#else
4948 for (auto &arg : call.arg_operands())
4949#endif
4950 {
4951 updateAnalysis(arg, args[argnum], &call);
4952 argnum++;
4953 }
4954 return;
4955 }
4956
4957 // All these are always valid => no direction check
4958 // CONSIDER(malloc)
4959 // TODO consider handling other allocation functions integer inputs
4960 if (startsWith(funcName, "_ZN3std2io5stdio6_print") ||
4961 startsWith(funcName, "_ZN4core3fmt")) {
4962 return;
4963 }
4964 /// GEMM
4965 if (funcName == "dgemm_64" || funcName == "dgemm_64_" ||
4966 funcName == "dgemm" || funcName == "dgemm_") {
4967 TypeTree ptrint;
4968 ptrint.insert({-1}, BaseType::Pointer);
4969 ptrint.insert({-1, 0}, BaseType::Integer);
4970 // transa, transb, m, n, k, lda, ldb, ldc
4971 for (int i : {0, 1, 2, 3, 4, 7, 9, 12})
4972 updateAnalysis(call.getArgOperand(i), ptrint, &call);
4973
4974 TypeTree ptrdbl;
4975 ptrdbl.insert({-1}, BaseType::Pointer);
4976 ptrdbl.insert({-1, 0}, Type::getDoubleTy(call.getContext()));
4977
4978 // alpha, a, b, beta, c
4979 for (int i : {5, 6, 8, 10, 11})
4980 updateAnalysis(call.getArgOperand(i), ptrdbl, &call);
4981 return;
4982 }
4983
4984 if (funcName == "__kmpc_fork_call") {
4985 Function *fn = dyn_cast<Function>(call.getArgOperand(2));
4986
4987 if (auto castinst = dyn_cast<ConstantExpr>(call.getArgOperand(2)))
4988 if (castinst->isCast())
4989 fn = dyn_cast<Function>(castinst->getOperand(0));
4990
4991 if (fn) {
4992#if LLVM_VERSION_MAJOR >= 14
4993 if (call.arg_size() - 3 != fn->getFunctionType()->getNumParams() - 2)
4994 return;
4995#else
4996 if (call.getNumArgOperands() - 3 !=
4997 fn->getFunctionType()->getNumParams() - 2)
4998 return;
4999#endif
5000
5001 if (direction & UP) {
5002 FnTypeInfo typeInfo(fn);
5003
5004 TypeTree IntPtr;
5005 IntPtr.insert({-1, -1}, BaseType::Integer);
5006 IntPtr.insert({-1}, BaseType::Pointer);
5007
5008 int argnum = 0;
5009 for (auto &arg : fn->args()) {
5010 if (argnum <= 1) {
5011 typeInfo.Arguments.insert(
5012 std::pair<Argument *, TypeTree>(&arg, IntPtr));
5013 typeInfo.KnownValues.insert(
5014 std::pair<Argument *, std::set<int64_t>>(&arg, {0}));
5015 } else {
5016 typeInfo.Arguments.insert(std::pair<Argument *, TypeTree>(
5017 &arg, getAnalysis(call.getArgOperand(argnum - 2 + 3))));
5018 std::set<int64_t> bounded;
5019 for (auto v : fntypeinfo.knownIntegralValues(
5020 call.getArgOperand(argnum - 2 + 3), DT, intseen, SE)) {
5021 if (abs(v) > MaxIntOffset)
5022 continue;
5023 bounded.insert(v);
5024 }
5025 typeInfo.KnownValues.insert(
5026 std::pair<Argument *, std::set<int64_t>>(&arg, bounded));
5027 }
5028
5029 ++argnum;
5030 }
5031
5032 if (EnzymePrintType) {
5033 llvm::errs() << " starting omp IPO of ";
5034 call.print(llvm::errs(), *MST);
5035 llvm::errs() << "\n";
5036 }
5037
5038 auto a = fn->arg_begin();
5039 ++a;
5040 ++a;
5042#if LLVM_VERSION_MAJOR >= 14
5043 for (unsigned i = 3; i < call.arg_size(); ++i)
5044#else
5045 for (unsigned i = 3; i < call.getNumArgOperands(); ++i)
5046#endif
5047 {
5048 auto dt = STR.query(a);
5049 updateAnalysis(call.getArgOperand(i), dt, &call);
5050 ++a;
5051 }
5052 }
5053 }
5054 return;
5055 }
5056 if (funcName == "__kmpc_for_static_init_4" ||
5057 funcName == "__kmpc_for_static_init_4u" ||
5058 funcName == "__kmpc_for_static_init_8" ||
5059 funcName == "__kmpc_for_static_init_8u") {
5060 TypeTree ptrint;
5061 ptrint.insert({-1}, BaseType::Pointer);
5062 size_t numBytes = 4;
5063 if (funcName == "__kmpc_for_static_init_8" ||
5064 funcName == "__kmpc_for_static_init_8u")
5065 numBytes = 8;
5066 for (size_t i = 0; i < numBytes; i++)
5067 ptrint.insert({-1, (int)i}, BaseType::Integer);
5068 updateAnalysis(call.getArgOperand(3), ptrint, &call);
5069 updateAnalysis(call.getArgOperand(4), ptrint, &call);
5070 updateAnalysis(call.getArgOperand(5), ptrint, &call);
5071 updateAnalysis(call.getArgOperand(6), ptrint, &call);
5072 updateAnalysis(call.getArgOperand(7),
5073 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5074 updateAnalysis(call.getArgOperand(8),
5075 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5076 return;
5077 }
5078 if (funcName == "omp_get_max_threads" || funcName == "omp_get_thread_num" ||
5079 funcName == "omp_get_num_threads" ||
5080 funcName == "__kmpc_global_thread_num") {
5081 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5082 return;
5083 }
5084 if (funcName == "_ZNSt6localeC1Ev") {
5085 TypeTree ptrint;
5086 ptrint.insert({-1}, BaseType::Pointer);
5087 ptrint.insert({-1, 0}, BaseType::Integer);
5088 updateAnalysis(call.getOperand(0), ptrint, &call);
5089 return;
5090 }
5091
5092 if (startsWith(funcName, "_ZNKSt3__14hash")) {
5093 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5094 return;
5095 }
5096
5097 if (startsWith(funcName, "_ZNKSt3__112basic_string") ||
5098 startsWith(funcName, "_ZNSt3__112basic_string") ||
5099 startsWith(funcName, "_ZNSt3__112__hash_table") ||
5100 startsWith(funcName, "_ZNKSt3__115basic_stringbuf")) {
5101 return;
5102 }
5103
5104 if (funcName == "__dynamic_cast" ||
5105 funcName == "_ZSt18_Rb_tree_decrementPKSt18_Rb_tree_node_base" ||
5106 funcName == "_ZSt18_Rb_tree_incrementPKSt18_Rb_tree_node_base" ||
5107 funcName == "_ZSt18_Rb_tree_decrementPSt18_Rb_tree_node_base" ||
5108 funcName == "_ZSt18_Rb_tree_incrementPSt18_Rb_tree_node_base") {
5109 updateAnalysis(&call, TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5110 return;
5111 }
5112 if (funcName == "memcmp") {
5113 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5114 updateAnalysis(call.getOperand(0),
5115 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5116 updateAnalysis(call.getOperand(1),
5117 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5118 updateAnalysis(call.getOperand(2),
5119 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5120 return;
5121 }
5122
5123 /// CUDA
5124 if (funcName == "cuDeviceGet") {
5125 // cuResult
5126 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5127 updateAnalysis(call.getOperand(0),
5128 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5129 updateAnalysis(call.getOperand(1),
5130 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5131 return;
5132 }
5133 if (funcName == "cuDeviceGetName") {
5134 // cuResult
5135 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5136 updateAnalysis(call.getOperand(0),
5137 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5138 updateAnalysis(call.getOperand(1),
5139 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5140 return;
5141 }
5142 if (funcName == "cudaRuntimeGetVersion" ||
5143 funcName == "cuDriverGetVersion" || funcName == "cuDeviceGetCount") {
5144 // cuResult
5145 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5146 TypeTree ptrint;
5147 ptrint.insert({-1}, BaseType::Pointer);
5148 ptrint.insert({-1, 0}, BaseType::Integer);
5149 updateAnalysis(call.getOperand(0), ptrint, &call);
5150 return;
5151 }
5152 if (funcName == "cuMemGetInfo_v2") {
5153 // cuResult
5154 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5155 TypeTree ptrint;
5156 ptrint.insert({-1}, BaseType::Pointer);
5157 ptrint.insert({-1, 0}, BaseType::Integer);
5158 updateAnalysis(call.getOperand(0), ptrint, &call);
5159 updateAnalysis(call.getOperand(1), ptrint, &call);
5160 return;
5161 }
5162 if (funcName == "cuDevicePrimaryCtxRetain" ||
5163 funcName == "cuCtxGetCurrent") {
5164 // cuResult
5165 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5166 updateAnalysis(call.getOperand(0),
5167 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5168 return;
5169 }
5170 if (funcName == "cuStreamQuery") {
5171 // cuResult
5172 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5173 return;
5174 }
5175 if (funcName == "cuMemAllocAsync" || funcName == "cuMemAlloc" ||
5176 funcName == "cuMemAlloc_v2" || funcName == "cudaMalloc" ||
5177 funcName == "cudaMallocAsync" || funcName == "cudaMallocHost" ||
5178 funcName == "cudaMallocFromPoolAsync") {
5179 TypeTree ptrptr;
5180 ptrptr.insert({-1}, BaseType::Pointer);
5181 ptrptr.insert({-1, 0}, BaseType::Pointer);
5182 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5183 updateAnalysis(call.getOperand(0), ptrptr, &call);
5184 updateAnalysis(call.getOperand(1),
5185 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5186 return;
5187 }
5188 if (funcName == "jl_hrtime" || funcName == "ijl_hrtime") {
5189 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5190 return;
5191 }
5192 if (funcName == "jl_get_task_tid" || funcName == "ijl_get_task_tid") {
5193 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5194 return;
5195 }
5196 if (funcName == "jl_get_binding_or_error" ||
5197 funcName == "ijl_get_binding_or_error") {
5198 updateAnalysis(&call, TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5199 return;
5200 }
5201 if (funcName == "julia.gc_loaded") {
5202 if (direction & UP)
5203 updateAnalysis(call.getArgOperand(1), getAnalysis(&call), &call);
5204 if (direction & DOWN)
5205 updateAnalysis(&call, getAnalysis(call.getArgOperand(1)), &call);
5206 return;
5207 }
5208 if (funcName == "julia.pointer_from_objref") {
5209 if (direction & UP)
5210 updateAnalysis(call.getArgOperand(0), getAnalysis(&call), &call);
5211 if (direction & DOWN)
5212 updateAnalysis(&call, getAnalysis(call.getArgOperand(0)), &call);
5213 return;
5214 }
5215 if (funcName == "_ZNSt6chrono3_V212steady_clock3nowEv") {
5216 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5217 return;
5218 }
5219
5220 /// MPI
5221 if (startsWith(funcName, "PMPI_"))
5222 funcName = funcName.substr(1);
5223 if (funcName == "MPI_Init") {
5224 TypeTree ptrint;
5225 ptrint.insert({-1}, BaseType::Pointer);
5226 ptrint.insert({-1, 0}, BaseType::Integer);
5227 updateAnalysis(call.getOperand(0), ptrint, &call);
5228 TypeTree ptrptrptr;
5229 ptrptrptr.insert({-1}, BaseType::Pointer);
5230 ptrptrptr.insert({-1, -1}, BaseType::Pointer);
5231 ptrptrptr.insert({-1, -1, 0}, BaseType::Pointer);
5232 updateAnalysis(call.getOperand(1), ptrptrptr, &call);
5233 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5234 return;
5235 }
5236 if (funcName == "MPI_Comm_size" || funcName == "MPI_Comm_rank" ||
5237 funcName == "MPI_Get_processor_name") {
5238 TypeTree ptrint;
5239 ptrint.insert({-1}, BaseType::Pointer);
5240 ptrint.insert({-1, 0}, BaseType::Integer);
5241 updateAnalysis(call.getOperand(1), ptrint, &call);
5242 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5243 return;
5244 }
5245 if (funcName == "MPI_Barrier" || funcName == "MPI_Finalize") {
5246 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5247 return;
5248 }
5249 if (funcName == "MPI_Send" || funcName == "MPI_Ssend" ||
5250 funcName == "MPI_Bsend" || funcName == "MPI_Recv" ||
5251 funcName == "MPI_Brecv" || funcName == "PMPI_Send" ||
5252 funcName == "PMPI_Ssend" || funcName == "PMPI_Bsend" ||
5253 funcName == "PMPI_Recv" || funcName == "PMPI_Brecv") {
5255
5256 if (Constant *C = dyn_cast<Constant>(call.getOperand(2))) {
5257 while (ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
5258 C = CE->getOperand(0);
5259 }
5260 if (auto GV = dyn_cast<GlobalVariable>(C)) {
5261 if (GV->getName() == "ompi_mpi_double") {
5262 buf.insert({0}, Type::getDoubleTy(C->getContext()));
5263 } else if (GV->getName() == "ompi_mpi_float") {
5264 buf.insert({0}, Type::getFloatTy(C->getContext()));
5265 } else if (GV->getName() == "ompi_mpi_cxx_bool") {
5266 buf.insert({0}, BaseType::Integer);
5267 }
5268 } else if (auto CI = dyn_cast<ConstantInt>(C)) {
5269 // MPICH
5270 if (CI->getValue() == 1275070475) {
5271 buf.insert({0}, Type::getDoubleTy(C->getContext()));
5272 } else if (CI->getValue() == 1275069450) {
5273 buf.insert({0}, Type::getFloatTy(C->getContext()));
5274 }
5275 }
5276 }
5277 updateAnalysis(call.getOperand(0), buf.Only(-1, &call), &call);
5278 updateAnalysis(call.getOperand(1),
5279 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5280 updateAnalysis(call.getOperand(3),
5281 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5282 updateAnalysis(call.getOperand(4),
5283 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5284 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5285 return;
5286 }
5287 if (funcName == "MPI_Isend" || funcName == "MPI_Irecv" ||
5288 funcName == "PMPI_Isend" || funcName == "PMPI_Irecv") {
5290
5291 if (Constant *C = dyn_cast<Constant>(call.getOperand(2))) {
5292 while (ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
5293 C = CE->getOperand(0);
5294 }
5295 if (auto GV = dyn_cast<GlobalVariable>(C)) {
5296 if (GV->getName() == "ompi_mpi_double") {
5297 buf.insert({0}, Type::getDoubleTy(C->getContext()));
5298 } else if (GV->getName() == "ompi_mpi_float") {
5299 buf.insert({0}, Type::getFloatTy(C->getContext()));
5300 } else if (GV->getName() == "ompi_mpi_cxx_bool") {
5301 buf.insert({0}, BaseType::Integer);
5302 }
5303 } else if (auto CI = dyn_cast<ConstantInt>(C)) {
5304 // MPICH
5305 if (CI->getValue() == 1275070475) {
5306 buf.insert({0}, Type::getDoubleTy(C->getContext()));
5307 } else if (CI->getValue() == 1275069450) {
5308 buf.insert({0}, Type::getFloatTy(C->getContext()));
5309 }
5310 }
5311 }
5312 updateAnalysis(call.getOperand(0), buf.Only(-1, &call), &call);
5313 updateAnalysis(call.getOperand(1),
5314 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5315 updateAnalysis(call.getOperand(3),
5316 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5317 updateAnalysis(call.getOperand(4),
5318 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5319 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5320 updateAnalysis(call.getOperand(6),
5321 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5322 return;
5323 }
5324 if (funcName == "MPI_Wait") {
5325 updateAnalysis(call.getOperand(0),
5326 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5327 updateAnalysis(call.getOperand(1),
5328 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5329 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5330 return;
5331 }
5332 if (funcName == "MPI_Waitany") {
5333 updateAnalysis(call.getOperand(0),
5334 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5335 updateAnalysis(call.getOperand(1),
5336 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5337 updateAnalysis(call.getOperand(2),
5338 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5339 updateAnalysis(call.getOperand(3),
5340 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5341 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5342 return;
5343 }
5344 if (funcName == "MPI_Waitall") {
5345 updateAnalysis(call.getOperand(0),
5346 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5347 updateAnalysis(call.getOperand(1),
5348 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5349 updateAnalysis(call.getOperand(2),
5350 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5351 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5352 return;
5353 }
5354 if (funcName == "MPI_Bcast") {
5355 updateAnalysis(call.getOperand(0),
5356 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5357 updateAnalysis(call.getOperand(1),
5358 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5359 updateAnalysis(call.getOperand(3),
5360 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5361 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5362 return;
5363 }
5364 if (canonicalizeMPIName(funcName) == "MPI_Reduce") {
5365 bool fortranABI = isFortranMPICall(funcName);
5367
5368 // The C ABI passes the datatype handle by value, allowing the buffer
5369 // element type to be deduced from it. The Fortran ABI passes it by
5370 // reference, where its classification remains a pointer.
5371 if (!fortranABI) {
5372 if (Constant *C = dyn_cast<Constant>(call.getOperand(3))) {
5373 while (ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
5374 C = CE->getOperand(0);
5375 }
5376 if (auto GV = dyn_cast<GlobalVariable>(C)) {
5377 if (GV->getName() == "ompi_mpi_double") {
5378 buf.insert({0}, Type::getDoubleTy(C->getContext()));
5379 } else if (GV->getName() == "ompi_mpi_float") {
5380 buf.insert({0}, Type::getFloatTy(C->getContext()));
5381 } else if (GV->getName() == "ompi_mpi_cxx_bool") {
5382 buf.insert({0}, BaseType::Integer);
5383 }
5384 } else if (auto CI = dyn_cast<ConstantInt>(C)) {
5385 // MPICH
5386 if (CI->getValue() == 1275070475) {
5387 buf.insert({0}, Type::getDoubleTy(C->getContext()));
5388 } else if (CI->getValue() == 1275069450) {
5389 buf.insert({0}, Type::getFloatTy(C->getContext()));
5390 }
5391 }
5392 }
5393 }
5394 // int MPI_Reduce(const void *sendbuf, void *recvbuf, int count,
5395 // MPI_Datatype datatype,
5396 // MPI_Op op, int root, MPI_Comm comm)
5397 // sendbuf
5398 updateAnalysis(call.getOperand(0), buf.Only(-1, &call), &call);
5399 // recvbuf
5400 updateAnalysis(call.getOperand(1), buf.Only(-1, &call), &call);
5401 if (!fortranABI) {
5402 // The C ABI passes the count argument by value and returns an error
5403 // code. The Fortran ABI passes it by reference (with an extra
5404 // trailing `ierr` argument) and is void, so the operand keeps just
5405 // its pointer classification; the pointee type is deduced from the
5406 // stores that initialize it.
5407 // count
5408 updateAnalysis(call.getOperand(2),
5409 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5410 // datatype
5411 // op
5412 // comm
5413 // result
5414 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call),
5415 &call);
5416 }
5417 // The data copied between the send and receive buffers has the same
5418 // underlying element type. Propagate type information between the two
5419 // buffers so that a buffer whose contents are otherwise unobserved
5420 // (e.g. a dummy argument that is only referenced by the MPI call)
5421 // inherits it.
5422 if (direction & UP) {
5423 auto &dl = call.getParent()->getParent()->getParent()->getDataLayout();
5424 TypeTree res = getAnalysis(call.getOperand(0))
5425 .PurgeAnything()
5426 .Data0()
5427 .ShiftIndices(dl, 0, 1, 0);
5428 TypeTree res2 = getAnalysis(call.getOperand(1))
5429 .PurgeAnything()
5430 .Data0()
5431 .ShiftIndices(dl, 0, 1, 0);
5432 bool Legal = true;
5433 res.checkedOrIn(res2, /*PointerIntSame*/ false, Legal);
5434 if (Legal) {
5435 res.insert({}, BaseType::Pointer);
5436 res = res.Only(-1, &call);
5437 updateAnalysis(call.getOperand(0), res, &call);
5438 updateAnalysis(call.getOperand(1), res, &call);
5439 }
5440 }
5441 return;
5442 }
5443 if (canonicalizeMPIName(funcName) == "MPI_Allreduce") {
5444 bool fortranABI = isFortranMPICall(funcName);
5446
5447 // The C ABI passes the datatype handle by value, allowing the buffer
5448 // element type to be deduced from it. The Fortran ABI passes it by
5449 // reference, where its classification remains a pointer.
5450 if (!fortranABI) {
5451 if (Constant *C = dyn_cast<Constant>(call.getOperand(3))) {
5452 while (ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
5453 C = CE->getOperand(0);
5454 }
5455 if (auto GV = dyn_cast<GlobalVariable>(C)) {
5456 if (GV->getName() == "ompi_mpi_double") {
5457 buf.insert({0}, Type::getDoubleTy(C->getContext()));
5458 } else if (GV->getName() == "ompi_mpi_float") {
5459 buf.insert({0}, Type::getFloatTy(C->getContext()));
5460 } else if (GV->getName() == "ompi_mpi_cxx_bool") {
5461 buf.insert({0}, BaseType::Integer);
5462 }
5463 } else if (auto CI = dyn_cast<ConstantInt>(C)) {
5464 // MPICH
5465 if (CI->getValue() == 1275070475) {
5466 buf.insert({0}, Type::getDoubleTy(C->getContext()));
5467 } else if (CI->getValue() == 1275069450) {
5468 buf.insert({0}, Type::getFloatTy(C->getContext()));
5469 }
5470 }
5471 }
5472 }
5473 // int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count,
5474 // MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
5475 // sendbuf
5476 updateAnalysis(call.getOperand(0), buf.Only(-1, &call), &call);
5477 // recvbuf
5478 updateAnalysis(call.getOperand(1), buf.Only(-1, &call), &call);
5479 if (!fortranABI) {
5480 // The C ABI passes the count argument by value and returns an error
5481 // code. The Fortran ABI passes it by reference (with an extra
5482 // trailing `ierr` argument) and is void, so the operand keeps just
5483 // its pointer classification; the pointee type is deduced from the
5484 // stores that initialize it.
5485 // count
5486 updateAnalysis(call.getOperand(2),
5487 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5488 // datatype
5489 // op
5490 // comm
5491 // result
5492 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call),
5493 &call);
5494 }
5495 // The data copied between the send and receive buffers has the same
5496 // underlying element type. Propagate type information between the two
5497 // buffers so that a buffer whose contents are otherwise unobserved
5498 // (e.g. a dummy argument that is only referenced by the MPI call)
5499 // inherits it.
5500 if (direction & UP) {
5501 auto &dl = call.getParent()->getParent()->getParent()->getDataLayout();
5502 TypeTree res = getAnalysis(call.getOperand(0))
5503 .PurgeAnything()
5504 .Data0()
5505 .ShiftIndices(dl, 0, 1, 0);
5506 TypeTree res2 = getAnalysis(call.getOperand(1))
5507 .PurgeAnything()
5508 .Data0()
5509 .ShiftIndices(dl, 0, 1, 0);
5510 bool Legal = true;
5511 res.checkedOrIn(res2, /*PointerIntSame*/ false, Legal);
5512 if (Legal) {
5513 res.insert({}, BaseType::Pointer);
5514 res = res.Only(-1, &call);
5515 updateAnalysis(call.getOperand(0), res, &call);
5516 updateAnalysis(call.getOperand(1), res, &call);
5517 }
5518 }
5519 return;
5520 }
5521 if (funcName == "MPI_Sendrecv_replace") {
5522 updateAnalysis(call.getOperand(0),
5523 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5524 updateAnalysis(call.getOperand(1),
5525 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5526 updateAnalysis(call.getOperand(3),
5527 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5528 updateAnalysis(call.getOperand(4),
5529 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5530 updateAnalysis(call.getOperand(5),
5531 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5532 updateAnalysis(call.getOperand(6),
5533 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5534 updateAnalysis(call.getOperand(8),
5535 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5536 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5537 return;
5538 }
5539 if (funcName == "MPI_Sendrecv") {
5540 updateAnalysis(call.getOperand(0),
5541 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5542 updateAnalysis(call.getOperand(1),
5543 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5544 updateAnalysis(call.getOperand(3),
5545 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5546 updateAnalysis(call.getOperand(4),
5547 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5548 updateAnalysis(call.getOperand(5),
5549 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5550 updateAnalysis(call.getOperand(6),
5551 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5552 updateAnalysis(call.getOperand(7),
5553 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5554 updateAnalysis(call.getOperand(8),
5555 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5556 updateAnalysis(call.getOperand(9),
5557 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5558 updateAnalysis(call.getOperand(11),
5559 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5560 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5561 return;
5562 }
5563 if (canonicalizeMPIName(funcName) == "MPI_Gather" ||
5564 canonicalizeMPIName(funcName) == "MPI_Scatter") {
5565 bool fortranABI = isFortranMPICall(funcName);
5566 updateAnalysis(call.getOperand(0),
5567 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5568 updateAnalysis(call.getOperand(3),
5569 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5570 if (!fortranABI) {
5571 // The C ABI passes the count and root arguments by value and returns
5572 // an error code. The Fortran ABI passes them all by reference (with
5573 // an extra trailing `ierr` argument) and is void, so those operands
5574 // keep just their pointer classification; their pointee types are
5575 // deduced from the stores that initialize them.
5576 updateAnalysis(call.getOperand(1),
5577 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5578 updateAnalysis(call.getOperand(4),
5579 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5580 updateAnalysis(call.getOperand(6),
5581 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5582 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call),
5583 &call);
5584 }
5585 // The data copied between the send and receive buffers has the same
5586 // underlying element type. Propagate type information between the two
5587 // buffers so that a buffer whose contents are otherwise unobserved
5588 // (e.g. a dummy argument that is only referenced by the MPI call)
5589 // inherits it.
5590 if (direction & UP) {
5591 auto &dl = call.getParent()->getParent()->getParent()->getDataLayout();
5592 TypeTree res = getAnalysis(call.getOperand(0))
5593 .PurgeAnything()
5594 .Data0()
5595 .ShiftIndices(dl, 0, 1, 0);
5596 TypeTree res2 = getAnalysis(call.getOperand(3))
5597 .PurgeAnything()
5598 .Data0()
5599 .ShiftIndices(dl, 0, 1, 0);
5600 bool Legal = true;
5601 res.checkedOrIn(res2, /*PointerIntSame*/ false, Legal);
5602 if (Legal) {
5603 res.insert({}, BaseType::Pointer);
5604 res = res.Only(-1, &call);
5605 updateAnalysis(call.getOperand(0), res, &call);
5606 updateAnalysis(call.getOperand(3), res, &call);
5607 }
5608 }
5609 return;
5610 }
5611 if (funcName == "MPI_Allgather") {
5612 updateAnalysis(call.getOperand(0),
5613 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5614 updateAnalysis(call.getOperand(1),
5615 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5616 updateAnalysis(call.getOperand(3),
5617 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5618 updateAnalysis(call.getOperand(4),
5619 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5620 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5621 return;
5622 }
5623 /// END MPI
5624
5625 // Prob Prog
5626 if (ci->hasFnAttribute("enzyme_notypeanalysis")) {
5627 return;
5628 }
5629
5630 // void _FortranAAssign(Descriptor &to, const Descriptor &from,
5631 // const char *sourceFile, int sourceLine)
5632 if (funcName == "_FortranAAssign" && call.arg_size() == 4) {
5633 auto &DL = call.getParent()->getParent()->getParent()->getDataLayout();
5634 for (int i = 0; i < 2; i++) {
5635 updateAnalysis(call.getOperand(i),
5636 fortranDescriptorTree(call.getOperand(i), DL), &call);
5637 }
5638 updateAnalysis(call.getOperand(2),
5639 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5640 updateAnalysis(call.getOperand(3),
5641 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5642 return;
5643 }
5644
5645 if (funcName == "memcpy" || funcName == "memmove") {
5646 // TODO have this call common mem transfer to copy data
5648 return;
5649 }
5650 if (funcName == "posix_memalign") {
5651 TypeTree ptrptr;
5652 ptrptr.insert({-1}, BaseType::Pointer);
5653 ptrptr.insert({-1, 0}, BaseType::Pointer);
5654 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5655 updateAnalysis(call.getOperand(0), ptrptr, &call);
5656 updateAnalysis(call.getOperand(1),
5657 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5658 updateAnalysis(call.getOperand(2),
5659 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5660 return;
5661 }
5662 if (funcName == "calloc") {
5663 updateAnalysis(&call, TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5664 updateAnalysis(call.getOperand(0),
5665 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5666 updateAnalysis(call.getOperand(1),
5667 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5668 return;
5669 }
5670 if (auto opidx = getAllocationIndexFromCall(&call)) {
5671 auto ptr = TypeTree(BaseType::Pointer);
5672 unsigned index = (size_t)*opidx;
5673 if (auto CI = dyn_cast<ConstantInt>(call.getOperand(index))) {
5674 auto &DL = call.getParent()->getParent()->getParent()->getDataLayout();
5675 auto LoadSize = CI->getZExtValue();
5676 // Only propagate mappings in range that aren't "Anything" into the
5677 // pointer
5678 ptr |= getAnalysis(&call).Lookup(LoadSize, DL);
5679 }
5680 updateAnalysis(&call, ptr.Only(-1, &call), &call);
5681 updateAnalysis(call.getOperand(index),
5682 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5683 return;
5684 }
5685 if (funcName == "malloc") {
5686 auto ptr = TypeTree(BaseType::Pointer);
5687 if (auto CI = dyn_cast<ConstantInt>(call.getOperand(0))) {
5688 auto &DL = call.getParent()->getParent()->getParent()->getDataLayout();
5689 auto LoadSize = CI->getZExtValue();
5690 // Only propagate mappings in range that aren't "Anything" into the
5691 // pointer
5692 ptr |= getAnalysis(&call).Lookup(LoadSize, DL);
5693 }
5694 updateAnalysis(&call, ptr.Only(-1, &call), &call);
5695 updateAnalysis(call.getOperand(0),
5696 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5697 return;
5698 }
5699 if (funcName == "__size_returning_new_experiment") {
5700 auto ptr = TypeTree(BaseType::Pointer);
5701 auto &DL = call.getParent()->getParent()->getParent()->getDataLayout();
5702 if (auto CI = dyn_cast<ConstantInt>(call.getOperand(0))) {
5703 auto LoadSize = CI->getZExtValue();
5704 // Only propagate mappings in range that aren't "Anything" into the
5705 // pointer
5706 ptr |= getAnalysis(&call).Lookup(LoadSize, DL);
5707 }
5708 ptr = ptr.Only(0, &call);
5709 ptr |= TypeTree(BaseType::Integer).Only(DL.getPointerSize(), &call);
5710 updateAnalysis(&call, ptr.Only(0, &call), &call);
5711 updateAnalysis(call.getOperand(0),
5712 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5713 return;
5714 }
5715 if (funcName == "julia.gc_alloc_obj" || funcName == "jl_gc_alloc_typed" ||
5716 funcName == "ijl_gc_alloc_typed") {
5717 auto ptr = TypeTree(BaseType::Pointer);
5718 if (auto CI = dyn_cast<ConstantInt>(call.getOperand(1))) {
5719 auto &DL = call.getParent()->getParent()->getParent()->getDataLayout();
5720 auto LoadSize = CI->getZExtValue();
5721 // Only propagate mappings in range that aren't "Anything" into the
5722 // pointer
5723 ptr |= getAnalysis(&call).Lookup(LoadSize, DL);
5724 }
5725 updateAnalysis(&call, ptr.Only(-1, &call), &call);
5726 updateAnalysis(call.getOperand(1),
5727 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5728 return;
5729 }
5730 if (funcName == "julia.except_enter" || funcName == "ijl_excstack_state" ||
5731 funcName == "jl_excstack_state") {
5732 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5733 return;
5734 }
5735 if (funcName == "jl_array_copy" || funcName == "ijl_array_copy" ||
5736 funcName == "jl_inactive_inout" ||
5737 funcName == "jl_genericmemory_copy_slice" ||
5738 funcName == "ijl_genericmemory_copy_slice") {
5739 if (direction & DOWN)
5740 updateAnalysis(&call, getAnalysis(call.getOperand(0)), &call);
5741 if (direction & UP)
5742 updateAnalysis(call.getOperand(0), getAnalysis(&call), &call);
5743 return;
5744 }
5745
5746 if (isAllocationFunction(funcName, TLI)) {
5747 size_t Idx = 0;
5748 for (auto &Arg : ci->args()) {
5749 if (Arg.getType()->isIntegerTy()) {
5750 updateAnalysis(call.getOperand(Idx),
5751 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5752 }
5753 Idx++;
5754 }
5755 assert(ci->getReturnType()->isPointerTy());
5756 auto ptr = TypeTree(BaseType::Pointer);
5757 if (shadowHandlers.find(funcName) == shadowHandlers.end() &&
5758 funcName != "swift_allocObject") {
5759 // aligned_alloc(alignment, size) takes the size second.
5760 if (auto CI = dyn_cast<ConstantInt>(
5761 call.getOperand(funcName == "aligned_alloc" ? 1 : 0))) {
5762 auto &DL =
5763 call.getParent()->getParent()->getParent()->getDataLayout();
5764 auto LoadSize = CI->getZExtValue();
5765 // Only propagate mappings in range that aren't "Anything" into the
5766 // pointer
5767 ptr |= getAnalysis(&call).Lookup(LoadSize, DL);
5768 }
5769 }
5770 updateAnalysis(&call, ptr.Only(-1, &call), &call);
5771 return;
5772 }
5773 if (funcName == "malloc_usable_size" || funcName == "malloc_size" ||
5774 funcName == "_msize") {
5775 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5776 updateAnalysis(call.getOperand(0),
5777 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5778 return;
5779 }
5780 if (funcName == "realloc") {
5781 size_t sz = 1;
5782 for (auto val : fntypeinfo.knownIntegralValues(call.getArgOperand(1), DT,
5783 intseen, SE)) {
5784 if (val >= 0) {
5785 sz = max(sz, (size_t)val);
5786 }
5787 }
5788
5789 auto &dl = call.getParent()->getParent()->getParent()->getDataLayout();
5790 TypeTree res = getAnalysis(call.getArgOperand(0))
5791 .PurgeAnything()
5792 .Data0()
5793 .ShiftIndices(dl, 0, sz, 0);
5794 TypeTree res2 =
5795 getAnalysis(&call).PurgeAnything().Data0().ShiftIndices(dl, 0, sz, 0);
5796
5797 res.orIn(res2, /*PointerIntSame*/ false);
5798 res.insert({}, BaseType::Pointer);
5799 res = res.Only(-1, &call);
5800 if (direction & DOWN) {
5801 updateAnalysis(&call, res, &call);
5802 }
5803 if (direction & UP) {
5804 updateAnalysis(call.getOperand(0), res, &call);
5805 }
5806 return;
5807 }
5808 if (funcName == "sigaction") {
5809 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5810 updateAnalysis(call.getOperand(0),
5811 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5812 updateAnalysis(call.getOperand(1),
5813 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5814 updateAnalysis(call.getOperand(2),
5815 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5816 return;
5817 }
5818 if (funcName == "mmap") {
5819 updateAnalysis(&call, TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5820 updateAnalysis(call.getOperand(0),
5821 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5822 updateAnalysis(call.getOperand(1),
5823 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5824 updateAnalysis(call.getOperand(2),
5825 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5826 updateAnalysis(call.getOperand(3),
5827 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5828 updateAnalysis(call.getOperand(4),
5829 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5830 updateAnalysis(call.getOperand(5),
5831 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5832 return;
5833 }
5834 if (funcName == "munmap") {
5835 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5836 updateAnalysis(call.getOperand(0),
5837 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5838 updateAnalysis(call.getOperand(1),
5839 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5840 return;
5841 }
5842 if (funcName == "pthread_mutex_lock" ||
5843 funcName == "pthread_mutex_trylock" ||
5844 funcName == "pthread_rwlock_rdlock" ||
5845 funcName == "pthread_rwlock_unlock" ||
5846 funcName == "pthread_attr_init" || funcName == "pthread_attr_destroy" ||
5847 funcName == "pthread_rwlock_unlock" ||
5848 funcName == "pthread_mutex_unlock") {
5849 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5850 updateAnalysis(call.getOperand(0),
5851 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5852 return;
5853 }
5854 if (isDeallocationFunction(funcName, TLI)) {
5855 bool cudaFree = isCudaDeallocationFunction(funcName);
5856 size_t Idx = 0;
5857 for (auto &Arg : ci->args()) {
5858 // The allocation freed by the CUDA driver API is a CUdeviceptr, an
5859 // integer at the LLVM level, but still a pointer.
5860 if (Idx == 0 && cudaFree) {
5861 updateAnalysis(call.getOperand(Idx),
5862 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5863 Idx++;
5864 continue;
5865 }
5866 if (Arg.getType()->isIntegerTy()) {
5867 updateAnalysis(call.getOperand(Idx),
5868 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5869 }
5870 if (Arg.getType()->isPointerTy()) {
5871 updateAnalysis(call.getOperand(Idx),
5872 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5873 }
5874 Idx++;
5875 }
5876 if (!ci->getReturnType()->isVoidTy()) {
5877 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call),
5878 &call);
5879 return;
5880 }
5881 assert(ci->getReturnType()->isVoidTy());
5882 return;
5883 }
5884 if (funcName == "memchr" || funcName == "memrchr") {
5885 updateAnalysis(&call, TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5886 updateAnalysis(call.getOperand(0),
5887 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5888 updateAnalysis(call.getOperand(2),
5889 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5890 return;
5891 }
5892 if (funcName == "strlen") {
5893 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5894 updateAnalysis(call.getOperand(0),
5895 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5896 return;
5897 }
5898 if (funcName == "strcmp") {
5899 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5900 updateAnalysis(call.getOperand(0),
5901 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5902 updateAnalysis(call.getOperand(1),
5903 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5904 return;
5905 }
5906 if (funcName == "bcmp") {
5907 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5908 updateAnalysis(call.getOperand(0),
5909 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5910 updateAnalysis(call.getOperand(1),
5911 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5912 updateAnalysis(call.getOperand(2),
5913 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5914 return;
5915 }
5916 if (funcName == "getcwd") {
5917 updateAnalysis(&call, TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5918 updateAnalysis(call.getOperand(0),
5919 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5920 updateAnalysis(call.getOperand(1),
5921 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5922 return;
5923 }
5924 if (funcName == "sysconf") {
5925 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5926 updateAnalysis(call.getOperand(0),
5927 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5928 return;
5929 }
5930 if (funcName == "dladdr") {
5931 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5932 updateAnalysis(call.getOperand(0),
5933 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5934 updateAnalysis(call.getOperand(1),
5935 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5936 return;
5937 }
5938 if (funcName == "__errno_location") {
5939 TypeTree ptrint;
5940 ptrint.insert({-1, -1}, BaseType::Integer);
5941 ptrint.insert({-1}, BaseType::Pointer);
5942 updateAnalysis(&call, ptrint, &call);
5943 return;
5944 }
5945 if (funcName == "getenv") {
5946 TypeTree ptrint;
5947 ptrint.insert({-1, -1}, BaseType::Integer);
5948 ptrint.insert({-1}, BaseType::Pointer);
5949 updateAnalysis(&call, ptrint, &call);
5950 updateAnalysis(call.getOperand(0),
5951 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5952 return;
5953 }
5954 if (funcName == "getcwd") {
5955 updateAnalysis(&call, TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5956 updateAnalysis(call.getOperand(0),
5957 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5958 updateAnalysis(call.getOperand(1),
5959 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5960 return;
5961 }
5962 if (funcName == "mprotect") {
5963 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5964 updateAnalysis(call.getOperand(0),
5965 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5966 updateAnalysis(call.getOperand(1),
5967 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5968 updateAnalysis(call.getOperand(2),
5969 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5970 return;
5971 }
5972 if (funcName == "memcmp") {
5973 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5974 updateAnalysis(call.getOperand(0),
5975 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5976 updateAnalysis(call.getOperand(1),
5977 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5978 updateAnalysis(call.getOperand(2),
5979 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5980 return;
5981 }
5982 if (funcName == "signal") {
5983 updateAnalysis(&call, TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5984 updateAnalysis(call.getOperand(0),
5985 TypeTree(BaseType::Integer).Only(-1, &call), &call);
5986 updateAnalysis(call.getOperand(1),
5987 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5988 return;
5989 }
5990 if (funcName == "write" || funcName == "read" || funcName == "writev" ||
5991 funcName == "readv") {
5992 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
5993 // FD type not going to be defined here
5994 // updateAnalysis(call.getOperand(0),
5995 // TypeTree(BaseType::Pointer).Only(-1),
5996 // &call);
5997 updateAnalysis(call.getOperand(1),
5998 TypeTree(BaseType::Pointer).Only(-1, &call), &call);
5999 updateAnalysis(call.getOperand(2),
6000 TypeTree(BaseType::Integer).Only(-1, &call), &call);
6001 return;
6002 }
6003 if (funcName == "gsl_sf_legendre_array_e") {
6004 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
6005 return;
6006 }
6007
6008 // CONSIDER(__lgamma_r_finite)
6009
6010 CONSIDER2(frexp, double, double, int *)
6011 CONSIDER(frexpf)
6012 CONSIDER(frexpl)
6013 CONSIDER2(ldexp, double, double, int)
6014 CONSIDER2(modf, double, double, double *)
6015 CONSIDER(modff)
6016 CONSIDER(modfl)
6017
6018 CONSIDER2(remquo, double, double, double, int *)
6019 CONSIDER(remquof)
6020 CONSIDER(remquol)
6021
6022 if (isMemFreeLibMFunction(funcName)) {
6023#if LLVM_VERSION_MAJOR >= 14
6024 for (size_t i = 0; i < call.arg_size(); ++i)
6025#else
6026 for (size_t i = 0; i < call.getNumArgOperands(); ++i)
6027#endif
6028 {
6029 Type *T = call.getArgOperand(i)->getType();
6030 if (T->isFloatingPointTy()) {
6032 call.getArgOperand(i),
6034 call.getArgOperand(i)->getType()->getScalarType()))
6035 .Only(-1, &call),
6036 &call);
6037 } else if (T->isIntegerTy()) {
6038 updateAnalysis(call.getArgOperand(i),
6039 TypeTree(BaseType::Integer).Only(-1, &call), &call);
6040 } else if (auto ST = dyn_cast<StructType>(T)) {
6041 assert(ST->getNumElements() >= 1);
6042 for (size_t i = 1; i < ST->getNumElements(); ++i) {
6043 assert(ST->getTypeAtIndex((unsigned)0) == ST->getTypeAtIndex(i));
6044 }
6045 if (ST->getTypeAtIndex((unsigned)0)->isFloatingPointTy())
6047 call.getArgOperand(i),
6049 ST->getTypeAtIndex((unsigned)0)->getScalarType()))
6050 .Only(-1, &call),
6051 &call);
6052 else if (ST->getTypeAtIndex((unsigned)0)->isIntegerTy()) {
6053 updateAnalysis(call.getArgOperand(i),
6054 TypeTree(BaseType::Integer).Only(-1, &call), &call);
6055 } else {
6056 llvm::errs() << *T << " - " << call << "\n";
6057 llvm_unreachable("Unknown type for libm");
6058 }
6059 } else if (auto AT = dyn_cast<ArrayType>(T)) {
6060 assert(AT->getNumElements() >= 1);
6061 if (AT->getElementType()->isFloatingPointTy())
6063 call.getArgOperand(i),
6064 TypeTree(ConcreteType(AT->getElementType()->getScalarType()))
6065 .Only(-1, &call),
6066 &call);
6067 else if (AT->getElementType()->isIntegerTy()) {
6068 updateAnalysis(call.getArgOperand(i),
6069 TypeTree(BaseType::Integer).Only(-1, &call), &call);
6070 } else {
6071 llvm::errs() << *T << " - " << call << "\n";
6072 llvm_unreachable("Unknown type for libm");
6073 }
6074 } else {
6075 llvm::errs() << *T << " - " << call << "\n";
6076 llvm_unreachable("Unknown type for libm");
6077 }
6078 }
6079 Type *T = call.getType();
6080 if (T->isFloatingPointTy()) {
6081 updateAnalysis(&call,
6082 TypeTree(ConcreteType(call.getType()->getScalarType()))
6083 .Only(-1, &call),
6084 &call);
6085 } else if (T->isIntegerTy()) {
6086 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call),
6087 &call);
6088 } else if (T->isVoidTy()) {
6089 } else if (auto ST = dyn_cast<StructType>(T)) {
6090 assert(ST->getNumElements() >= 1);
6091 TypeTree TT;
6092 auto &DL = call.getParent()->getParent()->getParent()->getDataLayout();
6093 for (size_t i = 0; i < ST->getNumElements(); ++i) {
6094 auto T = ST->getTypeAtIndex(i);
6096
6097 size_t Offset = getAggregateElementOffset(DL, ST, i);
6098
6099 size_t nextOffset;
6100 if (i + 1 == ST->getNumElements())
6101 nextOffset = (DL.getTypeSizeInBits(ST) + 7) / 8;
6102 else
6103 nextOffset = getAggregateElementOffset(DL, ST, i + 1);
6104
6105 if (T->isFloatingPointTy()) {
6106 CT = T;
6107 } else if (T->isIntegerTy()) {
6108 CT = BaseType::Integer;
6109 }
6110 if (CT != BaseType::Unknown) {
6111 TypeTree mid = TypeTree(CT).Only(-1, &call);
6112 TT |= mid.ShiftIndices(DL, /*init offset*/ 0,
6113 /*maxSize*/ nextOffset - Offset,
6114 /*addOffset*/ Offset);
6115 }
6116 }
6117 auto Size = (DL.getTypeSizeInBits(ST) + 7) / 8;
6118 TT.CanonicalizeInPlace(Size, DL);
6119 updateAnalysis(&call, TT, &call);
6120 } else if (auto AT = dyn_cast<ArrayType>(T)) {
6121 assert(AT->getNumElements() >= 1);
6122 if (AT->getElementType()->isFloatingPointTy())
6124 &call,
6125 TypeTree(ConcreteType(AT->getElementType()->getScalarType()))
6126 .Only(-1, &call),
6127 &call);
6128 else {
6129 llvm::errs() << *T << " - " << call << "\n";
6130 llvm_unreachable("Unknown type for libm");
6131 }
6132 } else {
6133 llvm::errs() << *T << " - " << call << "\n";
6134 llvm_unreachable("Unknown type for libm");
6135 }
6136 return;
6137 }
6138 if (funcName == "__lgamma_r_finite") {
6140 call.getArgOperand(0),
6141 TypeTree(ConcreteType(Type::getDoubleTy(call.getContext())))
6142 .Only(-1, &call),
6143 &call);
6144 updateAnalysis(call.getArgOperand(1),
6145 TypeTree(BaseType::Integer).Only(0, &call).Only(-1, &call),
6146 &call);
6148 &call,
6149 TypeTree(ConcreteType(Type::getDoubleTy(call.getContext())))
6150 .Only(-1, &call),
6151 &call);
6152 }
6153 if (funcName == "__fd_sincos_1" || funcName == "__fd_sincos_1f" ||
6154 funcName == "__fd_sincos_1l") {
6155 updateAnalysis(call.getArgOperand(0),
6156 TypeTree(ConcreteType(call.getArgOperand(0)->getType()))
6157 .Only(-1, &call),
6158 &call);
6159 updateAnalysis(&call,
6160 TypeTree(ConcreteType(call.getArgOperand(0)->getType()))
6161 .Only(-1, &call),
6162 &call);
6163 }
6164 if (funcName == "frexp" || funcName == "frexpf" || funcName == "frexpl") {
6165
6167 &call, TypeTree(ConcreteType(call.getType())).Only(-1, &call), &call);
6168 updateAnalysis(call.getOperand(0),
6169 TypeTree(ConcreteType(call.getType())).Only(-1, &call),
6170 &call);
6172 size_t objSize = 1;
6173
6174#if LLVM_VERSION_MAJOR < 17
6175 auto &DL = fntypeinfo.Function->getParent()->getDataLayout();
6176 objSize = DL.getTypeSizeInBits(
6177 call.getOperand(1)->getType()->getPointerElementType()) /
6178 8;
6179#endif
6180 for (size_t i = 0; i < objSize; ++i) {
6181 ival.insert({(int)i}, BaseType::Integer);
6182 }
6183 updateAnalysis(call.getOperand(1), ival.Only(-1, &call), &call);
6184 return;
6185 }
6186
6187 if (funcName == "__cxa_guard_acquire" || funcName == "printf" ||
6188 funcName == "vprintf" || funcName == "puts" || funcName == "fputc" ||
6189 funcName == "fprintf") {
6190 updateAnalysis(&call, TypeTree(BaseType::Integer).Only(-1, &call), &call);
6191 }
6192
6193 if (dontAnalyze(funcName))
6194 return;
6195
6196 if (!ci->empty() && !hasMetadata(ci, "enzyme_gradient") &&
6197 !hasMetadata(ci, "enzyme_derivative")) {
6198 visitIPOCall(call, *ci);
6199 }
6200 }
6201}
6202
6204 bool set = false;
6205 TypeTree vd;
6206 for (BasicBlock &BB : *fntypeinfo.Function) {
6207 for (auto &inst : BB) {
6208 if (auto ri = dyn_cast<ReturnInst>(&inst)) {
6209 if (auto rv = ri->getReturnValue()) {
6210 if (set == false) {
6211 set = true;
6212 vd = getAnalysis(rv);
6213 continue;
6214 }
6215 vd &= getAnalysis(rv);
6216 // TODO insert the selectinst anything propagation here
6217 // however this needs to be done simultaneously with preventing
6218 // anything from propagating up through the return value (if there
6219 // are multiple possible returns)
6220 }
6221 }
6222 }
6223 }
6224 if (fntypeinfo.Function->getAttributes().hasAttribute(
6225 AttributeList::ReturnIndex, "enzyme_type")) {
6226 auto attr = fntypeinfo.Function->getAttributes().getAttribute(
6227 AttributeList::ReturnIndex, "enzyme_type");
6228 auto TT = TypeTree::parse(attr.getValueAsString(),
6229 fntypeinfo.Function->getContext());
6230
6231 auto &dl = fntypeinfo.Function->getParent()->getDataLayout();
6232 for (const auto &pair : TT.getMapping()) {
6233 size_t chunk = 1;
6234 if (auto flt = pair.second.isFloat()) {
6235 chunk = dl.getTypeSizeInBits(flt) / 8;
6236 } else if (pair.second == BaseType::Pointer) {
6237 chunk = dl.getPointerSizeInBits() / 8;
6238 }
6239
6240 for (size_t i = 0; i < chunk; i++) {
6241 auto v2(pair.first);
6242 v2.back() += i;
6243 auto found = vd.getMapping().find(v2);
6244 if (found == vd.getMapping().end())
6245 continue;
6246 vd.remove(v2);
6247 }
6248
6249 vd.insert(pair.first, pair.second);
6250 }
6251 }
6252
6253 return vd;
6254}
6255
6256/// Helper function that calculates whether a given value must only be
6257/// an integer and cannot be cast/stored to be used as a ptr/integer
6258bool TypeAnalyzer::mustRemainInteger(Value *val, bool *returned) {
6259 std::map<Value *, std::pair<bool, bool>> &seen = mriseen;
6260 const DataLayout &DL = fntypeinfo.Function->getParent()->getDataLayout();
6261 if (seen.find(val) != seen.end()) {
6262 if (returned)
6263 *returned |= seen[val].second;
6264 return seen[val].first;
6265 }
6266 seen[val] = std::make_pair(true, false);
6267 for (auto u : val->users()) {
6268 if (auto SI = dyn_cast<StoreInst>(u)) {
6269 if (parseTBAA(*SI, DL, MST).Inner0().isIntegral())
6270 continue;
6271 seen[val].first = false;
6272 continue;
6273 }
6274 if (isa<CastInst>(u)) {
6275 if (!u->getType()->isIntOrIntVectorTy()) {
6276 seen[val].first = false;
6277 continue;
6278 } else if (!mustRemainInteger(u, returned)) {
6279 seen[val].first = false;
6280 seen[val].second |= seen[u].second;
6281 continue;
6282 } else
6283 continue;
6284 }
6285 if (isa<BinaryOperator>(u) || isa<IntrinsicInst>(u) || isa<PHINode>(u) ||
6286#if LLVM_VERSION_MAJOR <= 17
6287 isa<UDivOperator>(u) || isa<SDivOperator>(u) ||
6288#endif
6289 isa<LShrOperator>(u) || isa<AShrOperator>(u) || isa<AddOperator>(u) ||
6290 isa<MulOperator>(u) || isa<ShlOperator>(u)) {
6291 if (!mustRemainInteger(u, returned)) {
6292 seen[val].first = false;
6293 seen[val].second |= seen[u].second;
6294 }
6295 continue;
6296 }
6297 if (auto gep = dyn_cast<GetElementPtrInst>(u)) {
6298 if (gep->isInBounds() && gep->getPointerOperand() != val) {
6299 continue;
6300 }
6301 }
6302 if (returned && isa<ReturnInst>(u)) {
6303 *returned = true;
6304 seen[val].second = true;
6305 continue;
6306 }
6307 if (auto CI = dyn_cast<CallBase>(u)) {
6308 if (auto F = CI->getCalledFunction()) {
6309 if (!F->empty()) {
6310 int argnum = 0;
6311 bool subreturned = false;
6312 for (auto &arg : F->args()) {
6313 if (CI->getArgOperand(argnum) == val &&
6314 !mustRemainInteger(&arg, &subreturned)) {
6315 seen[val].first = false;
6316 seen[val].second |= seen[&arg].second;
6317 continue;
6318 }
6319 ++argnum;
6320 }
6321 if (subreturned && !mustRemainInteger(CI, returned)) {
6322 seen[val].first = false;
6323 seen[val].second |= seen[CI].second;
6324 continue;
6325 }
6326 continue;
6327 }
6328 }
6329 }
6330 if (isa<CmpInst>(u))
6331 continue;
6332 seen[val].first = false;
6333 seen[val].second = true;
6334 }
6335 if (returned && seen[val].second)
6336 *returned = true;
6337 return seen[val].first;
6338}
6339
6340FnTypeInfo TypeAnalyzer::getCallInfo(CallBase &call, Function &fn) {
6341 FnTypeInfo typeInfo(&fn);
6342
6343 size_t argnum = 0;
6344 for (auto &arg : fn.args()) {
6345 if (argnum >= call.arg_size()) {
6346 typeInfo.Arguments.insert(
6347 std::pair<Argument *, TypeTree>(&arg, TypeTree()));
6348 std::set<int64_t> bounded;
6349 typeInfo.KnownValues.insert(
6350 std::pair<Argument *, std::set<int64_t>>(&arg, bounded));
6351 ++argnum;
6352 continue;
6353 }
6354 auto dt = getAnalysis(call.getArgOperand(argnum));
6355 if (arg.getType()->isIntOrIntVectorTy() &&
6356 dt.Inner0() == BaseType::Anything) {
6357 if (mustRemainInteger(&arg)) {
6358 dt = TypeTree(BaseType::Integer).Only(-1, &call);
6359 }
6360 }
6361 typeInfo.Arguments.insert(std::pair<Argument *, TypeTree>(&arg, dt));
6362 std::set<int64_t> bounded;
6363 for (auto v : fntypeinfo.knownIntegralValues(call.getArgOperand(argnum), DT,
6364 intseen, SE)) {
6365 if (abs(v) > MaxIntOffset)
6366 continue;
6367 bounded.insert(v);
6368 }
6369 typeInfo.KnownValues.insert(
6370 std::pair<Argument *, std::set<int64_t>>(&arg, bounded));
6371 ++argnum;
6372 }
6373
6374 typeInfo.Return = getAnalysis(&call);
6375 return typeInfo;
6376}
6377
6378void TypeAnalyzer::visitIPOCall(CallBase &call, Function &fn) {
6379#if LLVM_VERSION_MAJOR >= 14
6380 if (call.arg_size() != fn.getFunctionType()->getNumParams())
6381 return;
6382#else
6383 if (call.getNumArgOperands() != fn.getFunctionType()->getNumParams())
6384 return;
6385#endif
6386
6387 assert(fntypeinfo.KnownValues.size() ==
6388 fntypeinfo.Function->getFunctionType()->getNumParams());
6389
6390 bool hasDown = direction & DOWN;
6391 bool hasUp = direction & UP;
6392
6393 if (hasDown) {
6394 if (call.getType()->isVoidTy())
6395 hasDown = false;
6396 else {
6397 if (getAnalysis(&call).IsFullyDetermined())
6398 hasDown = false;
6399 }
6400 }
6401 if (hasUp) {
6402 bool unknown = false;
6403#if LLVM_VERSION_MAJOR >= 14
6404 for (auto &arg : call.args())
6405#else
6406 for (auto &arg : call.arg_operands())
6407#endif
6408 {
6409 if (isa<ConstantData>(arg))
6410 continue;
6411 if (!getAnalysis(arg).IsFullyDetermined()) {
6412 unknown = true;
6413 break;
6414 }
6415 }
6416 if (!unknown)
6417 hasUp = false;
6418 }
6419
6420 // Fast path where all information has already been derived
6421 if (!hasUp && !hasDown)
6422 return;
6423
6424 FnTypeInfo typeInfo = getCallInfo(call, fn);
6425 typeInfo = preventTypeAnalysisLoops(typeInfo, call.getParent()->getParent());
6426
6427 if (EnzymePrintType) {
6428 llvm::errs() << " starting IPO of ";
6429 call.print(llvm::errs(), *MST);
6430 llvm::errs() << "\n";
6431 }
6432
6434
6435 if (EnzymePrintType) {
6436 llvm::errs() << " ending IPO of ";
6437 call.print(llvm::errs(), *MST);
6438 llvm::errs() << "\n";
6439 }
6440
6441 if (hasUp) {
6442 auto a = fn.arg_begin();
6443#if LLVM_VERSION_MAJOR >= 14
6444 for (auto &arg : call.args())
6445#else
6446 for (auto &arg : call.arg_operands())
6447#endif
6448 {
6449 auto dt = STR.query(a);
6450 if (EnzymePrintType) {
6451 llvm::errs() << " updating ";
6452 arg->print(llvm::errs(), *MST);
6453 llvm::errs() << " = " << dt.str() << " via IPO of ";
6454 call.print(llvm::errs(), *MST);
6455 llvm::errs() << " arg ";
6456 a->print(llvm::errs(), *MST);
6457 llvm::errs() << "\n";
6458 }
6459 updateAnalysis(arg, dt, &call);
6460 ++a;
6461 }
6462 }
6463
6464 if (hasDown) {
6465 TypeTree vd = STR.getReturnAnalysis();
6466 if (call.getType()->isIntOrIntVectorTy() &&
6467 vd.Inner0() == BaseType::Anything) {
6468 bool returned = false;
6469 if (mustRemainInteger(&call, &returned) && !returned) {
6470 vd = TypeTree(BaseType::Integer).Only(-1, &call);
6471 }
6472 }
6473 updateAnalysis(&call, vd, &call);
6474 }
6475}
6476
6478 assert(fn.KnownValues.size() ==
6479 fn.Function->getFunctionType()->getNumParams());
6480 assert(fn.Function);
6481 auto found = analyzedFunctions.find(fn);
6482 if (found != analyzedFunctions.end()) {
6483 auto &analysis = *found->second;
6484 if (analysis.fntypeinfo.Function != fn.Function) {
6485 llvm::errs() << " queryFunc: " << *fn.Function << "\n";
6486 llvm::errs() << " analysisFunc: " << *analysis.fntypeinfo.Function
6487 << "\n";
6488 }
6489 assert(analysis.fntypeinfo.Function == fn.Function);
6490
6491 return TypeResults(analysis);
6492 }
6493
6494 if (fn.Function->empty())
6495 return TypeResults(nullptr);
6496
6497 auto res = analyzedFunctions.emplace(fn, new TypeAnalyzer(fn, *this));
6498 auto &analysis = *res.first->second;
6499
6500 if (EnzymePrintType) {
6501 llvm::errs() << "analyzing function " << fn.Function->getName() << "\n";
6502 for (auto &pair : fn.Arguments) {
6503 llvm::errs() << " + knowndata: ";
6504 pair.first->print(llvm::errs(), *analysis.MST);
6505 llvm::errs() << " : " << pair.second.str();
6506 auto found = fn.KnownValues.find(pair.first);
6507 if (found != fn.KnownValues.end()) {
6508 llvm::errs() << " - " << to_string(found->second);
6509 }
6510 llvm::errs() << "\n";
6511 }
6512 llvm::errs() << " + retdata: " << fn.Return.str() << "\n";
6513 }
6514
6515 analysis.prepareArgs();
6516 analysis.considerTBAA();
6517 analysis.run();
6518
6519 if (analysis.fntypeinfo.Function != fn.Function) {
6520 llvm::errs() << " queryFunc: " << *fn.Function << "\n";
6521 llvm::errs() << " analysisFunc: " << *analysis.fntypeinfo.Function << "\n";
6522 }
6523 assert(analysis.fntypeinfo.Function == fn.Function);
6524
6525 {
6526 auto &analysis = *analyzedFunctions.find(fn)->second;
6527 if (analysis.fntypeinfo.Function != fn.Function) {
6528 llvm::errs() << " queryFunc: " << *fn.Function << "\n";
6529 llvm::errs() << " analysisFunc: " << *analysis.fntypeinfo.Function
6530 << "\n";
6531 }
6532 assert(analysis.fntypeinfo.Function == fn.Function);
6533 }
6534
6535 // Store the steady state result (if changed) to avoid
6536 // a second analysis later.
6537 analyzedFunctions.emplace(TypeResults(analysis).getAnalyzedTypeInfo(),
6538 res.first->second);
6539
6540 return TypeResults(analysis);
6541}
6542
6543TypeResults::TypeResults(TypeAnalyzer &analyzer) : analyzer(&analyzer) {}
6544TypeResults::TypeResults(std::nullptr_t) : analyzer(nullptr) {}
6545
6548 for (auto &arg : analyzer->fntypeinfo.Function->args()) {
6549 res.Arguments.insert(std::pair<Argument *, TypeTree>(&arg, query(&arg)));
6550 }
6551 res.Return = getReturnAnalysis();
6553 return res;
6554}
6555
6556FnTypeInfo TypeResults::getCallInfo(CallBase &CI, Function &fn) const {
6557 return analyzer->getCallInfo(CI, fn);
6558}
6559
6560const TypeTree &TypeResults::query(Value *val) const {
6561#ifndef NDEBUG
6562 if (auto inst = dyn_cast<Instruction>(val)) {
6563 assert(inst->getParent()->getParent() == analyzer->fntypeinfo.Function);
6564 }
6565 if (auto arg = dyn_cast<Argument>(val)) {
6566 assert(arg->getParent() == analyzer->fntypeinfo.Function);
6567 }
6568#endif
6569 return analyzer->getAnalysis(val);
6570}
6571
6572// Returns last non-padding/alignment location of the corresponding subtype T.
6573size_t skippedBytes(SmallSet<size_t, 8> &offs, Type *T, const DataLayout &DL,
6574 size_t offset = 0) {
6575 auto ST = dyn_cast<StructType>(T);
6576 if (!ST)
6577 return (DL.getTypeSizeInBits(T) + 7) / 8;
6578
6579 auto SL = DL.getStructLayout(ST);
6580 size_t prevOff = 0;
6581 for (size_t idx = 0; idx < ST->getNumElements(); idx++) {
6582 auto off = SL->getElementOffset(idx);
6583 if (off > prevOff)
6584 for (size_t i = prevOff; i < off; i++)
6585 offs.insert(offset + i);
6586 size_t subSize = skippedBytes(offs, ST->getElementType(idx), DL, prevOff);
6587 prevOff = off + subSize;
6588 }
6589 return prevOff;
6590}
6591
6592bool TypeResults::allFloat(Value *val) const {
6593 assert(val);
6594 assert(val->getType());
6595 const auto &q = query(val);
6596 auto dt = q[{-1}];
6597 if (dt != BaseType::Anything && dt != BaseType::Unknown)
6598 return dt.isFloat();
6599
6600 if (val->getType()->isTokenTy() || val->getType()->isVoidTy())
6601 return false;
6602 auto &dl = analyzer->fntypeinfo.Function->getParent()->getDataLayout();
6603 SmallSet<size_t, 8> offs;
6604 size_t ObjSize = skippedBytes(offs, val->getType(), dl);
6605
6606 for (size_t i = 0; i < ObjSize;) {
6607 dt = q[{(int)i}];
6608 if (auto FT = dt.isFloat()) {
6609 i += (dl.getTypeSizeInBits(FT) + 7) / 8;
6610 continue;
6611 }
6612 if (offs.count(i)) {
6613 i++;
6614 continue;
6615 }
6616 return false;
6617 }
6618 return true;
6619}
6620
6621bool TypeResults::anyFloat(Value *val, bool anythingIsFloat) const {
6622 assert(val);
6623 assert(val->getType());
6624 const auto &q = query(val);
6625 auto dt = q[{-1}];
6626 if (!anythingIsFloat && dt == BaseType::Anything)
6627 return false;
6628 if (dt != BaseType::Anything && dt != BaseType::Unknown)
6629 return dt.isFloat();
6630
6631 if (val->getType()->isTokenTy() || val->getType()->isVoidTy())
6632 return false;
6633 auto &dl = analyzer->fntypeinfo.Function->getParent()->getDataLayout();
6634 SmallSet<size_t, 8> offs;
6635 size_t ObjSize = skippedBytes(offs, val->getType(), dl);
6636
6637 for (size_t i = 0; i < ObjSize;) {
6638 dt = q[{(int)i}];
6639 if (dt == BaseType::Integer) {
6640 i++;
6641 continue;
6642 }
6643 if (!anythingIsFloat && dt == BaseType::Integer) {
6644 i++;
6645 continue;
6646 }
6647 if (dt == BaseType::Pointer) {
6648 i += dl.getPointerSize(0);
6649 continue;
6650 }
6651 if (offs.count(i)) {
6652 i++;
6653 continue;
6654 }
6655 return true;
6656 }
6657 return false;
6658}
6659
6660bool TypeResults::anyPointer(Value *val) const {
6661 assert(val);
6662 assert(val->getType());
6663 const auto &q = query(val);
6664 auto dt = q[{-1}];
6665 if (dt != BaseType::Anything && dt != BaseType::Unknown)
6666 return dt == BaseType::Pointer;
6667 if (val->getType()->isTokenTy() || val->getType()->isVoidTy())
6668 return false;
6669
6670 auto &dl = analyzer->fntypeinfo.Function->getParent()->getDataLayout();
6671 SmallSet<size_t, 8> offs;
6672 size_t ObjSize = skippedBytes(offs, val->getType(), dl);
6673
6674 for (size_t i = 0; i < ObjSize;) {
6675 dt = q[{(int)i}];
6676 if (dt == BaseType::Integer) {
6677 i++;
6678 continue;
6679 }
6680 if (auto FT = dt.isFloat()) {
6681 i += (dl.getTypeSizeInBits(FT) + 7) / 8;
6682 continue;
6683 }
6684 if (offs.count(i)) {
6685 i++;
6686 continue;
6687 }
6688 return true;
6689 }
6690 return false;
6691}
6692
6693void TypeResults::dump(llvm::raw_ostream &ss) const { analyzer->dump(ss); }
6694
6695ConcreteType TypeResults::intType(size_t num, Value *val, llvm::Instruction *I,
6696 GradientUtils *gutils,
6697 llvm::IRBuilder<> *BuilderIfShouldErr,
6698 bool pointerIntSame) const {
6699 assert(val);
6700 assert(val->getType());
6701 const auto &q = query(val);
6702 auto dt = q[{0}];
6703 /*
6704 size_t ObjSize = 1;
6705 if (val->getType()->isSized())
6706 ObjSize = (fn.Function->getParent()->getDataLayout().getTypeSizeInBits(
6707 val->getType()) +7) / 8;
6708 */
6709 dt.orIn(q[{-1}], pointerIntSame);
6710 for (size_t i = 1; i < num; ++i) {
6711 dt.orIn(q[{(int)i}], pointerIntSame);
6712 }
6713
6714 if (BuilderIfShouldErr && (!dt.isKnown() || dt == BaseType::Anything)) {
6715 std::string str;
6716 raw_string_ostream ss(str);
6717 ss << "Cannot deduce type of integer " << *val << "\n within " << *I
6718 << "\n num:" << num << " q:" << q.str() << " \n";
6719
6720 EmitNoTypeError(str, *I, nullptr, *BuilderIfShouldErr);
6721 }
6722 return dt;
6723}
6724
6725Type *TypeResults::addingType(size_t num, Value *val, size_t start) const {
6726 assert(val);
6727 assert(val->getType());
6728 const auto &q = query(val);
6729 Type *ty = q[{-1}].isFloat();
6730 for (size_t i = start; i < num; ++i) {
6731 auto ty2 = q[{(int)i}].isFloat();
6732 if (ty) {
6733 if (ty2)
6734 assert(ty == ty2);
6735 } else {
6736 ty = ty2;
6737 }
6738 }
6739 return ty;
6740}
6741
6742ConcreteType TypeResults::firstPointer(size_t num, Value *val, Instruction *I,
6743 GradientUtils *gutils,
6744 llvm::IRBuilder<> *BuilderIfShouldErr,
6745 bool pointerIntSame) const {
6746 assert(val);
6747 assert(val->getType());
6748 auto q = query(val).Data0();
6749 if (!(val->getType()->isPointerTy() || q[{}] == BaseType::Pointer)) {
6750 llvm::errs() << *analyzer->fntypeinfo.Function << "\n";
6751 dump();
6752 llvm::errs() << "val: " << *val << "\n";
6753 }
6754 assert(val->getType()->isPointerTy() || q[{}] == BaseType::Pointer);
6755
6756 auto dt = q[{-1}];
6757 for (size_t i = 0; i < num; ++i) {
6758 bool Legal = true;
6759 dt.checkedOrIn(q[{(int)i}], pointerIntSame, Legal);
6760 if (!Legal) {
6761 std::string str;
6762 raw_string_ostream ss(str);
6763 ss << "Illegal firstPointer, num: " << num << " q: " << q.str() << "\n";
6764 ss << " at " << *val << " from " << *I << "\n";
6765 if (CustomErrorHandler) {
6767 &analyzer, nullptr, nullptr);
6768 }
6769 llvm::errs() << ss.str() << "\n";
6770 llvm_unreachable("Illegal firstPointer");
6771 }
6772 }
6773
6774 if (BuilderIfShouldErr && (!dt.isKnown() || dt == BaseType::Anything)) {
6775 std::string str;
6776 raw_string_ostream ss(str);
6777 ss << "Cannot deduce type of integer " << *val << "\n within " << *I
6778 << "\n num:" << num << " q:" << q.str() << " \n";
6779
6780 EmitNoTypeError(str, *I, gutils, *BuilderIfShouldErr);
6781 }
6782 return dt;
6783}
6784
6785TypeTree defaultTypeTreeForLLVM(llvm::Type *ET, llvm::Instruction *I,
6786 bool intIsPointer) {
6787 if (ET->isIntOrIntVectorTy()) {
6788 if (intIsPointer)
6789 return TypeTree(BaseType::Pointer).Only(-1, I);
6790 else
6791 return TypeTree(BaseType::Integer).Only(-1, I);
6792 }
6793 if (ET->isFPOrFPVectorTy()) {
6794 return TypeTree(ConcreteType(ET->getScalarType())).Only(-1, I);
6795 }
6796 if (ET->isPointerTy()) {
6797 return TypeTree(BaseType::Pointer).Only(-1, I);
6798 }
6799 if (auto ST = dyn_cast<StructType>(ET)) {
6800 auto &DL = I->getParent()->getParent()->getParent()->getDataLayout();
6801
6802 TypeTree Out;
6803
6804 for (size_t i = 0; i < ST->getNumElements(); i++) {
6805 auto SubT =
6806 defaultTypeTreeForLLVM(ST->getElementType(i), I, intIsPointer);
6807 auto size = (DL.getTypeSizeInBits(ST->getElementType(i)) + 7) / 8;
6808 int Off = (int)getAggregateElementOffset(DL, ST, i);
6809 Out |= SubT.ShiftIndices(DL, 0, size, Off);
6810 }
6811 return Out;
6812 }
6813 if (auto AT = dyn_cast<ArrayType>(ET)) {
6814 auto SubT = defaultTypeTreeForLLVM(AT->getElementType(), I, intIsPointer);
6815 auto &DL = I->getParent()->getParent()->getParent()->getDataLayout();
6816
6817 TypeTree Out;
6818 for (size_t i = 0; i < AT->getNumElements(); i++) {
6819 int Off = (int)getAggregateElementOffset(DL, AT, i);
6820 auto size = (DL.getTypeSizeInBits(AT->getElementType()) + 7) / 8;
6821 Out |= SubT.ShiftIndices(DL, 0, size, Off);
6822 }
6823 return Out;
6824 }
6825 if (auto AT = dyn_cast<VectorType>(ET)) {
6826#if LLVM_VERSION_MAJOR >= 12
6827 assert(!AT->getElementCount().isScalable());
6828 size_t numElems = AT->getElementCount().getKnownMinValue();
6829#else
6830 size_t numElems = AT->getNumElements();
6831#endif
6832 auto SubT = defaultTypeTreeForLLVM(AT->getElementType(), I, intIsPointer);
6833 auto &DL = I->getParent()->getParent()->getParent()->getDataLayout();
6834
6835 TypeTree Out;
6836 for (size_t i = 0; i < numElems; i++) {
6837 int Off = (int)getAggregateElementOffset(DL, AT, i);
6838 auto size = (DL.getTypeSizeInBits(AT->getElementType()) + 7) / 8;
6839 Out |= SubT.ShiftIndices(DL, 0, size, Off);
6840 }
6841 return Out;
6842 }
6843 // Unhandled/unknown Type
6844 llvm::errs() << "Error Unknown Type: " << *ET << "\n";
6845 assert(0 && "Error Unknown Type: ");
6846 llvm_unreachable("Error Unknown Type: ");
6847 // return TypeTree();
6848}
6849
6850Function *TypeResults::getFunction() const {
6852}
6853
6857
6858std::set<int64_t> TypeResults::knownIntegralValues(Value *val) const {
6859 return analyzer->knownIntegralValues(val);
6860}
6861
6862std::set<int64_t> TypeAnalyzer::knownIntegralValues(Value *val) {
6863 return fntypeinfo.knownIntegralValues(val, DT, intseen, SE);
6864}
6865
6867
6869 llvm::Function *todiff) {
6870 FnTypeInfo oldTypeInfo = oldTypeInfo_;
6871 for (auto &pair : oldTypeInfo.KnownValues) {
6872 if (pair.second.size() != 0) {
6873 bool recursiveUse = false;
6874 std::set<std::pair<Value *, Value *>> seen;
6875 SetVector<std::pair<Value *, Value *>> todo;
6876 for (auto user : pair.first->users())
6877 todo.insert(std::make_pair(user, pair.first));
6878 while (todo.size()) {
6879 auto spair = todo.pop_back_val();
6880 if (seen.count(spair))
6881 continue;
6882 seen.insert(spair);
6883 auto [v, prev] = spair;
6884 if (isa<BinaryOperator>(v) || isa<PHINode>(v) || isa<Argument>(v)) {
6885 for (auto user : v->users())
6886 todo.insert(std::make_pair(user, v));
6887 continue;
6888 }
6889 if (auto ci = dyn_cast<CallBase>(v)) {
6890 if (ci->getCalledFunction() == todiff &&
6891 ci->getArgOperand(pair.first->getArgNo()) == prev) {
6892 if (prev == pair.first)
6893 continue;
6894 recursiveUse = true;
6895 break;
6896 }
6897 }
6898 }
6899 if (recursiveUse) {
6900 pair.second.clear();
6901 }
6902 }
6903 }
6904 return oldTypeInfo;
6905}
BaseType
Categories of potential types.
Definition BaseType.h:32
static llvm::SmallPtrSet< llvm::BasicBlock *, 4 > getGuaranteedUnreachable(llvm::Function *F)
static bool isDeallocationFunction(const llvm::StringRef name, const llvm::TargetLibraryInfo &TLI)
Return whether a given function is a known C/C++ memory deallocation function For updating below one ...
static bool isCudaDeallocationFunction(const llvm::StringRef name)
Return whether a given function frees a CUDA allocation.
static bool isAllocationFunction(const llvm::StringRef name, const llvm::TargetLibraryInfo &TLI)
Return whether a given function is a known C/C++ memory allocation function For updating below one sh...
static Operation * getFunctionFromCall(CallOpInterface iface)
constexpr const char * to_string(ActivityAnalyzer::UseActivity UA)
static std::string str(AugmentedStruct c)
Definition EnzymeLogic.h:62
StringMap< std::function< Value *(IRBuilder<> &, CallInst *, ArrayRef< Value * >, GradientUtils *)> > shadowHandlers
llvm::cl::opt< bool > EnzymePrintType
The following is not taken from LLVM.
static TypeTree parseTBAA(TBAAStructTypeNode AccessType, llvm::Instruction &I, const llvm::DataLayout &DL, std::shared_ptr< llvm::ModuleSlotTracker > MST)
Given a TBAA access node return the corresponding TypeTree This includes recursively parsing the acce...
Definition TBAA.h:439
TypeTree defaultTypeTreeForLLVM(llvm::Type *ET, llvm::Instruction *I, bool intIsPointer)
llvm::cl::opt< int > MaxIntOffset("enzyme-max-int-offset", cl::init(100), cl::Hidden, cl::desc("Maximum type tree offset"))
Maximum offset for type trees to keep.
static TypeTree fortranDescriptorTree(Value *desc, const DataLayout &DL)
Type of a pointer to an LLVM flang descriptor (CFI_cdesc_t).
std::set< SmallVector< T, 4 > > getSet(ArrayRef< std::set< T > > todo, size_t idx)
#define CONSIDER(fn)
static void AugmentWithJuliaObjectType(TypeTree &TT, Type *T, const DataLayout &DL)
static bool AllJuliaTypes(Type *T)
FnTypeInfo preventTypeAnalysisLoops(const FnTypeInfo &oldTypeInfo_, llvm::Function *todiff)
void getConstantAnalysis(Constant *Val, TypeAnalyzer &TA, std::map< llvm::Value *, TypeTree > &analysis)
Given a constant value, deduce any type information applicable.
#define CONSIDER2(fn,...)
llvm::cl::opt< bool > RustTypeRules("enzyme-rust-type", cl::init(false), cl::Hidden, cl::desc("Enable rust-specific type rules"))
void analyzeFuncTypesNoFn(CallBase &call, TypeAnalyzer &TA)
static SmallPtrSet< BasicBlock *, 1 > findLoopIndices(llvm::Value *val, LoopInfo &LI, DominatorTree &DT, SmallPtrSet< PHINode *, 1 > &seen)
llvm::cl::opt< bool > EnzymeStrictAliasing("enzyme-strict-aliasing", cl::init(true), cl::Hidden, cl::desc("Assume strict aliasing of types / type stability"))
size_t skippedBytes(SmallSet< size_t, 8 > &offs, Type *T, const DataLayout &DL, size_t offset=0)
static bool isItaniumEncoding(StringRef S)
static void checkEnzymeTypeExtent(TypeAnalyzer *TA, const TypeTree &TT, size_t RegSize, Instruction &I, Value *Val)
const llvm::StringMap< llvm::Intrinsic::ID > LIBM_FUNCTIONS
static bool AnyJuliaTypes(Type *T)
void analyzeFuncTypes(RT(*fn)(Args...), CallBase &call, TypeAnalyzer &TA)
void analyzeIntelSubscriptIntrinsic(IntrinsicInst &II, TypeAnalyzer &TA)
bool dontAnalyze(StringRef str)
FnTypeInfo preventTypeAnalysisLoops(const FnTypeInfo &oldTypeInfo_, llvm::Function *todiff)
static bool isMemFreeLibMFunction(llvm::StringRef str, llvm::Intrinsic::ID *ID=nullptr)
llvm::cl::opt< unsigned > EnzymeMaxTypeDepth
void EmitNoTypeError(const std::string &message, llvm::Instruction &inst, GradientUtils *gutils, llvm::IRBuilder<> &Builder2)
Definition Utils.cpp:4675
llvm::Optional< BlasInfo > extractBLAS(llvm::StringRef in)
Definition Utils.cpp:3871
LLVMValueRef(* CustomErrorHandler)(const char *, LLVMValueRef, ErrorType, const void *, LLVMValueRef, LLVMBuilderRef)
Definition Utils.cpp:62
bool collectOffset(GEPOperator *gep, const DataLayout &DL, unsigned BitWidth, MapVector< Value *, APInt > &VariableOffsets, APInt &ConstantOffset)
Definition Utils.cpp:4464
static bool isIntelSubscriptIntrinsic(const llvm::IntrinsicInst &II)
Definition Utils.h:1649
static llvm::StringRef canonicalizeMPIName(llvm::StringRef Name)
Canonicalize the name of an MPI routine across calling conventions: both the C convention ("MPI_Recv"...
Definition Utils.h:2780
static T max(T a, T b)
Pick the maximum value.
Definition Utils.h:406
@ Args
Return is a struct of all args.
static bool startsWith(llvm::StringRef string, llvm::StringRef prefix)
Definition Utils.h:847
void EmitFailure(llvm::StringRef RemarkName, const llvm::DiagnosticLocation &Loc, const llvm::Instruction *CodeRegion, Args &...args)
Definition Utils.h:347
static uint64_t getAggregateElementOffset(const llvm::DataLayout &DL, llvm::Type *T, llvm::ArrayRef< unsigned > Idxs)
The byte offset of the aggregate element addressed by Idxs within T, that is, what gep T,...
Definition Utils.h:1354
static void insertBeforeInst(llvm::Instruction *I, llvm::Instruction *Before)
Definition Utils.h:2562
static llvm::Value * getBaseObject(llvm::Value *V, bool offsetAllowed=true)
Definition Utils.h:1711
static bool isFortranMPICall(llvm::StringRef Name)
True if Name uses a Fortran ABI mangling of an MPI routine (trailing underscore(s),...
Definition Utils.h:2798
static llvm::MDNode * hasMetadata(const llvm::GlobalObject *O, llvm::StringRef kind)
Check if a global has metadata.
Definition Utils.h:483
static bool containsOnlyAtMostTopBit(const llvm::Value *V, llvm::Type *FT, const llvm::DataLayout &dl, llvm::Type **vFT=nullptr)
Definition Utils.h:2325
llvm::cl::opt< bool > EnzymeJuliaAddrLoad
@ IllegalFirstPointer
@ IllegalTypeAnalysis
static llvm::StringRef getFuncNameFromCall(const llvm::CallBase *op)
Definition Utils.h:1470
static llvm::Optional< size_t > getAllocationIndexFromCall(const llvm::CallBase *op)
Definition Utils.h:1519
Concrete SubType of a given value.
ConcreteType PurgeAnything() const
Keep only mappings where the type is not an Anything
Full interprocedural TypeAnalysis.
llvm::StringMap< std::function< bool(int, TypeTree &, llvm::ArrayRef< TypeTree >, llvm::ArrayRef< std::set< int64_t > >, llvm::CallBase *, TypeAnalyzer *)> > CustomRules
Map of custom function call handlers.
std::map< FnTypeInfo, std::shared_ptr< TypeAnalyzer > > analyzedFunctions
Map of possible query states to TypeAnalyzer intermediate results.
void clear()
Clear existing analyses.
TypeResults analyzeFunction(const FnTypeInfo &fn)
Analyze a particular function, returning the results.
Helper class that computes the fixed-point type results of a given function.
void visitMemTransferInst(llvm::MemTransferInst &MTI)
void visitFPToSIInst(llvm::FPToSIInst &I)
llvm::PostDominatorTree & PDT
FnTypeInfo getCallInfo(llvm::CallBase &CI, llvm::Function &fn)
void visitAllocaInst(llvm::AllocaInst &I)
const FnTypeInfo fntypeinfo
Calling context.
void visitExtractValueInst(llvm::ExtractValueInst &I)
void visitSIToFPInst(llvm::SIToFPInst &I)
const llvm::SmallPtrSet< llvm::BasicBlock *, 4 > notForAnalysis
llvm::DominatorTree & DT
std::set< int64_t > knownIntegralValues(llvm::Value *val)
void visitFPExtInst(llvm::FPExtInst &I)
void visitConstantExpr(llvm::ConstantExpr &CE)
TypeAnalysis & interprocedural
Calling TypeAnalysis to be used in the case of calls to other functions.
void visitGetElementPtrInst(llvm::GetElementPtrInst &gep)
void visitIntToPtrInst(llvm::IntToPtrInst &I)
void prepareArgs()
Analyze type info given by the arguments, possibly adding to work queue.
void visitShuffleVectorInst(llvm::ShuffleVectorInst &I)
llvm::TargetLibraryInfo & TLI
void visitUIToFPInst(llvm::UIToFPInst &I)
static constexpr uint8_t UP
void visitInsertValueInst(llvm::InsertValueInst &I)
void visitPHINode(llvm::PHINode &phi)
void visitValue(llvm::Value &val)
void visitSelectInst(llvm::SelectInst &I)
void visitIPOCall(llvm::CallBase &call, llvm::Function &fn)
std::shared_ptr< llvm::ModuleSlotTracker > MST
Cache of metadata indices, for faster printing.
llvm::SetVector< llvm::Value *, std::deque< llvm::Value * > > workList
List of value's which should be re-analyzed now with new information.
static constexpr uint8_t DOWN
const TypeTree & getAnalysis(llvm::Value *Val)
Get the current results for a given value.
void updateAnalysis(llvm::Value *val, BaseType data, llvm::Value *origin)
Add additional information to the Type info of val, readding it to the work queue as necessary.
void visitAddrSpaceCastInst(llvm::AddrSpaceCastInst &I)
bool Invalid
Whether an inconsistent update has been found This will only be set when direction !...
static constexpr uint8_t BOTH
void visitExtractElementInst(llvm::ExtractElementInst &I)
void visitLoadInst(llvm::LoadInst &I)
void visitCmpInst(llvm::CmpInst &I)
uint8_t direction
Directionality of checks.
std::map< llvm::Value *, TypeTree > analysis
Intermediate conservative, but correct Type analysis results.
void visitIntrinsicInst(llvm::IntrinsicInst &II)
void visitSExtInst(llvm::SExtInst &I)
void visitGEPOperator(llvm::GEPOperator &gep)
void considerTBAA()
Analyze type info given by the TBAA, possibly adding to work queue.
void visitCallBase(llvm::CallBase &call)
void visitFPTruncInst(llvm::FPTruncInst &I)
void visitStoreInst(llvm::StoreInst &I)
void visitAtomicRMWInst(llvm::AtomicRMWInst &I)
TypeAnalyzer(TypeAnalysis &TA)
void visitZExtInst(llvm::ZExtInst &I)
void runPHIHypotheses()
Hypothesize that undefined phi's are integers and try to prove that they are really integral.
void visitBinaryOperator(llvm::BinaryOperator &I)
void visitMemTransferCommon(llvm::CallBase &MTI)
void visitBinaryOperation(const llvm::DataLayout &DL, llvm::Type *T, llvm::Instruction::BinaryOps, llvm::Value *Args[2], TypeTree &Ret, TypeTree &LHS, TypeTree &RHS, llvm::Instruction *I)
void visitFPToUIInst(llvm::FPToUIInst &I)
void visitBitCastInst(llvm::BitCastInst &I)
llvm::LoopInfo & LI
void dump(llvm::raw_ostream &ss=llvm::errs())
void visitTruncInst(llvm::TruncInst &I)
void visitPtrToIntInst(llvm::PtrToIntInst &I)
llvm::ScalarEvolution & SE
void run()
Run the interprocedural type analysis starting from this function.
TypeTree getReturnAnalysis()
void visitInsertElementInst(llvm::InsertElementInst &I)
A holder class representing the results of running TypeAnalysis on a given function.
TypeResults(std::nullptr_t)
llvm::Type * addingType(size_t num, llvm::Value *val, size_t start=0) const
ConcreteType firstPointer(size_t num, llvm::Value *val, llvm::Instruction *I, GradientUtils *gutils=nullptr, llvm::IRBuilder<> *BuilderIfShouldErr=nullptr, bool pointerIntSame=false) const
Returns whether in the first num bytes there is pointer, int, float, or none If pointerIntSame is set...
void dump(llvm::raw_ostream &ss=llvm::errs()) const
Prints all known information.
bool anyFloat(llvm::Value *val, bool anythingIsFloat=true) const
Whether any part of the top level register can contain a float e.g.
TypeAnalyzer * analyzer
FnTypeInfo getAnalyzedTypeInfo() const
The TypeInfo calling convention.
bool anyPointer(llvm::Value *val) const
Whether any part of the top level register can contain a pointer e.g.
std::set< int64_t > knownIntegralValues(llvm::Value *val) const
The set of values val will take on during this program.
TypeTree getReturnAnalysis() const
The Type of the return.
const TypeTree & query(llvm::Value *val) const
The TypeTree of a particular Value.
ConcreteType intType(size_t num, llvm::Value *val, llvm::Instruction *I, GradientUtils *gutils=nullptr, llvm::IRBuilder<> *BuilderIfShouldErr=nullptr, bool pointerIntSame=false) const
bool allFloat(llvm::Value *val) const
Whether all of the top level register is known to contain float data.
llvm::Function * getFunction() const
FnTypeInfo getCallInfo(llvm::CallBase &CI, llvm::Function &fn) const
Class representing the underlying types of values as sequences of offsets to a ConcreteType.
Definition TypeTree.h:72
TypeTree Only(int Off, llvm::Instruction *orig) const
Prepend an offset to all mappings.
Definition TypeTree.h:473
TypeTree Data0() const
Peel off the outermost index at offset 0.
Definition TypeTree.h:515
const ConcreteTypeMapType & getMapping() const
Utility helper to lookup the mapping.
Definition TypeTree.h:173
static TypeTree parse(llvm::StringRef str, llvm::LLVMContext &ctx)
Definition TypeTree.h:86
TypeTree ShiftIndices(const llvm::DataLayout &dl, const int offset, const int maxSize, size_t addOffset=0) const
Replace mappings in the range in [offset, offset+maxSize] with those in.
Definition TypeTree.h:912
TypeTree Lookup(size_t len, const llvm::DataLayout &dl) const
Select all submappings whose first index is in range [0, len) and remove the first index.
Definition TypeTree.h:595
llvm::MDNode * toMD(llvm::LLVMContext &ctx)
Definition TypeTree.h:1475
ConcreteType Inner0() const
Optimized version of Data0()[{}].
Definition TypeTree.h:550
void remove(const std::vector< int > Seq)
Definition TypeTree.h:233
TypeTree ReplaceMinus() const
Replace -1 with 0.
Definition TypeTree.h:1131
static TypeTree fromMD(llvm::MDNode *md)
Definition TypeTree.h:1516
bool isKnownPastPointer() const
Whether this TypeTree knows any non-pointer information.
Definition TypeTree.h:445
TypeTree Clear(size_t start, size_t end, size_t len) const
Remove any mappings in the range [start, end) or [len, inf) This function has special handling for -1...
Definition TypeTree.h:558
TypeTree JustAnything() const
Keep only mappings where the type is an Anything
Definition TypeTree.h:1155
bool checkedOrIn(const std::vector< int > &Seq, ConcreteType RHS, bool PointerIntSame, bool &LegalOr)
Definition TypeTree.h:1180
void CanonicalizeInPlace(size_t len, const llvm::DataLayout &dl)
Given that this tree represents something of at most size len, canonicalize this, creating -1's where...
Definition TypeTree.h:678
std::string str() const
Returns a string representation of this TypeTree.
Definition TypeTree.h:1455
bool orIn(const std::vector< int > &Seq, ConcreteType RHS, bool PointerIntSame=false)
Definition TypeTree.h:1304
bool insert(const std::vector< int > Seq, ConcreteType CT, bool PointerIntSame=false)
Return if changed.
Definition TypeTree.h:236
bool binopIn(bool &Legal, const TypeTree &RHS, llvm::BinaryOperator::BinaryOps Op)
Set this to the logical binop of itself and RHS, using the Binop Op, returning true if this was chang...
Definition TypeTree.h:1392
TypeTree PurgeAnything() const
Keep only mappings where the type is not an Anything
Definition TypeTree.h:1113
llvm::Type * allFloat(llvm::Value *val, const llvm::DataLayout &dl, bool anythingIsFloat=false) const
Definition TypeTree.h:816
Struct containing all contextual type information for a particular function call.
std::map< llvm::Argument *, TypeTree > Arguments
Types of arguments.
llvm::Function * Function
Function being analyzed.
TypeTree Return
Type of return.
std::set< int64_t > knownIntegralValues(llvm::Value *val, const llvm::DominatorTree &DT, std::map< llvm::Value *, std::set< int64_t > > &intseen, llvm::ScalarEvolution &SE) const
The set of known values val will take.
std::map< llvm::Argument *, std::set< int64_t > > KnownValues
The specific constant(s) known to represented by an argument, if constant.
static void analyzeFuncTypesHelper(unsigned idx, CallBase &call, TypeAnalyzer &TA)
static void analyzeFuncTypesHelper(unsigned idx, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
static void analyzeType(Value *val, CallBase &call, TypeAnalyzer &TA)
This template class is defined to take the templated type T update the analysis of the first argument...