Skip to content
Snippets Groups Projects
Unverified Commit 05f2b5cc authored by Roman Lebedev's avatar Roman Lebedev
Browse files

[llvm-reduce] Reducing call operand bundles

Summary:
This would have been marginally useful to me during/for rG7ea46aee3670981827c04df89b2c3a1cbdc7561b.

With ongoing migration to representing assumes via operand bundles on the assume, this will be gradually more useful.

Reviewers: nickdesaulniers, diegotf, dblaikie, george.burgess.iv, jdoerfert, Tyker

Reviewed By: nickdesaulniers

Subscribers: hiraditya, mgorny, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D83177
parent 69dca6ef
No related branches found
No related tags found
No related merge requests found
; 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
}
......@@ -11,15 +11,16 @@ set(LLVM_LINK_COMPONENTS
)
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
......
......@@ -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 @@ inline void runDeltaPasses(TestRunner &Tester) {
reduceMetadataDeltaPass(Tester);
reduceArgumentsDeltaPass(Tester);
reduceInstructionsDeltaPass(Tester);
reduceOperandBundesDeltaPass(Tester);
// TODO: Implement the remaining Delta Passes
}
......
//===- 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 "TestRunner.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <iterator>
#include <vector>
namespace {
class Module;
} // namespace
using namespace llvm;
namespace {
/// Provides opaque interface for querying into ChunksToKeep without having to
/// actually understand what is going on.
struct Oracle {
/// Out of all the features that we promised to be,
/// how many have we already processed? 1-based!
int Index = 1;
/// The actual workhorse, contains the knowledge whether or not
/// some particular feature should be preserved this time.
ArrayRef<Chunk> ChunksToKeep;
public:
Oracle(ArrayRef<Chunk> ChunksToKeep_) : ChunksToKeep(ChunksToKeep_) {}
/// Should be called for each feature on which we are operating.
/// Name is self-explanatory - if returns true, then it should be preserved.
bool shouldKeep() {
if (ChunksToKeep.empty())
return false; // All further features are to be discarded.
// Does the current (front) chunk contain such a feature?
bool ShouldKeep = ChunksToKeep.front().contains(Index);
auto _ = make_scope_exit([&]() { ++Index; }); // Next time - next feature.
// Is this the last feature in the chunk?
if (ChunksToKeep.front().end == Index)
ChunksToKeep = ChunksToKeep.drop_front(); // Onto next chunk.
return ShouldKeep;
}
};
/// Given ChunksToKeep, produce a map of calls and indexes of operand bundles
/// to be preserved for each call.
class OperandBundleRemapper : public InstVisitor<OperandBundleRemapper> {
Oracle O;
public:
DenseMap<CallBase *, std::vector<unsigned>> CallsToRefine;
explicit OperandBundleRemapper(ArrayRef<Chunk> ChunksToKeep)
: O(ChunksToKeep) {}
/// So far only CallBase sub-classes can have operand bundles.
/// Let's see which of the operand bundles of this call are to be kept.
void visitCallBase(CallBase &Call) {
if (!Call.hasOperandBundles())
return; // No bundles to begin with.
// Insert this call into map, we will likely want to rebuild it.
auto &OperandBundlesToKeepIndexes = CallsToRefine[&Call];
OperandBundlesToKeepIndexes.reserve(Call.getNumOperandBundles());
// Enumerate every operand bundle on this call.
for_each(seq(0U, Call.getNumOperandBundles()), [&](unsigned BundleIndex) {
if (O.shouldKeep()) // Should we keep this one?
OperandBundlesToKeepIndexes.emplace_back(BundleIndex);
});
}
};
struct OperandBundleCounter : public InstVisitor<OperandBundleCounter> {
/// How many features (in this case, operand bundles) did we count, total?
int OperandBundeCount = 0;
OperandBundleCounter() {}
/// So far only CallBase sub-classes can have operand bundles.
void visitCallBase(CallBase &Call) {
// Just accumulate the total number of operand bundles.
OperandBundeCount += Call.getNumOperandBundles();
}
};
} // namespace
static void maybeRewriteCallWithDifferentBundles(
CallBase *OrigCall, ArrayRef<unsigned> OperandBundlesToKeepIndexes) {
if (OperandBundlesToKeepIndexes.size() == OrigCall->getNumOperandBundles())
return; // Not modifying operand bundles of this call after all.
std::vector<OperandBundleDef> NewBundles;
NewBundles.reserve(OperandBundlesToKeepIndexes.size());
// Actually copy over the bundles that we want to keep.
transform(OperandBundlesToKeepIndexes, std::back_inserter(NewBundles),
[OrigCall](unsigned Index) {
return OperandBundleDef(OrigCall->getOperandBundleAt(Index));
});
// Finally actually replace the bundles on the call.
CallBase *NewCall = CallBase::Create(OrigCall, NewBundles, OrigCall);
OrigCall->replaceAllUsesWith(NewCall);
OrigCall->eraseFromParent();
}
/// Removes out-of-chunk operand bundles from calls.
static void extractOperandBundesFromModule(std::vector<Chunk> ChunksToKeep,
Module *Program) {
OperandBundleRemapper R(ChunksToKeep);
R.visit(Program);
for_each(R.CallsToRefine, [](const auto &P) {
return maybeRewriteCallWithDifferentBundles(P.first, P.second);
});
}
/// Counts the amount of operand bundles.
static int countOperandBundes(Module *Program) {
OperandBundleCounter C;
// TODO: Silence index with --quiet flag
outs() << "----------------------------\n";
C.visit(Program);
outs() << "Number of operand bundles: " << C.OperandBundeCount << "\n";
return C.OperandBundeCount;
}
void llvm::reduceOperandBundesDeltaPass(TestRunner &Test) {
outs() << "*** Reducing OperandBundes...\n";
int OperandBundeCount = countOperandBundes(Test.getProgram());
runDeltaPass(Test, OperandBundeCount, extractOperandBundesFromModule);
}
//===- 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.
//
//===----------------------------------------------------------------------===//
namespace llvm {
class TestRunner;
void reduceOperandBundesDeltaPass(TestRunner &Test);
} // namespace llvm
......@@ -17,6 +17,7 @@ executable("llvm-reduce") {
"deltas/ReduceGlobalVars.cpp",
"deltas/ReduceInstructions.cpp",
"deltas/ReduceMetadata.cpp",
"deltas/ReduceOperandBundes.cpp",
"llvm-reduce.cpp",
]
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment