diff --git a/llvm/test/Reduce/remove-operand-bundles.ll b/llvm/test/Reduce/remove-operand-bundles.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Reduce/remove-operand-bundles.ll @@ -0,0 +1,41 @@ +; Test that llvm-reduce can remove uninteresting operand bundles from calls. +; +; RUN: rm -rf %t +; RUN: llvm-reduce --test FileCheck --test-arg --check-prefixes=CHECK-ALL,CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t +; RUN: cat %t | FileCheck --check-prefixes=CHECK-ALL,CHECK-FINAL %s + +; CHECK-ALL: declare void @f1() +; CHECK-ALL: declare void @f2() +; CHECK-ALL: declare void @f3() +declare void @f1() +declare void @f2() +declare void @f3() + +; CHECK-FINAL-LABEL: define void @interesting(i32 %arg0, i32 %arg1, i32 %arg2) { +; CHECK-FINAL-NEXT: entry: +; CHECK-FINAL-NEXT: call void @f1() [ "bundle0"(), "align"(i32 %arg0), "whatever0"() ] +; CHECK-FINAL-NEXT: call void @f2() +; CHECK-FINAL-NEXT: call void @f3() [ "align"(i32 %arg2) ] +; CHECK-FINAL-NEXT: ret void +; CHECK-FINAL-NEXT: } +define void @interesting(i32 %arg0, i32 %arg1, i32 %arg2) { +entry: +; CHECK-INTERESTINGNESS-LABEL: @interesting( + +; CHECK-INTERESTINGNESS: call void @f1() +; CHECK-INTERESTINGNESS: "bundle0"() +; CHECK-INTERESTINGNESS: "align"(i32 %arg0) +; CHECK-INTERESTINGNESS: "whatever0"() + +; CHECK-INTERESTINGNESS: call void @f2() + +; CHECK-INTERESTINGNESS: call void @f3() +; CHECK-INTERESTINGNESS: "align"(i32 %arg2) + +; CHECK-INTERESTINGNESS: ret + + call void @f1() [ "bundle0"(), "align"(i32 %arg0), "whatever0"() ] + call void @f2() [ "align"(i32 %arg1), "whatever1"(), "bundle1"() ] + call void @f3() [ "whatever2"(), "bundle2"(), "align"(i32 %arg2) ] + ret void +} diff --git a/llvm/tools/llvm-reduce/CMakeLists.txt b/llvm/tools/llvm-reduce/CMakeLists.txt --- a/llvm/tools/llvm-reduce/CMakeLists.txt +++ b/llvm/tools/llvm-reduce/CMakeLists.txt @@ -11,15 +11,16 @@ ) add_llvm_tool(llvm-reduce - llvm-reduce.cpp TestRunner.cpp deltas/Delta.cpp - deltas/ReduceFunctions.cpp - deltas/ReduceGlobalVars.cpp - deltas/ReduceMetadata.cpp deltas/ReduceArguments.cpp deltas/ReduceBasicBlocks.cpp + deltas/ReduceFunctions.cpp + deltas/ReduceGlobalVars.cpp deltas/ReduceInstructions.cpp + deltas/ReduceMetadata.cpp + deltas/ReduceOperandBundles.cpp + llvm-reduce.cpp DEPENDS intrinsics_gen diff --git a/llvm/tools/llvm-reduce/DeltaManager.h b/llvm/tools/llvm-reduce/DeltaManager.h --- a/llvm/tools/llvm-reduce/DeltaManager.h +++ b/llvm/tools/llvm-reduce/DeltaManager.h @@ -17,8 +17,9 @@ #include "deltas/ReduceBasicBlocks.h" #include "deltas/ReduceFunctions.h" #include "deltas/ReduceGlobalVars.h" -#include "deltas/ReduceMetadata.h" #include "deltas/ReduceInstructions.h" +#include "deltas/ReduceMetadata.h" +#include "deltas/ReduceOperandBundles.h" namespace llvm { @@ -30,6 +31,7 @@ reduceMetadataDeltaPass(Tester); reduceArgumentsDeltaPass(Tester); reduceInstructionsDeltaPass(Tester); + reduceOperandBundesDeltaPass(Tester); // TODO: Implement the remaining Delta Passes } diff --git a/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.h b/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.h @@ -0,0 +1,21 @@ +//===- ReduceOperandBundes.h - Specialized Delta Pass ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce uninteresting operand bundes from calls. +// +//===----------------------------------------------------------------------===// + +#include "Delta.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Cloning.h" + +namespace llvm { +void reduceOperandBundesDeltaPass(TestRunner &Test); +} // namespace llvm diff --git a/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp b/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp @@ -0,0 +1,99 @@ +//===- ReduceOperandBundes.cpp - Specialized Delta Pass -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements a function which calls the Generic Delta pass in order +// to reduce uninteresting operand bundes from calls. +// +//===----------------------------------------------------------------------===// + +#include "ReduceOperandBundles.h" +#include "Delta.h" +#include "llvm/ADT/Sequence.h" +#include "llvm/ADT/SmallVector.h" +#include +#include + +using namespace llvm; + +/// Created call identical to OrigCB but with NewBundles bundles instead. +static CallBase * +getCallWithDifferentBundles(CallBase *OrigCB, + ArrayRef NewBundles) { + switch (OrigCB->getOpcode()) { + case Instruction::Call: + return CallInst::Create(cast(OrigCB), NewBundles, OrigCB); + case Instruction::Invoke: + return InvokeInst::Create(cast(OrigCB), NewBundles, OrigCB); + case Instruction::CallBr: + return CallBrInst::Create(cast(OrigCB), NewBundles, OrigCB); + default: + llvm_unreachable("Unknownd CallBase!"); + } +} + +/// Removes out-of-chunk operand bundles from calls. +static void extractOperandBundesFromModule(std::vector ChunksToKeep, + Module *Program) { + int I = 0, OperandBundleCount = 0; + DenseMap> CallsToRefine; + + for (auto &F : *Program) + for (auto &BB : F) + for (auto &Instr : BB) + if (auto *Call = dyn_cast(&Instr)) { + if (!Call->hasOperandBundles()) + continue; + auto &OperandBundlesToKeepIndexes = CallsToRefine[Call]; // inserts + OperandBundlesToKeepIndexes.reserve(Call->getNumOperandBundles()); + for (unsigned BundleIdx : seq(0U, Call->getNumOperandBundles())) { + if (I >= (int)ChunksToKeep.size()) + continue; + if (ChunksToKeep[I].contains(++OperandBundleCount)) + OperandBundlesToKeepIndexes.emplace_back(BundleIdx); + if (ChunksToKeep[I].end == OperandBundleCount) + ++I; + } + } + + for (auto &Call : CallsToRefine) { + CallBase *OrigCall = Call.first; + ArrayRef OperandBundlesToKeepIndexes = Call.second; + if (OperandBundlesToKeepIndexes.size() == OrigCall->getNumOperandBundles()) + continue; // Not modifying operand bundles of this call after all. + + std::vector NewBundles; + NewBundles.reserve(OperandBundlesToKeepIndexes.size()); + for (unsigned Index : OperandBundlesToKeepIndexes) + NewBundles.emplace_back(OrigCall->getOperandBundleAt(Index)); + + CallBase *NewCall = getCallWithDifferentBundles(OrigCall, NewBundles); + OrigCall->replaceAllUsesWith(NewCall); + OrigCall->eraseFromParent(); + } +} + +/// Counts the amount of operand bundles. +static int countOperandBundes(Module *Program) { + // TODO: Silence index with --quiet flag + outs() << "----------------------------\n"; + int OperandBundeCount = 0; + for (auto &F : *Program) + for (auto &BB : F) + for (auto &I : BB) + if (auto *CB = dyn_cast(&I)) + OperandBundeCount += CB->getNumOperandBundles(); + outs() << "Number of operand bundles: " << OperandBundeCount << "\n"; + + return OperandBundeCount; +} + +void llvm::reduceOperandBundesDeltaPass(TestRunner &Test) { + outs() << "*** Reducing OperandBundes...\n"; + int OperandBundeCount = countOperandBundes(Test.getProgram()); + runDeltaPass(Test, OperandBundeCount, extractOperandBundesFromModule); +} diff --git a/llvm/utils/gn/secondary/llvm/tools/llvm-reduce/BUILD.gn b/llvm/utils/gn/secondary/llvm/tools/llvm-reduce/BUILD.gn --- a/llvm/utils/gn/secondary/llvm/tools/llvm-reduce/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/tools/llvm-reduce/BUILD.gn @@ -17,6 +17,7 @@ "deltas/ReduceGlobalVars.cpp", "deltas/ReduceInstructions.cpp", "deltas/ReduceMetadata.cpp", + "deltas/ReduceOperandBundes.cpp", "llvm-reduce.cpp", ] }