Index: lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -561,6 +561,32 @@ return NewStore; } +/// Returns true if instruction represent minmax pattern like: +/// select ((cmp load V1, load V2), V1, V2). +static bool isMinMaxPattern(Value *V) { + assert(V->getType()->isPointerTy() && "Expected pointer type."); + // Ignore all bitcasts. + while (auto *BC = dyn_cast(V)) + V = BC->getOperand(0); + auto *SelI = dyn_cast(V); + if (!SelI) + return false; + // Check that select is select ((cmp load V1, load V2), V1, V2) - minmax + // pattern. + auto *CmpI = dyn_cast(SelI->getCondition()); + auto *V1 = SelI->getTrueValue(); + auto *V2 = SelI->getFalseValue(); + if (!CmpI) + return false; + auto *CLI1 = dyn_cast(CmpI->getOperand(0)); + auto *CLI2 = dyn_cast(CmpI->getOperand(1)); + if (!CLI1 || !CLI2) + return false; + auto *LV1 = CLI1->getPointerOperand(); + auto *LV2 = CLI2->getPointerOperand(); + return (LV1 == V1 && LV2 == V2) || (LV1 == V2 && LV2 == V1); +} + /// \brief Combine loads to match the type of their uses' value after looking /// through intervening bitcasts. /// @@ -591,6 +617,9 @@ if (LI.getPointerOperand()->isSwiftError()) return nullptr; + if (isMinMaxPattern(LI.getPointerOperand())) + return nullptr; + Type *Ty = LI.getType(); const DataLayout &DL = IC.getDataLayout(); @@ -1298,6 +1327,32 @@ return false; } +/// Converts store (bitcast (load (bitcast (select ...)))) to +/// store (load (select ...)), where select is minmax: +/// select ((cmp load V1, load V2), V1, V2). +bool decanonicalizeLoadStoreOnSelect(InstCombiner &IC, StoreInst &SI) { + // bitcast? + if (!isa(SI.getPointerOperand())) + return false; + // load? integer? + auto *LI = dyn_cast(SI.getValueOperand()); + if (!LI || !LI->getType()->isIntegerTy()) + return false; + auto *LBC = dyn_cast(LI->getPointerOperand()); + // bitcast? + if (!LBC) + return false; + if (!isMinMaxPattern(LBC->getOperand(0))) + return false; + + IC.Builder.SetInsertPoint(LI); + LoadInst *NewLI = combineLoadToNewType( + IC, *LI, LBC->getOperand(0)->getType()->getPointerElementType()); + IC.Builder.SetInsertPoint(&SI); + combineStoreToNewValue(IC, SI, NewLI); + return true; +} + Instruction *InstCombiner::visitStoreInst(StoreInst &SI) { Value *Val = SI.getOperand(0); Value *Ptr = SI.getOperand(1); @@ -1322,6 +1377,10 @@ if (unpackStoreToAggregate(*this, SI)) return eraseInstFromFunction(SI); + // Try to decanonicalize store (bitcast (load (bitcast (select ...)))). + if (decanonicalizeLoadStoreOnSelect(*this, SI)) + return eraseInstFromFunction(SI); + // Replace GEP indices if possible. if (Instruction *NewGEPI = replaceGEPIdxWithZero(*this, Ptr, SI)) { Worklist.Add(NewGEPI); Index: test/Transforms/InstCombine/load-bitcast-select.ll =================================================================== --- test/Transforms/InstCombine/load-bitcast-select.ll +++ test/Transforms/InstCombine/load-bitcast-select.ll @@ -21,11 +21,8 @@ ; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[ARRAYIDX]], align 4 ; CHECK-NEXT: [[TMP2:%.*]] = load float, float* [[ARRAYIDX2]], align 4 ; CHECK-NEXT: [[CMP_I:%.*]] = fcmp fast olt float [[TMP1]], [[TMP2]] -; CHECK-NEXT: [[__B___A_I:%.*]] = select i1 [[CMP_I]], float* [[ARRAYIDX2]], float* [[ARRAYIDX]] -; CHECK-NEXT: [[TMP3:%.*]] = bitcast float* [[__B___A_I]] to i32* -; CHECK-NEXT: [[TMP4:%.*]] = load i32, i32* [[TMP3]], align 4 -; CHECK-NEXT: [[TMP5:%.*]] = bitcast float* [[ARRAYIDX]] to i32* -; CHECK-NEXT: store i32 [[TMP4]], i32* [[TMP5]], align 4 +; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[CMP_I]], float [[TMP2]], float [[TMP1]] +; CHECK-NEXT: store float [[TMP3]], float* [[ARRAYIDX]], align 4 ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_0]], 1 ; CHECK-NEXT: br label [[FOR_COND]] ;