39#define DEBUG_TYPE "aggressive-instcombine"
41STATISTIC(NumExprsReduced,
"Number of truncations eliminated by reducing bit "
42 "width of expression graph");
44 "Number of instructions whose bit width was reduced");
48 unsigned Opc =
I->getOpcode();
50 case Instruction::Trunc:
51 case Instruction::ZExt:
52 case Instruction::SExt:
56 case Instruction::Add:
57 case Instruction::Sub:
58 case Instruction::Mul:
59 case Instruction::And:
61 case Instruction::Xor:
62 case Instruction::Shl:
63 case Instruction::LShr:
64 case Instruction::AShr:
65 case Instruction::UDiv:
66 case Instruction::URem:
68 case Instruction::InsertElement:
70 case Instruction::ExtractElement:
72 case Instruction::Select:
74 case Instruction::PHI:
76 case Instruction::ShuffleVector:
86 for (
Use &
Op :
I->operands())
88 Ops.push_back(
Op.get());
91bool TruncInstCombine::buildTruncExpressionGraph() {
92 SmallVector<Value *, 8> Worklist;
93 SmallVector<Instruction *, 8>
Stack;
97 Worklist.push_back(CurrentTruncInst->getOperand(0));
99 while (!Worklist.empty()) {
100 Value *Curr = Worklist.back();
117 InstInfoMap.try_emplace(
I);
121 if (InstInfoMap.count(
I)) {
129 unsigned Opc =
I->getOpcode();
131 case Instruction::Trunc:
132 case Instruction::ZExt:
133 case Instruction::SExt:
139 case Instruction::Add:
140 case Instruction::Sub:
141 case Instruction::Mul:
142 case Instruction::And:
143 case Instruction::Or:
144 case Instruction::Xor:
145 case Instruction::Shl:
146 case Instruction::LShr:
147 case Instruction::AShr:
148 case Instruction::UDiv:
149 case Instruction::URem:
150 case Instruction::InsertElement:
151 case Instruction::ExtractElement:
152 case Instruction::Select:
153 case Instruction::ShuffleVector: {
159 case Instruction::PHI: {
165 Worklist.push_back(
Op);
178unsigned TruncInstCombine::getMinBitWidth() {
179 SmallVector<Value *, 8> Worklist;
180 SmallVector<Instruction *, 8>
Stack;
182 Value *Src = CurrentTruncInst->getOperand(0);
183 Type *DstTy = CurrentTruncInst->getType();
185 unsigned OrigBitWidth =
186 CurrentTruncInst->getOperand(0)->getType()->getScalarSizeInBits();
189 return TruncBitWidth;
191 Worklist.push_back(Src);
194 while (!Worklist.empty()) {
195 Value *Curr = Worklist.back();
205 auto &Info = InstInfoMap[
I];
218 std::max(Info.MinBitWidth, InstInfoMap[IOp].MinBitWidth);
224 unsigned ValidBitWidth = Info.ValidBitWidth;
228 Info.MinBitWidth = std::max(Info.MinBitWidth, Info.ValidBitWidth);
235 unsigned IOpBitwidth = InstInfoMap.lookup(IOp).ValidBitWidth;
236 if (IOpBitwidth >= ValidBitWidth)
238 InstInfoMap[IOp].ValidBitWidth = ValidBitWidth;
239 Worklist.push_back(IOp);
243 assert(MinBitWidth >= TruncBitWidth);
245 if (MinBitWidth > TruncBitWidth) {
252 Type *Ty = DL.getSmallestLegalIntType(DstTy->
getContext(), MinBitWidth);
261 bool FromLegal = MinBitWidth == 1 || DL.isLegalInteger(OrigBitWidth);
262 bool ToLegal = MinBitWidth == 1 || DL.isLegalInteger(MinBitWidth);
263 if (!DstTy->
isVectorTy() && FromLegal && !ToLegal)
269Type *TruncInstCombine::getBestTruncatedType() {
270 if (!buildTruncExpressionGraph())
277 unsigned DesiredBitWidth = 0;
278 for (
auto Itr : InstInfoMap) {
283 for (Use &U :
I->uses())
285 if (UI != CurrentTruncInst &&
286 (!InstInfoMap.count(UI) ||
293 unsigned ExtInstBitWidth =
294 I->getOperand(0)->getType()->getScalarSizeInBits();
295 if (DesiredBitWidth && DesiredBitWidth != ExtInstBitWidth)
297 DesiredBitWidth = ExtInstBitWidth;
301 unsigned OrigBitWidth =
302 CurrentTruncInst->getOperand(0)->getType()->getScalarSizeInBits();
312 for (
auto &Itr : InstInfoMap) {
315 KnownBits KnownRHS = computeKnownBits(
I->getOperand(1));
319 if (MinBitWidth == OrigBitWidth)
321 if (
I->getOpcode() == Instruction::LShr) {
322 KnownBits KnownLHS = computeKnownBits(
I->getOperand(0));
326 if (
I->getOpcode() == Instruction::AShr) {
327 unsigned NumSignBits = ComputeNumSignBits(
I->getOperand(0));
328 MinBitWidth = std::max(MinBitWidth, OrigBitWidth - NumSignBits + 1);
330 if (MinBitWidth >= OrigBitWidth)
332 Itr.second.MinBitWidth = MinBitWidth;
334 if (
I->getOpcode() == Instruction::UDiv ||
335 I->getOpcode() == Instruction::URem) {
336 unsigned MinBitWidth = 0;
337 for (
const auto &
Op :
I->operands()) {
338 KnownBits
Known = computeKnownBits(
Op);
340 std::max(
Known.getMaxValue().getActiveBits(), MinBitWidth);
341 if (MinBitWidth >= OrigBitWidth)
344 Itr.second.MinBitWidth = MinBitWidth;
350 unsigned MinBitWidth = getMinBitWidth();
354 if (MinBitWidth >= OrigBitWidth ||
355 (DesiredBitWidth && DesiredBitWidth != MinBitWidth))
364 assert(Ty && !Ty->isVectorTy() &&
"Expect Scalar Type");
370Value *TruncInstCombine::getReducedOperand(
Value *V,
Type *SclTy) {
379 Info
Entry = InstInfoMap.lookup(
I);
381 return Entry.NewValue;
384void TruncInstCombine::ReduceExpressionGraph(
Type *SclTy) {
385 NumInstrsReduced += InstInfoMap.size();
388 for (
auto &Itr : InstInfoMap) {
390 TruncInstCombine::Info &NodeInfo = Itr.second;
392 assert(!NodeInfo.NewValue &&
"Instruction has been evaluated");
395 Value *Res =
nullptr;
396 unsigned Opc =
I->getOpcode();
398 case Instruction::Trunc:
399 case Instruction::ZExt:
400 case Instruction::SExt: {
405 if (
I->getOperand(0)->getType() == Ty) {
407 NodeInfo.NewValue =
I->getOperand(0);
412 Res = Builder.CreateIntCast(
I->getOperand(0), Ty,
413 Opc == Instruction::SExt);
421 if (Entry != Worklist.end()) {
425 Worklist.erase(Entry);
427 Worklist.push_back(NewCI);
430 case Instruction::Add:
431 case Instruction::Sub:
432 case Instruction::Mul:
433 case Instruction::And:
434 case Instruction::Or:
435 case Instruction::Xor:
436 case Instruction::Shl:
437 case Instruction::LShr:
438 case Instruction::AShr:
439 case Instruction::UDiv:
440 case Instruction::URem: {
441 Value *
LHS = getReducedOperand(
I->getOperand(0), SclTy);
442 Value *
RHS = getReducedOperand(
I->getOperand(1), SclTy);
447 ResI->setIsExact(PEO->isExact());
450 case Instruction::ExtractElement: {
451 Value *Vec = getReducedOperand(
I->getOperand(0), SclTy);
452 Value *Idx =
I->getOperand(1);
453 Res = Builder.CreateExtractElement(Vec, Idx);
456 case Instruction::InsertElement: {
457 Value *Vec = getReducedOperand(
I->getOperand(0), SclTy);
458 Value *NewElt = getReducedOperand(
I->getOperand(1), SclTy);
459 Value *Idx =
I->getOperand(2);
460 Res = Builder.CreateInsertElement(Vec, NewElt, Idx);
463 case Instruction::Select: {
464 Value *Op0 =
I->getOperand(0);
465 Value *
LHS = getReducedOperand(
I->getOperand(1), SclTy);
466 Value *
RHS = getReducedOperand(
I->getOperand(2), SclTy);
467 Res = Builder.CreateSelect(Op0,
LHS,
RHS,
"",
I);
470 case Instruction::ShuffleVector: {
471 Value *
LHS = getReducedOperand(
I->getOperand(0), SclTy);
472 Value *
RHS = getReducedOperand(
I->getOperand(1), SclTy);
474 Res = Builder.CreateShuffleVector(
LHS,
RHS,
SI->getShuffleMask());
477 case Instruction::PHI: {
487 NodeInfo.NewValue = Res;
492 for (
auto &Node : OldNewPHINodes) {
493 PHINode *OldPN =
Node.first;
494 PHINode *NewPN =
Node.second;
496 NewPN->
addIncoming(getReducedOperand(std::get<0>(Incoming), SclTy),
497 std::get<1>(Incoming));
500 Value *Res = getReducedOperand(CurrentTruncInst->getOperand(0), SclTy);
501 Type *DstTy = CurrentTruncInst->getType();
504 Res = Builder.CreateIntCast(Res, DstTy,
false);
508 CurrentTruncInst->replaceAllUsesWith(Res);
512 CurrentTruncInst->eraseFromParent();
514 for (
auto &Node : OldNewPHINodes) {
515 PHINode *OldPN =
Node.first;
517 InstInfoMap.erase(OldPN);
528 if (
I.first->use_empty())
529 I.first->eraseFromParent();
532 "Only {SExt, ZExt}Inst might have unreduced users");
537 bool MadeIRChange =
false;
542 if (!DT.isReachableFromEntry(&BB))
546 Worklist.push_back(CI);
552 while (!Worklist.empty()) {
553 CurrentTruncInst = Worklist.pop_back_val();
555 if (
Type *NewDstSclTy = getBestTruncatedType()) {
557 dbgs() <<
"ICE: TruncInstCombine reducing type of expression graph "
559 << CurrentTruncInst <<
'\n');
560 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[]
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.
unsigned getActiveBits() const
Compute the number of active bits in the value.
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.
APInt getMaxValue() const
Return the maximal unsigned value possible given these KnownBits.