Index: lib/Transforms/Scalar/MergedLoadStoreMotion.cpp =================================================================== --- lib/Transforms/Scalar/MergedLoadStoreMotion.cpp +++ lib/Transforms/Scalar/MergedLoadStoreMotion.cpp @@ -83,6 +83,7 @@ #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Metadata.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/DebugCounter.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -91,6 +92,9 @@ #define DEBUG_TYPE "mldst-motion" +DEBUG_COUNTER(MLDSTCounter, "mldst-motion-transform", + "Controls which instructions to sink."); + namespace { //===----------------------------------------------------------------------===// // MergedLoadStoreMotion Pass @@ -229,6 +233,10 @@ if (A0 && A1 && A0->isIdenticalTo(A1) && A0->hasOneUse() && (A0->getParent() == S0->getParent()) && A1->hasOneUse() && (A1->getParent() == S1->getParent()) && isa(A0)) { + + if (!DebugCounter::shouldExecute(MLDSTCounter)) + return false; + LLVM_DEBUG(dbgs() << "Sink Instruction into BB \n"; BB->dump(); dbgs() << "Instruction Left\n"; S0->dump(); dbgs() << "\n"; dbgs() << "Instruction Right\n"; S1->dump(); dbgs() << "\n"); Index: test/Other/debugcounter-instmerge.ll =================================================================== --- /dev/null +++ test/Other/debugcounter-instmerge.ll @@ -0,0 +1,122 @@ +; REQUIRES: asserts +; RUN: opt -debug-counter=mldst-motion-transform-skip=1,mldst-motion-transform-count=1 \ +; RUN: -basicaa -memdep -mldst-motion -S < %s | FileCheck %s +;; Test that, with debug counters on, we only optimize the second sink opportunity. +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + +%struct.node = type { i32, %struct.node*, %struct.node*, %struct.node*, i32, i32, i32, i32 } + +; Function Attrs: nounwind uwtable +define void @sink_store1(%struct.node* nocapture %r, i32 %index) { +entry: + %node.0.in16 = getelementptr inbounds %struct.node, %struct.node* %r, i64 0, i32 2 + %node.017 = load %struct.node*, %struct.node** %node.0.in16, align 8 + %index.addr = alloca i32, align 4 + store i32 %index, i32* %index.addr, align 4 + %0 = load i32, i32* %index.addr, align 4 + %cmp = icmp slt i32 %0, 0 + br i1 %cmp, label %if.then, label %if.else + +; CHECK: if.then +if.then: ; preds = %entry + %1 = load i32, i32* %index.addr, align 4 + %p1 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6 + ; CHECK: store i32 + store i32 %1, i32* %p1, align 4 + br label %if.end + +; CHECK: if.else +if.else: ; preds = %entry + %2 = load i32, i32* %index.addr, align 4 + %add = add nsw i32 %2, 1 + %p2 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6 + ; CHECK: store i32 + store i32 %add, i32* %p2, align 4 + %p3 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 5, i32 6 + ; CHECK: store i32 + store i32 %add, i32* %p3, align 4 ; This is not a barrier + br label %if.end + +; CHECK: if.end +if.end: ; preds = %if.else, %if.then +; CHECK-NOT: store + ret void +} + +; CHECK-LABEL: sink_store2 +define void @sink_store2(%struct.node* nocapture %r, i32 %index) { +entry: + %node.0.in16 = getelementptr inbounds %struct.node, %struct.node* %r, i64 0, i32 2 + %node.017 = load %struct.node*, %struct.node** %node.0.in16, align 8 + %index.addr = alloca i32, align 4 + ; CHECK: store i32 + store i32 %index, i32* %index.addr, align 4 + %0 = load i32, i32* %index.addr, align 4 + %cmp = icmp slt i32 %0, 0 + br i1 %cmp, label %if.then, label %if.else + +; CHECK: if.then +if.then: ; preds = %entry + %1 = load i32, i32* %index.addr, align 4 + %p1 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6 + ; CHECK-NOT: store i32 + store i32 %1, i32* %p1, align 4 + %p2 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 5, i32 6 + ; CHECK: load i32, i32* + %not_barrier = load i32 , i32 * %p2, align 4 + br label %if.end + +; CHECK: if.else +if.else: ; preds = %entry + %2 = load i32, i32* %index.addr, align 4 + %add = add nsw i32 %2, 1 + %p3 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6 + ; CHECK-NOT: store i32 + store i32 %add, i32* %p3, align 4 + br label %if.end + +; CHECK: if.end +if.end: ; preds = %if.else, %if.then +; CHECK: store + ret void +} + +; CHECK-LABEL: sink_store3 +define void @sink_store3(%struct.node* nocapture %r, i32 %index) { +entry: + %node.0.in16 = getelementptr inbounds %struct.node, %struct.node* %r, i64 0, i32 2 + %node.017 = load %struct.node*, %struct.node** %node.0.in16, align 8 + %index.addr = alloca i32, align 4 + store i32 %index, i32* %index.addr, align 4 + %0 = load i32, i32* %index.addr, align 4 + %cmp = icmp slt i32 %0, 0 + br i1 %cmp, label %if.then, label %if.else + +; CHECK: if.then +if.then: ; preds = %entry + %1 = load i32, i32* %index.addr, align 4 + %p1 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6 + ; CHECK: store i32 + store i32 %1, i32* %p1, align 4 + %p2 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 4, i32 6 + ; CHECK: store i32 + store i32 %1, i32* %p2, align 4 + br label %if.end + +; CHECK: if.else +if.else: ; preds = %entry + %2 = load i32, i32* %index.addr, align 4 + %add = add nsw i32 %2, 1 + %p3 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 0, i32 6 + ; CHECK: store i32 + store i32 %add, i32* %p3, align 4 + %p4 = getelementptr inbounds %struct.node, %struct.node* %node.017, i32 4, i32 6 + ; CHECK: store i32 + store i32 %2, i32* %p4, align 4 + br label %if.end + +; CHECK: if.end +if.end: ; preds = %if.else, %if.then +; CHECK-NOT: store + ret void +}