#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/GVN.h"
+#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/MemorySSA.h"
using namespace llvm;
typedef SmallVector<Instruction *, 4> SmallVecInsn;
typedef SmallVectorImpl<Instruction *> SmallVecImplInsn;
+static void combineKnownMetadata(Instruction *ReplInst, Instruction *I) {
+ static const unsigned KnownIDs[] = {
+ LLVMContext::MD_tbaa, LLVMContext::MD_alias_scope,
+ LLVMContext::MD_noalias, LLVMContext::MD_range,
+ LLVMContext::MD_fpmath, LLVMContext::MD_invariant_load,
+ LLVMContext::MD_invariant_group};
+ combineMetadata(ReplInst, I, KnownIDs);
+}
+
// This pass hoists common computations across branches sharing common
// dominator. The primary goal is to reduce the code size, and in some
// cases reduce critical path (by exposing more ILP).
ClonedGep->insertBefore(HoistPt->getTerminator());
// Conservatively discard any optimization hints, they may differ on the
// other paths.
- ClonedGep->dropUnknownNonDebugMetadata();
- for (const Instruction *OtherInst : InstructionsToHoist) {
- const GetElementPtrInst *OtherGep;
+ for (Instruction *OtherInst : InstructionsToHoist) {
+ GetElementPtrInst *OtherGep;
if (auto *OtherLd = dyn_cast<LoadInst>(OtherInst))
OtherGep = cast<GetElementPtrInst>(OtherLd->getPointerOperand());
else
OtherGep = cast<GetElementPtrInst>(
cast<StoreInst>(OtherInst)->getPointerOperand());
ClonedGep->intersectOptionalDataWith(OtherGep);
+ combineKnownMetadata(ClonedGep, OtherGep);
}
Repl->replaceUsesOfWith(Gep, ClonedGep);
ClonedVal->insertBefore(HoistPt->getTerminator());
// Conservatively discard any optimization hints, they may differ on the
// other paths.
- ClonedVal->dropUnknownNonDebugMetadata();
- for (const Instruction *OtherInst : InstructionsToHoist) {
- const auto *OtherVal =
+ for (Instruction *OtherInst : InstructionsToHoist) {
+ auto *OtherVal =
cast<Instruction>(cast<StoreInst>(OtherInst)->getValueOperand());
ClonedVal->intersectOptionalDataWith(OtherVal);
+ combineKnownMetadata(ClonedVal, OtherVal);
}
Repl->replaceUsesOfWith(Val, ClonedVal);
}
Repl->moveBefore(HoistPt->getTerminator());
// TBAA may differ on one of the other paths, we need to get rid of
// anything which might conflict.
- Repl->dropUnknownNonDebugMetadata();
}
if (isa<LoadInst>(Repl))
++NumCallsRemoved;
}
Repl->intersectOptionalDataWith(I);
+ combineKnownMetadata(Repl, I);
I->replaceAllUsesWith(Repl);
I->eraseFromParent();
}
!4 = !{!"Simple C++ TBAA"}
!5 = !{!6, !6, i64 0}
!6 = !{!"_ZTS1e", !3, i64 0}
+
+define i32 @test4(i1 %b, i32* %y) {
+entry:
+ br i1 %b, label %if.then, label %if.end
+
+if.then: ; preds = %entry
+ %0 = load i32, i32* %y, align 4, !range !7
+ br label %return
+
+if.end: ; preds = %entry
+ %1 = load i32, i32* %y, align 4, !range !8
+ br label %return
+
+return: ; preds = %if.end, %if.then
+ %retval.0 = phi i32 [ %0, %if.then ], [ %1, %if.end ]
+ ret i32 %retval.0
+}
+; CHECK-LABEL: define i32 @test4(
+; CHECK: %[[load:.*]] = load i32, i32* %y, align 4, !range ![[range_md:.*]]
+; CHECK: %[[phi:.*]] = phi i32 [ %[[load]], %{{.*}} ], [ %[[load]], %{{.*}} ]
+; CHECK: ret i32 %[[phi]]
+
+!7 = !{i32 0, i32 2}
+!8 = !{i32 3, i32 4}
+; CHECK: ![[range_md]] = !{i32 0, i32 2, i32 3, i32 4}