LLVM: lib/Target/AMDGPU/AMDGPULibCalls.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
25#include
26
27#define DEBUG_TYPE "amdgpu-simplifylib"
28
29using namespace llvm;
31
33 cl::desc("Enable pre-link mode optimizations"),
36
38 cl::desc("Comma separated list of functions to replace with native, or all"),
41
42#define MATH_PI numbers::pi
43#define MATH_E numbers::e
44#define MATH_SQRT2 numbers::sqrt2
45#define MATH_SQRT1_2 numbers::inv_sqrt2
46
47namespace llvm {
48
50private:
54
56
57 bool UnsafeFPMath = false;
58
59
60 bool AllNative = false;
61
62 bool useNativeFunc(const StringRef F) const;
63
64
65
67
68 bool parseFunctionName(const StringRef &FMangledName, FuncInfo &FInfo);
69
71
72
73
74
76
77
79
80
82
83
84 bool evaluateScalarMathFunc(const FuncInfo &FInfo, double &Res0, double &Res1,
87
88
89
90 std::tuple<Value *, Value *, Value *> insertSinCos(Value *Arg,
94
95
97
98
101
102
104
105
106
107 bool shouldReplaceLibcallWithIntrinsic(const CallInst *CI,
108 bool AllowMinSizeF32 = false,
109 bool AllowF64 = false,
110 bool AllowStrictFP = false);
113
116 bool AllowMinSizeF32 = false,
117 bool AllowF64 = false,
118 bool AllowStrictFP = false);
119
120protected:
123
125
127 I->replaceAllUsesWith(With);
128 I->eraseFromParent();
129 }
130
133 }
134
135public:
137
139
142
143
145};
146
147}
148
149template
153 if (Function *F = dyn_cast(Callee.getCallee()))
154 R->setCallingConv(F->getCallingConv());
155 return R;
156}
157
158template
161 CallInst *R = B.CreateCall(Callee, {Arg1, Arg2}, Name);
162 if (Function *F = dyn_cast(Callee.getCallee()))
163 R->setCallingConv(F->getCallingConv());
164 return R;
165}
166
169 if (VectorType *VecTy = dyn_cast(FT->getReturnType()))
170 PowNExpTy = VectorType::get(PowNExpTy, VecTy->getElementCount());
171
172 return FunctionType::get(FT->getReturnType(),
173 {FT->getParamType(0), PowNExpTy}, false);
174}
175
176
177
178
182};
183
184
188 {0.0, 1.0},
190};
192 {0.0, 1.0}
193};
195 {0.5, 0.0},
196 {0.5, -0.0},
197 {0.0, 1.0},
198 {1.0, -1.0}
199};
201 {0.0, 0.0},
202 {-0.0, -0.0},
205};
207 {0.0, 0.0},
208 {-0.0, -0.0}
209};
211 {0.0, 0.0},
212 {-0.0, -0.0},
213 {0.5, 1.0},
214 {-0.5, -1.0}
215};
217 {0.0, 0.0},
218 {-0.0, -0.0},
221};
223 {0.0, 0.0},
224 {-0.0, -0.0}
225};
227 {0.0, 0.0},
228 {-0.0, -0.0},
229 {0.25, 1.0},
230 {-0.25, -1.0}
231};
233 {0.0, 0.0},
234 {-0.0, -0.0},
235 {1.0, 1.0},
236 {-1.0, -1.0},
237};
239 {1.0, 0.0},
240 {1.0, -0.0}
241};
243 {1.0, 0.0},
244 {1.0, -0.0}
245};
247 {1.0, 0.0},
248 {1.0, -0.0}
249};
251 {1.0, 0.0},
252 {1.0, -0.0}
253};
255 {0.0, 0.0},
256 {-0.0, -0.0}
257};
259 {1.0, 0.0},
260 {1.0, -0.0},
262};
264 {1.0, 0.0},
265 {1.0, -0.0},
266 {2.0, 1.0}
267};
269 {1.0, 0.0},
270 {1.0, -0.0},
271 {10.0, 1.0}
272};
274 {0.0, 0.0},
275 {-0.0, -0.0}
276};
278 {0.0, 1.0},
280};
282 {0.0, 1.0},
283 {1.0, 2.0}
284};
286 {0.0, 1.0},
287 {1.0, 10.0}
288};
290 {1.0, 1.0},
292};
294 {0.0, 0.0},
295 {-0.0, -0.0}
296};
298 {0.0, 0.0},
299 {-0.0, -0.0}
300};
302 {0.0, 0.0},
303 {-0.0, -0.0}
304};
306 {0.0, 0.0},
307 {1.0, 1.0},
309};
311 {0.0, 0.0},
312 {-0.0, -0.0}
313};
315 {0.0, 0.0},
316 {-0.0, -0.0}
317};
319 {0.0, 0.0},
320 {-0.0, -0.0}
321};
323 {1.0, 1.0},
324 {1.0, 2.0},
325 {2.0, 3.0},
326 {6.0, 4.0}
327};
328
330 switch(id) {
331 case AMDGPULibFunc::EI_DIVIDE:
332 case AMDGPULibFunc::EI_COS:
333 case AMDGPULibFunc::EI_EXP:
334 case AMDGPULibFunc::EI_EXP2:
335 case AMDGPULibFunc::EI_EXP10:
336 case AMDGPULibFunc::EI_LOG:
337 case AMDGPULibFunc::EI_LOG2:
338 case AMDGPULibFunc::EI_LOG10:
339 case AMDGPULibFunc::EI_POWR:
340 case AMDGPULibFunc::EI_RECIP:
341 case AMDGPULibFunc::EI_RSQRT:
342 case AMDGPULibFunc::EI_SIN:
343 case AMDGPULibFunc::EI_SINCOS:
344 case AMDGPULibFunc::EI_SQRT:
345 case AMDGPULibFunc::EI_TAN:
346 return true;
347 default:;
348 }
349 return false;
350}
351
353
355 switch(id) {
366 case AMDGPULibFunc::EI_NCOS:
373 case AMDGPULibFunc::EI_NEXP2:
378 case AMDGPULibFunc::EI_NLOG2:
381 case AMDGPULibFunc::EI_NRSQRT:
383 case AMDGPULibFunc::EI_NSIN:
387 case AMDGPULibFunc::EI_NSQRT:
393 default:;
394 }
396}
397
400}
401
404}
405
406FunctionCallee AMDGPULibCalls::getFunction(Module *M, const FuncInfo &fInfo) {
407
408
409
412}
413
414bool AMDGPULibCalls::parseFunctionName(const StringRef &FMangledName,
415 FuncInfo &FInfo) {
417}
418
420 return UnsafeFPMath || FPOp->isFast();
421}
422
424 return UnsafeFPMath ||
426}
427
430
432}
433
435 UnsafeFPMath = F.getFnAttribute("unsafe-fp-math").getValueAsBool();
439}
440
441bool AMDGPULibCalls::useNativeFunc(const StringRef F) const {
443}
444
446 AllNative = useNativeFunc("all") ||
449}
450
451bool AMDGPULibCalls::sincosUseNative(CallInst *aCI, const FuncInfo &FInfo) {
452 bool native_sin = useNativeFunc("sin");
453 bool native_cos = useNativeFunc("cos");
454
455 if (native_sin && native_cos) {
458
462
466
470 if (sinExpr && cosExpr) {
476
478 << " with native version of sin/cos");
479
481 return true;
482 }
483 }
484 return false;
485}
486
490 return false;
491
493 if (!parseFunctionName(Callee->getName(), FInfo) || !FInfo.isMangled() ||
496 !(AllNative || useNativeFunc(FInfo.getName()))) {
497 return false;
498 }
499
501 return sincosUseNative(aCI, FInfo);
502
505 if ()
506 return false;
507
510 << " with native version");
511 return true;
512}
513
514
515
516
517
518
519
520
522 const FuncInfo &FInfo) {
524 if (!Callee->isDeclaration())
525 return false;
526
527 assert(Callee->hasName() && "Invalid read_pipe/write_pipe function");
528 auto *M = Callee->getParent();
529 std::string Name = std::string(Callee->getName());
530 auto NumArg = CI->arg_size();
531 if (NumArg != 4 && NumArg != 6)
532 return false;
534 dyn_cast(CI->getArgOperand(NumArg - 2));
536 dyn_cast(CI->getArgOperand(NumArg - 1));
537 if (!PacketSize || !PacketAlign)
538 return false;
539
542 if (Alignment != Size)
543 return false;
544
545 unsigned PtrArgLoc = CI->arg_size() - 3;
548
550 for (unsigned I = 0; I != PtrArgLoc; ++I)
553
559 if ()
560 return false;
561
563 for (unsigned I = 0; I != PtrArgLoc; ++I)
565 Args.push_back(PtrArg);
566
567 auto *NCI = B.CreateCall(F, Args);
572
573 return true;
574}
575
578 if (isa(V))
579 return true;
580 if (isa(V))
581 return false;
582
583 if (const ConstantFP *CF = dyn_cast(V))
584 return CF->getValueAPF().isInteger();
585
586 auto *VFVTy = dyn_cast(V->getType());
587 const Constant *CV = dyn_cast(V);
588 if (VFVTy && CV) {
589 unsigned NumElts = VFVTy->getNumElements();
590 for (unsigned i = 0; i != NumElts; ++i) {
592 if (!Elt)
593 return false;
594 if (isa(Elt))
595 continue;
596
597 const ConstantFP *CFP = dyn_cast(Elt);
599 return false;
600 }
601
602 return true;
603 }
604
605 const Instruction *I = dyn_cast(V);
606 if ()
607 return false;
608
609 switch (I->getOpcode()) {
610 case Instruction::SIToFP:
611 case Instruction::UIToFP:
612
614 return true;
615
616
617
619 case Instruction::Call: {
620 const CallInst *CI = cast(I);
622 case Intrinsic::trunc:
623 case Intrinsic:🤣
624 case Intrinsic::ceil:
625 case Intrinsic::rint:
626 case Intrinsic::nearbyint:
627 case Intrinsic::round:
628 case Intrinsic::roundeven:
631 default:
632 break;
633 }
634
635 break;
636 }
637 default:
638 break;
639 }
640
641 return false;
642}
643
644
647
648 if (!Callee || Callee->isIntrinsic() || CI->isNoBuiltin())
649 return false;
650
652 if (!parseFunctionName(Callee->getName(), FInfo))
653 return false;
654
655
656
658 return false;
659
660 LLVM_DEBUG(dbgs() << "AMDIC: try folding " << *CI << '\n');
661
662 if (TDOFold(CI, FInfo))
663 return true;
664
667 B.setIsFPConstrained(true);
668
669 if (FPMathOperator *FPOp = dyn_cast(CI)) {
670
671
672
674 return true;
675
676
678 B.setFastMathFlags(FMF);
679
680
681
682
683 switch (FInfo.getId()) {
685 if (FMF.none())
686 return false;
687 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::exp,
690 if (FMF.none())
691 return false;
692 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::exp2,
695 if (FMF.none())
696 return false;
697 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::log,
700 if (FMF.none())
701 return false;
702 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::log2,
705 if (FMF.none())
706 return false;
707 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::log10,
710 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::minnum,
711 true, true);
713 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::maxnum,
714 true, true);
716 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::fma, true,
717 true);
719 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::fmuladd,
720 true, true);
722 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::fabs, true,
723 true, true);
725 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::copysign,
726 true, true, true);
728 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::floor, true,
729 true);
731 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::ceil, true,
732 true);
734 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::trunc, true,
735 true);
737 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::rint, true,
738 true);
740 return tryReplaceLibcallWithSimpleIntrinsic(B, CI, Intrinsic::round, true,
741 true);
743 if (!shouldReplaceLibcallWithIntrinsic(CI, true, true))
744 return false;
745
748 VecTy && !isa(Arg1->getType())) {
749 Value *SplatArg1 = B.CreateVectorSplat(VecTy->getElementCount(), Arg1);
751 }
752
754 CI->getModule(), Intrinsic::ldexp,
755 {CI->getType(), CI->getArgOperand(1)->getType()}));
756 return true;
757 }
759 Module *M = Callee->getParent();
762 CallInst *Call = cast(FPOp);
763
764
765
766 if (PowrFunc &&
768 FPOp->getOperand(0), 0,
769 SimplifyQuery(M->getDataLayout(), TLInfo, DT, AC, Call))) {
770 Call->setCalledFunction(PowrFunc);
771 return fold_pow(FPOp, B, PowrInfo) || true;
772 }
773
774
775 if (isKnownIntegral(FPOp->getOperand(1), M->getDataLayout(),
776 FPOp->getFastMathFlags())) {
780 if (PownFunc) {
781
782
783
784 Value *CastedArg =
785 B.CreateFPToSI(FPOp->getOperand(1), PownType->getParamType(1));
786
787 Call->removeParamAttrs(
789 Call->getParamAttributes(1)));
790 Call->setCalledFunction(PownFunc);
791 Call->setArgOperand(1, CastedArg);
792 return fold_pow(FPOp, B, PownInfo) || true;
793 }
794 }
795
796 return fold_pow(FPOp, B, FInfo);
797 }
800 return fold_pow(FPOp, B, FInfo);
802 return fold_rootn(FPOp, B, FInfo);
804
805 return tryReplaceLibcallWithSimpleIntrinsic(
806 B, CI, Intrinsic::sqrt, true, true, false);
809 return fold_sincos(FPOp, B, FInfo);
810 default:
811 break;
812 }
813 } else {
814
815 switch (FInfo.getId()) {
820 return fold_read_write_pipe(CI, B, FInfo);
821 default:
822 break;
823 }
824 }
825
826 return false;
827}
828
829bool AMDGPULibCalls::TDOFold(CallInst *CI, const FuncInfo &FInfo) {
830
833 return false;
834
835 int const sz = (int)tr.size();
837
841 for (int eltNo = 0; eltNo < getVecSize(FInfo); ++eltNo) {
842 ConstantFP *eltval = dyn_cast(
843 CV->getElementAsConstant((unsigned)eltNo));
844 assert(eltval && "Non-FP arguments in math function!");
845 bool found = false;
846 for (int i=0; i < sz; ++i) {
849 found = true;
850 break;
851 }
852 }
853 if (!found) {
854
855 return false;
856 }
857 }
862 for (double D : DVal)
866 } else {
869 }
870 LLVM_DEBUG(errs() << "AMDIC: " << *CI << " ---> " << *nval << "\n");
872 return true;
873 }
874 } else {
875
876 if (ConstantFP *CF = dyn_cast(opr0)) {
877 for (int i = 0; i < sz; ++i) {
878 if (CF->isExactlyValue(tr[i].input)) {
879 Value *nval = ConstantFP::get(CF->getType(), tr[i].result);
880 LLVM_DEBUG(errs() << "AMDIC: " << *CI << " ---> " << *nval << "\n");
882 return true;
883 }
884 }
885 }
886 }
887
888 return false;
889}
890
891namespace llvm {
892static double log2(double V) {
893#if _XOPEN_SOURCE >= 600 || defined(_ISOC99_SOURCE) || _POSIX_C_SOURCE >= 200112L
894 return ::log2(V);
895#else
897#endif
898}
899}
900
902 const FuncInfo &FInfo) {
906 "fold_pow: encounter a wrong function call");
907
908 Module *M = B.GetInsertBlock()->getModule();
912
913 const APFloat *CF = nullptr;
914 const APInt *CINT = nullptr;
917
918
919 int ci_opr1 = (CINT ? (int)CINT->getSExtValue() : 0x1111111);
920
921 if ((CF && CF->isZero()) || (CINT && ci_opr1 == 0)) {
922
923 LLVM_DEBUG(errs() << "AMDIC: " << *FPOp << " ---> 1\n");
924 Constant *cnval = ConstantFP::get(eltType, 1.0);
927 }
929 return true;
930 }
931 if ((CF && CF->isExactlyValue(1.0)) || (CINT && ci_opr1 == 1)) {
932
933 LLVM_DEBUG(errs() << "AMDIC: " << *FPOp << " ---> " << *opr0 << "\n");
935 return true;
936 }
937 if ((CF && CF->isExactlyValue(2.0)) || (CINT && ci_opr1 == 2)) {
938
939 LLVM_DEBUG(errs() << "AMDIC: " << *FPOp << " ---> " << *opr0 << " * "
940 << *opr0 << "\n");
941 Value *nval = B.CreateFMul(opr0, opr0, "__pow2");
943 return true;
944 }
945 if ((CF && CF->isExactlyValue(-1.0)) || (CINT && ci_opr1 == -1)) {
946
947 LLVM_DEBUG(errs() << "AMDIC: " << *FPOp << " ---> 1 / " << *opr0 << "\n");
948 Constant *cnval = ConstantFP::get(eltType, 1.0);
951 }
952 Value *nval = B.CreateFDiv(cnval, opr0, "__powrecip");
954 return true;
955 }
956
958
963 FInfo))) {
964 LLVM_DEBUG(errs() << "AMDIC: " << *FPOp << " ---> " << FInfo.getName()
965 << '(' << *opr0 << ")\n");
967 : "__pow2rsqrt");
969 return true;
970 }
971 }
972
974 return false;
975
976
977
978
979 if (CF) {
983 int ival = (int)dval;
984 if ((double)ival == dval) {
985 ci_opr1 = ival;
986 } else
987 ci_opr1 = 0x11111111;
988 }
989
990
991
992 unsigned abs_opr1 = (ci_opr1 < 0) ? -ci_opr1 : ci_opr1;
993 if (abs_opr1 <= 12) {
996 if (abs_opr1 == 0) {
997 cnval = ConstantFP::get(eltType, 1.0);
1000 }
1001 nval = cnval;
1002 } else {
1003 Value *valx2 = nullptr;
1004 nval = nullptr;
1005 while (abs_opr1 > 0) {
1006 valx2 = valx2 ? B.CreateFMul(valx2, valx2, "__powx2") : opr0;
1007 if (abs_opr1 & 1) {
1008 nval = nval ? B.CreateFMul(nval, valx2, "__powprod") : valx2;
1009 }
1010 abs_opr1 >>= 1;
1011 }
1012 }
1013
1014 if (ci_opr1 < 0) {
1015 cnval = ConstantFP::get(eltType, 1.0);
1018 }
1019 nval = B.CreateFDiv(cnval, nval, "__1powprod");
1020 }
1022 << ((ci_opr1 < 0) ? "1/prod(" : "prod(") << *opr0
1023 << ")\n");
1025 return true;
1026 }
1027
1028
1029 const bool ShouldUseIntrinsic = eltType->isFloatTy() || eltType->isHalfTy();
1030
1031
1032
1034 if (ShouldUseIntrinsic)
1037 else {
1039 if (!ExpExpr)
1040 return false;
1041 }
1042
1043 bool needlog = false;
1044 bool needabs = false;
1045 bool needcopysign = false;
1048 CF = nullptr;
1050
1051 if (CF) {
1055
1057 cnval = ConstantFP::get(eltType, V);
1060 } else {
1061 needlog = true;
1063 }
1064 } else {
1066
1067 if (!CDV) {
1068 needlog = true;
1070 } else {
1072 "Wrong vector size detected");
1073
1075 for (int i=0; i < getVecSize(FInfo); ++i) {
1077 if (V < 0.0) needcopysign = true;
1080 }
1083 for (double D : DVal)
1087 } else {
1090 }
1091 }
1092 }
1093
1095
1096
1098 return false;
1099 }
1100
1102 if (needabs) {
1103 nval = B.CreateUnaryIntrinsic(Intrinsic::fabs, opr0, nullptr, "__fabs");
1104 } else {
1105 nval = cnval ? cnval : opr0;
1106 }
1107 if (needlog) {
1109 if (ShouldUseIntrinsic) {
1112 } else {
1114 if (!LogExpr)
1115 return false;
1116 }
1117
1119 }
1120
1122
1123 opr1 = B.CreateSIToFP(opr1, nval->getType(), "pownI2F");
1124 }
1125 nval = B.CreateFMul(opr1, nval, "__ylogx");
1127
1128 if (needcopysign) {
1134 opr_n = B.CreateZExtOrTrunc(opr_n, nTy, "__ytou");
1135 else
1136 opr_n = B.CreateFPToSI(opr1, nTy, "__ytou");
1137
1138 Value *sign = B.CreateShl(opr_n, size-1, "__yeven");
1139 sign = B.CreateAnd(B.CreateBitCast(opr0, nTy), sign, "__pow_sign");
1140 nval = B.CreateOr(B.CreateBitCast(nval, nTy), sign);
1141 nval = B.CreateBitCast(nval, opr0->getType());
1142 }
1143
1145 << "exp2(" << *opr1 << " * log2(" << *opr0 << "))\n");
1147
1148 return true;
1149}
1150
1152 const FuncInfo &FInfo) {
1155
1156 const APInt *CINT = nullptr;
1158 return false;
1159
1160 Function *Parent = B.GetInsertBlock()->getParent();
1161
1163 if (ci_opr1 == 1 && !Parent->hasFnAttribute(Attribute::StrictFP)) {
1164
1165
1166
1167 LLVM_DEBUG(errs() << "AMDIC: " << *FPOp << " ---> " << *opr0 << '\n');
1169 return true;
1170 }
1171
1172 Module *M = B.GetInsertBlock()->getModule();
1173
1174 CallInst *CI = cast(FPOp);
1175 if (ci_opr1 == 2 &&
1176 shouldReplaceLibcallWithIntrinsic(CI,
1177 true,
1178 true)) {
1179
1180 LLVM_DEBUG(errs() << "AMDIC: " << *FPOp << " ---> sqrt(" << *opr0 << ")\n");
1181
1182 CallInst *NewCall = B.CreateUnaryIntrinsic(Intrinsic::sqrt, opr0, CI);
1184
1185
1186
1187 MDBuilder MDHelper(M->getContext());
1188 MDNode *FPMD = MDHelper.createFPMath(std::max(FPOp->getFPAccuracy(), 2.0f));
1189 NewCall->setMetadata(LLVMContext::MD_fpmath, FPMD);
1190
1192 return true;
1193 }
1194
1195 if (ci_opr1 == 3) {
1198 LLVM_DEBUG(errs() << "AMDIC: " << *FPOp << " ---> cbrt(" << *opr0
1199 << ")\n");
1202 return true;
1203 }
1204 } else if (ci_opr1 == -1) {
1205 LLVM_DEBUG(errs() << "AMDIC: " << *FPOp << " ---> 1.0 / " << *opr0 << "\n");
1206 Value *nval = B.CreateFDiv(ConstantFP::get(opr0->getType(), 1.0),
1207 opr0,
1208 "__rootn2div");
1210 return true;
1211 }
1212
1213 if (ci_opr1 == -2 &&
1214 shouldReplaceLibcallWithIntrinsic(CI,
1215 true,
1216 true)) {
1217
1218
1219
1220
1221 MDBuilder MDHelper(M->getContext());
1222 MDNode *FPMD = MDHelper.createFPMath(std::max(FPOp->getFPAccuracy(), 2.0f));
1223
1224
1227
1228 CallInst *Sqrt = B.CreateUnaryIntrinsic(Intrinsic::sqrt, opr0, CI);
1230 B.CreateFDiv(ConstantFP::get(opr0->getType(), 1.0), Sqrt));
1233 RSqrt->setMetadata(LLVMContext::MD_fpmath, FPMD);
1234
1235 LLVM_DEBUG(errs() << "AMDIC: " << *FPOp << " ---> rsqrt(" << *opr0
1236 << ")\n");
1238 return true;
1239 }
1240
1241 return false;
1242}
1243
1244
1246 const FuncInfo &FInfo) {
1248 return nullptr;
1249 FuncInfo nf = FInfo;
1251 return getFunction(M, nf);
1252}
1253
1254
1255
1256
1257bool AMDGPULibCalls::shouldReplaceLibcallWithIntrinsic(const CallInst *CI,
1258 bool AllowMinSizeF32,
1259 bool AllowF64,
1260 bool AllowStrictFP) {
1262 const bool IsF32 = FltTy->isFloatTy();
1263
1264
1265 if (!IsF32 && !FltTy->isHalfTy() && (!AllowF64 || !FltTy->isDoubleTy()))
1266 return false;
1267
1268
1269
1271 return false;
1272
1274
1275 if (!AllowStrictFP && ParentF->hasFnAttribute(Attribute::StrictFP))
1276 return false;
1277
1278 if (IsF32 && !AllowMinSizeF32 && ParentF->hasMinSize())
1279 return false;
1280 return true;
1281}
1282
1283void AMDGPULibCalls::replaceLibCallWithSimpleIntrinsic(IRBuilder<> &B,
1291 if (Arg0VecTy && !Arg1VecTy) {
1292 Value *SplatRHS = B.CreateVectorSplat(Arg0VecTy->getElementCount(), Arg1);
1294 } else if (!Arg0VecTy && Arg1VecTy) {
1295 Value *SplatLHS = B.CreateVectorSplat(Arg1VecTy->getElementCount(), Arg0);
1297 }
1298 }
1299
1301 CI->getModule(), IntrID, {CI->getType()}));
1302}
1303
1304bool AMDGPULibCalls::tryReplaceLibcallWithSimpleIntrinsic(
1306 bool AllowF64, bool AllowStrictFP) {
1307 if (!shouldReplaceLibcallWithIntrinsic(CI, AllowMinSizeF32, AllowF64,
1308 AllowStrictFP))
1309 return false;
1310 replaceLibCallWithSimpleIntrinsic(B, CI, IntrID);
1311 return true;
1312}
1313
1314std::tuple<Value *, Value *, Value *>
1317 DebugLoc DL = B.getCurrentDebugLocation();
1318 Function *F = B.GetInsertBlock()->getParent();
1319 B.SetInsertPointPastAllocas(F);
1320
1322
1323 if (Instruction *ArgInst = dyn_cast(Arg)) {
1324
1325
1326
1327
1328 B.SetInsertPoint(ArgInst->getParent(), ++ArgInst->getIterator());
1329
1330
1331 B.SetCurrentDebugLocation(DL);
1332 }
1333
1335
1336
1337
1338
1339 Value *CastAlloc = B.CreateAddrSpaceCast(Alloc, CosPtrTy);
1340
1342
1343
1344
1345
1347 return {SinCos, LoadCos, SinCos};
1348}
1349
1350
1352 const FuncInfo &fInfo) {
1355
1359 return false;
1360
1362
1364 CallInst *CI = cast(FPOp);
1365
1366 Function *F = B.GetInsertBlock()->getParent();
1368
1369
1370
1372 SinCosLibFuncPrivate.getLeads()[0].PtrKind =
1374
1376 SinCosLibFuncGeneric.getLeads()[0].PtrKind =
1378
1379 FunctionCallee FSinCosPrivate = getFunction(M, SinCosLibFuncPrivate);
1380 FunctionCallee FSinCosGeneric = getFunction(M, SinCosLibFuncGeneric);
1381 FunctionCallee FSinCos = FSinCosPrivate ? FSinCosPrivate : FSinCosGeneric;
1382 if (!FSinCos)
1383 return false;
1384
1389 fInfo);
1390 const std::string PairName = PartnerInfo.mangle();
1391
1394 const std::string SinCosPrivateName = SinCosLibFuncPrivate.mangle();
1395 const std::string SinCosGenericName = SinCosLibFuncGeneric.mangle();
1396
1397
1400
1402
1403 for (User* U : CArgVal->users()) {
1404 CallInst *XI = dyn_cast(U);
1406 continue;
1407
1409 if (!UCallee)
1410 continue;
1411
1412 bool Handled = true;
1413
1414 if (UCallee->getName() == SinName)
1416 else if (UCallee->getName() == CosName)
1418 else if (UCallee->getName() == SinCosPrivateName ||
1419 UCallee->getName() == SinCosGenericName)
1421 else
1422 Handled = false;
1423
1424 if (Handled) {
1426 auto *OtherOp = cast(XI);
1427 FMF &= OtherOp->getFastMathFlags();
1429 FPMath, XI->getMetadata(LLVMContext::MD_fpmath));
1430 }
1431 }
1432
1433 if (SinCalls.empty() || CosCalls.empty())
1434 return false;
1435
1436 B.setFastMathFlags(FMF);
1437 B.setDefaultFPMathTag(FPMath);
1439 B.SetCurrentDebugLocation(DbgLoc);
1440
1441 auto [Sin, Cos, SinCos] = insertSinCos(CArgVal, FMF, B, FSinCos);
1442
1445 C->replaceAllUsesWith(Res);
1446
1447
1448 };
1449
1450 replaceTrigInsts(SinCalls, Sin);
1451 replaceTrigInsts(CosCalls, Cos);
1452 replaceTrigInsts(SinCosCalls, SinCos);
1453
1454
1456 return true;
1457}
1458
1459bool AMDGPULibCalls::evaluateScalarMathFunc(const FuncInfo &FInfo, double &Res0,
1460 double &Res1, Constant *copr0,
1462
1463
1464
1465 double opr0 = 0.0, opr1 = 0.0;
1466 ConstantFP *fpopr0 = dyn_cast_or_null(copr0);
1467 ConstantFP *fpopr1 = dyn_cast_or_null(copr1);
1468 if (fpopr0) {
1472 }
1473
1474 if (fpopr1) {
1478 }
1479
1480 switch (FInfo.getId()) {
1481 default : return false;
1482
1484 Res0 = acos(opr0);
1485 return true;
1486
1488
1489 Res0 = log(opr0 + sqrt(opr0*opr0 - 1.0));
1490 return true;
1491
1493 Res0 = acos(opr0) / MATH_PI;
1494 return true;
1495
1497 Res0 = asin(opr0);
1498 return true;
1499
1501
1502 Res0 = log(opr0 + sqrt(opr0*opr0 + 1.0));
1503 return true;
1504
1506 Res0 = asin(opr0) / MATH_PI;
1507 return true;
1508
1510 Res0 = atan(opr0);
1511 return true;
1512
1514
1515 Res0 = (log(opr0 + 1.0) - log(opr0 - 1.0))/2.0;
1516 return true;
1517
1519 Res0 = atan(opr0) / MATH_PI;
1520 return true;
1521
1523 Res0 = (opr0 < 0.0) ? -pow(-opr0, 1.0/3.0) : pow(opr0, 1.0/3.0);
1524 return true;
1525
1527 Res0 = cos(opr0);
1528 return true;
1529
1531 Res0 = cosh(opr0);
1532 return true;
1533
1535 Res0 = cos(MATH_PI * opr0);
1536 return true;
1537
1539 Res0 = exp(opr0);
1540 return true;
1541
1543 Res0 = pow(2.0, opr0);
1544 return true;
1545
1547 Res0 = pow(10.0, opr0);
1548 return true;
1549
1551 Res0 = log(opr0);
1552 return true;
1553
1555 Res0 = log(opr0) / log(2.0);
1556 return true;
1557
1559 Res0 = log(opr0) / log(10.0);
1560 return true;
1561
1563 Res0 = 1.0 / sqrt(opr0);
1564 return true;
1565
1567 Res0 = sin(opr0);
1568 return true;
1569
1571 Res0 = sinh(opr0);
1572 return true;
1573
1575 Res0 = sin(MATH_PI * opr0);
1576 return true;
1577
1579 Res0 = tan(opr0);
1580 return true;
1581
1583 Res0 = tanh(opr0);
1584 return true;
1585
1587 Res0 = tan(MATH_PI * opr0);
1588 return true;
1589
1590
1593 Res0 = pow(opr0, opr1);
1594 return true;
1595
1597 if (ConstantInt *iopr1 = dyn_cast_or_null(copr1)) {
1598 double val = (double)iopr1->getSExtValue();
1599 Res0 = pow(opr0, val);
1600 return true;
1601 }
1602 return false;
1603 }
1604
1606 if (ConstantInt *iopr1 = dyn_cast_or_null(copr1)) {
1607 double val = (double)iopr1->getSExtValue();
1608 Res0 = pow(opr0, 1.0 / val);
1609 return true;
1610 }
1611 return false;
1612 }
1613
1614
1616 Res0 = sin(opr0);
1617 Res1 = cos(opr0);
1618 return true;
1619 }
1620
1621 return false;
1622}
1623
1624bool AMDGPULibCalls::evaluateCall(CallInst *aCI, const FuncInfo &FInfo) {
1625 int numArgs = (int)aCI->arg_size();
1626 if (numArgs > 3)
1627 return false;
1628
1631 if (numArgs > 0) {
1632 if ((copr0 = dyn_cast(aCI->getArgOperand(0))) == nullptr)
1633 return false;
1634 }
1635
1636 if (numArgs > 1) {
1637 if ((copr1 = dyn_cast(aCI->getArgOperand(1))) == nullptr) {
1639 return false;
1640 }
1641 }
1642
1643
1644
1645
1646 double DVal0[16], DVal1[16];
1647 int FuncVecSize = getVecSize(FInfo);
1649 if (FuncVecSize == 1) {
1650 if (!evaluateScalarMathFunc(FInfo, DVal0[0], DVal1[0], copr0, copr1)) {
1651 return false;
1652 }
1653 } else {
1654 ConstantDataVector *CDV0 = dyn_cast_or_null(copr0);
1655 ConstantDataVector *CDV1 = dyn_cast_or_null(copr1);
1656 for (int i = 0; i < FuncVecSize; ++i) {
1659 if (!evaluateScalarMathFunc(FInfo, DVal0[i], DVal1[i], celt0, celt1)) {
1660 return false;
1661 }
1662 }
1663 }
1664
1667 if (FuncVecSize == 1) {
1668 nval0 = ConstantFP::get(aCI->getType(), DVal0[0]);
1669 if (hasTwoResults)
1670 nval1 = ConstantFP::get(aCI->getType(), DVal1[0]);
1671 } else {
1673 SmallVector <float, 0> FVal0, FVal1;
1674 for (int i = 0; i < FuncVecSize; ++i)
1675 FVal0.push_back((float)DVal0[i]);
1678 if (hasTwoResults) {
1679 for (int i = 0; i < FuncVecSize; ++i)
1680 FVal1.push_back((float)DVal1[i]);
1683 }
1684 } else {
1687 if (hasTwoResults) {
1690 }
1691 }
1692 }
1693
1694 if (hasTwoResults) {
1695
1697 "math function with ptr arg not supported yet");
1699 }
1700
1702 return true;
1703}
1704
1710
1711 bool Changed = false;
1712
1714 F.printAsOperand(dbgs(), false, F.getParent()); dbgs() << '\n';);
1715
1716 for (auto &BB : F) {
1718
1719 CallInst *CI = dyn_cast(I);
1720 ++I;
1721
1722 if (CI) {
1723 if (Simplifier.fold(CI))
1724 Changed = true;
1725 }
1726 }
1727 }
1729}
1730
1735
1739
1740 bool Changed = false;
1741 for (auto &BB : F) {
1743
1744 CallInst *CI = dyn_cast(I);
1745 ++I;
1746 if (CI && Simplifier.useNative(CI))
1747 Changed = true;
1748 }
1749 }
1751}
static bool isKnownIntegral(const Value *V, const DataLayout &DL, FastMathFlags FMF)
static const TableEntry tbl_log[]
static const TableEntry tbl_tgamma[]
static AMDGPULibFunc::EType getArgType(const AMDGPULibFunc &FInfo)
static const TableEntry tbl_expm1[]
static const TableEntry tbl_asinpi[]
static const TableEntry tbl_cos[]
static const TableEntry tbl_exp10[]
static CallInst * CreateCallEx(IRB &B, FunctionCallee Callee, Value *Arg, const Twine &Name="")
static CallInst * CreateCallEx2(IRB &B, FunctionCallee Callee, Value *Arg1, Value *Arg2, const Twine &Name="")
static const TableEntry tbl_rsqrt[]
static const TableEntry tbl_atanh[]
static const TableEntry tbl_cosh[]
static const TableEntry tbl_asin[]
static const TableEntry tbl_sinh[]
static const TableEntry tbl_acos[]
static const TableEntry tbl_tan[]
static const TableEntry tbl_cospi[]
static const TableEntry tbl_tanpi[]
static cl::opt< bool > EnablePreLink("amdgpu-prelink", cl::desc("Enable pre-link mode optimizations"), cl::init(false), cl::Hidden)
static bool HasNative(AMDGPULibFunc::EFuncId id)
ArrayRef< TableEntry > TableRef
static int getVecSize(const AMDGPULibFunc &FInfo)
static const TableEntry tbl_sin[]
static const TableEntry tbl_atan[]
static const TableEntry tbl_log2[]
static const TableEntry tbl_acospi[]
static const TableEntry tbl_sqrt[]
static const TableEntry tbl_asinh[]
static TableRef getOptTable(AMDGPULibFunc::EFuncId id)
static const TableEntry tbl_acosh[]
static const TableEntry tbl_exp[]
static const TableEntry tbl_cbrt[]
static const TableEntry tbl_sinpi[]
static const TableEntry tbl_atanpi[]
static FunctionType * getPownType(FunctionType *FT)
static const TableEntry tbl_erf[]
static const TableEntry tbl_log10[]
static const TableEntry tbl_erfc[]
static cl::list< std::string > UseNative("amdgpu-use-native", cl::desc("Comma separated list of functions to replace with native, or all"), cl::CommaSeparated, cl::ValueOptional, cl::Hidden)
static const TableEntry tbl_tanh[]
static const TableEntry tbl_exp2[]
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
#define DEBUG_WITH_TYPE(TYPE,...)
DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug information.
AMD GCN specific subclass of TargetSubtarget.
FunctionAnalysisManager FAM
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static void replaceCall(FPMathOperator *I, Value *With)
bool isUnsafeFiniteOnlyMath(const FPMathOperator *FPOp) const
bool canIncreasePrecisionOfConstantFold(const FPMathOperator *FPOp) const
static void replaceCall(Instruction *I, Value *With)
bool useNative(CallInst *CI)
void initFunction(Function &F, FunctionAnalysisManager &FAM)
bool isUnsafeMath(const FPMathOperator *FPOp) const
static unsigned getEPtrKindFromAddrSpace(unsigned AS)
Wrapper class for AMDGPULIbFuncImpl.
static bool parse(StringRef MangledName, AMDGPULibFunc &Ptr)
std::string getName() const
Get unmangled name for mangled library function and name for unmangled library function.
static FunctionCallee getOrInsertFunction(llvm::Module *M, const AMDGPULibFunc &fInfo)
void setPrefix(ENamePrefix PFX)
bool isCompatibleSignature(const Module &M, const FunctionType *FuncTy) const
Param * getLeads()
Get leading parameters for mangled lib functions.
ENamePrefix getPrefix() const
double convertToDouble() const
Converts this APFloat to host double value.
bool isExactlyValue(double V) const
We don't rely on operator== working on double values, as it returns true for things that are clearly ...
float convertToFloat() const
Converts this APFloat to host float value.
Class for arbitrary precision integers.
int64_t getSExtValue() const
Get sign extended value.
an instruction to allocate memory on the stack
A container for analyses that lazily runs them and caches their results.
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
bool empty() const
empty - Check if the array is empty.
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
InstListType::iterator iterator
Instruction iterators...
bool isNoBuiltin() const
Return true if the call should not be treated as a call to a builtin.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
bool isStrictFP() const
Determine if the call requires strict floating point semantics.
bool isNoInline() const
Return true if the call should not be inlined.
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
FunctionType * getFunctionType() const
Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
unsigned arg_size() const
AttributeList getAttributes() const
Return the attributes for this call.
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
unsigned getNumElements() const
Return the number of elements in the array or vector.
Constant * getElementAsConstant(unsigned i) const
Return a Constant for a specified index's element.
APFloat getElementAsAPFloat(unsigned i) const
If this is a sequential container of floating point type, return the specified element as an APFloat.
A vector constant whose element type is a simple 1/2/4/8-byte integer or float/double,...
static Constant * getSplat(unsigned NumElts, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
static Constant * get(LLVMContext &Context, ArrayRef< uint8_t > Elts)
get() constructors - Return a constant with vector type with an element count and element type matchi...
ConstantFP - Floating Point Values [float, double].
const APFloat & getValue() const
const APFloat & getValueAPF() const
bool isExactlyValue(const APFloat &V) const
We don't rely on operator== working on double values, as it returns true for things that are clearly ...
This is the shared class of boolean and integer constants.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Align getAlignValue() const
Return the constant as an llvm::Align, interpreting 0 as Align(1).
This is an important base class in LLVM.
Constant * getAggregateElement(unsigned Elt) const
For aggregates (struct/array/vector) return the constant that corresponds to the specified element if...
static DILocation * getMergedLocations(ArrayRef< DILocation * > Locs)
Try to combine the vector of locations passed as input in a single one.
A parsed version of the target data layout string in and methods for querying it.
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Utility class for floating point operations which can have information about relaxed accuracy require...
bool isFast() const
Test if this operation allows all non-strict floating-point transforms.
bool hasNoNaNs() const
Test if this operation's arguments and results are assumed not-NaN.
FastMathFlags getFastMathFlags() const
Convenience function for getting all the fast-math flags.
bool hasNoInfs() const
Test if this operation's arguments and results are assumed not-infinite.
bool hasApproxFunc() const
Test if this operation allows approximations of math library functions or intrinsics.
float getFPAccuracy() const
Get the maximum error permitted by this operation in ULPs.
Convenience struct for specifying and reasoning about fast-math flags.
void setAllowContract(bool B=true)
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
FunctionType * getFunctionType()
Class to represent function types.
Type * getParamType(unsigned i) const
Parameter type accessors.
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
bool hasMinSize() const
Optimize this function for minimum size (-Oz).
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
void setFastMathFlags(FastMathFlags FMF)
Convenience function for setting multiple fast-math flags on this instruction, which must be an opera...
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
const Function * getFunction() const
Return the function this instruction belongs to.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
This is an important class for using LLVM in a threaded context.
An instruction for reading from memory.
static MDNode * getMostGenericFPMath(MDNode *A, MDNode *B)
A Module instance is used to store all the information related to an LLVM module.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
StringRef - Represent a constant reference to a string, i.e.
Analysis pass providing the TargetLibraryInfo.
Provides information about what library functions are available for the current target.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
bool isFloatTy() const
Return true if this is 'float', a 32-bit IEEE fp type.
unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
bool isHalfTy() const
Return true if this is 'half', a 16-bit IEEE fp type.
Type * getWithNewType(Type *EltTy) const
Given vector type, change the element type, whilst keeping the old number of elements.
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
static IntegerType * getInt32Ty(LLVMContext &C)
bool isIntegerTy() const
True if this is an instance of IntegerType.
TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
void dropAllReferences()
Drop all references to operands.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
LLVMContext & getContext() const
All values hold a context through their type.
StringRef getName() const
Return a constant reference to the value's name.
void takeName(Value *V)
Transfer the name from V to this value.
Base class of all SIMD vector types.
const ParentTy * getParent() const
self_iterator getIterator()
@ FLAT_ADDRESS
Address space for flat memory.
@ PRIVATE_ADDRESS
Address space for private memory.
APInt pow(const APInt &X, int64_t N)
Compute X^N for N>=0.
AttributeMask typeIncompatible(Type *Ty, AttributeSet AS, AttributeSafetyKind ASK=ASK_ALL)
Which attributes cannot be applied to a type.
@ C
The default llvm calling convention, compatible with C.
Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
bool match(Val *V, const Pattern &P)
apint_match m_APIntAllowPoison(const APInt *&Res)
Match APInt while allowing poison in splat vector constants.
apfloat_match m_APFloatAllowPoison(const APFloat *&Res)
Match APFloat while allowing poison in splat vector constants.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
static double log2(double V)
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
bool isKnownNeverInfinity(const Value *V, unsigned Depth, const SimplifyQuery &SQ)
Return true if the floating-point scalar value is not an infinity or if the floating-point vector val...
bool isKnownNeverInfOrNaN(const Value *V, unsigned Depth, const SimplifyQuery &SQ)
Return true if the floating-point value can never contain a NaN or infinity.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
bool cannotBeOrderedLessThanZero(const Value *V, unsigned Depth, const SimplifyQuery &SQ)
Return true if we can prove that the specified FP value is either NaN or never less than -0....
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
This struct is a compact representation of a valid (non-zero power of two) alignment.