//===- BypassSlowDivision.cpp - Bypass slow division ----------------------===// // // 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 file contains an optimization for div and rem on architectures that // execute short instructions significantly faster than longer instructions. // For example, on Intel Atom 32-bit divides are slow enough that during // runtime it is profitable to check the value of the operands, and if they are // positive and less than 256 use an unsigned 8-bit divide. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/BypassSlowDivision.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" #include "llvm/Support/KnownBits.h" #include <cassert> #include <cstdint> usingnamespacellvm; #define DEBUG_TYPE … namespace { struct QuotRemPair { … }; /// A quotient and remainder, plus a BB from which they logically "originate". /// If you use Quotient or Remainder in a Phi node, you should use BB as its /// corresponding predecessor. struct QuotRemWithBB { … }; DivCacheTy; BypassWidthsTy; VisitedSetTy; enum ValueRange { … }; class FastDivInsertionTask { … }; } // end anonymous namespace FastDivInsertionTask::FastDivInsertionTask(Instruction *I, const BypassWidthsTy &BypassWidths) { … } /// Reuses previously-computed dividend or remainder from the current BB if /// operands and operation are identical. Otherwise calls insertFastDivAndRem to /// perform the optimization and caches the resulting dividend and remainder. /// If no replacement can be generated, nullptr is returned. Value *FastDivInsertionTask::getReplacement(DivCacheTy &Cache) { … } /// Check if a value looks like a hash. /// /// The routine is expected to detect values computed using the most common hash /// algorithms. Typically, hash computations end with one of the following /// instructions: /// /// 1) MUL with a constant wider than BypassType /// 2) XOR instruction /// /// And even if we are wrong and the value is not a hash, it is still quite /// unlikely that such values will fit into BypassType. /// /// To detect string hash algorithms like FNV we have to look through PHI-nodes. /// It is implemented as a depth-first search for values that look neither long /// nor hash-like. bool FastDivInsertionTask::isHashLikeValue(Value *V, VisitedSetTy &Visited) { … } /// Check if an integer value fits into our bypass type. ValueRange FastDivInsertionTask::getValueRange(Value *V, VisitedSetTy &Visited) { … } /// Add new basic block for slow div and rem operations and put it before /// SuccessorBB. QuotRemWithBB FastDivInsertionTask::createSlowBB(BasicBlock *SuccessorBB) { … } /// Add new basic block for fast div and rem operations and put it before /// SuccessorBB. QuotRemWithBB FastDivInsertionTask::createFastBB(BasicBlock *SuccessorBB) { … } /// Creates Phi nodes for result of Div and Rem. QuotRemPair FastDivInsertionTask::createDivRemPhiNodes(QuotRemWithBB &LHS, QuotRemWithBB &RHS, BasicBlock *PhiBB) { … } /// Creates a runtime check to test whether both the divisor and dividend fit /// into BypassType. The check is inserted at the end of MainBB. True return /// value means that the operands fit. Either of the operands may be NULL if it /// doesn't need a runtime check. Value *FastDivInsertionTask::insertOperandRuntimeCheck(Value *Op1, Value *Op2) { … } /// Substitutes the div/rem instruction with code that checks the value of the /// operands and uses a shorter-faster div/rem instruction when possible. std::optional<QuotRemPair> FastDivInsertionTask::insertFastDivAndRem() { … } /// This optimization identifies DIV/REM instructions in a BB that can be /// profitably bypassed and carried out with a shorter, faster divide. bool llvm::bypassSlowDivision(BasicBlock *BB, const BypassWidthsTy &BypassWidths) { … }