diff --git a/llvm/test/tools/llvm-reduce/remove-operands.ll b/llvm/test/tools/llvm-reduce/remove-operands.ll --- a/llvm/test/tools/llvm-reduce/remove-operands.ll +++ b/llvm/test/tools/llvm-reduce/remove-operands.ll @@ -1,20 +1,23 @@ ; Test that llvm-reduce can reduce operands to their default values. ; ; RUN: llvm-reduce --delta-passes=operands --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t -; RUN: cat %t | FileCheck %s +; RUN: cat %t | FileCheck %s --check-prefixes=CHECK-FINAL,CHECK-FINAL-UNDEF +; RUN: llvm-reduce --delta-passes=operands --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t --default-reduced-value=zero +; RUN: cat %t | FileCheck %s --check-prefixes=CHECK-FINAL,CHECK-FINAL-ZERO ; CHECK-INTERESTINGNESS: ret i32 -; CHECK-LABEL: define i32 @main() { +; CHECK-FINAL-LABEL: define i32 @main() { define i32 @main() { -; CHECK-LABEL: lb1: -; CHECK-NEXT: br label %lb2 +; CHECK-FINAL-LABEL: lb1: +; CHECK-FINAL-NEXT: br label %lb2 lb1: br label %lb2 -; CHECK-LABEL: lb2: -; CHECK-NEXT: ret i32 undef +; CHECK-FINAL-LABEL: lb2: +; CHECK-FINAL-UNDEF: ret i32 undef +; CHECK-FINAL-ZERO: ret i32 0 lb2: ret i32 10 } diff --git a/llvm/tools/llvm-reduce/deltas/Delta.h b/llvm/tools/llvm-reduce/deltas/Delta.h --- a/llvm/tools/llvm-reduce/deltas/Delta.h +++ b/llvm/tools/llvm-reduce/deltas/Delta.h @@ -23,6 +23,8 @@ namespace llvm { +Constant *defaultValueForType(Type *Ty); + struct Chunk { int Begin; int End; diff --git a/llvm/tools/llvm-reduce/deltas/Delta.cpp b/llvm/tools/llvm-reduce/deltas/Delta.cpp --- a/llvm/tools/llvm-reduce/deltas/Delta.cpp +++ b/llvm/tools/llvm-reduce/deltas/Delta.cpp @@ -14,6 +14,7 @@ #include "Delta.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/Verifier.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ToolOutputFile.h" @@ -27,6 +28,30 @@ "abort-on-invalid-reduction", cl::desc("Abort if any reduction results in invalid IR")); +enum class DefaultReducedValueType { Zero, Undef }; + +static cl::opt DefaultReducedValue( + "default-reduced-value", + cl::desc("The type of constant to reduce values to"), + cl::init(DefaultReducedValueType::Undef), + cl::values(clEnumValN(DefaultReducedValueType::Zero, "zero", + "Reduce values to 0/null/zeroinitializer"), + clEnumValN(DefaultReducedValueType::Undef, "undef", + "Reduce values to undef"))); + +Constant *llvm::defaultValueForType(Type *Ty) { + if (Ty->isLabelTy()) + return nullptr; + if (Ty->isVoidTy()) + return UndefValue::get(Ty); + switch (DefaultReducedValue) { + case DefaultReducedValueType::Zero: + return Constant::getNullValue(Ty); + case DefaultReducedValueType::Undef: + return UndefValue::get(Ty); + } +} + void writeOutput(llvm::Module *M, llvm::StringRef Message); bool isReduced(Module &M, TestRunner &Test, SmallString<128> &CurrentFilepath) { diff --git a/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp b/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp @@ -71,7 +71,7 @@ if (!ArgsToKeep.count(&A)) { // By adding undesired arguments to the VMap, CloneFunction will remove // them from the resulting Function - VMap[&A] = UndefValue::get(A.getType()); + VMap[&A] = defaultValueForType(A.getType()); for (auto *U : A.users()) if (auto *I = dyn_cast(*&U)) InstToDelete.push_back(I); @@ -81,7 +81,7 @@ if (!V) continue; auto *I = cast(V); - I->replaceAllUsesWith(UndefValue::get(I->getType())); + I->replaceAllUsesWith(defaultValueForType(I->getType())); if (!I->isTerminator()) I->eraseFromParent(); } diff --git a/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp b/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "ReduceBasicBlocks.h" +#include "deltas/Delta.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" @@ -41,14 +42,14 @@ if (auto *IndBI = dyn_cast(Term)) Address = IndBI->getAddress(); - Term->replaceAllUsesWith(UndefValue::get(Term->getType())); + Term->replaceAllUsesWith(defaultValueForType(Term->getType())); Term->eraseFromParent(); if (ChunkSucessors.empty()) { auto *FnRetTy = BB.getParent()->getReturnType(); - ReturnInst::Create(BB.getContext(), - FnRetTy->isVoidTy() ? nullptr : UndefValue::get(FnRetTy), - &BB); + ReturnInst::Create( + BB.getContext(), + FnRetTy->isVoidTy() ? nullptr : defaultValueForType(FnRetTy), &BB); return; } @@ -71,7 +72,8 @@ if (!BBsToKeep.count(SwInst.getDefaultDest())) { auto *FnRetTy = SwInst.getParent()->getParent()->getReturnType(); ReturnInst::Create(SwInst.getContext(), - FnRetTy->isVoidTy() ? nullptr : UndefValue::get(FnRetTy), + FnRetTy->isVoidTy() ? nullptr + : defaultValueForType(FnRetTy), SwInst.getParent()); SwInst.eraseFromParent(); } else @@ -122,7 +124,7 @@ for (auto &BB : BBsToDelete) { // Instructions might be referenced in other BBs for (auto &I : *BB) - I.replaceAllUsesWith(UndefValue::get(I.getType())); + I.replaceAllUsesWith(defaultValueForType(I.getType())); BB->eraseFromParent(); } } diff --git a/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp b/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp @@ -44,8 +44,8 @@ // And finally, we can actually delete them. for (Function &F : FuncsToRemove) { - // Replace all *still* remaining uses with undef. - F.replaceAllUsesWith(UndefValue::get(F.getType())); + // Replace all *still* remaining uses. + F.replaceAllUsesWith(defaultValueForType(F.getType())); // And finally, fully drop it. F.eraseFromParent(); } diff --git a/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp b/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "ReduceGlobalVars.h" +#include "deltas/Delta.h" #include "llvm/IR/Constants.h" #include @@ -37,7 +38,7 @@ if (auto *Inst = dyn_cast(U)) InstToRemove.push_back(Inst); - GV.replaceAllUsesWith(UndefValue::get(GV.getType())); + GV.replaceAllUsesWith(defaultValueForType(GV.getType())); ToRemove.push_back(&GV); } @@ -46,7 +47,7 @@ if (!V) continue; auto *Inst = cast(V); - Inst->replaceAllUsesWith(UndefValue::get(Inst->getType())); + Inst->replaceAllUsesWith(defaultValueForType(Inst->getType())); Inst->eraseFromParent(); } diff --git a/llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp b/llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "ReduceInstructions.h" +#include "deltas/Delta.h" using namespace llvm; @@ -38,7 +39,7 @@ for (auto &BB : F) for (auto &Inst : BB) if (!InstToKeep.count(&Inst)) { - Inst.replaceAllUsesWith(UndefValue::get(Inst.getType())); + Inst.replaceAllUsesWith(defaultValueForType(Inst.getType())); InstToDelete.push_back(&Inst); } diff --git a/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp b/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp @@ -11,26 +11,15 @@ //===----------------------------------------------------------------------===// #include "ReduceOperands.h" +#include "Delta.h" #include "llvm/IR/Constants.h" #include "llvm/IR/InstIterator.h" using namespace llvm; -/// Returns if the given operand is undef. -static bool operandIsUndefValue(Use &Op) { - if (auto *C = dyn_cast(Op)) { - return isa(C); - } - return false; -} - -/// Returns if an operand can be reduced to undef. -/// TODO: make this logic check what types are reducible rather than -/// check what types that are not reducible. -static bool canReduceOperand(Use &Op) { - auto *Ty = Op->getType(); - // Can't reduce labels to undef - return !Ty->isLabelTy() && !operandIsUndefValue(Op); +/// Returns if an operand can be reduced to the given constant. +static bool canReduceOperand(Use &Op, Constant *Reduced) { + return Reduced && dyn_cast(&Op) != Reduced; } /// Sets Operands to undef. @@ -43,9 +32,9 @@ for (auto &I : instructions(&F)) { for (auto &Op : I.operands()) { // Filter Operands then set to undef. - if (canReduceOperand(Op) && !O.shouldKeep()) { - auto *Ty = Op->getType(); - Op.set(UndefValue::get(Ty)); + auto *Reduced = defaultValueForType(Op->getType()); + if (canReduceOperand(Op, Reduced) && !O.shouldKeep()) { + Op.set(Reduced); } } } @@ -58,7 +47,7 @@ for (auto &F : Program->functions()) { for (auto &I : instructions(&F)) { for (auto &Op : I.operands()) { - if (canReduceOperand(Op)) { + if (canReduceOperand(Op, defaultValueForType(Op->getType()))) { Count++; } } diff --git a/llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp b/llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp --- a/llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp +++ b/llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp @@ -33,7 +33,7 @@ for (StringRef Name : SpecialGlobalNames) { if (auto *Used = Program->getNamedGlobal(Name)) { - Used->replaceAllUsesWith(UndefValue::get(Used->getType())); + Used->replaceAllUsesWith(defaultValueForType(Used->getType())); Used->eraseFromParent(); } }