Index: lib/Transforms/IPO/MergeFunctions.cpp =================================================================== --- lib/Transforms/IPO/MergeFunctions.cpp +++ lib/Transforms/IPO/MergeFunctions.cpp @@ -1119,6 +1119,9 @@ /// again. void mergeTwoFunctions(Function *F, Function *G); + /// Update the range metadata used by loads in F so that F can replace G. + void mergeRangeMetadata(Function *F, const Function *G); + /// Replace G with a thunk or an alias to F. Deletes G. void writeThunkOrAlias(Function *F, Function *G); @@ -1343,6 +1346,8 @@ // Merge two equivalent functions. Upon completion, Function G is deleted. void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) { + mergeRangeMetadata(F, G); + if (F->mayBeOverridden()) { assert(G->mayBeOverridden()); @@ -1376,6 +1381,51 @@ ++NumFunctionsMerged; } +// Update the range metadata used by loads in F so that F can replace G. +void MergeFunctions::mergeRangeMetadata(Function *F, const Function *G) { + // Find all loads in F and their counterparts in G, then update the range + // metadata in F to be the union of the ranges in F and G. Iterate over the + // functions in CFG-order, the same way that compare does. + SmallVector FBBs; + SmallVector GBBs; + SmallSet VisitedBBs; // in terms of F. + + FBBs.push_back(&F->getEntryBlock()); + GBBs.push_back(&G->getEntryBlock()); + + VisitedBBs.insert(FBBs[0]); + while (!FBBs.empty()) { + BasicBlock *FBB = FBBs.pop_back_val(); + const BasicBlock *GBB = GBBs.pop_back_val(); + + BasicBlock::iterator FI = FBB->begin(), FE = FBB->end(); + BasicBlock::const_iterator GI = GBB->begin(), GE = GBB->end(); + do { + if (LoadInst *FLI = dyn_cast(FI)) { + const LoadInst *GLI = dyn_cast(GI); + assert(GLI); + FLI->setMetadata(LLVMContext::MD_range, + MDNode::getMostGenericRange( + FLI->getMetadata(LLVMContext::MD_range), + GLI->getMetadata(LLVMContext::MD_range))); + } + ++FI; ++GI; + } while (FI != FE && GI != GE); + + const TerminatorInst *FTI = FBB->getTerminator(); + const TerminatorInst *GTI = GBB->getTerminator(); + + assert(FTI->getNumSuccessors() == GTI->getNumSuccessors()); + for (unsigned i = 0, e = FTI->getNumSuccessors(); i != e; ++i) { + if (!VisitedBBs.insert(FTI->getSuccessor(i))) + continue; + + FBBs.push_back(FTI->getSuccessor(i)); + GBBs.push_back(GTI->getSuccessor(i)); + } + } +} + // Insert a ComparableFunction into the FnSet, or merge it away if equal to one // that was already inserted. bool MergeFunctions::insert(ComparableFunction &NewF) { Index: test/Transforms/MergeFunc/ranges.ll =================================================================== --- /dev/null +++ test/Transforms/MergeFunc/ranges.ll @@ -0,0 +1,52 @@ +; RUN: opt -mergefunc -S < %s | FileCheck %s +define i1 @ne_with_range(i8*, i8*) { +; The range must be eliminated here, when this is merged with ne_without_range +; CHECK-LABEL: @ne_with_range +; CHECK-NEXT: %v1 = load i8* %0{{$}} +; CHECK-NEXT: %v2 = load i8* %1{{$}} +; CHECK-NEXT: %out = icmp ne i8 %v1, %v2 +; CHECK-NEXT: ret i1 %out + %v1 = load i8* %0, !range !0 + %v2 = load i8* %1, !range !0 + %out = icmp ne i8 %v1, %v2 + ret i1 %out +} + +define i1 @eq_with_range(i8*, i8*) { +; The range must be a merge of the ranges used in the two functions, the check +; for the range being correct is at the end of the file +; CHECK-LABEL: @eq_with_range +; CHECK: %v1 = load i8* %0, !range !0 +; CHECK: %v2 = load i8* %1, !range !0 +; CHECK: %out = icmp eq i8 %v1, %v2 +; CHECK: ret i1 %out + %v1 = load i8* %0, !range !0 + %v2 = load i8* %1, !range !0 + %out = icmp eq i8 %v1, %v2 + ret i1 %out +} + +define i1 @ne_without_range(i8*, i8*) { +; CHECK-LABEL: @ne_without_range +; CHECK-NEXT: tail call i1 @ne_with_range +; CHECK-NEXT: ret i1 + %v1 = load i8* %0 + %v2 = load i8* %1 + %out = icmp ne i8 %v1, %v2 + ret i1 %out +} + +define i1 @eq_with_different_range(i8*, i8*) { +; CHECK-LABEL: @eq_with_different_range +; CHECK-NEXT: tail call i1 @eq_with_range +; CHECK-NEXT: ret i1 + %v1 = load i8* %0, !range !1 + %v2 = load i8* %1, !range !1 + %out = icmp eq i8 %v1, %v2 + ret i1 %out +} + +; The merged range for the @eq_* functions +; CHECK: !0 = metadata !{i8 0, i8 2, i8 5, i8 7} +!0 = metadata !{i8 0, i8 2} +!1 = metadata !{i8 5, i8 7}