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 (F)

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 (F)

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 (I)

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

1056 V = log2(std::abs(V));

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;

1078 V = log2(std::abs(V));

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.