40#define DEBUG_TYPE "aggressive-instcombine"
42STATISTIC(NumExprsReduced,
"Number of truncations eliminated by reducing bit "
43 "width of expression graph");
45 "Number of instructions whose bit width was reduced");
49 unsigned Opc =
I->getOpcode();
51 case Instruction::Trunc:
52 case Instruction::ZExt:
53 case Instruction::SExt:
57 case Instruction::Add:
58 case Instruction::Sub:
59 case Instruction::Mul:
60 case Instruction::And:
62 case Instruction::Xor:
63 case Instruction::Shl:
64 case Instruction::LShr:
65 case Instruction::AShr:
66 case Instruction::UDiv:
67 case Instruction::URem:
69 case Instruction::InsertElement:
71 case Instruction::ExtractElement:
73 case Instruction::Select:
75 case Instruction::PHI:
77 case Instruction::ShuffleVector:
79 case Instruction::Call: {
81 return IID == Intrinsic::umin || IID == Intrinsic::umax;
91 for (
Use &
Op :
I->operands())
93 Ops.push_back(
Op.get());
96bool TruncInstCombine::buildTruncExpressionGraph() {
97 SmallVector<Value *, 8> Worklist;
98 SmallVector<Instruction *, 8>
Stack;
102 Worklist.push_back(CurrentTruncInst->getOperand(0));
104 while (!Worklist.empty()) {
105 Value *Curr = Worklist.back();
122 InstInfoMap.try_emplace(
I);
126 if (InstInfoMap.count(
I)) {
134 unsigned Opc =
I->getOpcode();
136 case Instruction::Trunc:
137 case Instruction::ZExt:
138 case Instruction::SExt:
144 case Instruction::Add:
145 case Instruction::Sub:
146 case Instruction::Mul:
147 case Instruction::And:
148 case Instruction::Or:
149 case Instruction::Xor:
150 case Instruction::Shl:
151 case Instruction::LShr:
152 case Instruction::AShr:
153 case Instruction::UDiv:
154 case Instruction::URem:
155 case Instruction::InsertElement:
156 case Instruction::ExtractElement:
157 case Instruction::Select:
158 case Instruction::ShuffleVector: {
164 case Instruction::PHI: {
170 Worklist.push_back(
Op);
173 case Instruction::Call: {
175 if (IID == Intrinsic::umin || IID == Intrinsic::umax) {
193unsigned TruncInstCombine::getMinBitWidth() {
194 SmallVector<Value *, 8> Worklist;
195 SmallVector<Instruction *, 8>
Stack;
197 Value *Src = CurrentTruncInst->getOperand(0);
198 Type *DstTy = CurrentTruncInst->getType();
200 unsigned OrigBitWidth =
201 CurrentTruncInst->getOperand(0)->getType()->getScalarSizeInBits();
204 return TruncBitWidth;
206 Worklist.push_back(Src);
209 while (!Worklist.empty()) {
210 Value *Curr = Worklist.back();
220 auto &Info = InstInfoMap[
I];
233 std::max(Info.MinBitWidth, InstInfoMap[IOp].MinBitWidth);
239 unsigned ValidBitWidth = Info.ValidBitWidth;
243 Info.MinBitWidth = std::max(Info.MinBitWidth, Info.ValidBitWidth);
250 unsigned IOpBitwidth = InstInfoMap.lookup(IOp).ValidBitWidth;
251 if (IOpBitwidth >= ValidBitWidth)
253 InstInfoMap[IOp].ValidBitWidth = ValidBitWidth;
254 Worklist.push_back(IOp);
258 assert(MinBitWidth >= TruncBitWidth);
260 if (MinBitWidth > TruncBitWidth) {
267 Type *Ty = DL.getSmallestLegalIntType(DstTy->
getContext(), MinBitWidth);
276 bool FromLegal = MinBitWidth == 1 || DL.isLegalInteger(OrigBitWidth);
277 bool ToLegal = MinBitWidth == 1 || DL.isLegalInteger(MinBitWidth);
278 if (!DstTy->
isVectorTy() && FromLegal && !ToLegal)
284Type *TruncInstCombine::getBestTruncatedType() {
285 if (!buildTruncExpressionGraph())
292 unsigned DesiredBitWidth = 0;
293 for (
auto Itr : InstInfoMap) {
298 for (Use &U :
I->uses())
300 if (UI != CurrentTruncInst &&
301 (!InstInfoMap.count(UI) ||
308 unsigned ExtInstBitWidth =
309 I->getOperand(0)->getType()->getScalarSizeInBits();
310 if (DesiredBitWidth && DesiredBitWidth != ExtInstBitWidth)
312 DesiredBitWidth = ExtInstBitWidth;
316 unsigned OrigBitWidth =
317 CurrentTruncInst->getOperand(0)->getType()->getScalarSizeInBits();
327 for (
auto &Itr : InstInfoMap) {
330 KnownBits KnownRHS = computeKnownBits(
I->getOperand(1));
334 if (MinBitWidth == OrigBitWidth)
336 if (
I->getOpcode() == Instruction::LShr) {
337 KnownBits KnownLHS = computeKnownBits(
I->getOperand(0));
340 if (
I->getOpcode() == Instruction::AShr) {
341 unsigned NumSignBits = ComputeNumSignBits(
I->getOperand(0));
342 MinBitWidth = std::max(MinBitWidth, OrigBitWidth - NumSignBits + 1);
344 if (MinBitWidth >= OrigBitWidth)
346 Itr.second.MinBitWidth = MinBitWidth;
347 }
else if (
I->getOpcode() == Instruction::UDiv ||
348 I->getOpcode() == Instruction::URem) {
349 unsigned MinBitWidth = 0;
350 for (
const auto &
Op :
I->operands()) {
351 KnownBits
Known = computeKnownBits(
Op);
352 MinBitWidth = std::max(
Known.countMaxActiveBits(), MinBitWidth);
353 if (MinBitWidth >= OrigBitWidth)
356 Itr.second.MinBitWidth = MinBitWidth;
358 switch (
II->getIntrinsicID()) {
359 case Intrinsic::umin:
360 case Intrinsic::umax: {
361 unsigned MinBitWidth = 0;
362 for (
const auto &
Op :
II->args()) {
363 KnownBits
Known = computeKnownBits(
Op);
364 MinBitWidth = std::max(
Known.countMaxActiveBits(), MinBitWidth);
365 if (MinBitWidth >= OrigBitWidth)
368 Itr.second.MinBitWidth = MinBitWidth;
379 unsigned MinBitWidth = getMinBitWidth();
383 if (MinBitWidth >= OrigBitWidth ||
384 (DesiredBitWidth && DesiredBitWidth != MinBitWidth))
393 assert(Ty && !Ty->isVectorTy() &&
"Expect Scalar Type");
399Value *TruncInstCombine::getReducedOperand(
Value *V,
Type *SclTy) {
408 Info
Entry = InstInfoMap.lookup(
I);
410 return Entry.NewValue;
413void TruncInstCombine::ReduceExpressionGraph(
Type *SclTy) {
414 NumInstrsReduced += InstInfoMap.size();
417 for (
auto &Itr : InstInfoMap) {
419 TruncInstCombine::Info &NodeInfo = Itr.second;
421 assert(!NodeInfo.NewValue &&
"Instruction has been evaluated");
424 Value *Res =
nullptr;
425 unsigned Opc =
I->getOpcode();
427 case Instruction::Trunc:
428 case Instruction::ZExt:
429 case Instruction::SExt: {
434 if (
I->getOperand(0)->getType() == Ty) {
436 NodeInfo.NewValue =
I->getOperand(0);
441 Res = Builder.CreateIntCast(
I->getOperand(0), Ty,
442 Opc == Instruction::SExt);
450 if (Entry != Worklist.end()) {
454 Worklist.erase(Entry);
456 Worklist.push_back(NewCI);
459 case Instruction::Add:
460 case Instruction::Sub:
461 case Instruction::Mul:
462 case Instruction::And:
463 case Instruction::Or:
464 case Instruction::Xor:
465 case Instruction::Shl:
466 case Instruction::LShr:
467 case Instruction::AShr:
468 case Instruction::UDiv:
469 case Instruction::URem: {
470 Value *
LHS = getReducedOperand(
I->getOperand(0), SclTy);
471 Value *
RHS = getReducedOperand(
I->getOperand(1), SclTy);
476 ResI->setIsExact(PEO->isExact());
479 case Instruction::ExtractElement: {
480 Value *Vec = getReducedOperand(
I->getOperand(0), SclTy);
481 Value *Idx =
I->getOperand(1);
482 Res = Builder.CreateExtractElement(Vec, Idx);
485 case Instruction::InsertElement: {
486 Value *Vec = getReducedOperand(
I->getOperand(0), SclTy);
487 Value *NewElt = getReducedOperand(
I->getOperand(1), SclTy);
488 Value *Idx =
I->getOperand(2);
489 Res = Builder.CreateInsertElement(Vec, NewElt, Idx);
492 case Instruction::Select: {
493 Value *Op0 =
I->getOperand(0);
494 Value *
LHS = getReducedOperand(
I->getOperand(1), SclTy);
495 Value *
RHS = getReducedOperand(
I->getOperand(2), SclTy);
496 Res = Builder.CreateSelect(Op0,
LHS,
RHS,
"",
I);
499 case Instruction::ShuffleVector: {
500 Value *
LHS = getReducedOperand(
I->getOperand(0), SclTy);
501 Value *
RHS = getReducedOperand(
I->getOperand(1), SclTy);
503 Res = Builder.CreateShuffleVector(
LHS,
RHS,
SI->getShuffleMask());
506 case Instruction::PHI: {
512 case Instruction::Call: {
514 if (IID == Intrinsic::umin || IID == Intrinsic::umax) {
515 Value *
LHS = getReducedOperand(
I->getOperand(0), SclTy);
516 Value *
RHS = getReducedOperand(
I->getOperand(1), SclTy);
517 Res = Builder.CreateBinaryIntrinsic(IID,
LHS,
RHS);
526 NodeInfo.NewValue = Res;
531 for (
auto &Node : OldNewPHINodes) {
532 PHINode *OldPN =
Node.first;
533 PHINode *NewPN =
Node.second;
535 NewPN->
addIncoming(getReducedOperand(std::get<0>(Incoming), SclTy),
536 std::get<1>(Incoming));
539 Value *Res = getReducedOperand(CurrentTruncInst->getOperand(0), SclTy);
540 Type *DstTy = CurrentTruncInst->getType();
543 Res = Builder.CreateIntCast(Res, DstTy,
false);
547 CurrentTruncInst->replaceAllUsesWith(Res);
551 CurrentTruncInst->eraseFromParent();
553 for (
auto &Node : OldNewPHINodes) {
554 PHINode *OldPN =
Node.first;
556 InstInfoMap.erase(OldPN);
567 if (
I.first->use_empty())
568 I.first->eraseFromParent();
571 "Only {SExt, ZExt}Inst might have unreduced users");
576 bool MadeIRChange =
false;
581 if (!DT.isReachableFromEntry(&BB))
585 Worklist.push_back(CI);
591 while (!Worklist.empty()) {
592 CurrentTruncInst = Worklist.pop_back_val();
594 if (
Type *NewDstSclTy = getBestTruncatedType()) {
596 dbgs() <<
"ICE: TruncInstCombine reducing type of expression graph "
597 "post-dominated by: "
598 << CurrentTruncInst <<
'\n');
599 ReduceExpressionGraph(NewDstSclTy);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
uint64_t IntrinsicInst * II
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static Type * getReducedType(Value *V, Type *Ty)
Given a reduced scalar type Ty and a V value, return a reduced type for V, according to its type,...
static void getRelevantOperands(Instruction *I, SmallVectorImpl< Value * > &Ops)
Given an instruction and a container, it fills all the relevant operands of that instruction,...
static bool isRelevantOperand(const Instruction *I, unsigned OpNo)
Return whether operand OpNo of I is reducible.
uint64_t getLimitedValue(uint64_t Limit=UINT64_MAX) const
If this value is smaller than the specified limit, return it, otherwise return the limit value.
LLVM_ABI APInt uadd_sat(const APInt &RHS) const
static LLVM_ABI Constant * getTrunc(Constant *C, Type *Ty, bool OnlyIfReduced=false)
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
iterator_range< const_block_iterator > blocks() const
op_range incoming_values()
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
bool run(Function &F)
Perform TruncInst pattern optimization on given function.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
NodeAddr< NodeBase * > Node
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
@ Known
Known to have no common set bits.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI Constant * ConstantFoldConstant(const Constant *C, const DataLayout &DL, const TargetLibraryInfo *TLI=nullptr)
ConstantFoldConstant - Fold the constant using the specified DataLayout.
auto reverse(ContainerTy &&C)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
unsigned countMaxActiveBits() const
Returns the maximum number of bits needed to represent all possible unsigned values with these known ...
APInt getMaxValue() const
Return the maximal unsigned value possible given these KnownBits.