diff --git a/llvm/test/tools/llvm-reduce/remove-invoked-functions.ll b/llvm/test/tools/llvm-reduce/remove-invoked-functions.ll --- a/llvm/test/tools/llvm-reduce/remove-invoked-functions.ll +++ b/llvm/test/tools/llvm-reduce/remove-invoked-functions.ll @@ -6,7 +6,7 @@ define i32 @maybe_throwing_callee(i32 %arg) { ; CHECK-ALL: call void @thrown() ; CHECK-INTERESTINGNESS: ret i32 -; CHECK-FINAL: ret i32 undef +; CHECK-FINAL: ret i32 0 call void @thrown() ret i32 %arg } 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,32 @@ -; Test that llvm-reduce can reduce operands to their default values. +; Test that llvm-reduce can reduce operands ; -; 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: llvm-reduce --abort-on-invalid-reduction --delta-passes=operands-undef --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t +; RUN: cat %t | FileCheck %s --check-prefixes=CHECK,UNDEF +; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=operands-one --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t +; RUN: cat %t | FileCheck %s --check-prefixes=CHECK,ONE +; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=operands-zero --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t +; RUN: cat %t | FileCheck %s --check-prefixes=CHECK,ZERO +; RUN: llvm-reduce --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t +; RUN: cat %t | FileCheck %s --check-prefixes=CHECK,ZERO +; CHECK-INTERESTINGNESS: br label ; CHECK-INTERESTINGNESS: ret i32 -; CHECK-LABEL: define i32 @main() { -define i32 @main() { +%t = type { i32, i8 } + +; CHECK-LABEL: define i32 @main +define i32 @main(%t* %a) { ; CHECK-LABEL: lb1: -; CHECK-NEXT: br label %lb2 +; CHECK: br label %lb2 lb1: + %b = getelementptr %t, %t* %a, i32 1, i32 0 br label %lb2 ; CHECK-LABEL: lb2: -; CHECK-NEXT: ret i32 undef +; UNDEF: ret i32 undef +; ONE: ret i32 1 +; ZERO: ret i32 0 lb2: ret i32 10 } diff --git a/llvm/tools/llvm-reduce/DeltaManager.cpp b/llvm/tools/llvm-reduce/DeltaManager.cpp --- a/llvm/tools/llvm-reduce/DeltaManager.cpp +++ b/llvm/tools/llvm-reduce/DeltaManager.cpp @@ -51,7 +51,9 @@ DELTA_PASS("metadata", reduceMetadataDeltaPass) \ DELTA_PASS("arguments", reduceArgumentsDeltaPass) \ DELTA_PASS("instructions", reduceInstructionsDeltaPass) \ - DELTA_PASS("operands", reduceOperandsDeltaPass) \ + DELTA_PASS("operands-undef", reduceOperandsUndefDeltaPass) \ + DELTA_PASS("operands-one", reduceOperandsOneDeltaPass) \ + DELTA_PASS("operands-zero", reduceOperandsZeroDeltaPass) \ DELTA_PASS("operands-to-args", reduceOperandsToArgsDeltaPass) \ DELTA_PASS("operand-bundles", reduceOperandBundesDeltaPass) \ DELTA_PASS("attributes", reduceAttributesDeltaPass) \ diff --git a/llvm/tools/llvm-reduce/deltas/ReduceOperands.h b/llvm/tools/llvm-reduce/deltas/ReduceOperands.h --- a/llvm/tools/llvm-reduce/deltas/ReduceOperands.h +++ b/llvm/tools/llvm-reduce/deltas/ReduceOperands.h @@ -1,14 +1,10 @@ -//===- ReduceOperands.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 to reduce operands to undef. -// -//===----------------------------------------------------------------------===// #ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEOPERANDS_H #define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEOPERANDS_H @@ -16,7 +12,9 @@ #include "Delta.h" namespace llvm { -void reduceOperandsDeltaPass(TestRunner &Test); +void reduceOperandsUndefDeltaPass(TestRunner &Test); +void reduceOperandsOneDeltaPass(TestRunner &Test); +void reduceOperandsZeroDeltaPass(TestRunner &Test); } // namespace llvm #endif 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 @@ -1,61 +1,41 @@ -//===- ReduceOperands.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 to reduce operands to undef. -// -//===----------------------------------------------------------------------===// #include "ReduceOperands.h" #include "llvm/IR/Constants.h" #include "llvm/IR/InstIterator.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/Type.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); -} - -/// Sets Operands to undef. -static void extractOperandsFromModule(Oracle &O, Module &Program) { - // Extract Operands from the module. +static void +extractOperandsFromModule(Oracle &O, Module &Program, + function_ref ReduceValue) { for (auto &F : Program.functions()) { 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 = ReduceValue(Op); + if (Reduced && !O.shouldKeep()) { + Op.set(Reduced); } } } } } -/// Counts the amount of operands in the module that can be reduced. -static int countOperands(Module &Program) { +static int countOperands(Module &Program, + function_ref ReduceValue) { int Count = 0; for (auto &F : Program.functions()) { for (auto &I : instructions(&F)) { for (auto &Op : I.operands()) { - if (canReduceOperand(Op)) { + if (ReduceValue(Op)) { Count++; } } @@ -64,8 +44,54 @@ return Count; } -void llvm::reduceOperandsDeltaPass(TestRunner &Test) { - errs() << "*** Reducing Operands...\n"; - int Count = countOperands(Test.getProgram()); - runDeltaPass(Test, Count, extractOperandsFromModule); +void llvm::reduceOperandsUndefDeltaPass(TestRunner &Test) { + errs() << "*** Reducing Operands to undef...\n"; + auto ReduceValue = [](Use &Op) -> Value * { + if (isa(Op.getUser())) + return nullptr; + if (Op->getType()->isLabelTy()) + return nullptr; + return isa(*Op) ? nullptr : UndefValue::get(Op->getType()); + }; + int Count = countOperands(Test.getProgram(), ReduceValue); + runDeltaPass(Test, Count, [ReduceValue](Oracle &O, Module &Program) { + extractOperandsFromModule(O, Program, ReduceValue); + }); +} + +void llvm::reduceOperandsOneDeltaPass(TestRunner &Test) { + errs() << "*** Reducing Operands to one...\n"; + auto ReduceValue = [](Use &Op) -> Value * { + // TODO: support floats + if (isa(Op.getUser())) + return nullptr; + auto *Ty = dyn_cast(Op->getType()); + if (!Ty) + return nullptr; + auto *C = dyn_cast(Op); + return (C && C->isOneValue()) ? nullptr : ConstantInt::get(Ty, 1); + }; + int Count = countOperands(Test.getProgram(), ReduceValue); + runDeltaPass(Test, Count, [ReduceValue](Oracle &O, Module &Program) { + extractOperandsFromModule(O, Program, ReduceValue); + }); +} + +void llvm::reduceOperandsZeroDeltaPass(TestRunner &Test) { + errs() << "*** Reducing Operands to zero...\n"; + auto ReduceValue = [](Use &Op) -> Value * { + // TODO: be more precise about which GEP operands we can reduce (e.g. array + // indexes) + if (isa(Op.getUser())) + return nullptr; + if (Op->getType()->isLabelTy()) + return nullptr; + auto *C = dyn_cast(Op); + return (C && C->isNullValue()) ? nullptr + : Constant::getNullValue(Op->getType()); + }; + int Count = countOperands(Test.getProgram(), ReduceValue); + runDeltaPass(Test, Count, [ReduceValue](Oracle &O, Module &Program) { + extractOperandsFromModule(O, Program, ReduceValue); + }); }