1bdd1243dSDimitry Andric //===--- ExpandLargeFpConvert.cpp - Expand large fp convert----------------===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric // 9bdd1243dSDimitry Andric 10bdd1243dSDimitry Andric // This pass expands ‘fptoui .. to’, ‘fptosi .. to’, ‘uitofp .. to’, 11bdd1243dSDimitry Andric // ‘sitofp .. to’ instructions with a bitwidth above a threshold into 12bdd1243dSDimitry Andric // auto-generated functions. This is useful for targets like x86_64 that cannot 13bdd1243dSDimitry Andric // lower fp convertions with more than 128 bits. 14bdd1243dSDimitry Andric // 15bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 16bdd1243dSDimitry Andric 175f757f3fSDimitry Andric #include "llvm/CodeGen/ExpandLargeFpConvert.h" 18bdd1243dSDimitry Andric #include "llvm/ADT/SmallVector.h" 19bdd1243dSDimitry Andric #include "llvm/ADT/StringExtras.h" 20bdd1243dSDimitry Andric #include "llvm/Analysis/GlobalsModRef.h" 21bdd1243dSDimitry Andric #include "llvm/CodeGen/Passes.h" 22bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetLowering.h" 23bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 24bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 25bdd1243dSDimitry Andric #include "llvm/IR/IRBuilder.h" 26bdd1243dSDimitry Andric #include "llvm/IR/InstIterator.h" 27bdd1243dSDimitry Andric #include "llvm/IR/PassManager.h" 28bdd1243dSDimitry Andric #include "llvm/InitializePasses.h" 29bdd1243dSDimitry Andric #include "llvm/Pass.h" 30bdd1243dSDimitry Andric #include "llvm/Support/CommandLine.h" 31bdd1243dSDimitry Andric #include "llvm/Target/TargetMachine.h" 32bdd1243dSDimitry Andric 33bdd1243dSDimitry Andric using namespace llvm; 34bdd1243dSDimitry Andric 35bdd1243dSDimitry Andric static cl::opt<unsigned> 36bdd1243dSDimitry Andric ExpandFpConvertBits("expand-fp-convert-bits", cl::Hidden, 37bdd1243dSDimitry Andric cl::init(llvm::IntegerType::MAX_INT_BITS), 38bdd1243dSDimitry Andric cl::desc("fp convert instructions on integers with " 39bdd1243dSDimitry Andric "more than <N> bits are expanded.")); 40bdd1243dSDimitry Andric 41bdd1243dSDimitry Andric /// Generate code to convert a fp number to integer, replacing FPToS(U)I with 42bdd1243dSDimitry Andric /// the generated code. This currently generates code similarly to compiler-rt's 43bdd1243dSDimitry Andric /// implementations. 44bdd1243dSDimitry Andric /// 45bdd1243dSDimitry Andric /// An example IR generated from compiler-rt/fixsfdi.c looks like below: 46bdd1243dSDimitry Andric /// define dso_local i64 @foo(float noundef %a) local_unnamed_addr #0 { 47bdd1243dSDimitry Andric /// entry: 48bdd1243dSDimitry Andric /// %0 = bitcast float %a to i32 49bdd1243dSDimitry Andric /// %conv.i = zext i32 %0 to i64 50bdd1243dSDimitry Andric /// %tobool.not = icmp sgt i32 %0, -1 51bdd1243dSDimitry Andric /// %conv = select i1 %tobool.not, i64 1, i64 -1 52bdd1243dSDimitry Andric /// %and = lshr i64 %conv.i, 23 53bdd1243dSDimitry Andric /// %shr = and i64 %and, 255 54bdd1243dSDimitry Andric /// %and2 = and i64 %conv.i, 8388607 55bdd1243dSDimitry Andric /// %or = or i64 %and2, 8388608 56bdd1243dSDimitry Andric /// %cmp = icmp ult i64 %shr, 127 57bdd1243dSDimitry Andric /// br i1 %cmp, label %cleanup, label %if.end 58bdd1243dSDimitry Andric /// 59bdd1243dSDimitry Andric /// if.end: ; preds = %entry 60bdd1243dSDimitry Andric /// %sub = add nuw nsw i64 %shr, 4294967169 61bdd1243dSDimitry Andric /// %conv5 = and i64 %sub, 4294967232 62bdd1243dSDimitry Andric /// %cmp6.not = icmp eq i64 %conv5, 0 63bdd1243dSDimitry Andric /// br i1 %cmp6.not, label %if.end12, label %if.then8 64bdd1243dSDimitry Andric /// 65bdd1243dSDimitry Andric /// if.then8: ; preds = %if.end 66bdd1243dSDimitry Andric /// %cond11 = select i1 %tobool.not, i64 9223372036854775807, i64 -9223372036854775808 67bdd1243dSDimitry Andric /// br label %cleanup 68bdd1243dSDimitry Andric /// 69bdd1243dSDimitry Andric /// if.end12: ; preds = %if.end 70bdd1243dSDimitry Andric /// %cmp13 = icmp ult i64 %shr, 150 71bdd1243dSDimitry Andric /// br i1 %cmp13, label %if.then15, label %if.else 72bdd1243dSDimitry Andric /// 73bdd1243dSDimitry Andric /// if.then15: ; preds = %if.end12 74bdd1243dSDimitry Andric /// %sub16 = sub nuw nsw i64 150, %shr 75bdd1243dSDimitry Andric /// %shr17 = lshr i64 %or, %sub16 76bdd1243dSDimitry Andric /// %mul = mul nsw i64 %shr17, %conv 77bdd1243dSDimitry Andric /// br label %cleanup 78bdd1243dSDimitry Andric /// 79bdd1243dSDimitry Andric /// if.else: ; preds = %if.end12 80bdd1243dSDimitry Andric /// %sub18 = add nsw i64 %shr, -150 81bdd1243dSDimitry Andric /// %shl = shl i64 %or, %sub18 82bdd1243dSDimitry Andric /// %mul19 = mul nsw i64 %shl, %conv 83bdd1243dSDimitry Andric /// br label %cleanup 84bdd1243dSDimitry Andric /// 85bdd1243dSDimitry Andric /// cleanup: ; preds = %entry, %if.else, %if.then15, %if.then8 86bdd1243dSDimitry Andric /// %retval.0 = phi i64 [ %cond11, %if.then8 ], [ %mul, %if.then15 ], [ %mul19, %if.else ], [ 0, %entry ] 87bdd1243dSDimitry Andric /// ret i64 %retval.0 88bdd1243dSDimitry Andric /// } 89bdd1243dSDimitry Andric /// 90bdd1243dSDimitry Andric /// Replace fp to integer with generated code. 91bdd1243dSDimitry Andric static void expandFPToI(Instruction *FPToI) { 92bdd1243dSDimitry Andric IRBuilder<> Builder(FPToI); 93bdd1243dSDimitry Andric auto *FloatVal = FPToI->getOperand(0); 94bdd1243dSDimitry Andric IntegerType *IntTy = cast<IntegerType>(FPToI->getType()); 95bdd1243dSDimitry Andric 96bdd1243dSDimitry Andric unsigned BitWidth = FPToI->getType()->getIntegerBitWidth(); 97bdd1243dSDimitry Andric unsigned FPMantissaWidth = FloatVal->getType()->getFPMantissaWidth() - 1; 98bdd1243dSDimitry Andric 99bdd1243dSDimitry Andric // FIXME: fp16's range is covered by i32. So `fptoi half` can convert 100bdd1243dSDimitry Andric // to i32 first following a sext/zext to target integer type. 101bdd1243dSDimitry Andric Value *A1 = nullptr; 102bdd1243dSDimitry Andric if (FloatVal->getType()->isHalfTy()) { 103bdd1243dSDimitry Andric if (FPToI->getOpcode() == Instruction::FPToUI) { 104bdd1243dSDimitry Andric Value *A0 = Builder.CreateFPToUI(FloatVal, Builder.getIntNTy(32)); 105bdd1243dSDimitry Andric A1 = Builder.CreateZExt(A0, IntTy); 106bdd1243dSDimitry Andric } else { // FPToSI 107bdd1243dSDimitry Andric Value *A0 = Builder.CreateFPToSI(FloatVal, Builder.getIntNTy(32)); 108bdd1243dSDimitry Andric A1 = Builder.CreateSExt(A0, IntTy); 109bdd1243dSDimitry Andric } 110bdd1243dSDimitry Andric FPToI->replaceAllUsesWith(A1); 111bdd1243dSDimitry Andric FPToI->dropAllReferences(); 112bdd1243dSDimitry Andric FPToI->eraseFromParent(); 113bdd1243dSDimitry Andric return; 114bdd1243dSDimitry Andric } 115bdd1243dSDimitry Andric 116bdd1243dSDimitry Andric // fp80 conversion is implemented by fpext to fp128 first then do the 117bdd1243dSDimitry Andric // conversion. 118bdd1243dSDimitry Andric FPMantissaWidth = FPMantissaWidth == 63 ? 112 : FPMantissaWidth; 119*0fca6ea1SDimitry Andric unsigned FloatWidth = 120*0fca6ea1SDimitry Andric PowerOf2Ceil(FloatVal->getType()->getScalarSizeInBits()); 121bdd1243dSDimitry Andric unsigned ExponentWidth = FloatWidth - FPMantissaWidth - 1; 122bdd1243dSDimitry Andric unsigned ExponentBias = (1 << (ExponentWidth - 1)) - 1; 123bdd1243dSDimitry Andric Value *ImplicitBit = Builder.CreateShl( 124bdd1243dSDimitry Andric Builder.getIntN(BitWidth, 1), Builder.getIntN(BitWidth, FPMantissaWidth)); 125bdd1243dSDimitry Andric Value *SignificandMask = 126bdd1243dSDimitry Andric Builder.CreateSub(ImplicitBit, Builder.getIntN(BitWidth, 1)); 127bdd1243dSDimitry Andric Value *NegOne = Builder.CreateSExt( 128bdd1243dSDimitry Andric ConstantInt::getSigned(Builder.getInt32Ty(), -1), IntTy); 129bdd1243dSDimitry Andric Value *NegInf = 130bdd1243dSDimitry Andric Builder.CreateShl(ConstantInt::getSigned(IntTy, 1), 131bdd1243dSDimitry Andric ConstantInt::getSigned(IntTy, BitWidth - 1)); 132bdd1243dSDimitry Andric 133bdd1243dSDimitry Andric BasicBlock *Entry = Builder.GetInsertBlock(); 134bdd1243dSDimitry Andric Function *F = Entry->getParent(); 135bdd1243dSDimitry Andric Entry->setName(Twine(Entry->getName(), "fp-to-i-entry")); 136bdd1243dSDimitry Andric BasicBlock *End = 137bdd1243dSDimitry Andric Entry->splitBasicBlock(Builder.GetInsertPoint(), "fp-to-i-cleanup"); 138bdd1243dSDimitry Andric BasicBlock *IfEnd = 139bdd1243dSDimitry Andric BasicBlock::Create(Builder.getContext(), "fp-to-i-if-end", F, End); 140bdd1243dSDimitry Andric BasicBlock *IfThen5 = 141bdd1243dSDimitry Andric BasicBlock::Create(Builder.getContext(), "fp-to-i-if-then5", F, End); 142bdd1243dSDimitry Andric BasicBlock *IfEnd9 = 143bdd1243dSDimitry Andric BasicBlock::Create(Builder.getContext(), "fp-to-i-if-end9", F, End); 144bdd1243dSDimitry Andric BasicBlock *IfThen12 = 145bdd1243dSDimitry Andric BasicBlock::Create(Builder.getContext(), "fp-to-i-if-then12", F, End); 146bdd1243dSDimitry Andric BasicBlock *IfElse = 147bdd1243dSDimitry Andric BasicBlock::Create(Builder.getContext(), "fp-to-i-if-else", F, End); 148bdd1243dSDimitry Andric 149bdd1243dSDimitry Andric Entry->getTerminator()->eraseFromParent(); 150bdd1243dSDimitry Andric 151bdd1243dSDimitry Andric // entry: 152bdd1243dSDimitry Andric Builder.SetInsertPoint(Entry); 153bdd1243dSDimitry Andric Value *FloatVal0 = FloatVal; 154bdd1243dSDimitry Andric // fp80 conversion is implemented by fpext to fp128 first then do the 155bdd1243dSDimitry Andric // conversion. 156bdd1243dSDimitry Andric if (FloatVal->getType()->isX86_FP80Ty()) 157bdd1243dSDimitry Andric FloatVal0 = 158bdd1243dSDimitry Andric Builder.CreateFPExt(FloatVal, Type::getFP128Ty(Builder.getContext())); 159bdd1243dSDimitry Andric Value *ARep0 = 160bdd1243dSDimitry Andric Builder.CreateBitCast(FloatVal0, Builder.getIntNTy(FloatWidth)); 161bdd1243dSDimitry Andric Value *ARep = Builder.CreateZExt(ARep0, FPToI->getType()); 162bdd1243dSDimitry Andric Value *PosOrNeg = Builder.CreateICmpSGT( 163bdd1243dSDimitry Andric ARep0, ConstantInt::getSigned(Builder.getIntNTy(FloatWidth), -1)); 164bdd1243dSDimitry Andric Value *Sign = Builder.CreateSelect(PosOrNeg, ConstantInt::getSigned(IntTy, 1), 165bdd1243dSDimitry Andric ConstantInt::getSigned(IntTy, -1)); 166bdd1243dSDimitry Andric Value *And = 167bdd1243dSDimitry Andric Builder.CreateLShr(ARep, Builder.getIntN(BitWidth, FPMantissaWidth)); 168bdd1243dSDimitry Andric Value *And2 = Builder.CreateAnd( 169bdd1243dSDimitry Andric And, Builder.getIntN(BitWidth, (1 << ExponentWidth) - 1)); 170bdd1243dSDimitry Andric Value *Abs = Builder.CreateAnd(ARep, SignificandMask); 171bdd1243dSDimitry Andric Value *Or = Builder.CreateOr(Abs, ImplicitBit); 172bdd1243dSDimitry Andric Value *Cmp = 173bdd1243dSDimitry Andric Builder.CreateICmpULT(And2, Builder.getIntN(BitWidth, ExponentBias)); 174bdd1243dSDimitry Andric Builder.CreateCondBr(Cmp, End, IfEnd); 175bdd1243dSDimitry Andric 176bdd1243dSDimitry Andric // if.end: 177bdd1243dSDimitry Andric Builder.SetInsertPoint(IfEnd); 178bdd1243dSDimitry Andric Value *Add1 = Builder.CreateAdd( 179*0fca6ea1SDimitry Andric And2, ConstantInt::getSigned( 180*0fca6ea1SDimitry Andric IntTy, -static_cast<int64_t>(ExponentBias + BitWidth))); 181*0fca6ea1SDimitry Andric Value *Cmp3 = Builder.CreateICmpULT( 182*0fca6ea1SDimitry Andric Add1, ConstantInt::getSigned(IntTy, -static_cast<int64_t>(BitWidth))); 183bdd1243dSDimitry Andric Builder.CreateCondBr(Cmp3, IfThen5, IfEnd9); 184bdd1243dSDimitry Andric 185bdd1243dSDimitry Andric // if.then5: 186bdd1243dSDimitry Andric Builder.SetInsertPoint(IfThen5); 187bdd1243dSDimitry Andric Value *PosInf = Builder.CreateXor(NegOne, NegInf); 188bdd1243dSDimitry Andric Value *Cond8 = Builder.CreateSelect(PosOrNeg, PosInf, NegInf); 189bdd1243dSDimitry Andric Builder.CreateBr(End); 190bdd1243dSDimitry Andric 191bdd1243dSDimitry Andric // if.end9: 192bdd1243dSDimitry Andric Builder.SetInsertPoint(IfEnd9); 193bdd1243dSDimitry Andric Value *Cmp10 = Builder.CreateICmpULT( 194bdd1243dSDimitry Andric And2, Builder.getIntN(BitWidth, ExponentBias + FPMantissaWidth)); 195bdd1243dSDimitry Andric Builder.CreateCondBr(Cmp10, IfThen12, IfElse); 196bdd1243dSDimitry Andric 197bdd1243dSDimitry Andric // if.then12: 198bdd1243dSDimitry Andric Builder.SetInsertPoint(IfThen12); 199bdd1243dSDimitry Andric Value *Sub13 = Builder.CreateSub( 200bdd1243dSDimitry Andric Builder.getIntN(BitWidth, ExponentBias + FPMantissaWidth), And2); 201bdd1243dSDimitry Andric Value *Shr14 = Builder.CreateLShr(Or, Sub13); 202bdd1243dSDimitry Andric Value *Mul = Builder.CreateMul(Shr14, Sign); 203bdd1243dSDimitry Andric Builder.CreateBr(End); 204bdd1243dSDimitry Andric 205bdd1243dSDimitry Andric // if.else: 206bdd1243dSDimitry Andric Builder.SetInsertPoint(IfElse); 207bdd1243dSDimitry Andric Value *Sub15 = Builder.CreateAdd( 208*0fca6ea1SDimitry Andric And2, ConstantInt::getSigned( 209*0fca6ea1SDimitry Andric IntTy, -static_cast<int64_t>(ExponentBias + FPMantissaWidth))); 210bdd1243dSDimitry Andric Value *Shl = Builder.CreateShl(Or, Sub15); 211bdd1243dSDimitry Andric Value *Mul16 = Builder.CreateMul(Shl, Sign); 212bdd1243dSDimitry Andric Builder.CreateBr(End); 213bdd1243dSDimitry Andric 214bdd1243dSDimitry Andric // cleanup: 215bdd1243dSDimitry Andric Builder.SetInsertPoint(End, End->begin()); 216bdd1243dSDimitry Andric PHINode *Retval0 = Builder.CreatePHI(FPToI->getType(), 4); 217bdd1243dSDimitry Andric 218bdd1243dSDimitry Andric Retval0->addIncoming(Cond8, IfThen5); 219bdd1243dSDimitry Andric Retval0->addIncoming(Mul, IfThen12); 220bdd1243dSDimitry Andric Retval0->addIncoming(Mul16, IfElse); 221bdd1243dSDimitry Andric Retval0->addIncoming(Builder.getIntN(BitWidth, 0), Entry); 222bdd1243dSDimitry Andric 223bdd1243dSDimitry Andric FPToI->replaceAllUsesWith(Retval0); 224bdd1243dSDimitry Andric FPToI->dropAllReferences(); 225bdd1243dSDimitry Andric FPToI->eraseFromParent(); 226bdd1243dSDimitry Andric } 227bdd1243dSDimitry Andric 228bdd1243dSDimitry Andric /// Generate code to convert a fp number to integer, replacing S(U)IToFP with 229bdd1243dSDimitry Andric /// the generated code. This currently generates code similarly to compiler-rt's 230bdd1243dSDimitry Andric /// implementations. This implementation has an implicit assumption that integer 231bdd1243dSDimitry Andric /// width is larger than fp. 232bdd1243dSDimitry Andric /// 233bdd1243dSDimitry Andric /// An example IR generated from compiler-rt/floatdisf.c looks like below: 234bdd1243dSDimitry Andric /// define dso_local float @__floatdisf(i64 noundef %a) local_unnamed_addr #0 { 235bdd1243dSDimitry Andric /// entry: 236bdd1243dSDimitry Andric /// %cmp = icmp eq i64 %a, 0 237bdd1243dSDimitry Andric /// br i1 %cmp, label %return, label %if.end 238bdd1243dSDimitry Andric /// 239bdd1243dSDimitry Andric /// if.end: ; preds = %entry 240bdd1243dSDimitry Andric /// %shr = ashr i64 %a, 63 241bdd1243dSDimitry Andric /// %xor = xor i64 %shr, %a 242bdd1243dSDimitry Andric /// %sub = sub nsw i64 %xor, %shr 243bdd1243dSDimitry Andric /// %0 = tail call i64 @llvm.ctlz.i64(i64 %sub, i1 true), !range !5 244bdd1243dSDimitry Andric /// %cast = trunc i64 %0 to i32 245bdd1243dSDimitry Andric /// %sub1 = sub nuw nsw i32 64, %cast 246bdd1243dSDimitry Andric /// %sub2 = xor i32 %cast, 63 247bdd1243dSDimitry Andric /// %cmp3 = icmp ult i32 %cast, 40 248bdd1243dSDimitry Andric /// br i1 %cmp3, label %if.then4, label %if.else 249bdd1243dSDimitry Andric /// 250bdd1243dSDimitry Andric /// if.then4: ; preds = %if.end 251bdd1243dSDimitry Andric /// switch i32 %sub1, label %sw.default [ 252bdd1243dSDimitry Andric /// i32 25, label %sw.bb 253bdd1243dSDimitry Andric /// i32 26, label %sw.epilog 254bdd1243dSDimitry Andric /// ] 255bdd1243dSDimitry Andric /// 256bdd1243dSDimitry Andric /// sw.bb: ; preds = %if.then4 257bdd1243dSDimitry Andric /// %shl = shl i64 %sub, 1 258bdd1243dSDimitry Andric /// br label %sw.epilog 259bdd1243dSDimitry Andric /// 260bdd1243dSDimitry Andric /// sw.default: ; preds = %if.then4 261bdd1243dSDimitry Andric /// %sub5 = sub nsw i64 38, %0 262bdd1243dSDimitry Andric /// %sh_prom = and i64 %sub5, 4294967295 263bdd1243dSDimitry Andric /// %shr6 = lshr i64 %sub, %sh_prom 264bdd1243dSDimitry Andric /// %shr9 = lshr i64 274877906943, %0 265bdd1243dSDimitry Andric /// %and = and i64 %shr9, %sub 266bdd1243dSDimitry Andric /// %cmp10 = icmp ne i64 %and, 0 267bdd1243dSDimitry Andric /// %conv11 = zext i1 %cmp10 to i64 268bdd1243dSDimitry Andric /// %or = or i64 %shr6, %conv11 269bdd1243dSDimitry Andric /// br label %sw.epilog 270bdd1243dSDimitry Andric /// 271bdd1243dSDimitry Andric /// sw.epilog: ; preds = %sw.default, %if.then4, %sw.bb 272bdd1243dSDimitry Andric /// %a.addr.0 = phi i64 [ %or, %sw.default ], [ %sub, %if.then4 ], [ %shl, %sw.bb ] 273bdd1243dSDimitry Andric /// %1 = lshr i64 %a.addr.0, 2 274bdd1243dSDimitry Andric /// %2 = and i64 %1, 1 275bdd1243dSDimitry Andric /// %or16 = or i64 %2, %a.addr.0 276bdd1243dSDimitry Andric /// %inc = add nsw i64 %or16, 1 277bdd1243dSDimitry Andric /// %3 = and i64 %inc, 67108864 278bdd1243dSDimitry Andric /// %tobool.not = icmp eq i64 %3, 0 279bdd1243dSDimitry Andric /// %spec.select.v = select i1 %tobool.not, i64 2, i64 3 280bdd1243dSDimitry Andric /// %spec.select = ashr i64 %inc, %spec.select.v 281bdd1243dSDimitry Andric /// %spec.select56 = select i1 %tobool.not, i32 %sub2, i32 %sub1 282bdd1243dSDimitry Andric /// br label %if.end26 283bdd1243dSDimitry Andric /// 284bdd1243dSDimitry Andric /// if.else: ; preds = %if.end 285bdd1243dSDimitry Andric /// %sub23 = add nuw nsw i64 %0, 4294967256 286bdd1243dSDimitry Andric /// %sh_prom24 = and i64 %sub23, 4294967295 287bdd1243dSDimitry Andric /// %shl25 = shl i64 %sub, %sh_prom24 288bdd1243dSDimitry Andric /// br label %if.end26 289bdd1243dSDimitry Andric /// 290bdd1243dSDimitry Andric /// if.end26: ; preds = %sw.epilog, %if.else 291bdd1243dSDimitry Andric /// %a.addr.1 = phi i64 [ %shl25, %if.else ], [ %spec.select, %sw.epilog ] 292bdd1243dSDimitry Andric /// %e.0 = phi i32 [ %sub2, %if.else ], [ %spec.select56, %sw.epilog ] 293bdd1243dSDimitry Andric /// %conv27 = trunc i64 %shr to i32 294bdd1243dSDimitry Andric /// %and28 = and i32 %conv27, -2147483648 295bdd1243dSDimitry Andric /// %add = shl nuw nsw i32 %e.0, 23 296bdd1243dSDimitry Andric /// %shl29 = add nuw nsw i32 %add, 1065353216 297bdd1243dSDimitry Andric /// %conv31 = trunc i64 %a.addr.1 to i32 298bdd1243dSDimitry Andric /// %and32 = and i32 %conv31, 8388607 299bdd1243dSDimitry Andric /// %or30 = or i32 %and32, %and28 300bdd1243dSDimitry Andric /// %or33 = or i32 %or30, %shl29 301bdd1243dSDimitry Andric /// %4 = bitcast i32 %or33 to float 302bdd1243dSDimitry Andric /// br label %return 303bdd1243dSDimitry Andric /// 304bdd1243dSDimitry Andric /// return: ; preds = %entry, %if.end26 305bdd1243dSDimitry Andric /// %retval.0 = phi float [ %4, %if.end26 ], [ 0.000000e+00, %entry ] 306bdd1243dSDimitry Andric /// ret float %retval.0 307bdd1243dSDimitry Andric /// } 308bdd1243dSDimitry Andric /// 309bdd1243dSDimitry Andric /// Replace integer to fp with generated code. 310bdd1243dSDimitry Andric static void expandIToFP(Instruction *IToFP) { 311bdd1243dSDimitry Andric IRBuilder<> Builder(IToFP); 312bdd1243dSDimitry Andric auto *IntVal = IToFP->getOperand(0); 313bdd1243dSDimitry Andric IntegerType *IntTy = cast<IntegerType>(IntVal->getType()); 314bdd1243dSDimitry Andric 315bdd1243dSDimitry Andric unsigned BitWidth = IntVal->getType()->getIntegerBitWidth(); 316bdd1243dSDimitry Andric unsigned FPMantissaWidth = IToFP->getType()->getFPMantissaWidth() - 1; 317bdd1243dSDimitry Andric // fp80 conversion is implemented by conversion tp fp128 first following 318bdd1243dSDimitry Andric // a fptrunc to fp80. 319bdd1243dSDimitry Andric FPMantissaWidth = FPMantissaWidth == 63 ? 112 : FPMantissaWidth; 320bdd1243dSDimitry Andric // FIXME: As there is no related builtins added in compliler-rt, 321bdd1243dSDimitry Andric // here currently utilized the fp32 <-> fp16 lib calls to implement. 322bdd1243dSDimitry Andric FPMantissaWidth = FPMantissaWidth == 10 ? 23 : FPMantissaWidth; 323*0fca6ea1SDimitry Andric FPMantissaWidth = FPMantissaWidth == 7 ? 23 : FPMantissaWidth; 324bdd1243dSDimitry Andric unsigned FloatWidth = PowerOf2Ceil(FPMantissaWidth); 325bdd1243dSDimitry Andric bool IsSigned = IToFP->getOpcode() == Instruction::SIToFP; 326bdd1243dSDimitry Andric 327bdd1243dSDimitry Andric assert(BitWidth > FloatWidth && "Unexpected conversion. expandIToFP() " 328bdd1243dSDimitry Andric "assumes integer width is larger than fp."); 329bdd1243dSDimitry Andric 330bdd1243dSDimitry Andric Value *Temp1 = 331bdd1243dSDimitry Andric Builder.CreateShl(Builder.getIntN(BitWidth, 1), 332bdd1243dSDimitry Andric Builder.getIntN(BitWidth, FPMantissaWidth + 3)); 333bdd1243dSDimitry Andric 334bdd1243dSDimitry Andric BasicBlock *Entry = Builder.GetInsertBlock(); 335bdd1243dSDimitry Andric Function *F = Entry->getParent(); 336bdd1243dSDimitry Andric Entry->setName(Twine(Entry->getName(), "itofp-entry")); 337bdd1243dSDimitry Andric BasicBlock *End = 338bdd1243dSDimitry Andric Entry->splitBasicBlock(Builder.GetInsertPoint(), "itofp-return"); 339bdd1243dSDimitry Andric BasicBlock *IfEnd = 340bdd1243dSDimitry Andric BasicBlock::Create(Builder.getContext(), "itofp-if-end", F, End); 341bdd1243dSDimitry Andric BasicBlock *IfThen4 = 342bdd1243dSDimitry Andric BasicBlock::Create(Builder.getContext(), "itofp-if-then4", F, End); 343bdd1243dSDimitry Andric BasicBlock *SwBB = 344bdd1243dSDimitry Andric BasicBlock::Create(Builder.getContext(), "itofp-sw-bb", F, End); 345bdd1243dSDimitry Andric BasicBlock *SwDefault = 346bdd1243dSDimitry Andric BasicBlock::Create(Builder.getContext(), "itofp-sw-default", F, End); 347bdd1243dSDimitry Andric BasicBlock *SwEpilog = 348bdd1243dSDimitry Andric BasicBlock::Create(Builder.getContext(), "itofp-sw-epilog", F, End); 349bdd1243dSDimitry Andric BasicBlock *IfThen20 = 350bdd1243dSDimitry Andric BasicBlock::Create(Builder.getContext(), "itofp-if-then20", F, End); 351bdd1243dSDimitry Andric BasicBlock *IfElse = 352bdd1243dSDimitry Andric BasicBlock::Create(Builder.getContext(), "itofp-if-else", F, End); 353bdd1243dSDimitry Andric BasicBlock *IfEnd26 = 354bdd1243dSDimitry Andric BasicBlock::Create(Builder.getContext(), "itofp-if-end26", F, End); 355bdd1243dSDimitry Andric 356bdd1243dSDimitry Andric Entry->getTerminator()->eraseFromParent(); 357bdd1243dSDimitry Andric 358bdd1243dSDimitry Andric Function *CTLZ = 359bdd1243dSDimitry Andric Intrinsic::getDeclaration(F->getParent(), Intrinsic::ctlz, IntTy); 360bdd1243dSDimitry Andric ConstantInt *True = Builder.getTrue(); 361bdd1243dSDimitry Andric 362bdd1243dSDimitry Andric // entry: 363bdd1243dSDimitry Andric Builder.SetInsertPoint(Entry); 364bdd1243dSDimitry Andric Value *Cmp = Builder.CreateICmpEQ(IntVal, ConstantInt::getSigned(IntTy, 0)); 365bdd1243dSDimitry Andric Builder.CreateCondBr(Cmp, End, IfEnd); 366bdd1243dSDimitry Andric 367bdd1243dSDimitry Andric // if.end: 368bdd1243dSDimitry Andric Builder.SetInsertPoint(IfEnd); 369bdd1243dSDimitry Andric Value *Shr = 370bdd1243dSDimitry Andric Builder.CreateAShr(IntVal, Builder.getIntN(BitWidth, BitWidth - 1)); 371bdd1243dSDimitry Andric Value *Xor = Builder.CreateXor(Shr, IntVal); 372bdd1243dSDimitry Andric Value *Sub = Builder.CreateSub(Xor, Shr); 373bdd1243dSDimitry Andric Value *Call = Builder.CreateCall(CTLZ, {IsSigned ? Sub : IntVal, True}); 374bdd1243dSDimitry Andric Value *Cast = Builder.CreateTrunc(Call, Builder.getInt32Ty()); 375bdd1243dSDimitry Andric int BitWidthNew = FloatWidth == 128 ? BitWidth : 32; 376bdd1243dSDimitry Andric Value *Sub1 = Builder.CreateSub(Builder.getIntN(BitWidthNew, BitWidth), 377bdd1243dSDimitry Andric FloatWidth == 128 ? Call : Cast); 378bdd1243dSDimitry Andric Value *Sub2 = Builder.CreateSub(Builder.getIntN(BitWidthNew, BitWidth - 1), 379bdd1243dSDimitry Andric FloatWidth == 128 ? Call : Cast); 380bdd1243dSDimitry Andric Value *Cmp3 = Builder.CreateICmpSGT( 381*0fca6ea1SDimitry Andric Sub1, Builder.getIntN(BitWidthNew, FPMantissaWidth + 1)); 382bdd1243dSDimitry Andric Builder.CreateCondBr(Cmp3, IfThen4, IfElse); 383bdd1243dSDimitry Andric 384bdd1243dSDimitry Andric // if.then4: 385bdd1243dSDimitry Andric Builder.SetInsertPoint(IfThen4); 386bdd1243dSDimitry Andric llvm::SwitchInst *SI = Builder.CreateSwitch(Sub1, SwDefault); 387bdd1243dSDimitry Andric SI->addCase(Builder.getIntN(BitWidthNew, FPMantissaWidth + 2), SwBB); 388bdd1243dSDimitry Andric SI->addCase(Builder.getIntN(BitWidthNew, FPMantissaWidth + 3), SwEpilog); 389bdd1243dSDimitry Andric 390bdd1243dSDimitry Andric // sw.bb: 391bdd1243dSDimitry Andric Builder.SetInsertPoint(SwBB); 392bdd1243dSDimitry Andric Value *Shl = 393bdd1243dSDimitry Andric Builder.CreateShl(IsSigned ? Sub : IntVal, Builder.getIntN(BitWidth, 1)); 394bdd1243dSDimitry Andric Builder.CreateBr(SwEpilog); 395bdd1243dSDimitry Andric 396bdd1243dSDimitry Andric // sw.default: 397bdd1243dSDimitry Andric Builder.SetInsertPoint(SwDefault); 398bdd1243dSDimitry Andric Value *Sub5 = Builder.CreateSub( 399bdd1243dSDimitry Andric Builder.getIntN(BitWidthNew, BitWidth - FPMantissaWidth - 3), 400bdd1243dSDimitry Andric FloatWidth == 128 ? Call : Cast); 401bdd1243dSDimitry Andric Value *ShProm = Builder.CreateZExt(Sub5, IntTy); 402bdd1243dSDimitry Andric Value *Shr6 = Builder.CreateLShr(IsSigned ? Sub : IntVal, 403bdd1243dSDimitry Andric FloatWidth == 128 ? Sub5 : ShProm); 404bdd1243dSDimitry Andric Value *Sub8 = 405bdd1243dSDimitry Andric Builder.CreateAdd(FloatWidth == 128 ? Call : Cast, 406bdd1243dSDimitry Andric Builder.getIntN(BitWidthNew, FPMantissaWidth + 3)); 407bdd1243dSDimitry Andric Value *ShProm9 = Builder.CreateZExt(Sub8, IntTy); 408bdd1243dSDimitry Andric Value *Shr9 = Builder.CreateLShr(ConstantInt::getSigned(IntTy, -1), 409bdd1243dSDimitry Andric FloatWidth == 128 ? Sub8 : ShProm9); 410bdd1243dSDimitry Andric Value *And = Builder.CreateAnd(Shr9, IsSigned ? Sub : IntVal); 411bdd1243dSDimitry Andric Value *Cmp10 = Builder.CreateICmpNE(And, Builder.getIntN(BitWidth, 0)); 412bdd1243dSDimitry Andric Value *Conv11 = Builder.CreateZExt(Cmp10, IntTy); 413bdd1243dSDimitry Andric Value *Or = Builder.CreateOr(Shr6, Conv11); 414bdd1243dSDimitry Andric Builder.CreateBr(SwEpilog); 415bdd1243dSDimitry Andric 416bdd1243dSDimitry Andric // sw.epilog: 417bdd1243dSDimitry Andric Builder.SetInsertPoint(SwEpilog); 418bdd1243dSDimitry Andric PHINode *AAddr0 = Builder.CreatePHI(IntTy, 3); 419bdd1243dSDimitry Andric AAddr0->addIncoming(Or, SwDefault); 420bdd1243dSDimitry Andric AAddr0->addIncoming(IsSigned ? Sub : IntVal, IfThen4); 421bdd1243dSDimitry Andric AAddr0->addIncoming(Shl, SwBB); 422bdd1243dSDimitry Andric Value *A0 = Builder.CreateTrunc(AAddr0, Builder.getInt32Ty()); 423bdd1243dSDimitry Andric Value *A1 = Builder.CreateLShr(A0, Builder.getIntN(32, 2)); 424bdd1243dSDimitry Andric Value *A2 = Builder.CreateAnd(A1, Builder.getIntN(32, 1)); 425bdd1243dSDimitry Andric Value *Conv16 = Builder.CreateZExt(A2, IntTy); 426bdd1243dSDimitry Andric Value *Or17 = Builder.CreateOr(AAddr0, Conv16); 427bdd1243dSDimitry Andric Value *Inc = Builder.CreateAdd(Or17, Builder.getIntN(BitWidth, 1)); 428bdd1243dSDimitry Andric Value *Shr18 = nullptr; 429bdd1243dSDimitry Andric if (IsSigned) 430bdd1243dSDimitry Andric Shr18 = Builder.CreateAShr(Inc, Builder.getIntN(BitWidth, 2)); 431bdd1243dSDimitry Andric else 432bdd1243dSDimitry Andric Shr18 = Builder.CreateLShr(Inc, Builder.getIntN(BitWidth, 2)); 433bdd1243dSDimitry Andric Value *A3 = Builder.CreateAnd(Inc, Temp1, "a3"); 434bdd1243dSDimitry Andric Value *PosOrNeg = Builder.CreateICmpEQ(A3, Builder.getIntN(BitWidth, 0)); 435bdd1243dSDimitry Andric Value *ExtractT60 = Builder.CreateTrunc(Shr18, Builder.getIntNTy(FloatWidth)); 436bdd1243dSDimitry Andric Value *Extract63 = Builder.CreateLShr(Shr18, Builder.getIntN(BitWidth, 32)); 437bdd1243dSDimitry Andric Value *ExtractT64 = nullptr; 438bdd1243dSDimitry Andric if (FloatWidth > 80) 439bdd1243dSDimitry Andric ExtractT64 = Builder.CreateTrunc(Sub2, Builder.getInt64Ty()); 440bdd1243dSDimitry Andric else 441bdd1243dSDimitry Andric ExtractT64 = Builder.CreateTrunc(Extract63, Builder.getInt32Ty()); 442bdd1243dSDimitry Andric Builder.CreateCondBr(PosOrNeg, IfEnd26, IfThen20); 443bdd1243dSDimitry Andric 444bdd1243dSDimitry Andric // if.then20 445bdd1243dSDimitry Andric Builder.SetInsertPoint(IfThen20); 446bdd1243dSDimitry Andric Value *Shr21 = nullptr; 447bdd1243dSDimitry Andric if (IsSigned) 448bdd1243dSDimitry Andric Shr21 = Builder.CreateAShr(Inc, Builder.getIntN(BitWidth, 3)); 449bdd1243dSDimitry Andric else 450bdd1243dSDimitry Andric Shr21 = Builder.CreateLShr(Inc, Builder.getIntN(BitWidth, 3)); 451bdd1243dSDimitry Andric Value *ExtractT = Builder.CreateTrunc(Shr21, Builder.getIntNTy(FloatWidth)); 452bdd1243dSDimitry Andric Value *Extract = Builder.CreateLShr(Shr21, Builder.getIntN(BitWidth, 32)); 453bdd1243dSDimitry Andric Value *ExtractT62 = nullptr; 454bdd1243dSDimitry Andric if (FloatWidth > 80) 455bdd1243dSDimitry Andric ExtractT62 = Builder.CreateTrunc(Sub1, Builder.getIntNTy(64)); 456bdd1243dSDimitry Andric else 457bdd1243dSDimitry Andric ExtractT62 = Builder.CreateTrunc(Extract, Builder.getIntNTy(32)); 458bdd1243dSDimitry Andric Builder.CreateBr(IfEnd26); 459bdd1243dSDimitry Andric 460bdd1243dSDimitry Andric // if.else: 461bdd1243dSDimitry Andric Builder.SetInsertPoint(IfElse); 462bdd1243dSDimitry Andric Value *Sub24 = Builder.CreateAdd( 463bdd1243dSDimitry Andric FloatWidth == 128 ? Call : Cast, 464bdd1243dSDimitry Andric ConstantInt::getSigned(Builder.getIntNTy(BitWidthNew), 465bdd1243dSDimitry Andric -(BitWidth - FPMantissaWidth - 1))); 466bdd1243dSDimitry Andric Value *ShProm25 = Builder.CreateZExt(Sub24, IntTy); 467bdd1243dSDimitry Andric Value *Shl26 = Builder.CreateShl(IsSigned ? Sub : IntVal, 468bdd1243dSDimitry Andric FloatWidth == 128 ? Sub24 : ShProm25); 469bdd1243dSDimitry Andric Value *ExtractT61 = Builder.CreateTrunc(Shl26, Builder.getIntNTy(FloatWidth)); 470bdd1243dSDimitry Andric Value *Extract65 = Builder.CreateLShr(Shl26, Builder.getIntN(BitWidth, 32)); 471bdd1243dSDimitry Andric Value *ExtractT66 = nullptr; 472bdd1243dSDimitry Andric if (FloatWidth > 80) 473bdd1243dSDimitry Andric ExtractT66 = Builder.CreateTrunc(Sub2, Builder.getIntNTy(64)); 474bdd1243dSDimitry Andric else 475bdd1243dSDimitry Andric ExtractT66 = Builder.CreateTrunc(Extract65, Builder.getInt32Ty()); 476bdd1243dSDimitry Andric Builder.CreateBr(IfEnd26); 477bdd1243dSDimitry Andric 478bdd1243dSDimitry Andric // if.end26: 479bdd1243dSDimitry Andric Builder.SetInsertPoint(IfEnd26); 480bdd1243dSDimitry Andric PHINode *AAddr1Off0 = Builder.CreatePHI(Builder.getIntNTy(FloatWidth), 3); 481bdd1243dSDimitry Andric AAddr1Off0->addIncoming(ExtractT, IfThen20); 482bdd1243dSDimitry Andric AAddr1Off0->addIncoming(ExtractT60, SwEpilog); 483bdd1243dSDimitry Andric AAddr1Off0->addIncoming(ExtractT61, IfElse); 484bdd1243dSDimitry Andric PHINode *AAddr1Off32 = nullptr; 485bdd1243dSDimitry Andric if (FloatWidth > 32) { 486bdd1243dSDimitry Andric AAddr1Off32 = 487bdd1243dSDimitry Andric Builder.CreatePHI(Builder.getIntNTy(FloatWidth > 80 ? 64 : 32), 3); 488bdd1243dSDimitry Andric AAddr1Off32->addIncoming(ExtractT62, IfThen20); 489bdd1243dSDimitry Andric AAddr1Off32->addIncoming(ExtractT64, SwEpilog); 490bdd1243dSDimitry Andric AAddr1Off32->addIncoming(ExtractT66, IfElse); 491bdd1243dSDimitry Andric } 492bdd1243dSDimitry Andric PHINode *E0 = nullptr; 493bdd1243dSDimitry Andric if (FloatWidth <= 80) { 494bdd1243dSDimitry Andric E0 = Builder.CreatePHI(Builder.getIntNTy(BitWidthNew), 3); 495bdd1243dSDimitry Andric E0->addIncoming(Sub1, IfThen20); 496bdd1243dSDimitry Andric E0->addIncoming(Sub2, SwEpilog); 497bdd1243dSDimitry Andric E0->addIncoming(Sub2, IfElse); 498bdd1243dSDimitry Andric } 499bdd1243dSDimitry Andric Value *And29 = nullptr; 500bdd1243dSDimitry Andric if (FloatWidth > 80) { 501bdd1243dSDimitry Andric Value *Temp2 = Builder.CreateShl(Builder.getIntN(BitWidth, 1), 502bdd1243dSDimitry Andric Builder.getIntN(BitWidth, 63)); 503bdd1243dSDimitry Andric And29 = Builder.CreateAnd(Shr, Temp2, "and29"); 504bdd1243dSDimitry Andric } else { 505bdd1243dSDimitry Andric Value *Conv28 = Builder.CreateTrunc(Shr, Builder.getIntNTy(32)); 506bdd1243dSDimitry Andric And29 = Builder.CreateAnd( 507bdd1243dSDimitry Andric Conv28, ConstantInt::getSigned(Builder.getIntNTy(32), 0x80000000)); 508bdd1243dSDimitry Andric } 509bdd1243dSDimitry Andric unsigned TempMod = FPMantissaWidth % 32; 510bdd1243dSDimitry Andric Value *And34 = nullptr; 511bdd1243dSDimitry Andric Value *Shl30 = nullptr; 512bdd1243dSDimitry Andric if (FloatWidth > 80) { 513bdd1243dSDimitry Andric TempMod += 32; 514bdd1243dSDimitry Andric Value *Add = Builder.CreateShl(AAddr1Off32, Builder.getIntN(64, TempMod)); 515bdd1243dSDimitry Andric Shl30 = Builder.CreateAdd( 516bdd1243dSDimitry Andric Add, 517bdd1243dSDimitry Andric Builder.getIntN(64, ((1ull << (62ull - TempMod)) - 1ull) << TempMod)); 518bdd1243dSDimitry Andric And34 = Builder.CreateZExt(Shl30, Builder.getIntNTy(128)); 519bdd1243dSDimitry Andric } else { 520bdd1243dSDimitry Andric Value *Add = Builder.CreateShl(E0, Builder.getIntN(32, TempMod)); 521bdd1243dSDimitry Andric Shl30 = Builder.CreateAdd( 522bdd1243dSDimitry Andric Add, Builder.getIntN(32, ((1 << (30 - TempMod)) - 1) << TempMod)); 523bdd1243dSDimitry Andric And34 = Builder.CreateAnd(FloatWidth > 32 ? AAddr1Off32 : AAddr1Off0, 524bdd1243dSDimitry Andric Builder.getIntN(32, (1 << TempMod) - 1)); 525bdd1243dSDimitry Andric } 526bdd1243dSDimitry Andric Value *Or35 = nullptr; 527bdd1243dSDimitry Andric if (FloatWidth > 80) { 528bdd1243dSDimitry Andric Value *And29Trunc = Builder.CreateTrunc(And29, Builder.getIntNTy(128)); 529bdd1243dSDimitry Andric Value *Or31 = Builder.CreateOr(And29Trunc, And34); 530bdd1243dSDimitry Andric Value *Or34 = Builder.CreateShl(Or31, Builder.getIntN(128, 64)); 531bdd1243dSDimitry Andric Value *Temp3 = Builder.CreateShl(Builder.getIntN(128, 1), 532bdd1243dSDimitry Andric Builder.getIntN(128, FPMantissaWidth)); 533bdd1243dSDimitry Andric Value *Temp4 = Builder.CreateSub(Temp3, Builder.getIntN(128, 1)); 534bdd1243dSDimitry Andric Value *A6 = Builder.CreateAnd(AAddr1Off0, Temp4); 535bdd1243dSDimitry Andric Or35 = Builder.CreateOr(Or34, A6); 536bdd1243dSDimitry Andric } else { 537bdd1243dSDimitry Andric Value *Or31 = Builder.CreateOr(And34, And29); 538bdd1243dSDimitry Andric Or35 = Builder.CreateOr(IsSigned ? Or31 : And34, Shl30); 539bdd1243dSDimitry Andric } 540bdd1243dSDimitry Andric Value *A4 = nullptr; 541bdd1243dSDimitry Andric if (IToFP->getType()->isDoubleTy()) { 542bdd1243dSDimitry Andric Value *ZExt1 = Builder.CreateZExt(Or35, Builder.getIntNTy(FloatWidth)); 543bdd1243dSDimitry Andric Value *Shl1 = Builder.CreateShl(ZExt1, Builder.getIntN(FloatWidth, 32)); 544bdd1243dSDimitry Andric Value *And1 = 545bdd1243dSDimitry Andric Builder.CreateAnd(AAddr1Off0, Builder.getIntN(FloatWidth, 0xFFFFFFFF)); 546bdd1243dSDimitry Andric Value *Or1 = Builder.CreateOr(Shl1, And1); 547bdd1243dSDimitry Andric A4 = Builder.CreateBitCast(Or1, IToFP->getType()); 548bdd1243dSDimitry Andric } else if (IToFP->getType()->isX86_FP80Ty()) { 549bdd1243dSDimitry Andric Value *A40 = 550bdd1243dSDimitry Andric Builder.CreateBitCast(Or35, Type::getFP128Ty(Builder.getContext())); 551bdd1243dSDimitry Andric A4 = Builder.CreateFPTrunc(A40, IToFP->getType()); 552*0fca6ea1SDimitry Andric } else if (IToFP->getType()->isHalfTy() || IToFP->getType()->isBFloatTy()) { 553bdd1243dSDimitry Andric // Deal with "half" situation. This is a workaround since we don't have 554bdd1243dSDimitry Andric // floattihf.c currently as referring. 555bdd1243dSDimitry Andric Value *A40 = 556bdd1243dSDimitry Andric Builder.CreateBitCast(Or35, Type::getFloatTy(Builder.getContext())); 557bdd1243dSDimitry Andric A4 = Builder.CreateFPTrunc(A40, IToFP->getType()); 558bdd1243dSDimitry Andric } else // float type 559bdd1243dSDimitry Andric A4 = Builder.CreateBitCast(Or35, IToFP->getType()); 560bdd1243dSDimitry Andric Builder.CreateBr(End); 561bdd1243dSDimitry Andric 562bdd1243dSDimitry Andric // return: 563bdd1243dSDimitry Andric Builder.SetInsertPoint(End, End->begin()); 564bdd1243dSDimitry Andric PHINode *Retval0 = Builder.CreatePHI(IToFP->getType(), 2); 565bdd1243dSDimitry Andric Retval0->addIncoming(A4, IfEnd26); 566bdd1243dSDimitry Andric Retval0->addIncoming(ConstantFP::getZero(IToFP->getType(), false), Entry); 567bdd1243dSDimitry Andric 568bdd1243dSDimitry Andric IToFP->replaceAllUsesWith(Retval0); 569bdd1243dSDimitry Andric IToFP->dropAllReferences(); 570bdd1243dSDimitry Andric IToFP->eraseFromParent(); 571bdd1243dSDimitry Andric } 572bdd1243dSDimitry Andric 573*0fca6ea1SDimitry Andric static void scalarize(Instruction *I, SmallVectorImpl<Instruction *> &Replace) { 574*0fca6ea1SDimitry Andric VectorType *VTy = cast<FixedVectorType>(I->getType()); 575*0fca6ea1SDimitry Andric 576*0fca6ea1SDimitry Andric IRBuilder<> Builder(I); 577*0fca6ea1SDimitry Andric 578*0fca6ea1SDimitry Andric unsigned NumElements = VTy->getElementCount().getFixedValue(); 579*0fca6ea1SDimitry Andric Value *Result = PoisonValue::get(VTy); 580*0fca6ea1SDimitry Andric for (unsigned Idx = 0; Idx < NumElements; ++Idx) { 581*0fca6ea1SDimitry Andric Value *Ext = Builder.CreateExtractElement(I->getOperand(0), Idx); 582*0fca6ea1SDimitry Andric Value *Cast = Builder.CreateCast(cast<CastInst>(I)->getOpcode(), Ext, 583*0fca6ea1SDimitry Andric I->getType()->getScalarType()); 584*0fca6ea1SDimitry Andric Result = Builder.CreateInsertElement(Result, Cast, Idx); 585*0fca6ea1SDimitry Andric if (isa<Instruction>(Cast)) 586*0fca6ea1SDimitry Andric Replace.push_back(cast<Instruction>(Cast)); 587*0fca6ea1SDimitry Andric } 588*0fca6ea1SDimitry Andric I->replaceAllUsesWith(Result); 589*0fca6ea1SDimitry Andric I->dropAllReferences(); 590*0fca6ea1SDimitry Andric I->eraseFromParent(); 591*0fca6ea1SDimitry Andric } 592*0fca6ea1SDimitry Andric 593bdd1243dSDimitry Andric static bool runImpl(Function &F, const TargetLowering &TLI) { 594bdd1243dSDimitry Andric SmallVector<Instruction *, 4> Replace; 595*0fca6ea1SDimitry Andric SmallVector<Instruction *, 4> ReplaceVector; 596bdd1243dSDimitry Andric bool Modified = false; 597bdd1243dSDimitry Andric 598bdd1243dSDimitry Andric unsigned MaxLegalFpConvertBitWidth = 599bdd1243dSDimitry Andric TLI.getMaxLargeFPConvertBitWidthSupported(); 600bdd1243dSDimitry Andric if (ExpandFpConvertBits != llvm::IntegerType::MAX_INT_BITS) 601bdd1243dSDimitry Andric MaxLegalFpConvertBitWidth = ExpandFpConvertBits; 602bdd1243dSDimitry Andric 603bdd1243dSDimitry Andric if (MaxLegalFpConvertBitWidth >= llvm::IntegerType::MAX_INT_BITS) 604bdd1243dSDimitry Andric return false; 605bdd1243dSDimitry Andric 606bdd1243dSDimitry Andric for (auto &I : instructions(F)) { 607bdd1243dSDimitry Andric switch (I.getOpcode()) { 608bdd1243dSDimitry Andric case Instruction::FPToUI: 609bdd1243dSDimitry Andric case Instruction::FPToSI: { 610*0fca6ea1SDimitry Andric // TODO: This pass doesn't handle scalable vectors. 611*0fca6ea1SDimitry Andric if (I.getOperand(0)->getType()->isScalableTy()) 612bdd1243dSDimitry Andric continue; 613bdd1243dSDimitry Andric 614*0fca6ea1SDimitry Andric auto *IntTy = cast<IntegerType>(I.getType()->getScalarType()); 615bdd1243dSDimitry Andric if (IntTy->getIntegerBitWidth() <= MaxLegalFpConvertBitWidth) 616bdd1243dSDimitry Andric continue; 617bdd1243dSDimitry Andric 618*0fca6ea1SDimitry Andric if (I.getOperand(0)->getType()->isVectorTy()) 619*0fca6ea1SDimitry Andric ReplaceVector.push_back(&I); 620*0fca6ea1SDimitry Andric else 621bdd1243dSDimitry Andric Replace.push_back(&I); 622bdd1243dSDimitry Andric Modified = true; 623bdd1243dSDimitry Andric break; 624bdd1243dSDimitry Andric } 625bdd1243dSDimitry Andric case Instruction::UIToFP: 626bdd1243dSDimitry Andric case Instruction::SIToFP: { 627*0fca6ea1SDimitry Andric // TODO: This pass doesn't handle scalable vectors. 628*0fca6ea1SDimitry Andric if (I.getOperand(0)->getType()->isScalableTy()) 629bdd1243dSDimitry Andric continue; 630bdd1243dSDimitry Andric 631*0fca6ea1SDimitry Andric auto *IntTy = 632*0fca6ea1SDimitry Andric cast<IntegerType>(I.getOperand(0)->getType()->getScalarType()); 633bdd1243dSDimitry Andric if (IntTy->getIntegerBitWidth() <= MaxLegalFpConvertBitWidth) 634bdd1243dSDimitry Andric continue; 635bdd1243dSDimitry Andric 636*0fca6ea1SDimitry Andric if (I.getOperand(0)->getType()->isVectorTy()) 637*0fca6ea1SDimitry Andric ReplaceVector.push_back(&I); 638*0fca6ea1SDimitry Andric else 639bdd1243dSDimitry Andric Replace.push_back(&I); 640bdd1243dSDimitry Andric Modified = true; 641bdd1243dSDimitry Andric break; 642bdd1243dSDimitry Andric } 643bdd1243dSDimitry Andric default: 644bdd1243dSDimitry Andric break; 645bdd1243dSDimitry Andric } 646bdd1243dSDimitry Andric } 647bdd1243dSDimitry Andric 648*0fca6ea1SDimitry Andric while (!ReplaceVector.empty()) { 649*0fca6ea1SDimitry Andric Instruction *I = ReplaceVector.pop_back_val(); 650*0fca6ea1SDimitry Andric scalarize(I, Replace); 651*0fca6ea1SDimitry Andric } 652*0fca6ea1SDimitry Andric 653bdd1243dSDimitry Andric if (Replace.empty()) 654bdd1243dSDimitry Andric return false; 655bdd1243dSDimitry Andric 656bdd1243dSDimitry Andric while (!Replace.empty()) { 657bdd1243dSDimitry Andric Instruction *I = Replace.pop_back_val(); 658bdd1243dSDimitry Andric if (I->getOpcode() == Instruction::FPToUI || 659bdd1243dSDimitry Andric I->getOpcode() == Instruction::FPToSI) { 660bdd1243dSDimitry Andric expandFPToI(I); 661bdd1243dSDimitry Andric } else { 662bdd1243dSDimitry Andric expandIToFP(I); 663bdd1243dSDimitry Andric } 664bdd1243dSDimitry Andric } 665bdd1243dSDimitry Andric 666bdd1243dSDimitry Andric return Modified; 667bdd1243dSDimitry Andric } 668bdd1243dSDimitry Andric 669bdd1243dSDimitry Andric namespace { 670bdd1243dSDimitry Andric class ExpandLargeFpConvertLegacyPass : public FunctionPass { 671bdd1243dSDimitry Andric public: 672bdd1243dSDimitry Andric static char ID; 673bdd1243dSDimitry Andric 674bdd1243dSDimitry Andric ExpandLargeFpConvertLegacyPass() : FunctionPass(ID) { 675bdd1243dSDimitry Andric initializeExpandLargeFpConvertLegacyPassPass( 676bdd1243dSDimitry Andric *PassRegistry::getPassRegistry()); 677bdd1243dSDimitry Andric } 678bdd1243dSDimitry Andric 679bdd1243dSDimitry Andric bool runOnFunction(Function &F) override { 680bdd1243dSDimitry Andric auto *TM = &getAnalysis<TargetPassConfig>().getTM<TargetMachine>(); 681bdd1243dSDimitry Andric auto *TLI = TM->getSubtargetImpl(F)->getTargetLowering(); 682bdd1243dSDimitry Andric return runImpl(F, *TLI); 683bdd1243dSDimitry Andric } 684bdd1243dSDimitry Andric 685bdd1243dSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 686bdd1243dSDimitry Andric AU.addRequired<TargetPassConfig>(); 687bdd1243dSDimitry Andric AU.addPreserved<AAResultsWrapperPass>(); 688bdd1243dSDimitry Andric AU.addPreserved<GlobalsAAWrapperPass>(); 689bdd1243dSDimitry Andric } 690bdd1243dSDimitry Andric }; 691bdd1243dSDimitry Andric } // namespace 692bdd1243dSDimitry Andric 6935f757f3fSDimitry Andric PreservedAnalyses ExpandLargeFpConvertPass::run(Function &F, 6945f757f3fSDimitry Andric FunctionAnalysisManager &FAM) { 6955f757f3fSDimitry Andric const TargetSubtargetInfo *STI = TM->getSubtargetImpl(F); 6965f757f3fSDimitry Andric return runImpl(F, *STI->getTargetLowering()) ? PreservedAnalyses::none() 6975f757f3fSDimitry Andric : PreservedAnalyses::all(); 6985f757f3fSDimitry Andric } 6995f757f3fSDimitry Andric 700bdd1243dSDimitry Andric char ExpandLargeFpConvertLegacyPass::ID = 0; 701bdd1243dSDimitry Andric INITIALIZE_PASS_BEGIN(ExpandLargeFpConvertLegacyPass, "expand-large-fp-convert", 702bdd1243dSDimitry Andric "Expand large fp convert", false, false) 703bdd1243dSDimitry Andric INITIALIZE_PASS_END(ExpandLargeFpConvertLegacyPass, "expand-large-fp-convert", 704bdd1243dSDimitry Andric "Expand large fp convert", false, false) 705bdd1243dSDimitry Andric 706bdd1243dSDimitry Andric FunctionPass *llvm::createExpandLargeFpConvertPass() { 707bdd1243dSDimitry Andric return new ExpandLargeFpConvertLegacyPass(); 708bdd1243dSDimitry Andric } 709