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();
118 if (!DT.isReachableFromEntry(
I->getParent()))
127 InstInfoMap.try_emplace(
I);
131 if (InstInfoMap.count(
I)) {
139 unsigned Opc =
I->getOpcode();
141 case Instruction::Trunc:
142 case Instruction::ZExt:
143 case Instruction::SExt:
149 case Instruction::Add:
150 case Instruction::Sub:
151 case Instruction::Mul:
152 case Instruction::And:
153 case Instruction::Or:
154 case Instruction::Xor:
155 case Instruction::Shl:
156 case Instruction::LShr:
157 case Instruction::AShr:
158 case Instruction::UDiv:
159 case Instruction::URem:
160 case Instruction::InsertElement:
161 case Instruction::ExtractElement:
162 case Instruction::Select:
163 case Instruction::ShuffleVector: {
169 case Instruction::PHI: {
175 Worklist.push_back(
Op);
178 case Instruction::Call: {
180 if (IID == Intrinsic::umin || IID == Intrinsic::umax) {
198unsigned TruncInstCombine::getMinBitWidth() {
199 SmallVector<Value *, 8> Worklist;
200 SmallVector<Instruction *, 8>
Stack;
202 Value *Src = CurrentTruncInst->getOperand(0);
203 Type *DstTy = CurrentTruncInst->getType();
205 unsigned OrigBitWidth =
206 CurrentTruncInst->getOperand(0)->getType()->getScalarSizeInBits();
209 return TruncBitWidth;
211 Worklist.push_back(Src);
214 while (!Worklist.empty()) {
215 Value *Curr = Worklist.back();
225 auto &Info = InstInfoMap[
I];
238 std::max(Info.MinBitWidth, InstInfoMap[IOp].MinBitWidth);
244 unsigned ValidBitWidth = Info.ValidBitWidth;
248 Info.MinBitWidth = std::max(Info.MinBitWidth, Info.ValidBitWidth);
255 unsigned IOpBitwidth = InstInfoMap.lookup(IOp).ValidBitWidth;
256 if (IOpBitwidth >= ValidBitWidth)
258 InstInfoMap[IOp].ValidBitWidth = ValidBitWidth;
259 Worklist.push_back(IOp);
263 assert(MinBitWidth >= TruncBitWidth);
265 if (MinBitWidth > TruncBitWidth) {
272 Type *Ty = DL.getSmallestLegalIntType(DstTy->
getContext(), MinBitWidth);
281 bool FromLegal = MinBitWidth == 1 || DL.isLegalInteger(OrigBitWidth);
282 bool ToLegal = MinBitWidth == 1 || DL.isLegalInteger(MinBitWidth);
283 if (!DstTy->
isVectorTy() && FromLegal && !ToLegal)
289Type *TruncInstCombine::getBestTruncatedType() {
290 if (!buildTruncExpressionGraph())
297 unsigned DesiredBitWidth = 0;
298 for (
auto Itr : InstInfoMap) {
303 for (Use &U :
I->uses())
305 if (UI != CurrentTruncInst &&
306 (!InstInfoMap.count(UI) ||
313 unsigned ExtInstBitWidth =
314 I->getOperand(0)->getType()->getScalarSizeInBits();
315 if (DesiredBitWidth && DesiredBitWidth != ExtInstBitWidth)
317 DesiredBitWidth = ExtInstBitWidth;
321 unsigned OrigBitWidth =
322 CurrentTruncInst->getOperand(0)->getType()->getScalarSizeInBits();
332 for (
auto &Itr : InstInfoMap) {
335 KnownBits KnownRHS = computeKnownBits(
I->getOperand(1));
339 if (MinBitWidth == OrigBitWidth)
341 if (
I->getOpcode() == Instruction::LShr) {
342 KnownBits KnownLHS = computeKnownBits(
I->getOperand(0));
345 if (
I->getOpcode() == Instruction::AShr) {
346 unsigned NumSignBits = ComputeNumSignBits(
I->getOperand(0));
347 MinBitWidth = std::max(MinBitWidth, OrigBitWidth - NumSignBits + 1);
349 if (MinBitWidth >= OrigBitWidth)
351 Itr.second.MinBitWidth = MinBitWidth;
352 }
else if (
I->getOpcode() == Instruction::UDiv ||
353 I->getOpcode() == Instruction::URem) {
354 unsigned MinBitWidth = 0;
355 for (
const auto &
Op :
I->operands()) {
356 KnownBits
Known = computeKnownBits(
Op);
357 MinBitWidth = std::max(
Known.countMaxActiveBits(), MinBitWidth);
358 if (MinBitWidth >= OrigBitWidth)
361 Itr.second.MinBitWidth = MinBitWidth;
363 switch (
II->getIntrinsicID()) {
364 case Intrinsic::umin:
365 case Intrinsic::umax: {
366 unsigned MinBitWidth = 0;
367 for (
const auto &
Op :
II->args()) {
368 KnownBits
Known = computeKnownBits(
Op);
369 MinBitWidth = std::max(
Known.countMaxActiveBits(), MinBitWidth);
370 if (MinBitWidth >= OrigBitWidth)
373 Itr.second.MinBitWidth = MinBitWidth;
384 unsigned MinBitWidth = getMinBitWidth();
388 if (MinBitWidth >= OrigBitWidth ||
389 (DesiredBitWidth && DesiredBitWidth != MinBitWidth))
398 assert(Ty && !Ty->isVectorTy() &&
"Expect Scalar Type");
404Value *TruncInstCombine::getReducedOperand(
Value *V,
Type *SclTy) {
413 Info
Entry = InstInfoMap.lookup(
I);
415 return Entry.NewValue;
418void TruncInstCombine::ReduceExpressionGraph(
Type *SclTy) {
419 NumInstrsReduced += InstInfoMap.size();
422 for (
auto &Itr : InstInfoMap) {
424 TruncInstCombine::Info &NodeInfo = Itr.second;
426 assert(!NodeInfo.NewValue &&
"Instruction has been evaluated");
429 Value *Res =
nullptr;
430 unsigned Opc =
I->getOpcode();
432 case Instruction::Trunc:
433 case Instruction::ZExt:
434 case Instruction::SExt: {
439 if (
I->getOperand(0)->getType() == Ty) {
441 NodeInfo.NewValue =
I->getOperand(0);
446 Res = Builder.CreateIntCast(
I->getOperand(0), Ty,
447 Opc == Instruction::SExt);
455 if (Entry != Worklist.end()) {
459 Worklist.erase(Entry);
461 Worklist.push_back(NewCI);
464 case Instruction::Add:
465 case Instruction::Sub:
466 case Instruction::Mul:
467 case Instruction::And:
468 case Instruction::Or:
469 case Instruction::Xor:
470 case Instruction::Shl:
471 case Instruction::LShr:
472 case Instruction::AShr:
473 case Instruction::UDiv:
474 case Instruction::URem: {
475 Value *
LHS = getReducedOperand(
I->getOperand(0), SclTy);
476 Value *
RHS = getReducedOperand(
I->getOperand(1), SclTy);
481 ResI->setIsExact(PEO->isExact());
484 case Instruction::ExtractElement: {
485 Value *Vec = getReducedOperand(
I->getOperand(0), SclTy);
486 Value *Idx =
I->getOperand(1);
487 Res = Builder.CreateExtractElement(Vec, Idx);
490 case Instruction::InsertElement: {
491 Value *Vec = getReducedOperand(
I->getOperand(0), SclTy);
492 Value *NewElt = getReducedOperand(
I->getOperand(1), SclTy);
493 Value *Idx =
I->getOperand(2);
494 Res = Builder.CreateInsertElement(Vec, NewElt, Idx);
497 case Instruction::Select: {
498 Value *Op0 =
I->getOperand(0);
499 Value *
LHS = getReducedOperand(
I->getOperand(1), SclTy);
500 Value *
RHS = getReducedOperand(
I->getOperand(2), SclTy);
501 Res = Builder.CreateSelect(Op0,
LHS,
RHS,
"",
I);
504 case Instruction::ShuffleVector: {
505 Value *
LHS = getReducedOperand(
I->getOperand(0), SclTy);
506 Value *
RHS = getReducedOperand(
I->getOperand(1), SclTy);
508 Res = Builder.CreateShuffleVector(
LHS,
RHS,
SI->getShuffleMask());
511 case Instruction::PHI: {
517 case Instruction::Call: {
519 if (IID == Intrinsic::umin || IID == Intrinsic::umax) {
520 Value *
LHS = getReducedOperand(
I->getOperand(0), SclTy);
521 Value *
RHS = getReducedOperand(
I->getOperand(1), SclTy);
522 Res = Builder.CreateBinaryIntrinsic(IID,
LHS,
RHS);
531 NodeInfo.NewValue = Res;
536 for (
auto &Node : OldNewPHINodes) {
537 PHINode *OldPN =
Node.first;
538 PHINode *NewPN =
Node.second;
540 NewPN->
addIncoming(getReducedOperand(std::get<0>(Incoming), SclTy),
541 std::get<1>(Incoming));
544 Value *Res = getReducedOperand(CurrentTruncInst->getOperand(0), SclTy);
545 Type *DstTy = CurrentTruncInst->getType();
548 Res = Builder.CreateIntCast(Res, DstTy,
false);
552 CurrentTruncInst->replaceAllUsesWith(Res);
556 CurrentTruncInst->eraseFromParent();
558 for (
auto &Node : OldNewPHINodes) {
559 PHINode *OldPN =
Node.first;
561 InstInfoMap.erase(OldPN);
572 if (
I.first->use_empty())
573 I.first->eraseFromParent();
576 "Only {SExt, ZExt}Inst might have unreduced users");
581 bool MadeIRChange =
false;
586 if (!DT.isReachableFromEntry(&BB))
590 Worklist.push_back(CI);
596 while (!Worklist.empty()) {
597 CurrentTruncInst = Worklist.pop_back_val();
599 if (
Type *NewDstSclTy = getBestTruncatedType()) {
601 dbgs() <<
"ICE: TruncInstCombine reducing type of expression graph "
602 "post-dominated by: "
603 << CurrentTruncInst <<
'\n');
604 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.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
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...
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.