You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
9.3 KiB
252 lines
9.3 KiB
4 months ago
|
//===-- BypassSlowDivision.cpp - Bypass slow division ---------------------===//
|
||
|
//
|
||
|
// The LLVM Compiler Infrastructure
|
||
|
//
|
||
|
// This file is distributed under the University of Illinois Open Source
|
||
|
// License. See LICENSE.TXT for details.
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
//
|
||
|
// 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/IR/Function.h"
|
||
|
#include "llvm/IR/IRBuilder.h"
|
||
|
#include "llvm/IR/Instructions.h"
|
||
|
|
||
|
using namespace llvm;
|
||
|
|
||
|
#define DEBUG_TYPE "bypass-slow-division"
|
||
|
|
||
|
namespace {
|
||
|
struct DivOpInfo {
|
||
|
bool SignedOp;
|
||
|
Value *Dividend;
|
||
|
Value *Divisor;
|
||
|
|
||
|
DivOpInfo(bool InSignedOp, Value *InDividend, Value *InDivisor)
|
||
|
: SignedOp(InSignedOp), Dividend(InDividend), Divisor(InDivisor) {}
|
||
|
};
|
||
|
|
||
|
struct DivPhiNodes {
|
||
|
PHINode *Quotient;
|
||
|
PHINode *Remainder;
|
||
|
|
||
|
DivPhiNodes(PHINode *InQuotient, PHINode *InRemainder)
|
||
|
: Quotient(InQuotient), Remainder(InRemainder) {}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
namespace llvm {
|
||
|
template<>
|
||
|
struct DenseMapInfo<DivOpInfo> {
|
||
|
static bool isEqual(const DivOpInfo &Val1, const DivOpInfo &Val2) {
|
||
|
return Val1.SignedOp == Val2.SignedOp &&
|
||
|
Val1.Dividend == Val2.Dividend &&
|
||
|
Val1.Divisor == Val2.Divisor;
|
||
|
}
|
||
|
|
||
|
static DivOpInfo getEmptyKey() {
|
||
|
return DivOpInfo(false, nullptr, nullptr);
|
||
|
}
|
||
|
|
||
|
static DivOpInfo getTombstoneKey() {
|
||
|
return DivOpInfo(true, nullptr, nullptr);
|
||
|
}
|
||
|
|
||
|
static unsigned getHashValue(const DivOpInfo &Val) {
|
||
|
return (unsigned)(reinterpret_cast<uintptr_t>(Val.Dividend) ^
|
||
|
reinterpret_cast<uintptr_t>(Val.Divisor)) ^
|
||
|
(unsigned)Val.SignedOp;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
typedef DenseMap<DivOpInfo, DivPhiNodes> DivCacheTy;
|
||
|
}
|
||
|
|
||
|
// insertFastDiv - Substitutes the div/rem instruction with code that checks the
|
||
|
// value of the operands and uses a shorter-faster div/rem instruction when
|
||
|
// possible and the longer-slower div/rem instruction otherwise.
|
||
|
static bool insertFastDiv(Instruction *I, IntegerType *BypassType,
|
||
|
bool UseDivOp, bool UseSignedOp,
|
||
|
DivCacheTy &PerBBDivCache) {
|
||
|
Function *F = I->getParent()->getParent();
|
||
|
// Get instruction operands
|
||
|
Value *Dividend = I->getOperand(0);
|
||
|
Value *Divisor = I->getOperand(1);
|
||
|
|
||
|
if (isa<ConstantInt>(Divisor) ||
|
||
|
(isa<ConstantInt>(Dividend) && isa<ConstantInt>(Divisor))) {
|
||
|
// Operations with immediate values should have
|
||
|
// been solved and replaced during compile time.
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Basic Block is split before divide
|
||
|
BasicBlock *MainBB = &*I->getParent();
|
||
|
BasicBlock *SuccessorBB = MainBB->splitBasicBlock(I);
|
||
|
|
||
|
// Add new basic block for slow divide operation
|
||
|
BasicBlock *SlowBB =
|
||
|
BasicBlock::Create(F->getContext(), "", MainBB->getParent(), SuccessorBB);
|
||
|
SlowBB->moveBefore(SuccessorBB);
|
||
|
IRBuilder<> SlowBuilder(SlowBB, SlowBB->begin());
|
||
|
Value *SlowQuotientV;
|
||
|
Value *SlowRemainderV;
|
||
|
if (UseSignedOp) {
|
||
|
SlowQuotientV = SlowBuilder.CreateSDiv(Dividend, Divisor);
|
||
|
SlowRemainderV = SlowBuilder.CreateSRem(Dividend, Divisor);
|
||
|
} else {
|
||
|
SlowQuotientV = SlowBuilder.CreateUDiv(Dividend, Divisor);
|
||
|
SlowRemainderV = SlowBuilder.CreateURem(Dividend, Divisor);
|
||
|
}
|
||
|
SlowBuilder.CreateBr(SuccessorBB);
|
||
|
|
||
|
// Add new basic block for fast divide operation
|
||
|
BasicBlock *FastBB =
|
||
|
BasicBlock::Create(F->getContext(), "", MainBB->getParent(), SuccessorBB);
|
||
|
FastBB->moveBefore(SlowBB);
|
||
|
IRBuilder<> FastBuilder(FastBB, FastBB->begin());
|
||
|
Value *ShortDivisorV = FastBuilder.CreateCast(Instruction::Trunc, Divisor,
|
||
|
BypassType);
|
||
|
Value *ShortDividendV = FastBuilder.CreateCast(Instruction::Trunc, Dividend,
|
||
|
BypassType);
|
||
|
|
||
|
// udiv/urem because optimization only handles positive numbers
|
||
|
Value *ShortQuotientV = FastBuilder.CreateExactUDiv(ShortDividendV,
|
||
|
ShortDivisorV);
|
||
|
Value *ShortRemainderV = FastBuilder.CreateURem(ShortDividendV,
|
||
|
ShortDivisorV);
|
||
|
Value *FastQuotientV = FastBuilder.CreateCast(Instruction::ZExt,
|
||
|
ShortQuotientV,
|
||
|
Dividend->getType());
|
||
|
Value *FastRemainderV = FastBuilder.CreateCast(Instruction::ZExt,
|
||
|
ShortRemainderV,
|
||
|
Dividend->getType());
|
||
|
FastBuilder.CreateBr(SuccessorBB);
|
||
|
|
||
|
// Phi nodes for result of div and rem
|
||
|
IRBuilder<> SuccessorBuilder(SuccessorBB, SuccessorBB->begin());
|
||
|
PHINode *QuoPhi = SuccessorBuilder.CreatePHI(I->getType(), 2);
|
||
|
QuoPhi->addIncoming(SlowQuotientV, SlowBB);
|
||
|
QuoPhi->addIncoming(FastQuotientV, FastBB);
|
||
|
PHINode *RemPhi = SuccessorBuilder.CreatePHI(I->getType(), 2);
|
||
|
RemPhi->addIncoming(SlowRemainderV, SlowBB);
|
||
|
RemPhi->addIncoming(FastRemainderV, FastBB);
|
||
|
|
||
|
// Replace I with appropriate phi node
|
||
|
if (UseDivOp)
|
||
|
I->replaceAllUsesWith(QuoPhi);
|
||
|
else
|
||
|
I->replaceAllUsesWith(RemPhi);
|
||
|
I->eraseFromParent();
|
||
|
|
||
|
// Combine operands into a single value with OR for value testing below
|
||
|
MainBB->getInstList().back().eraseFromParent();
|
||
|
IRBuilder<> MainBuilder(MainBB, MainBB->end());
|
||
|
Value *OrV = MainBuilder.CreateOr(Dividend, Divisor);
|
||
|
|
||
|
// BitMask is inverted to check if the operands are
|
||
|
// larger than the bypass type
|
||
|
uint64_t BitMask = ~BypassType->getBitMask();
|
||
|
Value *AndV = MainBuilder.CreateAnd(OrV, BitMask);
|
||
|
|
||
|
// Compare operand values and branch
|
||
|
Value *ZeroV = ConstantInt::getSigned(Dividend->getType(), 0);
|
||
|
Value *CmpV = MainBuilder.CreateICmpEQ(AndV, ZeroV);
|
||
|
MainBuilder.CreateCondBr(CmpV, FastBB, SlowBB);
|
||
|
|
||
|
// Cache phi nodes to be used later in place of other instances
|
||
|
// of div or rem with the same sign, dividend, and divisor
|
||
|
DivOpInfo Key(UseSignedOp, Dividend, Divisor);
|
||
|
DivPhiNodes Value(QuoPhi, RemPhi);
|
||
|
PerBBDivCache.insert(std::pair<DivOpInfo, DivPhiNodes>(Key, Value));
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// reuseOrInsertFastDiv - Reuses previously computed dividend or remainder from
|
||
|
// the current BB if operands and operation are identical. Otherwise calls
|
||
|
// insertFastDiv to perform the optimization and caches the resulting dividend
|
||
|
// and remainder.
|
||
|
static bool reuseOrInsertFastDiv(Instruction *I, IntegerType *BypassType,
|
||
|
bool UseDivOp, bool UseSignedOp,
|
||
|
DivCacheTy &PerBBDivCache) {
|
||
|
// Get instruction operands
|
||
|
DivOpInfo Key(UseSignedOp, I->getOperand(0), I->getOperand(1));
|
||
|
DivCacheTy::iterator CacheI = PerBBDivCache.find(Key);
|
||
|
|
||
|
if (CacheI == PerBBDivCache.end()) {
|
||
|
// If previous instance does not exist, insert fast div
|
||
|
return insertFastDiv(I, BypassType, UseDivOp, UseSignedOp, PerBBDivCache);
|
||
|
}
|
||
|
|
||
|
// Replace operation value with previously generated phi node
|
||
|
DivPhiNodes &Value = CacheI->second;
|
||
|
if (UseDivOp) {
|
||
|
// Replace all uses of div instruction with quotient phi node
|
||
|
I->replaceAllUsesWith(Value.Quotient);
|
||
|
} else {
|
||
|
// Replace all uses of rem instruction with remainder phi node
|
||
|
I->replaceAllUsesWith(Value.Remainder);
|
||
|
}
|
||
|
|
||
|
// Remove redundant operation
|
||
|
I->eraseFromParent();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// bypassSlowDivision - This optimization identifies DIV instructions in a BB
|
||
|
// that can be profitably bypassed and carried out with a shorter, faster
|
||
|
// divide.
|
||
|
bool llvm::bypassSlowDivision(
|
||
|
BasicBlock *BB, const DenseMap<unsigned int, unsigned int> &BypassWidths) {
|
||
|
DivCacheTy DivCache;
|
||
|
|
||
|
bool MadeChange = false;
|
||
|
Instruction* Next = &*BB->begin();
|
||
|
while (Next != nullptr) {
|
||
|
// We may add instructions immediately after I, but we want to skip over
|
||
|
// them.
|
||
|
Instruction* I = Next;
|
||
|
Next = Next->getNextNode();
|
||
|
|
||
|
// Get instruction details
|
||
|
unsigned Opcode = I->getOpcode();
|
||
|
bool UseDivOp = Opcode == Instruction::SDiv || Opcode == Instruction::UDiv;
|
||
|
bool UseRemOp = Opcode == Instruction::SRem || Opcode == Instruction::URem;
|
||
|
bool UseSignedOp = Opcode == Instruction::SDiv ||
|
||
|
Opcode == Instruction::SRem;
|
||
|
|
||
|
// Only optimize div or rem ops
|
||
|
if (!UseDivOp && !UseRemOp)
|
||
|
continue;
|
||
|
|
||
|
// Skip division on vector types, only optimize integer instructions
|
||
|
if (!I->getType()->isIntegerTy())
|
||
|
continue;
|
||
|
|
||
|
// Get bitwidth of div/rem instruction
|
||
|
IntegerType *T = cast<IntegerType>(I->getType());
|
||
|
unsigned int bitwidth = T->getBitWidth();
|
||
|
|
||
|
// Continue if bitwidth is not bypassed
|
||
|
DenseMap<unsigned int, unsigned int>::const_iterator BI = BypassWidths.find(bitwidth);
|
||
|
if (BI == BypassWidths.end())
|
||
|
continue;
|
||
|
|
||
|
// Get type for div/rem instruction with bypass bitwidth
|
||
|
IntegerType *BT = IntegerType::get(I->getContext(), BI->second);
|
||
|
|
||
|
MadeChange |= reuseOrInsertFastDiv(I, BT, UseDivOp, UseSignedOp, DivCache);
|
||
|
}
|
||
|
|
||
|
return MadeChange;
|
||
|
}
|