//===--- ExpandLargeFpConvert.cpp - Expand large fp convert----------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This pass expands ‘fptoui .. to’, ‘fptosi .. to’, ‘uitofp .. to’, // ‘sitofp .. to’ instructions with a bitwidth above a threshold into // auto-generated functions. This is useful for targets like x86_64 that cannot // lower fp convertions with more than 128 bits. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/ExpandLargeFpConvert.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/PassManager.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetMachine.h" usingnamespacellvm; static cl::opt<unsigned> ExpandFpConvertBits("expand-fp-convert-bits", cl::Hidden, cl::init(llvm::IntegerType::MAX_INT_BITS), cl::desc("fp convert instructions on integers with " "more than <N> bits are expanded.")); /// Generate code to convert a fp number to integer, replacing FPToS(U)I with /// the generated code. This currently generates code similarly to compiler-rt's /// implementations. /// /// An example IR generated from compiler-rt/fixsfdi.c looks like below: /// define dso_local i64 @foo(float noundef %a) local_unnamed_addr #0 { /// entry: /// %0 = bitcast float %a to i32 /// %conv.i = zext i32 %0 to i64 /// %tobool.not = icmp sgt i32 %0, -1 /// %conv = select i1 %tobool.not, i64 1, i64 -1 /// %and = lshr i64 %conv.i, 23 /// %shr = and i64 %and, 255 /// %and2 = and i64 %conv.i, 8388607 /// %or = or i64 %and2, 8388608 /// %cmp = icmp ult i64 %shr, 127 /// br i1 %cmp, label %cleanup, label %if.end /// /// if.end: ; preds = %entry /// %sub = add nuw nsw i64 %shr, 4294967169 /// %conv5 = and i64 %sub, 4294967232 /// %cmp6.not = icmp eq i64 %conv5, 0 /// br i1 %cmp6.not, label %if.end12, label %if.then8 /// /// if.then8: ; preds = %if.end /// %cond11 = select i1 %tobool.not, i64 9223372036854775807, i64 -9223372036854775808 /// br label %cleanup /// /// if.end12: ; preds = %if.end /// %cmp13 = icmp ult i64 %shr, 150 /// br i1 %cmp13, label %if.then15, label %if.else /// /// if.then15: ; preds = %if.end12 /// %sub16 = sub nuw nsw i64 150, %shr /// %shr17 = lshr i64 %or, %sub16 /// %mul = mul nsw i64 %shr17, %conv /// br label %cleanup /// /// if.else: ; preds = %if.end12 /// %sub18 = add nsw i64 %shr, -150 /// %shl = shl i64 %or, %sub18 /// %mul19 = mul nsw i64 %shl, %conv /// br label %cleanup /// /// cleanup: ; preds = %entry, %if.else, %if.then15, %if.then8 /// %retval.0 = phi i64 [ %cond11, %if.then8 ], [ %mul, %if.then15 ], [ %mul19, %if.else ], [ 0, %entry ] /// ret i64 %retval.0 /// } /// /// Replace fp to integer with generated code. static void expandFPToI(Instruction *FPToI) { … } /// Generate code to convert a fp number to integer, replacing S(U)IToFP with /// the generated code. This currently generates code similarly to compiler-rt's /// implementations. This implementation has an implicit assumption that integer /// width is larger than fp. /// /// An example IR generated from compiler-rt/floatdisf.c looks like below: /// define dso_local float @__floatdisf(i64 noundef %a) local_unnamed_addr #0 { /// entry: /// %cmp = icmp eq i64 %a, 0 /// br i1 %cmp, label %return, label %if.end /// /// if.end: ; preds = %entry /// %shr = ashr i64 %a, 63 /// %xor = xor i64 %shr, %a /// %sub = sub nsw i64 %xor, %shr /// %0 = tail call i64 @llvm.ctlz.i64(i64 %sub, i1 true), !range !5 /// %cast = trunc i64 %0 to i32 /// %sub1 = sub nuw nsw i32 64, %cast /// %sub2 = xor i32 %cast, 63 /// %cmp3 = icmp ult i32 %cast, 40 /// br i1 %cmp3, label %if.then4, label %if.else /// /// if.then4: ; preds = %if.end /// switch i32 %sub1, label %sw.default [ /// i32 25, label %sw.bb /// i32 26, label %sw.epilog /// ] /// /// sw.bb: ; preds = %if.then4 /// %shl = shl i64 %sub, 1 /// br label %sw.epilog /// /// sw.default: ; preds = %if.then4 /// %sub5 = sub nsw i64 38, %0 /// %sh_prom = and i64 %sub5, 4294967295 /// %shr6 = lshr i64 %sub, %sh_prom /// %shr9 = lshr i64 274877906943, %0 /// %and = and i64 %shr9, %sub /// %cmp10 = icmp ne i64 %and, 0 /// %conv11 = zext i1 %cmp10 to i64 /// %or = or i64 %shr6, %conv11 /// br label %sw.epilog /// /// sw.epilog: ; preds = %sw.default, %if.then4, %sw.bb /// %a.addr.0 = phi i64 [ %or, %sw.default ], [ %sub, %if.then4 ], [ %shl, %sw.bb ] /// %1 = lshr i64 %a.addr.0, 2 /// %2 = and i64 %1, 1 /// %or16 = or i64 %2, %a.addr.0 /// %inc = add nsw i64 %or16, 1 /// %3 = and i64 %inc, 67108864 /// %tobool.not = icmp eq i64 %3, 0 /// %spec.select.v = select i1 %tobool.not, i64 2, i64 3 /// %spec.select = ashr i64 %inc, %spec.select.v /// %spec.select56 = select i1 %tobool.not, i32 %sub2, i32 %sub1 /// br label %if.end26 /// /// if.else: ; preds = %if.end /// %sub23 = add nuw nsw i64 %0, 4294967256 /// %sh_prom24 = and i64 %sub23, 4294967295 /// %shl25 = shl i64 %sub, %sh_prom24 /// br label %if.end26 /// /// if.end26: ; preds = %sw.epilog, %if.else /// %a.addr.1 = phi i64 [ %shl25, %if.else ], [ %spec.select, %sw.epilog ] /// %e.0 = phi i32 [ %sub2, %if.else ], [ %spec.select56, %sw.epilog ] /// %conv27 = trunc i64 %shr to i32 /// %and28 = and i32 %conv27, -2147483648 /// %add = shl nuw nsw i32 %e.0, 23 /// %shl29 = add nuw nsw i32 %add, 1065353216 /// %conv31 = trunc i64 %a.addr.1 to i32 /// %and32 = and i32 %conv31, 8388607 /// %or30 = or i32 %and32, %and28 /// %or33 = or i32 %or30, %shl29 /// %4 = bitcast i32 %or33 to float /// br label %return /// /// return: ; preds = %entry, %if.end26 /// %retval.0 = phi float [ %4, %if.end26 ], [ 0.000000e+00, %entry ] /// ret float %retval.0 /// } /// /// Replace integer to fp with generated code. static void expandIToFP(Instruction *IToFP) { … } static void scalarize(Instruction *I, SmallVectorImpl<Instruction *> &Replace) { … } static bool runImpl(Function &F, const TargetLowering &TLI) { … } namespace { class ExpandLargeFpConvertLegacyPass : public FunctionPass { … }; } // namespace PreservedAnalyses ExpandLargeFpConvertPass::run(Function &F, FunctionAnalysisManager &FAM) { … } char ExpandLargeFpConvertLegacyPass::ID = …; INITIALIZE_PASS_BEGIN(ExpandLargeFpConvertLegacyPass, "expand-large-fp-convert", "Expand large fp convert", false, false) INITIALIZE_PASS_END(ExpandLargeFpConvertLegacyPass, "expand-large-fp-convert", "Expand large fp convert", false, false) FunctionPass *llvm::createExpandLargeFpConvertPass() { … }