diff --git a/llvm/test/Reduce/remove-args.ll b/llvm/test/Reduce/remove-args.ll --- a/llvm/test/Reduce/remove-args.ll +++ b/llvm/test/Reduce/remove-args.ll @@ -1,6 +1,6 @@ ; Test that llvm-reduce can remove uninteresting function arguments from function definitions as well as their calls. ; -; RUN: rm -rf %t +; RUN: rm -f %t ; RUN: llvm-reduce --test %python --test-arg %p/Inputs/remove-args.py %s -o %t ; RUN: cat %t | FileCheck -implicit-check-not=uninteresting %s diff --git a/llvm/test/Reduce/remove-call-site-attributes.ll b/llvm/test/Reduce/remove-call-site-attributes.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Reduce/remove-call-site-attributes.ll @@ -0,0 +1,39 @@ +; Test that llvm-reduce can remove uninteresting operand bundles from calls. +; +; RUN: rm -f %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 i32 @f1(i32, i32) +declare i32 @f1(i32, i32) + +; CHECK-FINAL-LABEL: define i32 @interesting(i32 %arg0, i32 %arg1) { +; CHECK-FINAL-NEXT: entry: +; CHECK-FINAL-NEXT: %r = call "attr0" i32 @f1(i32 "attr4" %arg0, i32 %arg1) #0 +; CHECK-FINAL-NEXT: ret i32 %r +; CHECK-FINAL-NEXT: } +define i32 @interesting(i32 %arg0, i32 %arg1) { +entry: +; CHECK-INTERESTINGNESS-LABEL: @interesting( + +; CHECK-INTERESTINGNESS: %r = call +; CHECK-INTERESTINGNESS-SAME: "attr0" +; CHECK-INTERESTINGNESS-SAME: i32 @f1( +; CHECK-INTERESTINGNESS-SAME: i32 +; CHECK-INTERESTINGNESS-SAME: "attr4" +; CHECK-INTERESTINGNESS-SAME: %arg0 +; CHECK-INTERESTINGNESS-SAME: i32 +; CHECK-INTERESTINGNESS-SAME: %arg1 +; CHECK-INTERESTINGNESS-SAME: #0 +; CHECK-INTERESTINGNESS: ret i32 %r + + %r = call "attr0" "attr1" "attr2" i32 @f1(i32 "attr3" "attr4" "attr5" %arg0, i32 "attr6" "attr7" "attr8" %arg1) #0 + ret i32 %r +} + +; CHECK-INTERESTINGNESS: attributes #0 = { +; CHECK-INTERESTINGNESS-SAME: "attr10" + +; CHECK-FINAL: attributes #0 = { "attr10" } + +attributes #0 = { "attr9" "attr10" "attr11" } diff --git a/llvm/test/Reduce/remove-funcs.ll b/llvm/test/Reduce/remove-funcs.ll --- a/llvm/test/Reduce/remove-funcs.ll +++ b/llvm/test/Reduce/remove-funcs.ll @@ -1,7 +1,7 @@ ; Test that llvm-reduce can remove uninteresting functions as well as ; their InstCalls. ; -; RUN: rm -rf %t +; RUN: rm -f %t ; RUN: llvm-reduce --test %python --test-arg %p/Inputs/remove-funcs.py %s -o %t ; RUN: cat %t | FileCheck -implicit-check-not=uninteresting %s diff --git a/llvm/test/Reduce/remove-function-attributes.ll b/llvm/test/Reduce/remove-function-attributes.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Reduce/remove-function-attributes.ll @@ -0,0 +1,24 @@ +; Test that llvm-reduce can remove uninteresting attributes. +; +; RUN: rm -f %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-INTERESTINGNESS: declare +; CHECK-INTERESTINGNESS-SAME: "attr0" +; CHECK-INTERESTINGNESS-SAME: void @f0 +; CHECK-INTERESTINGNESS-SAME: i32 +; CHECK-INTERESTINGNESS-SAME: i32 +; CHECK-INTERESTINGNESS-SAME: "attr6" +; CHECK-INTERESTINGNESS-SAME: #0 + +; CHECK-FINAL: declare "attr0" void @f0(i32, i32 "attr6") #0 + +declare "attr0" "attr1" "attr2" void @f0(i32 "attr3" "attr4" "attr5", i32 "attr6" "attr7" "attr8") #0 + +; CHECK-INTERESTINGNESS: attributes #0 = { +; CHECK-INTERESTINGNESS-SAME: "attr10" + +; CHECK-FINAL: attributes #0 = { "attr10" } + +attributes #0 = { "attr9" "attr10" "attr11" } diff --git a/llvm/test/Reduce/remove-global-variable-attributes.ll b/llvm/test/Reduce/remove-global-variable-attributes.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Reduce/remove-global-variable-attributes.ll @@ -0,0 +1,28 @@ +; Test that llvm-reduce can remove uninteresting attributes. +; +; RUN: rm -f %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: @gv0 = global i32 0 #0 +; CHECK-ALL-NEXT: @gv1 = global i32 0 #1 +; CHECK-ALL-NEXT: @gv2 = global i32 0 +@gv0 = global i32 0 #0 +@gv1 = global i32 0 #1 +@gv2 = global i32 0 #2 + +; CHECK-INTERESTINGNESS: attributes #0 = { +; CHECK-INTERESTINGNESS-SAME: "attr0" +; CHECK-INTERESTINGNESS-SAME: "attr2" + +; CHECK-INTERESTINGNESS-NEXT: attributes #1 = { +; CHECK-INTERESTINGNESS-SAME: "attr4" + +; CHECK-FINAL: attributes #0 = { "attr0" "attr2" } +; CHECK-FINAL-NEXT: attributes #1 = { "attr4" } + +; CHECK-FINAL-NOT: attributes #2 + +attributes #0 = { "attr0" "attr1" "attr2"} +attributes #1 = { "attr3" "attr4" "attr5"} +attributes #2 = { "attr6" "attr7" "attr8"} diff --git a/llvm/test/Reduce/remove-global-vars.ll b/llvm/test/Reduce/remove-global-vars.ll --- a/llvm/test/Reduce/remove-global-vars.ll +++ b/llvm/test/Reduce/remove-global-vars.ll @@ -1,7 +1,7 @@ ; Test that llvm-reduce can remove uninteresting Global Variables as well as ; their direct uses (which in turn are replaced with 'undef'). ; -; RUN: rm -rf %t +; RUN: rm -f %t ; RUN: llvm-reduce --test %python --test-arg %p/Inputs/remove-global-vars.py %s -o %t ; RUN: cat %t | FileCheck -implicit-check-not=uninteresting %s diff --git a/llvm/test/Reduce/remove-metadata.ll b/llvm/test/Reduce/remove-metadata.ll --- a/llvm/test/Reduce/remove-metadata.ll +++ b/llvm/test/Reduce/remove-metadata.ll @@ -1,7 +1,7 @@ ; Test that llvm-reduce can remove uninteresting metadata from an IR file. ; The Metadata pass erases named & unnamed metadata nodes. ; -; RUN: rm -rf %t +; RUN: rm -f %t ; RUN: llvm-reduce --test %python --test-arg %p/Inputs/remove-metadata.py %s -o %t ; RUN: cat %t | FileCheck -implicit-check-not=! %s diff --git a/llvm/test/Reduce/remove-multiple-use-of-args-in-same-instruction.ll b/llvm/test/Reduce/remove-multiple-use-of-args-in-same-instruction.ll --- a/llvm/test/Reduce/remove-multiple-use-of-args-in-same-instruction.ll +++ b/llvm/test/Reduce/remove-multiple-use-of-args-in-same-instruction.ll @@ -1,6 +1,6 @@ ; Test that llvm-reduce can remove uninteresting function arguments from function definitions as well as their calls. ; -; RUN: rm -rf %t +; RUN: rm -f %t ; RUN: llvm-reduce --test %python --test-arg %p/Inputs/remove-multiple-use-of-args-in-same-instruction.py %s -o %t ; RUN: cat %t | FileCheck -implicit-check-not=uninteresting %s diff --git a/llvm/test/Reduce/remove-multiple-use-of-global-vars-in-same-instruction.ll b/llvm/test/Reduce/remove-multiple-use-of-global-vars-in-same-instruction.ll --- a/llvm/test/Reduce/remove-multiple-use-of-global-vars-in-same-instruction.ll +++ b/llvm/test/Reduce/remove-multiple-use-of-global-vars-in-same-instruction.ll @@ -1,6 +1,6 @@ ; Test that llvm-reduce can remove uninteresting function arguments from function definitions as well as their calls. ; -; RUN: rm -rf %t +; RUN: rm -f %t ; RUN: llvm-reduce --test %python --test-arg %p/Inputs/remove-multiple-use-of-global-vars-in-same-instruction.py %s -o %t ; RUN: cat %t | FileCheck -implicit-check-not=uninteresting %s diff --git a/llvm/test/Reduce/remove-operand-bundles.ll b/llvm/test/Reduce/remove-operand-bundles.ll --- a/llvm/test/Reduce/remove-operand-bundles.ll +++ b/llvm/test/Reduce/remove-operand-bundles.ll @@ -1,6 +1,6 @@ ; Test that llvm-reduce can remove uninteresting operand bundles from calls. ; -; RUN: rm -rf %t +; RUN: rm -f %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 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 @@ -14,6 +14,7 @@ TestRunner.cpp deltas/Delta.cpp deltas/ReduceArguments.cpp + deltas/ReduceAttributes.cpp deltas/ReduceBasicBlocks.cpp deltas/ReduceFunctions.cpp deltas/ReduceGlobalVars.cpp 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 @@ -14,6 +14,7 @@ #include "TestRunner.h" #include "deltas/Delta.h" #include "deltas/ReduceArguments.h" +#include "deltas/ReduceAttributes.h" #include "deltas/ReduceBasicBlocks.h" #include "deltas/ReduceFunctions.h" #include "deltas/ReduceGlobalVars.h" @@ -32,6 +33,7 @@ reduceArgumentsDeltaPass(Tester); reduceInstructionsDeltaPass(Tester); reduceOperandBundesDeltaPass(Tester); + reduceAttributesDeltaPass(Tester); // TODO: Implement the remaining Delta Passes } diff --git a/llvm/tools/llvm-reduce/deltas/ReduceAttributes.h b/llvm/tools/llvm-reduce/deltas/ReduceAttributes.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-reduce/deltas/ReduceAttributes.h @@ -0,0 +1,20 @@ +//===- ReduceAttributes.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 attributes. +// +//===----------------------------------------------------------------------===// + +namespace llvm { + +class TestRunner; + +void reduceAttributesDeltaPass(TestRunner &Test); + +} // namespace llvm diff --git a/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp b/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp @@ -0,0 +1,196 @@ +//===- ReduceAttributes.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 "ReduceAttributes.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/Sequence.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/InstVisitor.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include + +namespace llvm { +class LLVMContext; +} // namespace llvm + +using namespace llvm; + +namespace { + +using AttrPtrVecTy = std::vector; +using AttrPtrIdxVecVecTy = std::pair; +using AttrPtrVecVecTy = SmallVector; + +/// Given ChunksToKeep, produce a map of global variables/functions/calls +/// and indexes of attributes to be preserved for each of them. +class AttributeRemapper : public InstVisitor { + Oracle O; + +public: + DenseMap GlobalVariablesToRefine; + DenseMap FunctionsToRefine; + DenseMap CallsToRefine; + + explicit AttributeRemapper(ArrayRef ChunksToKeep) : O(ChunksToKeep) {} + + void visitModule(Module &M) { + for (GlobalVariable &GV : M.getGlobalList()) + visitGlobalVariable(GV); + } + + void visitGlobalVariable(GlobalVariable &GV) { + // Global variables only have one attribute set. + const AttributeSet &AS = GV.getAttributes(); + if (!AS.getNumAttributes()) + return; // No attributes to begin with. + visitAttributeSet(AS, GlobalVariablesToRefine[&GV]); + } + + void visitFunction(Function &F) { + visitAttributeList(F.getAttributes(), FunctionsToRefine[&F]); + } + + void visitCallBase(CallBase &I) { + visitAttributeList(I.getAttributes(), CallsToRefine[&I]); + } + + void visitAttributeList(const AttributeList &AL, + AttrPtrVecVecTy &AttributeSetsToPreserve) { + assert(AttributeSetsToPreserve.empty() && "Should not be sharing vectors."); + AttributeSetsToPreserve.reserve(AL.getNumAttrSets()); + for (unsigned SetIdx : seq(AL.index_begin(), AL.index_end())) { + AttrPtrIdxVecVecTy AttributesToPreserve; + AttributesToPreserve.first = SetIdx; + visitAttributeSet(AL.getAttributes(AttributesToPreserve.first), + AttributesToPreserve.second); + if (!AttributesToPreserve.second.empty()) + AttributeSetsToPreserve.emplace_back(std::move(AttributesToPreserve)); + } + } + + void visitAttributeSet(const AttributeSet &AS, + AttrPtrVecTy &AttrsToPreserve) { + assert(AttrsToPreserve.empty() && "Should not be sharing vectors."); + AttrsToPreserve.reserve(AS.getNumAttributes()); + for (const Attribute &A : AS) + if (O.shouldKeep()) + AttrsToPreserve.emplace_back(&A); + } +}; + +struct AttributeCounter : public InstVisitor { + /// How many features (in this case, attributes) did we count, total? + int AttributeCount = 0; + + void visitModule(Module &M) { + for (GlobalVariable &GV : M.getGlobalList()) + visitGlobalVariable(GV); + } + + void visitGlobalVariable(GlobalVariable &GV) { + // Global variables only have one attribute set. + visitAttributeSet(GV.getAttributes()); + } + + void visitFunction(Function &F) { visitAttributeList(F.getAttributes()); } + + void visitCallBase(CallBase &I) { visitAttributeList(I.getAttributes()); } + + void visitAttributeList(const AttributeList &AL) { + for (const AttributeSet &AS : AL) + visitAttributeSet(AS); + } + + void visitAttributeSet(const AttributeSet &AS) { + AttributeCount += AS.getNumAttributes(); + } +}; + +} // namespace + +AttributeSet +convertAttributeRefToAttributeSet(LLVMContext &C, + ArrayRef Attributes) { + AttrBuilder B; + for_each(Attributes, [&](const Attribute *A) { B.addAttribute(*A); }); + return AttributeSet::get(C, B); +} + +AttributeList convertAttributeRefVecToAttributeList( + LLVMContext &C, ArrayRef AttributeSets) { + std::vector> SetVec; + SetVec.reserve(AttributeSets.size()); + + transform(AttributeSets, std::back_inserter(SetVec), + [&C](const AttrPtrIdxVecVecTy &V) { + return std::make_pair( + V.first, convertAttributeRefToAttributeSet(C, V.second)); + }); + + sort(SetVec, [](const std::pair &LHS, + const std::pair &RHS) { + return LHS.first < RHS.first; // All values are unique. + }); + + return AttributeList::get(C, SetVec); +} + +/// Removes out-of-chunk attributes from module. +static void extractAttributesFromModule(std::vector ChunksToKeep, + Module *Program) { + AttributeRemapper R(ChunksToKeep); + R.visit(Program); + + LLVMContext &C = Program->getContext(); + for_each(R.GlobalVariablesToRefine, [&C](const auto &I) { + I.first->setAttributes(convertAttributeRefToAttributeSet(C, I.second)); + }); + for_each(R.FunctionsToRefine, [&C](const auto &I) { + I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second)); + }); + for_each(R.CallsToRefine, [&C](const auto &I) { + I.first->setAttributes(convertAttributeRefVecToAttributeList(C, I.second)); + }); +} + +/// Counts the amount of attributes. +static int countAttributes(Module *Program) { + AttributeCounter C; + + // TODO: Silence index with --quiet flag + outs() << "----------------------------\n"; + C.visit(Program); + outs() << "Number of attributes: " << C.AttributeCount << "\n"; + + return C.AttributeCount; +} + +void llvm::reduceAttributesDeltaPass(TestRunner &Test) { + outs() << "*** Reducing Attributes...\n"; + int AttributeCount = countAttributes(Test.getProgram()); + runDeltaPass(Test, AttributeCount, extractAttributesFromModule); +} diff --git a/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp b/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp @@ -67,8 +67,6 @@ /// 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. 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 @@ -12,6 +12,7 @@ "TestRunner.cpp", "deltas/Delta.cpp", "deltas/ReduceArguments.cpp", + "deltas/ReduceAttributes.cpp", "deltas/ReduceBasicBlocks.cpp", "deltas/ReduceFunctions.cpp", "deltas/ReduceGlobalVars.cpp",