[llvm-reduce] Count chunks by running a preliminary reduction

Having a separate counting method runs the risk of a mismatch between
the actual reduction method and the counting method.

Instead, create an Oracle that always returns true for shouldKeep(), run
the reduction, and count how many times shouldKeep() was called. The
module should not be modified if shouldKeep() always returns true.

Reviewed By: Meinersbur

Differential Revision: https://reviews.llvm.org/D113537
This commit is contained in:
Arthur Eubanks 2021-11-11 18:45:59 -08:00
parent be0b47d530
commit 6f288bd772
20 changed files with 47 additions and 341 deletions

View File

@ -102,9 +102,18 @@ static bool increaseGranularity(std::vector<Chunk> &Chunks) {
/// given test.
template <typename T>
void runDeltaPassInt(
TestRunner &Test, int Targets,
TestRunner &Test,
function_ref<void(Oracle &, T &)> ExtractChunksFromModule) {
assert(Targets >= 0);
int Targets;
{
// Count the number of targets by counting the number of calls to
// Oracle::shouldKeep() but always returning true so no changes are
// made.
std::vector<Chunk> AllChunks = {{0, INT_MAX}};
Oracle Counter(AllChunks);
ExtractChunksFromModule(Counter, Test.getProgram());
Targets = Counter.count();
}
if (!Targets) {
errs() << "\nNothing to reduce\n";
return;
@ -119,7 +128,7 @@ void runDeltaPassInt(
assert(!verifyReducerWorkItem(Test.getProgram(), &errs()) &&
"input module is broken before making changes");
std::vector<Chunk> ChunksStillConsideredInteresting = {{1, Targets}};
std::vector<Chunk> ChunksStillConsideredInteresting = {{0, Targets - 1}};
std::unique_ptr<ReducerWorkItem> ReducedProgram;
for (unsigned int Level = 0; Level < StartingGranularityLevel; Level++) {
@ -198,13 +207,13 @@ void runDeltaPassInt(
}
void llvm::runDeltaPass(
TestRunner &Test, int Targets,
TestRunner &Test,
function_ref<void(Oracle &, Module &)> ExtractChunksFromModule) {
runDeltaPassInt<Module>(Test, Targets, ExtractChunksFromModule);
runDeltaPassInt<Module>(Test, ExtractChunksFromModule);
}
void llvm::runDeltaPass(
TestRunner &Test, int Targets,
TestRunner &Test,
function_ref<void(Oracle &, MachineFunction &)> ExtractChunksFromModule) {
runDeltaPassInt<MachineFunction>(Test, Targets, ExtractChunksFromModule);
runDeltaPassInt<MachineFunction>(Test, ExtractChunksFromModule);
}

View File

@ -52,8 +52,8 @@ struct Chunk {
/// actually understand what is going on.
class Oracle {
/// Out of all the features that we promised to be,
/// how many have we already processed? 1-based!
int Index = 1;
/// how many have we already processed?
int Index = 0;
/// The actual workhorse, contains the knowledge whether or not
/// some particular feature should be preserved this time.
@ -65,19 +65,24 @@ public:
/// 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())
if (ChunksToKeep.empty()) {
++Index;
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.
++Index;
return ShouldKeep;
}
int count() { return Index; }
};
/// This function implements the Delta Debugging algorithm, it receives a
@ -92,9 +97,6 @@ public:
/// RemoveFunctions) and receives three key parameters:
/// * Test: The main TestRunner instance which is used to run the provided
/// interesting-ness test, as well as to store and access the reduced Program.
/// * Targets: The amount of Targets that are going to be reduced by the
/// algorithm, for example, the RemoveGlobalVars pass would send the amount of
/// initialized GVs.
/// * ExtractChunksFromModule: A function used to tailor the main program so it
/// only contains Targets that are inside Chunks of the given iteration.
/// Note: This function is implemented by each specialized Delta pass
@ -102,10 +104,10 @@ public:
/// Other implementations of the Delta Debugging algorithm can also be found in
/// the CReduce, Delta, and Lithium projects.
void runDeltaPass(
TestRunner &Test, int Targets,
TestRunner &Test,
function_ref<void(Oracle &, Module &)> ExtractChunksFromModule);
void runDeltaPass(
TestRunner &Test, int Targets,
TestRunner &Test,
function_ref<void(Oracle &, MachineFunction &)> ExtractChunksFromModule);
} // namespace llvm

View File

@ -29,22 +29,8 @@ static void extractAliasesFromModule(Oracle &O, Module &Program) {
}
}
/// Counts the amount of aliases and prints their respective name & index.
static int countAliases(Module &Program) {
// TODO: Silence index with --quiet flag
errs() << "----------------------------\n";
errs() << "Aliases Index Reference:\n";
int Count = 0;
for (auto &GA : Program.aliases())
errs() << "\t" << ++Count << ": " << GA.getName() << "\n";
errs() << "----------------------------\n";
return Count;
}
void llvm::reduceAliasesDeltaPass(TestRunner &Test) {
errs() << "*** Reducing Aliases ...\n";
int Functions = countAliases(Test.getProgram());
runDeltaPass(Test, Functions, extractAliasesFromModule);
runDeltaPass(Test, extractAliasesFromModule);
errs() << "----------------------------\n";
}

View File

@ -115,27 +115,7 @@ static void extractArgumentsFromModule(Oracle &O, Module &Program) {
}
}
/// Counts the amount of arguments in functions and prints their respective
/// name, index, and parent function name
static int countArguments(Module &Program) {
// TODO: Silence index with --quiet flag
outs() << "----------------------------\n";
outs() << "Param Index Reference:\n";
int ArgsCount = 0;
for (auto &F : Program)
if (shouldRemoveArguments(F)) {
outs() << " " << F.getName() << "\n";
for (auto &A : F.args())
outs() << "\t" << ++ArgsCount << ": " << A.getName() << "\n";
outs() << "----------------------------\n";
}
return ArgsCount;
}
void llvm::reduceArgumentsDeltaPass(TestRunner &Test) {
outs() << "*** Reducing Arguments...\n";
int ArgCount = countArguments(Test.getProgram());
runDeltaPass(Test, ArgCount, extractArgumentsFromModule);
runDeltaPass(Test, extractArgumentsFromModule);
}

View File

@ -180,20 +180,7 @@ static void extractAttributesFromModule(Oracle &O, Module &Program) {
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);
runDeltaPass(Test, extractAttributesFromModule);
}

View File

@ -139,24 +139,7 @@ static void extractBasicBlocksFromModule(Oracle &O, Module &Program) {
}
}
/// Counts the amount of basic blocks and prints their name & respective index
static int countBasicBlocks(Module &Program) {
// TODO: Silence index with --quiet flag
outs() << "----------------------------\n";
int BBCount = 0;
for (auto &F : Program)
for (auto &BB : F) {
if (BB.hasName())
outs() << "\t" << ++BBCount << ": " << BB.getName() << "\n";
else
outs() << "\t" << ++BBCount << ": Unnamed\n";
}
return BBCount;
}
void llvm::reduceBasicBlocksDeltaPass(TestRunner &Test) {
outs() << "*** Reducing Basic Blocks...\n";
int BBCount = countBasicBlocks(Test.getProgram());
runDeltaPass(Test, BBCount, extractBasicBlocksFromModule);
runDeltaPass(Test, extractBasicBlocksFromModule);
}

View File

@ -29,25 +29,8 @@ static void extractFunctionBodiesFromModule(Oracle &O, Module &Program) {
}
}
/// Counts the amount of non-declaration functions and prints their
/// respective name & index
static int countFunctionDefinitions(Module &Program) {
// TODO: Silence index with --quiet flag
errs() << "----------------------------\n";
errs() << "Function Definition Index Reference:\n";
int FunctionDefinitionCount = 0;
for (auto &F : Program)
if (!F.isDeclaration())
errs() << "\t" << ++FunctionDefinitionCount << ": " << F.getName()
<< "\n";
errs() << "----------------------------\n";
return FunctionDefinitionCount;
}
void llvm::reduceFunctionBodiesDeltaPass(TestRunner &Test) {
errs() << "*** Reducing Function Bodies...\n";
int Functions = countFunctionDefinitions(Test.getProgram());
runDeltaPass(Test, Functions, extractFunctionBodiesFromModule);
runDeltaPass(Test, extractFunctionBodiesFromModule);
errs() << "----------------------------\n";
}

View File

@ -48,27 +48,8 @@ static void extractFunctionsFromModule(Oracle &O, Module &Program) {
}
}
/// Counts the amount of functions and prints their
/// respective name & index
static int countFunctions(Module &Program) {
// TODO: Silence index with --quiet flag
errs() << "----------------------------\n";
errs() << "Function Index Reference:\n";
int FunctionCount = 0;
for (auto &F : Program) {
if (F.isIntrinsic() && !F.use_empty())
continue;
errs() << '\t' << ++FunctionCount << ": " << F.getName() << '\n';
}
errs() << "----------------------------\n";
return FunctionCount;
}
void llvm::reduceFunctionsDeltaPass(TestRunner &Test) {
errs() << "*** Reducing Functions...\n";
int Functions = countFunctions(Test.getProgram());
runDeltaPass(Test, Functions, extractFunctionsFromModule);
runDeltaPass(Test, extractFunctionsFromModule);
errs() << "----------------------------\n";
}

View File

@ -26,18 +26,7 @@ static void reduceGOs(Oracle &O, Module &Program) {
}
}
static int countGOs(Module &Program) {
int SectionCount = count_if(Program.global_objects(), [](GlobalObject &GO) {
return shouldReduceSection(GO);
});
int AlignCount = count_if(Program.global_objects(), [](GlobalObject &GO) {
return shouldReduceAlign(GO);
});
return SectionCount + AlignCount;
}
void llvm::reduceGlobalObjectsDeltaPass(TestRunner &Test) {
outs() << "*** Reducing GlobalObjects...\n";
int GVCount = countGOs(Test.getProgram());
runDeltaPass(Test, GVCount, reduceGOs);
runDeltaPass(Test, reduceGOs);
}

View File

@ -57,28 +57,7 @@ static void reduceGVs(Oracle &O, Module &Program) {
}
}
static int countGVs(Module &Program) {
int DSOLocalCount = count_if(Program.global_values(), [](GlobalValue &GV) {
return shouldReduceDSOLocal(GV);
});
int VisibilityCount = count_if(Program.global_values(), [](GlobalValue &GV) {
return shouldReduceVisibility(GV);
});
int UnnamedAddrCount = count_if(Program.global_values(), [](GlobalValue &GV) {
return shouldReduceUnnamedAddress(GV);
});
int DLLStorageClassCount =
count_if(Program.global_values(),
[](GlobalValue &GV) { return shouldReduceDLLStorageClass(GV); });
int ThreadLocalCount = count_if(Program.global_values(), [](GlobalValue &GV) {
return shouldReduceThreadLocal(GV);
});
return DSOLocalCount + VisibilityCount + UnnamedAddrCount +
DLLStorageClassCount + ThreadLocalCount;
}
void llvm::reduceGlobalValuesDeltaPass(TestRunner &Test) {
outs() << "*** Reducing GlobalValues...\n";
int GVCount = countGVs(Test.getProgram());
runDeltaPass(Test, GVCount, reduceGVs);
runDeltaPass(Test, reduceGVs);
}

View File

@ -28,22 +28,7 @@ static void extractGVsFromModule(Oracle &O, Module &Program) {
}
}
/// Counts the amount of initialized GVs and displays their
/// respective name & index
static int countGVs(Module &Program) {
// TODO: Silence index with --quiet flag
outs() << "----------------------------\n";
outs() << "GlobalVariable Index Reference:\n";
int GVCount = 0;
for (auto &GV : Program.globals())
if (GV.hasInitializer())
outs() << "\t" << ++GVCount << ": " << GV.getName() << "\n";
outs() << "----------------------------\n";
return GVCount;
}
void llvm::reduceGlobalsInitializersDeltaPass(TestRunner &Test) {
outs() << "*** Reducing GVs initializers...\n";
int GVCount = countGVs(Test.getProgram());
runDeltaPass(Test, GVCount, extractGVsFromModule);
runDeltaPass(Test, extractGVsFromModule);
}

View File

@ -57,21 +57,7 @@ static void extractGVsFromModule(Oracle &O, Module &Program) {
GV->eraseFromParent();
}
/// Counts the amount of GVs and displays their
/// respective name & index
static int countGVs(Module &Program) {
// TODO: Silence index with --quiet flag
outs() << "----------------------------\n";
outs() << "GlobalVariable Index Reference:\n";
int GVCount = 0;
for (auto &GV : Program.globals())
outs() << "\t" << ++GVCount << ": " << GV.getName() << "\n";
outs() << "----------------------------\n";
return GVCount;
}
void llvm::reduceGlobalsDeltaPass(TestRunner &Test) {
outs() << "*** Reducing GVs...\n";
int GVCount = countGVs(Test.getProgram());
runDeltaPass(Test, GVCount, extractGVsFromModule);
runDeltaPass(Test, extractGVsFromModule);
}

View File

@ -49,22 +49,7 @@ static void extractInstrFromModule(Oracle &O, Module &Program) {
I->eraseFromParent();
}
/// Counts the amount of basic blocks and prints their name & respective index
static unsigned countInstructions(Module &Program) {
// TODO: Silence index with --quiet flag
outs() << "----------------------------\n";
int InstCount = 0;
for (auto &F : Program)
for (auto &BB : F)
// Well-formed blocks have terminators, which we cannot remove.
InstCount += BB.getInstList().size() - 1;
outs() << "Number of instructions: " << InstCount << "\n";
return InstCount;
}
void llvm::reduceInstructionsDeltaPass(TestRunner &Test) {
outs() << "*** Reducing Instructions...\n";
unsigned InstCount = countInstructions(Test.getProgram());
runDeltaPass(Test, InstCount, extractInstrFromModule);
runDeltaPass(Test, extractInstrFromModule);
}

View File

@ -44,23 +44,6 @@ static Register getPrevDefOfRCInMBB(MachineBasicBlock &MBB,
return 0;
}
static unsigned countInstructions(MachineFunction &MF) {
unsigned Count = 0;
MachineInstr *TopMI = nullptr;
for (auto &MBB : MF) {
for (auto &MI : MBB) {
if (MI.isTerminator())
continue;
if (MBB.isEntryBlock() && !TopMI) {
TopMI = &MI;
continue;
}
Count++;
}
}
return Count;
}
static void extractInstrFromModule(Oracle &O, MachineFunction &MF) {
MachineDominatorTree MDT;
MDT.runOnMachineFunction(MF);
@ -138,6 +121,5 @@ static void extractInstrFromModule(Oracle &O, MachineFunction &MF) {
void llvm::reduceInstructionsMIRDeltaPass(TestRunner &Test) {
outs() << "*** Reducing Instructions...\n";
unsigned InstCount = countInstructions(Test.getProgram());
runDeltaPass(Test, InstCount, extractInstrFromModule);
runDeltaPass(Test, extractInstrFromModule);
}

View File

@ -61,37 +61,8 @@ static void extractMetadataFromModule(Oracle &O, Module &Program) {
}
}
static int countMetadataTargets(Module &Program) {
int NamedMetadataNodes = Program.named_metadata_size();
// Get metadata attached to globals.
int GlobalMetadataArgs = 0;
SmallVector<std::pair<unsigned, MDNode *>> MDs;
for (GlobalVariable &GV : Program.globals()) {
GV.getAllMetadata(MDs);
GlobalMetadataArgs += MDs.size();
}
// Get metadata attached to functions & instructions.
int FunctionMetadataArgs = 0;
int InstructionMetadataArgs = 0;
for (Function &F : Program) {
F.getAllMetadata(MDs);
FunctionMetadataArgs += MDs.size();
for (Instruction &I : instructions(F)) {
I.getAllMetadata(MDs);
InstructionMetadataArgs += MDs.size();
}
}
return NamedMetadataNodes + GlobalMetadataArgs + FunctionMetadataArgs +
InstructionMetadataArgs;
}
void llvm::reduceMetadataDeltaPass(TestRunner &Test) {
outs() << "*** Reducing Metadata...\n";
int MDCount = countMetadataTargets(Test.getProgram());
runDeltaPass(Test, MDCount, extractMetadataFromModule);
runDeltaPass(Test, extractMetadataFromModule);
outs() << "----------------------------\n";
}

View File

@ -28,23 +28,7 @@ static void clearModuleData(Oracle &O, Module &Program) {
Program.setModuleInlineAsm("");
}
static int countModuleData(Module &M) {
int Count = 0;
if (!M.getModuleIdentifier().empty())
++Count;
if (!M.getSourceFileName().empty())
++Count;
if (!M.getDataLayoutStr().empty())
++Count;
if (!M.getTargetTriple().empty())
++Count;
if (!M.getModuleInlineAsm().empty())
++Count;
return Count;
}
void llvm::reduceModuleDataDeltaPass(TestRunner &Test) {
outs() << "*** Reducing Module Data...\n";
int Count = countModuleData(Test.getProgram());
runDeltaPass(Test, Count, clearModuleData);
runDeltaPass(Test, clearModuleData);
}

View File

@ -103,20 +103,7 @@ static void extractOperandBundesFromModule(Oracle &O, Module &Program) {
maybeRewriteCallWithDifferentBundles(I.first, I.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);
runDeltaPass(Test, extractOperandBundesFromModule);
}

View File

@ -29,20 +29,6 @@ extractOperandsFromModule(Oracle &O, Module &Program,
}
}
static int countOperands(Module &Program,
function_ref<Value *(Use &)> ReduceValue) {
int Count = 0;
for (auto &F : Program.functions()) {
for (auto &I : instructions(&F)) {
for (auto &Op : I.operands()) {
if (ReduceValue(Op))
Count++;
}
}
}
return Count;
}
static bool isOne(Use &Op) {
auto *C = dyn_cast<Constant>(Op);
return C && C->isOneValue();
@ -76,8 +62,7 @@ void llvm::reduceOperandsUndefDeltaPass(TestRunner &Test) {
// Don't replace existing ConstantData Uses.
return isa<ConstantData>(*Op) ? nullptr : UndefValue::get(Op->getType());
};
int Count = countOperands(Test.getProgram(), ReduceValue);
runDeltaPass(Test, Count, [ReduceValue](Oracle &O, Module &Program) {
runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
extractOperandsFromModule(O, Program, ReduceValue);
});
}
@ -94,8 +79,7 @@ void llvm::reduceOperandsOneDeltaPass(TestRunner &Test) {
// Don't replace existing ones and zeroes.
return (isOne(Op) || isZero(Op)) ? nullptr : ConstantInt::get(Ty, 1);
};
int Count = countOperands(Test.getProgram(), ReduceValue);
runDeltaPass(Test, Count, [ReduceValue](Oracle &O, Module &Program) {
runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
extractOperandsFromModule(O, Program, ReduceValue);
});
}
@ -108,8 +92,7 @@ void llvm::reduceOperandsZeroDeltaPass(TestRunner &Test) {
// Don't replace existing zeroes.
return isZero(Op) ? nullptr : Constant::getNullValue(Op->getType());
};
int Count = countOperands(Test.getProgram(), ReduceValue);
runDeltaPass(Test, Count, [ReduceValue](Oracle &O, Module &Program) {
runDeltaPass(Test, [ReduceValue](Oracle &O, Module &Program) {
extractOperandsFromModule(O, Program, ReduceValue);
});
}

View File

@ -192,27 +192,7 @@ static void reduceOperandsToArgs(Oracle &O, Module &Program) {
}
}
/// Counts the amount of operands in the module that can be reduced.
static int countOperands(Module &Program) {
int Count = 0;
for (Function &F : Program.functions()) {
if (!canReplaceFunction(&F))
continue;
for (Instruction &I : instructions(&F)) {
for (Use &Op : I.operands()) {
if (!canReduceUse(Op))
continue;
Count += 1;
}
}
}
return Count;
}
void llvm::reduceOperandsToArgsDeltaPass(TestRunner &Test) {
outs() << "*** Converting operands to function arguments ...\n";
int ArgCount = countOperands(Test.getProgram());
return runDeltaPass(Test, ArgCount, reduceOperandsToArgs);
return runDeltaPass(Test, reduceOperandsToArgs);
}

View File

@ -35,24 +35,8 @@ static void extractSpecialGlobalsFromModule(Oracle &O, Module &Program) {
}
}
/// Counts the amount of special globals and prints their
/// respective name & index
static int countSpecialGlobals(Module &Program) {
// TODO: Silence index with --quiet flag
errs() << "----------------------------\n";
errs() << "Special Globals Index Reference:\n";
int Count = 0;
for (StringRef Name : SpecialGlobalNames) {
if (auto *Used = Program.getNamedGlobal(Name))
errs() << "\t" << ++Count << ": " << Used->getName() << "\n";
}
errs() << "----------------------------\n";
return Count;
}
void llvm::reduceSpecialGlobalsDeltaPass(TestRunner &Test) {
errs() << "*** Reducing Special Globals ...\n";
int Functions = countSpecialGlobals(Test.getProgram());
runDeltaPass(Test, Functions, extractSpecialGlobalsFromModule);
runDeltaPass(Test, extractSpecialGlobalsFromModule);
errs() << "----------------------------\n";
}