Index: lib/Transforms/Utils/Local.cpp =================================================================== --- lib/Transforms/Utils/Local.cpp +++ lib/Transforms/Utils/Local.cpp @@ -1599,12 +1599,14 @@ /// A potential constituent of a bitreverse or bswap expression. See /// collectBitParts for a fuller explanation. struct BitPart { - BitPart(Value *P, unsigned BW) : Provider(P) { + BitPart(Value *P, unsigned BW) : Provider(P), ExtraOr(nullptr) { Provenance.resize(BW); } /// The Value that this is a bitreverse/bswap of. Value *Provider; + /// An extra optional value to be ORred into the result. + Value *ExtraOr; /// The "provenance" of each bit. Provenance[A] = B means that bit A /// in Provider becomes bit B in the result of this expression. SmallVector Provenance; // int8_t means max size is i128. @@ -1656,11 +1658,27 @@ if (!A || !B) return Result; + auto IsIdentityTransform = [](ArrayRef A) { + for (size_t I = 0; I < A.size(); ++I) + if (A[I] != (int8_t)I) + return false; + return true; + }; + + // If one of the values is a simple provider... + if (B->Provider && IsIdentityTransform(B->Provenance)) { + Result = BitPart(*A); + Result->ExtraOr = B->Provider; + return Result; + } + // Try and merge the two together. - if (!A->Provider || A->Provider != B->Provider) + if (!A->Provider || A->Provider != B->Provider || + (A->ExtraOr && B->ExtraOr && A->ExtraOr != B->ExtraOr)) return Result; Result = BitPart(A->Provider, BitWidth); + Result->ExtraOr = A->ExtraOr ? A->ExtraOr : B->ExtraOr; for (unsigned i = 0; i < A->Provenance.size(); ++i) { if (A->Provenance[i] != BitPart::Unset && B->Provenance[i] != BitPart::Unset && @@ -1686,7 +1704,7 @@ auto &Res = collectBitParts(I->getOperand(0), MatchBSwaps, MatchBitReversals, BPS); - if (!Res) + if (!Res || Res->ExtraOr) return Result; Result = Res; @@ -1793,7 +1811,12 @@ else return false; + IRBuilder<> B(I); Function *F = Intrinsic::getDeclaration(I->getModule(), Intrin, ITy); - InsertedInsts.push_back(CallInst::Create(F, Res->Provider, "rev", I)); + InsertedInsts.push_back(B.CreateCall(F, Res->Provider)); + + if (Res->ExtraOr) + InsertedInsts.push_back( + cast(B.CreateOr(InsertedInsts.back(), Res->ExtraOr))); return true; } Index: test/Transforms/CodeGenPrepare/ARM/bitreverse-recognize.ll =================================================================== --- test/Transforms/CodeGenPrepare/ARM/bitreverse-recognize.ll +++ test/Transforms/CodeGenPrepare/ARM/bitreverse-recognize.ll @@ -25,6 +25,29 @@ br i1 %exitcond, label %for.cond.cleanup, label %for.body, !llvm.loop !3 } +; CHECK-LABEL: @g +define i32 @g(i32 %a, i32 %b) #0 { +; CHECK: %0 = call i32 @llvm.bitreverse.i32(i32 %a) +; CHECK: %1 = or i32 %0, %b +entry: + br label %for.body + +for.cond.cleanup: ; preds = %for.body + ret i32 %or + +for.body: ; preds = %for.body, %entry + %i.08 = phi i32 [ 0, %entry ], [ %inc, %for.body ] + %b.07 = phi i32 [ %b, %entry ], [ %or, %for.body ] + %shr = lshr i32 %a, %i.08 + %and = and i32 %shr, 1 + %sub = sub nuw nsw i32 31, %i.08 + %shl = shl i32 %and, %sub + %or = or i32 %shl, %b.07 + %inc = add nuw nsw i32 %i.08, 1 + %exitcond = icmp eq i32 %inc, 32 + br i1 %exitcond, label %for.cond.cleanup, label %for.body, !llvm.loop !3 +} + attributes #0 = { norecurse nounwind readnone "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a8" "target-features"="+dsp,+neon,+vfp3" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.module.flags = !{!0, !1}